Hi people,
I will start to develop a site and one of the features I want to add is to render markdown documents of some entities.
What would you say is the best CakePHP 3 approach to do it?
Do you know any plugin or standard way so solve it?
Hi people,
I will start to develop a site and one of the features I want to add is to render markdown documents of some entities.
What would you say is the best CakePHP 3 approach to do it?
Do you know any plugin or standard way so solve it?
There’s a plugin for it but it hasn’t been updated in years (so might need some updates):
Hi,
Thanks for your answer. I’ll take a look at it.
Pick the PHP markdown parser library that suits your needs. Wrap it into in a light Helper as the plugin @FinlayDaG33k mentioned 1 does. Personally I prefer CommonMarkdown, so I use:
<?php
// ...
use Cake\View\Helper;
use League\CommonMark\CommonMarkConverter;
class CommonmarkHelper extends Helper
{
protected $_converter;
/**
* Parse text as CommonMark
*
* @param string $text text to parse
*
* @return string
*/
public function parse($text)
{
return $this->_getParser()->convertToHtml($text);
}
/**
* Get parser
*
* @return CommonMarkConverter
*/
protected function _getParser()
{
if ($this->_converter !== null) {
return $this->_converter;
}
$this->_converter = new CommonMarkConverter();
return $this->_converter;
}
}
And then in the template:
echo $Commonmark->parse($markdownContent);
Hi Schlaefer, your answer is great and I think it applies the same logic exposed in the plugin that Finlay recommends.
I think I expressed my motivation very poorly in the first post. I don’t want to render Markdown documents. What I want to do is to generate Markdown code based on the data of an entity.
That means something like this https://github.com/FriendsOfCake/cakephp-csvview but for .md output instead of .csv
In fact, I think I have to do exactly what that plugin does.
Understood. In that case a custom view class is probably the right solution. The setup the csview plugin uses is mentioned in the docs here [1]. Then bring your own code to build the representation - in your case the markdown - from the entity.
[1] https://book.cakephp.org/3.0/en/views.html#creating-your-own-view-classes
Thanks Schlaefer. I’ll work it this way and post the results when it’s done!
Finally I implemented this view class:
<?php
namespace App\View;
use Cake\View\View;
use Cake\Datasource\EntityInterface;
class MarkdownView extends View
{
public function loadHelpers()
{
if (isset($this->viewVars['_serialize'])) {
return;
}
parent::loadHelpers();
}
public function render($view = null, $layout = null)
{
if (isset($this->viewVars['_serialize'])) {
return $this->_serialize();
}
if ($view !== false && $this->_getViewFileName($view)) {
return parent::render($view, false);
}
}
protected function _serialize()
{
$content = "";
if (isset($this->viewVars['_header'])) {
$content = $this->_renderHeader($this->viewVars['_header']);
}
$vars = $this->_dataToSerialize($this->viewVars['_serialize']);
$content = $content.$this->_renderContent($vars);
return $content;
}
protected function _renderHeader(array $header) {
$retval = "---\n\n";
foreach ($header as $key => $value) {
$retval = $retval.$key.": ".$value."\n";
}
$retval = $retval."\n\n---\n\n";
return($retval);
}
protected function _renderContent(array $vars, $level = 0) {
$retval = "";
foreach ($vars as $key => $value) {
if (!(strpos($key, "_") === 0) && !(strpos($key, "[") === 0) && !(strpos($key, "*") === 0))
{
if (is_array($value)) {
$retval = $retval.str_repeat("#", $level + 1)." ".$key."\n\n";
$retval = $retval.$this->_renderContent($value, $level + 1);
} else if (is_object($value) && method_exists($value, "toArray")) {
$var = $value->toArray();
$retval = $retval.str_repeat("#", $level + 1)." ".$key."\n\n";
$retval = $retval.$this->_renderContent($var, $level + 1);
} else {
$retval = $retval.str_repeat("#", $level + 1)." ".$key."\n\n";
$retval = $retval."".$value."\n\n";
}
}
}
return($retval);
}
protected function _dataToSerialize($serialize = true)
{
if ($serialize === true) {
$data = array_diff_key(
$this->viewVars,
array_flip($this->_specialVars)
);
if (empty($data)) {
return null;
}
return $data;
}
if (is_array($serialize)) {
$data = [];
foreach ($serialize as $alias => $key) {
if (is_numeric($alias)) {
$alias = $key;
}
if (array_key_exists($key, $this->viewVars)) {
$data[$alias] = $this->viewVars[$key];
}
}
return !empty($data) ? $data : null;
}
return isset($this->viewVars[$serialize]) ? $this->viewVars[$serialize] : null;
}
}
I didn’t make it very configurable and made a lot of assumptions. It works… but it’s main result is that I’m approaching this the wrong way. After doing this, I realize that this is not really a case of serialization, but a case of custom template for each entity. That will give me a lot of options to customize each markdown document.
I appreciate all of your points of view.