Elwinar

Minimalist by design

Minimal template inheritance

2015.04.10

I loved Laravel ever since the third version. I came to use it after CodeIgniter started losing speed, and never looked back. Laravel introduced me to Composer, Eloquent, a great number of Symfony components, and many other patterns of web development. It has it flaws, but the framework is mostly great.

There is only one thing that I never liked about it, and that’s Blade. To be honest, there is others (see here for a raging example of what bugs me). But Blade is a central part of the system. The first reason I don’t like it is that the syntax is simply awful. Second, it’s basically useless: PHP don’t need a templating engine because PHP is by nature a templating engine.

Lets look at a simple example of a piece of a blade template:

<html>
    <head>
        <title>{{ $title }}</title>
    </head>
    <nav>
        <ul>
@if (Auth::check())
            <li><a href="/logout">Logout</a></li>
@else
            <li><a href="/login">Login</a></li>
@endif
        </ul>
    </nav>
    <h1>Welcome</h1>
    <p>You are the {{ $count }} visitor.</p>
</html>

And see the same example using a vanilla PHP:

<html>
    <head>
        <title><?= $title ?></title>
    </head>
    <nav>
        <ul>
<?php if (Auth::check()) { ?>
            <li><a href="/logout">Logout</a></li>
<?php } else { ?>
            <li><a href="/login">Login</a></li>
<?php } ?>
        </ul>
    </nav>
    <h1>Welcome</h1>
    <p>You are the <?= $count ?> visitor.</p>
</html>

The syntax isn’t particularly less readable, and most of the niceties introduced by templating engines shouldn’t be used anyhow. Not that logic-less templates are better than others, but logic in templates should be limited to presentation logic. And you really don’t need all this luxury of conditionals, partials, etc, when you have PHP at hand.

Laravel 3 and 4 had a simple solution, the controller layouts. In short, you grouped your controllers methods in objects, and theses objects could extend a base class that would handle the layout-view mechanism. Poor alternative to real template inheritance, but largely enough for the job.

Controller object are disappearing from Laravel 5. That’s a fact. They are still alive because they are great for automatic code generation, but the tendency is to use anonymous functions to handle routes. The controller layouts therefore disappeared already. So, two options at hand (I don’t like Blade, remember ?):

  1. Re-implement a layout mechanism
  2. Do template inheritance in PHP

I chose the second solution. After all, template inheritance is simple: process your view with its data, and catch the inheritance declaration one way or another (parsing, method call, etc). Then, treat the inherited template as the view, and add the result of the view rendering to the data. Loop until you don’t have a template to inherit from, and return this.

Here is a simple example in PHP using fake functions to get to the point without worrying about framework or other things:

function render($view, $data) {
    global $template;
    $result = make($view, $data);
    while($template !== null) {
        $result = make($template, array_merge($data, [
            '_view' => $result,
        ]));
    }
    return $result;
}

The view just have to set the global var $template to inherit from it. It is rough around the edges, and really basic. You would want to refine it by adding helpers, etc, but the general idea is here.

Based on this code, I made a package for Laravel 5 called Minit, don’t hesitate to check it out (readme coming soon). Here is an example of view using Minit:

<?php extends('app') ?>
<h1>Hello <?= $world ?></h1>

Plain old PHP with template inheritance.

Et voilĂ  !