Zend Framework 3中如何为不同的模块设置不同的布局

How to set different layouts for different modules in Zend Framework 3

如何在 Zend Framework 3 中为不同的模块设置不同的布局,而不是在整个站点中使用一个相同的布局模板?

您可以使用以下代码在特定控制器操作的布局之间切换:

// A controller's action method that uses an alternative
// layout template.
public function indexAction() 
{
  //...

  // Use the Layout plugin to access the ViewModel
  // object associated with layout template.
  $this->layout()->setTemplate('layout/layout2');

  //...
}

In addition to the Layout controller plugin, there is the Layout view helper which provides the same capabilities. With the Layout view helper, you can, for example, switch layout from the "static" page which has no specific controller action.

设置控制器所有操作的布局

如果控制器class的所有操作方法都需要使用相同的替代布局,您可以覆盖AbstractActionControllerclass的onDispatch()方法并调用setTemplate()方法在那里,如下例所示:

// Add this alias in the beginning of the controller file
use Zend\Mvc\MvcEvent;

// ...

class IndexController extends AbstractActionController 
{
  /** 
   * We override the parent class' onDispatch() method to
   * set an alternative layout for all actions in this controller.
   */
  public function onDispatch(MvcEvent $e) 
  {
    // Call the base class' onDispatch() first and grab the response
    $response = parent::onDispatch($e);        

    // Set alternative layout
    $this->layout()->setTemplate('layout/layout2');                

    // Return the response
    return $response;
  }
}

Reference

Zend Framework - Issue


> You may want to alter the layout based on the current module. This requires (a) detecting if the controller matched in routing belongs to this module, and then (b) changing the template of the View Model. 



The place to do these actions is in a listener. It should listen either to the “route” event at low (negative) priority, or on the “dispatch” event, at any priority. Typically, you will register this during the bootstrap event.

namespace Content;

class Module
{
    /**
     * @param  \Zend\Mvc\MvcEvent $e The MvcEvent instance
     * @return void
     */
    public function onBootstrap($e)
    {
        // Register a dispatch event
        $app = $e->getParam('application');
        $app->getEventManager()->attach('dispatch', array($this, 'setLayout'));
    }

    /**
     * @param  \Zend\Mvc\MvcEvent $e The MvcEvent instance
     * @return void
     */
    public function setLayout($e)
    {
        $matches    = $e->getRouteMatch();
        $controller = $matches->getParam('controller');
        if (false === strpos($controller, __NAMESPACE__)) {
            // not a controller from this module
            return;
        }

        // Set the layout template
        $viewModel = $e->getViewModel();
        $viewModel->setTemplate('content/layout');
    }
}

手册上面说了,但是如果你想使用这些代码,你需要:

// module/Content/config/module.config.php

return [

    /* whatever else */

    'view_manager' => [
        'template_map' => [
            'content/layout' => __DIR__ . '/../view/layout/layout.phtml'

        ]
    ]
];

不久,当所有模块初始化(bootstrap)成功后,Zend会自动调用onBootstrap(),绑定'dispatch'事件到setLayout()方法,其中控制器名称与当前模块的命名空间匹配,如果成功,使用setTemplate()设置布局模板。

例如

Module/Namespace: Content,

Controller: Content\Controller\MatchMeController,(成功!)

Controller: Other\Controller\DontMatchMeController,(失败!)

但是有一个小缺点:setLayout()使用

strpos(controller, __NAMESPACE__) === false

来识别当前模块,但是如果我在其他模块中有 ContentController 怎么办?所以使用

strpos(controller, __NAMESPACE__) !== 0

相反。

------------

Zend Framework - Issue

手册很详细,还提到了很多其他的东西,比如为不同的控制器(或动作)设置不同的布局。