twig:首先渲染子模板,然后传递给父模板

twig: rendering child templates first, then passing to parent template

我是 Twig 的新手,需要检查我在 MVC 中使用它的方式是否是 'correct' 方式。我有一种感觉,它不是;

我想为我站点中的每个区域设置一个控制器,并让每个控制器呈现它们自己的树枝模板。我阅读了有关在 twig 模板中包含 twig 模板的信息,例如:

main.twig

{% include 'header.twig' %}
{% include 'menu.twig' %}
{% include 'content.twig' %}
{% include 'footer.twig' %}

这个问题是我无法 运行 在包含模板之前为每个区域设置单独的控制器。我必须将所有区域的变量一次传递给 main.twig,但我不喜欢这样做。

所以我现在执行以下操作:

  $regions=[];

  //...preprocessing menu items here in a controller...
  $template=$twig->loadTemplate('regions/menu.twig');
  $regions['menu'] = $template->render(array(
    'home' => 'Go to Home',
    'contact' => 'Contact page'
  ));

  //...other regions...

  $template=$twig->loadTemplate('main.twig');
  echo $template->render([
      'regions'=>$regions
  ]);

然后使用原始值打印 main.twig 内的区域:{{regions.menu|raw}}

这样我就可以完全控制传递到每个模板的数据,这正是我想要的。但是我觉得我现在没有按照预期的方式使用 Twig,因为我将渲染 html 保存在变量中,然后再次渲染它。

如果我试图以更好的方式实现,请告诉我。

我认为这会造成大量开销,因为无论何时您想要创建新 page/controller,您总是需要 copy/paste 区域。理想情况下是使用包含包含的主模板,并让您的视图从基础模板扩展。


base.twig.html

<!DOCTYPE html>
<html>
    <head>
        <title>{{ page.title | default('') }}</title>
        <link rel="stylesheet" type="text/css" href="default.css" />
        {% block css %}
        {% endblock %}
    </head>
    <body>
        {% block nav %}
        <nav id="main">
            {% for link in main.links %}
            <a href="{{ link.url }}">{{ link.title }}</a>
            {% endfor %}
        </nav>
        {% endblock %}
        <div id="content">
        {% block content %}
        {% endblock %}
        </div>
        {% block javascript %}
        {% endblock %}
    </body>
</html>

{% extends "base.twig.html" %}
{% block content %}
    <h1>{{ title }}</h1>
{% endblock %}

如果你想为每个区域都有一个控制器,你可以创建一个助手 class,它调用你需要的所有控制器,返回一个由 class 名称定义的 multi-dimensional 数组该地区的。 这样你的变量就永远不会发生冲突,因为你可以通过例如访问它们。 main.title / menu.title / 标题

(代码只是pseudo-code,没有test/run,只是给大家一个思路)

<?php
    $regions = (new \Project\Regions\Container())->addRegion('Main')
                                                 ->addRegion('Menu');

    echo $twig->render('child.html', array_merge($regions->getParameters(), [
        'title' => 'Hello World',
    ]);


    class Container {
        private $regions = [];

        public function __construct($regions = []) {
            $this->regions = $regions;
        }

        public function setRegions($regions = []) {
            $this->regions = $regions;
            return $this;
        }

        public function addRegion($region) {
            if (!in_array($region, $this->regions)) $this->regions[] = $region;
            return $this;
        }

        public function getParameters() {
            $data = [];
            foreach($this->regions as $region) {
                $class = '\Project\Regions\'.$region;
                if (!class_exists($class)) continue;
                $data[strtolower($region)] = (new $class())->getParameters();
            }
            return $data;
        }
    }


<?php   
    namespace Project\Regions;

    abstract class Region {
        public function getParameters() {
            return [];
        }
    }


<?php
    namespace Project\Regions;

    class Page extends Region {
        public function getParamters() {
            return [
                'title' => 'foo',
            ];
        }
    }


<?php   
    namespace Project\Regions;

    class Menu extends Region {
            return [
                'title' => 'bar',
            ];  
    }