【问题标题】:twig: rendering child templates first, then passing to parent templatetwig:先渲染子模板,然后传递给父模板
【发布时间】:2016-07-13 10:37:48
【问题描述】:

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

我希望我的站点中的每个区域都有一个控制器,并让每个控制器呈现自己的树枝模板。我阅读了有关在树枝模板中包含树枝模板的信息,例如:

ma​​in.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 保存在变量中,然后再次渲染它。

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

【问题讨论】:

  • 为什么不想一次传递所有数据?唯一的其他解决方案是编写一个Twig_Extension,它能够获取每个包含所需的数据。
  • 例如,几个区域可能具有变量“标题”,如果我将所有变量一次性传递给主模板,它们就会发生冲突;或者我必须将所有变量收集在一个深的巨型对象中,这看起来很不方便而且也不漂亮。我对所有其他 MVC 结构的习惯是让每个控制器分别用它自己的变量调用他们的视图,在我看来,这种功能划分是最类似于 MVC 的方式。感谢您提供有关扩展的信息,我将对此进行调查。另外,您认为我目前的方法有什么问题吗?(例如在效率方面)

标签: php templates model-view-controller twig templating


【解决方案1】:

我认为这会导致大量开销,因为每当您想创建新页面/控制器时,您总是需要复制/粘贴区域。理想的做法是使用包含包含的主模板,并让您的视图从基础模板扩展。


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 %}

如果您想为每个区域创建一个控制器,您可以创建一个辅助类来调用您需要的所有控制器,并返回一个由区域的类名定义的多维数组。 这样,您的变量将永远不会发生冲突,因为您可以通过例如访问它们。 main.title / menu.title / 标题

(代码只是伪代码,没有测试/运行它,只是给你一个想法)

<?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',
            ];  
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-04
    • 2019-02-23
    • 1970-01-01
    相关资源
    最近更新 更多