"Deep" template inheritance #47

Open
Giuseppe-Mazzapica opened this Issue Nov 19, 2014 · 2 comments

Projects

None yet

3 participants

@Giuseppe-Mazzapica

Currently, template files can override layout sections only one level deep: included templates (partials) can define sections, but they are not overridable from "main" templates.

Assuming this layout:

<?= $this->fetch('header.php') ?>

<body>
...
</body>

<?= $this->fetch('footer.php') ?>

And following header.php

<html>
<head>

<?php if ( $this->section('styles') ) : ?>
    <?= $this->section('styles') ?>
<?php else: ?>
    <style src="path/to/default/css.css">
<?php endif ?>

</head>

The section "styles" can't be overridden from a template that uses the layout, because when layout includes the partial it creates another template object that is not aware of parent template sections.

In my fork, I added this commit, that, by passing parent template sections to included template objects, allows "deep" inheritance (i.e. inheritance for partials) as seen in Twig and other non-php engines.

If you like it I can write unit test and submit a PR.

Edit
The linked commit has a bug, because template render() method doesn't take name. Fixed here.

@reinink
Member
reinink commented Dec 27, 2014

Hah, sometimes I feel like I'm going in circles. Plates used to work in this way, but many folks found it confusing that nested templates automatically received all other template variables, which is why they became isolated like they are now. Albeit, you're not asking for that, but rather that the sections be shared. I'll need to think about this one a little more, because I believe this would be a backwards breaking change.

One question, have you tried using actual layouts instead? Layouts in Plates do share all sections, and you can even stack layouts for more complex configurations. I believe it would do exactly what you're looking for.

@Giuseppe-Mazzapica

Yes, I use layouts, I use them layout a lot, but I think you didn't understand the problem or, more probably, I didn't explain it well.

First of all let me say that this issue is completely different from partial-specific data VS shared data between partial and templates, because you can pass partial-specific data to partial, but you can't pass partial-specific sections.

In Plates, when using partial, is not possible to use sections at all: start() and stop() methods have no effects in partials, because isn't possible override a section that is defined in a partial.

Let me try to better explain this.

Have a look to this stacked layouts code:

template.php

<html>
<head>
    <title><?=$this->e($title)?></title>
</head>
<body>

    <div id="wrapper">

        <div id="main">
             <?= $this->section('main', 'Welcome to home page') ?>
        </div>

        <div id="sidebar">
             <?= $this->section('sidebar', $this->fetch('default-sidebar') ?>
        </div>

    </div>
</body>
</html>

blog.php

<?php $this->layout('template') ?>

<?php $this->start('main') ?>

    <header>
        <?php if ($this->section('header')): ?>
            <?= $this->section('header') ?>
        <?php else: ?>
             <h1>My Blog</h1>
             <p><em>An awesome blog you will like.</em></p>
        <?php endif ?>
    <header>

    <?php if ($this->section('content')) : ?>
            <?= $this->section('content') ?>
    <?php else : ?>
            <ul id="posts">
                 <?php foreach($posts as $post) : ?>
                     <li><a href="<?= $post->link ?>"><?= $this->e($post->title) ?></a></li>
                  <?php endforeach ?>
            </ul>
    <?php endif ?>

<?php $this->stop() ?>

article.php

<?php $this->layout('blog') ?>

<?php $this->start('header') ?>
    <h1><?= $this->e($post->title) ?></h1>
<?php $this->stop() ?>

<?php $this->start('content') ?>
<article>
    <?=  $this->e($post->content) ?>
    <footer><?=  $this->e($post->date) ?></footer>
</article>
<?php $this->stop() ?>

Here I used stacked layouts with different sections (as seen in Twig or other modern engines) instead of the unique content section that IMHO is a very limited way to implement template inheritance.

As example, in code above, I can create a article-with-slideshow.php template by overriding only the header section, without touching the content section. And please note that this is a very trivial example: create complex views using stacked layouts with only the content section is something impossible. Or is possible with a lot of copy and paste, that is something that should be avoided...

However, in Plates code above just works, and that's awesome.

But now, let's assume I want to create another template: article-adv.php that is identical to article.php but it has an adv frame somewhere in the sidebar.

Going up to layout stack I see that I can override 'sidebar' section with a custom one, e.g.

article-adv.php

<?php $this->layout('article') ?>

<?php $this->start('sidebar') ?>
<?= $this->fetch('adv-sidebar') ?>
<?php $this->stop() ?>

Fine. However, adv-sidebar.php will be just a copy and paste of default-sidebar.php with just a very little modification. But isn't template inheritance all about write DRY templates code?

Having to copy and paste a template to modify only a div is something that a modern template engine should avoid, IMHO.

Now lets assume that default-sidebar.php somewhere contains

<?= $this->section('side-adv', '') ?>

In the file article-adv.php I could just define the section 'side-adv' to add the adv code, but that is not possible in Plates, because any section defined in a partial can't be overridden.

The only way to do that in Plates is to put the default sidebar code directly inside the main template file, instead of in the default-sidebar.php partial.

This means that in Plates you can't use partials and sections togheter that is something allowed by all the modern template engines and, to me, make a lot of sense, as I tried to explain here.

Sorry for the book-sized issue, at least I hope that my point is clear now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment