Laravel: There is a Markdown parser and you don’t know it

“So that’s why it can parse Markdown mails!”

Italo Baeza Cabrera
3 min readApr 15, 2019

Hi! I come from the future! You should read this new article about the Markdown parser included with Laravel.

I know that makes perfect sense to let your users to create text using a WYSIWYG editor like CKEditor, Jodit, TinyMCE, or whatever, but there are occasions where you can’t have that luxury. Markdown is a cheap answer to style text without having to sanitize every tag.

Markdown is also a convenient way to slim the text since HTML tags add more overhead to the text length comparing both. Using Markdown to store text in your database is totally fine, as long its parsed to the view in someway.

Parsing Markdown to HTML can be done through a lot of packages, but Parsedown comes included with Laravel, mainly because this package is used to make mails using Markdown language — the more you know.

Let’s use Markdown then!

In this example, we will allow the user to submit text to our application, but we will allow Markdown text.

So, let’s make a form where the user can write Markdown in our frontend.

<form action="/publish" method="post">
@csrf
<input type="text" name="title" required>
<p>You can write your article using Markdown:</p>
<input type="text" name="text" required>
<button type="submit">Submit this Article</button>
</form>

After that, comes the magic. How we can retrieve the text written in Markdown and parse it as HTML? This is where Parsedown comes into play.

For convenience, we will register the Parsedown as a singleton service in our application, so we can automatically inject it wherever we want, using the app\Providers\AppServiceProvider class. It’s optional, so if you don’t use it anywhere, you can just instance it normally where you require it.

/**
* Register application services.
*
*
@return void
*/
public function register()
{
$this->app->singleton(Parsedown::class);
// ...
}

After that, let’s say in our Article model, we want to take out the Markdown text stored and retrieve it as HTML. No problem, we can use an accessor in our Article Model.

/**
* Get the Article's text as HTML
*
* @return \Illuminate\Support\HtmlString
*/
public static function getTextAttribute($value)
{
return new HtmlString(
app(Parsedown::class)->setSafeMode(true)->text($text)
);
}

The important part here is the HtmlString class. When Blade templates receives an object that implements the Htmlable interface, like the simple HtmlString class, it will use the toHtml() method instead of parsing it as a string.

In this case, your view will receive a HtmlString and return the HTML generated by the Parsedown package, which is very simplistic.

Safe mode?

Yeah, about that. Parsedown comes with a flag called safeMode() that “sanitizes” the output HTML. You can combine this with packages like Purifier to clean what comes out if you want to be 100% sure what is displayed doesn’t break your site, or doesn’t inject scripts.

Caching the parsing

Since the parsing may take some precious computation time, it’s not bad to handle this using hashes and cache, specially when the text to parse is big.

This can be a very basic but useful way to not parse the text every time.

/**
* Get the Article's text as HTML
*
* @return \Illuminate\Support\HtmlString
*/
public function getTextAttribute($value)
{
// Hash the text with the lowest computational hasher available.
$key = 'article|'.$this->id.'|'.hash(MHASH_ADLER32, $value);
// If the cache with this hash exists, return it, otherwise
// parse it again and save it into the cache for 1 day.
return Cache::remember($key, 86400, function () use ($value) {
return $this->parseMarkdownToHtml($text);
})
}
/**
* Get the Article's text as HTML
*
* @return \Illuminate\Support\HtmlString
*/
protected function parseMarkdownToHtml(string $text)
{
return new HtmlString(app(Parsedown::class)->text($text));
}

Of course you can expand on this, like saving the hash to a column in the database, and using that information to forget the old cache and put the new information.

And that’s it. There is no need to install additional packages or create your own parser for your data.

--

--

Italo Baeza Cabrera

Graphic Designer graduate. Full Stack Web Developer. Retired Tech & Gaming Editor. https://italobc.com