Reducing dependencies and expanding Laravel Blade

Posted: 2022-05-05 08:05:06 by Alasdair Keyes

Direct Link | RSS feed


I've recently spent a couple of days moving my site to the latest version of Laravel. There were some problems upgrading through such a large number of major versions which I'll likely do a blog post about later.

Whilst I was re-adding my Composer dependencies I was looking at what I really needed. My blog posts are written in markdown and stored in a the database, the Laravel template engine, Blade, converts them from Markdown to HTML. For this task I was using the parsedown/laravel plugin (https://packagist.org/packages/parsedown/laravel)which uses erusev/parsedown (https://packagist.org/packages/erusev/parsedown)underneath to do the actual markdown processing.

I try to minimise dependencies used for two reasons,

  1. Reduced complexity in the codebase
  2. Reduced attack vectors either from attacks directly against my site or supply chain attacks through PHP's Composer system.

Whilst browsing through the Laravel Docs I noticed that they have an inbuilt Str::markdown (https://laravel.com/docs/9.x/helpers#method-str-markdown) helper which might allow me to do the same thing. Under the hood it uses Commonmark from the PHP League (https://commonmark.thephpleague.com/)

I used a couple of custom options on Parsedown, which I needed to be sure worked with the Laravel version.

$parseDown = Parsedown::instance();
$parseDown->setUrlsLinked(false);
$parseDown->setMarkupEscaped(false);

setUrlsLinked: false means that URLs aren't automatically converted into a href links and setMarkupEscaped: false means that I can include HTML markup in my blog posts if I desire.

After reading through the Common mark docs I the relative options were allow_unsafe_links: true and html_input: allow flag and I'd be set. Although these are defaults for Commonmark, I want to explicitly declare them in case defaults change in future.

I only used markdown in my templates and Parsedown automatically adds a blade directive of @parsedown("# Markdown Title") which I made use of. My first task was to create a Blade directive to process markdown in my templates, I decided on the name processMarkdown()

I created app/Providers/CustomBladeFunctionProvider.

<?php
  
declare(strict_types=1);

namespace App\Providers;

use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;

class CustomBladeFunctionProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot(): void
    {
        // Provide @processMarkdown
        Blade::directive('processMarkdown', function ($parameter) {
            return "<?= rtrim(Str::markdown($parameter, [ 'allow_unsafe_links' => true, 'html_input' => 'allow' ])); ?>";
        });
    }
}

Then added this to my providers in config/app.php.

...
    'providers' => [
        ...
        App\Providers\CustomBladeFunctionProvider::class,
        ...
    ],
...

Then all I needed to do was update my templates from

@parsedown($blogPost->body)
@processMarkdown($blogPost->body)

And then remove the parsedown/laravel dependency to slim down my codebase.


If you found this useful, please feel free to donate via bitcoin to 1NT2ErDzLDBPB8CDLk6j1qUdT6FmxkMmNz

© Alasdair Keyes

IT Consultancy Services

I'm now available for IT consultancy and software development services - Cloudee LTD.



Happy user of Digital Ocean (Affiliate link)


Version:master-28fc6e6b4b


Validate HTML 5