View Rendering

I have seen quite a few examples in which html is rendered using template files. The files tend to be mostly html with bits of php tossed in. Or the template files might actually have their own languages such as Twig.

For a recent project I decided to try using mostly php with bits of html added. Sort of what ReactJS does with component::render().

The results of a soccer tournament are shown here: http://ng2016.zayso.org/results/poolplay

The page is pretty simple. Your basic layout with headers/menus/footer and a content section consisting of a search form, legend, team standings and game results.

The results view code (as well as the entire application) is here: https://github.com/cerad/ng2016/blob/master/src/AppBundle/Action/Results2016/MedalRound/ResultsMedalRoundView.php

Stripped down a bit it looks like:

class ResultsMedalRoundView extends AbstractView2
{
    private $searchForm;

    /** @var  ResultsPool[] */
    private $pools;

    public function __construct(
        ResultsMedalRoundSearchForm $searchForm
    ) {
        $this->searchForm  = $searchForm;
    }
    public function __invoke(Request $request)
    {
        $this->pools = $request->attributes->get('pools');
    
        return new Response($this->renderPage());
    }
    private function renderPage()
    {
        $content = <<<EOD
<div id="layout-block">
{$this->searchForm->render()}
{$this->renderLegend()}
{$this->renderPools()}
</div>
EOD;
       // The base template contains the header/menu/footer
       $baseTemplate = $this->getBaseTemplate();
       $baseTemplate->setContent($content);
       return $baseTemplate->render()
}
private function renderLegend()
{
    return <<<EOD
<div class="results-legend">
<h2>GS=Goals Scored, YC=Caution, RC=Sendoff, TE=Total Ejections</h2>
</div>
<hr>
EOD;
}
private function renderPools()
{
    if (count($this->pools) < 1) {
        return null;
    }
    $html = <<<EOD
<div id="layout-block">
<table class="results" border = "1">
EOD;

    // Pull the header info from the first pool
    $pool = array_values($this->pools)[0];
    $division = $pool->division;
    $program  = $pool->program;
    $html .= $this->renderGameHeader($program,$division);

    foreach($this->pools as $pool) {
        foreach($pool->getGames() as $game) {
            $html .= $this->renderGame($game);
        }
    }
    $html .= <<<EOD
</tbody>
</table>
<br/>
</div>
EOD;

    return $html;
}
// Assorted other render methods

So the form view class is injected and rendered using it’s own render method.

The results view class only has one public method (__invoke) which returns a response object. Don’t be alarmed by the view having access to the request object. In this context, the request is simply used a container for passing data along.

The renderPage method first creates the content html by calling other render methods as necessary. A master page template class is then called to generated the complete html page.

The herdoc syntax (http://php.net/manual/en/language.types.string.php) is used to build up fragments of html. So the templates are still more or less readable while remaining mostly php.

Comments on this approach to rendering html?

I’d say technically it’s a valid approach but I’d be concerned about readability.

First, in standard templates the html code sequence is in most cases very similar to the final source sent to the browser - there is less fragmentation of code and fewer non-html (programmatic) chunks. In a view class like yours the overall code differs much more to what the browser will receive and will make it more difficult to spot common problems like unclosed tags, etc.

Second, keeping html in heredoc quotes usually means your IDE will not syntax-colour it nor provide closing tags correction or html auto-completion.

Third, such views can be hard to read and edit by non PHP programmers. While simple template commands are quite easy to learn by designers (even in pure PHP templates), the concept of classes, methods and other OOP stuff may be a bigger barrier.

What were you trying to achieve with this method? I think it might work in some very specific scenarios where html code needs a lot of complex presentation programming logic because programming is obviously more flexible in PHP than in template languages. But I wouldn’t recommend it as a general practice.

Mostly I wanted to see what an alternative approach to Twig would look like. Been using Twig for 5+ years now and it is certainly one of the top template systems but it has things which annoy me. For comparison, here is a Twig version from an earlier tournament: https://github.com/cerad/ng2014/blob/master/src/Cerad/Bundle/TournBundle/Resources/views/Results/PoolPlay/ResultsPoolPlayIndex.html.twig

Twig templates are file based which means basically implementing a version of autoloading just to find your files. Twig supports this sort of stuff with namespaces but I always found it to be a bit awkward. By convention you would solve this by storing your templates in a dedicated directory but I would rather have my templates be stored with the rest of my code.

Templates cannot be injected into other templates. In the example shown, the form template is pretty much standalone and could be used in other pages. To do this in twig requires including the form template which ends up linking the results template directly to it’s search form template. I’m just more comfortable with dependency injection.

I like breaking up large tasks into smaller tasks. If I need to render a list of games I’ll use one template for the table and then another template for each row (i.e. individual game). In some cases, I’ll use templates for individual columns. Hence the set of render methods in the example. For twig you would do this by including sub templates which results in additional files. Just makes things harder to manage.

As with all template languages, twig has rather limited support for actually programming. Even simple filters, transforms, loops etc are a bit awkward at best. Twig solves this by allowing for the creation of extensions. Twig extensions are basically global functions designed to be accessed from inside of twig templates. I found myself writing quite a few of these functions which, being global, can be difficult to manage. And it was yet another file deal with.

I think the biggest impetus was dissatisfaction with the Symfony forms system. The Symfony form component works great when used as designed but I found it extremely difficult to extend to other use cases. Just plain frustrating. And then to render the form required using special twig functions. You pretty much had to accept the layouts generated. Even making small changes was awkward and difficult to maintain. And if you try to adjust the templates themselves you would enter a surreal world of twig templates calling twig extensions which in turn call other templates and then those call more extensions. I could never get my head around the entire form rendering system which made moving to more javascript functionality more challenging then it needed to be.

So when I saw the way React allows you to render form components using it’s jsx templates I decide to give it a try in php. For me it turned out to much easier to render forms the way I wanted them to be. And once I was rendering forms then it was a pretty small step to rendering everything.

Apologies for the long post but hey, you asked.

Sorry for replying late, I’ve been quite busy recently,

I’ve been mostly using Smarty but I tried Twig in a few projects and I found it a bit more clumsy than Smarty. I’m not sure about Twig but in Smarty you can create local template functions, which are actually written in the template language and exist only in the scope of a single template. They can be more manageable than global template functions. Or, you can easily capture (like with ob_start() ) a piece of template code and reuse it locally multiple times. Or, pass parameters to included templates and effectively treat them like separate functions.

However, these are only minor implementation details and this doesn’t solve the bigger problem you are trying to tackle. It looks like you want to use full power of an OO programming language for creating and organizing your templates. I think this is a valid approach and has the potential of being more flexible than any template language since you can split your code in logical chunks, make them reusable and use dependency injection and other programmatic stuff at your disposal.

The question is - why hasn’t this approach become more widespread? I think one of the reasons may be that such templates require good OOP skills, which may not be common among front-end coders. Another reason might be because including HTML code in PHP doesn’t look elegant - the best you can do is use heredoc syntax; sometimes you can get out of PHP mode and in back again and this way get some syntax colouring in IDE but still this doesn’t look very nice. Whereas, in template systems, especially when you use template inheritance the overall code layout looks much simpler.

And the last reason - maybe most people don’t feel the need for this? My experience is that templating logic is usually simpler than back-end programming logic and the simple tools provided by template engines work just fine. Your idea of splitting the template into smallest parts like each row or column being a separate template is nice but I’ve never found it to be a critical issue. On the one hand you gain greater separation and reusability and on the other more fragmentation of code and potentially making it harder to read at first glance. Including template files and using template functions has been good enough for me and I like the fact that a HTML coder can look at the templates and find his way relatively easy.

Having said that, I think the best way to find out is to try it out - if you do a project using OO templating in PHP it will be great to hear about your experience! Actually, once I thought about the same thing as you, however I’ve never found enough reasons to try it in practice.

I was actually curious how the Symfony forms work in real life :smiley: I might hold off for now…

Thanks for the feedback. Every two years the American Youth Soccer Organization hosts a rather large soccer tournament. About 240 teams from across the country. In 2014 they actually had two full size tournaments running at the same time.

I have been fortunate enough to provide the software for the last three tournaments. I use these events as a test platform for trying out different ideas.

Here is the source for the 2016 tournament: https://github.com/cerad/ng2016
Complete source warts and all. It uses the view rendering process described in this post. Overall I think the code organized well though the real test will come in a couple of years when I need to update it.
The site itself is still active at: http://ng2016.zayso.org/welcome

Here is the source for the 2014 tournament:
https://github.com/cerad/ng2014
It uses a more conventional Symfony approach with twig templates, forms and doctrine entities. Fair warning, the code organization is a complete mess. We were trying to generalize things but it did end well. The tournament itself was fine.

Here is a typical twig schedule template from 2014:
https://github.com/cerad/ng2014/blob/master/src/Cerad/Bundle/TournBundle/Resources/views/Schedule/Official/ScheduleOfficialList.html.twig

Not difficult to read but it is just one of six scheduling templates. Lot of copy/pasting and some of them got pretty hairy,

Here is the single schedule template used in 2016:
https://github.com/cerad/ng2016/blob/master/src/AppBundle/Action/Schedule2016/ScheduleTemplate.php

More difficult to read but this one file basically generates six different schedule views. Time will tell which approach I continue with.

I have not tried Twig but I have Smarty (unfortunately). I think many times templating engines do more harm than good, and 99.9% of the times are too overkill and even make harder to get the job done. I prefer to keep it simple with a small templating utility function that simply takes in a template file location and an array of available variables to the template scope i.e.

public static function template($file, $vars)
    {
        $rv = '';
        if(is_array($vars))
        {
            foreach ($vars as $name => $val)
            {
                $varName = self::formatVarName($name);
                
                $$varName=$val;
            }
        }
        if(is_file($file))
        {
            ob_start();
            include($file);
            $rv = ob_get_clean();
        }
        else
        {
            throw new Exception("Invalid template file given: ". $file);
        }
        return $rv;
    }

For me the code above does the job and does it pretty fast and without any unwanted features. I have a function that prepares the variables (to reduce the logic in the template file) and calls the template. It is simple and helps me keep stuff in focus. I find the overcomplexity of templating engines not enjoyable in the least. Plus there is a big overhead per each one of your templates, which anyways would most probably use 1% of the features offered

Looks good to me! Given the constraints of php I think you did a good job with separating the concerns. Looks a bit messy sometimes but this is unavoidable when mixing php with html, template code also has its share of readability problems. Hard to really choose the winner, we can only assess it after maintaining a site for a longer period and see how it affects maintenance work. I think for a skilled OO programmer this can be a very convenient and flexible coding style.

But your code example presents a templating engine (albeit a very simple one), which is conceptually the same as Twig or Smarty, except it uses php as template language. This discussion is not about differences between templating engines but about not using templates at all - instead having view rendering classes using OOP to output html code.

Yes but I do find, probably, that by simplifying the template engine bit it will be easier not to lose the focus in the controller and model logic.

But controllers and models should be independent from the templates anyway, so it shouldn’t matter how complex your template engine is - the controllers and models are unaffected.

The views also have their logic that is concerned with the display - and this logic should not creep out to the controllers or models. If your views are composed only of templates then no matter how simple or complex your template engine is you have to include the same view logic in them.

This situation would be different if your templates were just a part of your views, for example the views being composed of php classes (one layer) and those classes using templates in certain parts (second layer). Then you might have some leeway in putting the display logic into one or the other layer in a gradual manner - for example, if you have a complex template engine then you might put more logic into templates (because they can handle the logic elegantly), and if your template engine is very basic then you might put the logic in the view classes and use the templates only as a very basic and dummy html generation tool. @ahundiak got rid of that template layer altogether leaving only the view classes.

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.