在Twig模板中包含控制器,而不是在其他模板中


Including controllers in Twig templates, rather than other templates

据我所知,像Twig这样的模板引擎的主要设计思想是从视图中删除所有PHP代码,并让呈现视图的控制器设置视图中所需的所有参数。

但是,假设一个视图由不同的"块"组成:一个页眉、一个页脚、一个购物车和一个产品列表。您可以让order_controller.php检查客户是否已登录(因为如果没有登录,则头部不包含链接"Log off"),以及获取所有可用产品的列表(以在产品块中显示它们),以及在$_SESSION中获取购物车的内容(以在购物车块中显示它们)。

但是,让order_controller只获取一个东西可能更有趣:产品列表。然后由控制器呈现的视图将包含其他块(页眉、页脚和购物车)的不同include,但它们不会包含它们的视图。他们将包括其他控制器(showheader_controller, showfooter_controller和showcart_controller),这反过来会呈现他们自己的单个块(showheader_controller将只呈现头视图等…)。简而言之:你应该在主视图中包含渲染视图的控制器。检查客户是否登录的逻辑将是showheader_controller,原因很简单,头视图是唯一需要知道这一点的视图。从$_SESSION加载购物车内容的逻辑应该是showcart_controller,因为购物车视图是唯一需要访问此数据的视图,等等……

这样,您就可以拥有大量显示标题的控制器,但不是让每个控制器重复检查客户是否登录的逻辑,而是将它放在一个地方(呈现标题视图的控制器)。如果有一个Twig函数可以在视图的那个点上包含任何外部源,问题就会解决(因为我可以只包含其他控制器),但它只允许包含其他模板(不能包含php逻辑,否则它会有点破坏目的)。

我现在解决这个问题的方法是让order_controller有这个逻辑:

  • 获取产品列表
  • 启动输出流缓冲(ob_start())
  • 包含渲染标题的控制器(showheader_controller)
  • 将缓冲区的内容存储在$headerView变量中
  • 清理缓冲区
  • 启动输出流缓冲(ob_start())
  • 包含渲染购物车的控制器(showcart_controller)
  • 将缓冲区的内容存储在变量$cartView中。
  • 清理缓冲区

在视图中,我输出设置的变量的内容:

{{ headerView | raw }}

必须添加raw-filter,因为headerView变量包含html标签。

它工作得很好,但并不完全"整洁"。

我的问题是:有没有更好的方法来实现这个策略?

首先,这可以通过更好地实现MVC分离来简化。控制器的工作几乎仅仅是对事件作出反应,并促使模型对该事件作出适当的反应。控制器的工作不是与视图牵手,视图也不是完全依赖于控制器。

模型是您的核心应用程序,建模您的应用程序应该做的所有事情。视图的工作是可视化应用程序中正在发生的事情,为用户提供与之交互的东西。控制器只是用户和应用程序之间的一个小粘合剂,它让用户控制应用程序。

因此,控制器对诸如"用户访问过的主页"之类的事件作出反应,触发模型中必要的事件,这导致视图更新以表示应用程序的新状态。视图可以做它需要做的任何事情。视图不仅仅是一个Twig模板。视图可以与模型对话以获取更多信息。最后,不是控制器需要向Twig模板发送必要的数据,而是视图需要在呈现模板之前为模板设置必要的数据。控制器代码少,视图代码多。

如果你想让它更模块化,你可以定义自定义的Twig标签或函数,它们可以从需要获取的任何地方获取必要的数据。例如:

<div class="head">{{ user_login_status() }}</div>

user_login_status是一个Twig扩展函数,可以与模型对话以获取显示状态所需的数据。

希望你明白。

相关文章: