thephpleague / plates

Native PHP template system
https://platesphp.com
MIT License
1.47k stars 180 forks source link

Default Layout Extension #183

Closed ragboyjr closed 6 years ago

ragboyjr commented 6 years ago

If a template doesn't specify a layout, then look in the current directory for a file named _layout.phtml, this will be the default layout used.

123

ragboyjr commented 6 years ago

Implementation wise, I think this would best be solved by creating a new RenderTemplate that decorates the RenderTemplates and will inject a default layout which will be used.

carbontwelve commented 6 years ago

Just throwing in my two cent to this: I commonly configure my view folders with the following layout:

.
└── views/
    ├── _templates/
    |   └── default.phtml
    └── page.phtml

In this case it would be useful to specify a default path for Plates to go looking for the default layout.

ragboyjr commented 6 years ago

This is now implemented in the v4.0-dev branch. You just set the default_layout_path config value which determines where to look for the default layout if no layout was given. Any valid template name will work, so you can give a relative path or non-relative.

ragboyjr commented 6 years ago

Reopening since i've found a few flaws in testing.

We need to fix this behavior so that only the root template will have a default layout, else, don't apply it.

ragboyjr commented 6 years ago
<?php

namespace League\Plates\Extension\LayoutSections;

use League\Plates;

final class DefaultLayoutRenderTemplate extends Plates\RenderTemplate\RenderTemplateDecorator
{
    private $layout_path;

    public function __construct(Plates\RenderTemplate $render, $layout_path) {
        parent::__construct($render);
        $this->layout_path = $layout_path;
    }

    public function renderTemplate(Plates\Template $template, Plates\RenderTemplate $rt = null) {
        $ref = $template->reference;
        $contents = $this->render->renderTemplate($template, $rt ?: $this);

        if ($ref()->get('layout') || $ref()->parent) {
            return $contents;
        }

        $layout = $ref()->fork($this->layout_path);
        $ref()->with('layout', $layout->reference);

        return $contents;
    }

    public static function factory($layout_path) {
        return function(Plates\RenderTemplate $rt) use ($layout_path) {
            return new self($rt, $layout_path);
        };
    }
}
ragboyjr commented 6 years ago

Also, we'll need to add the ability to opt-out of a default layout per individual template. You can always set/override the layout, but no way to actually opt-out of one just yet. Maybe we could just utilize an attribute for no_layout which the DefaultLayoutRenderTemplate will check.