Pages

2013年8月28日水曜日

ZendFramework2 モジュール毎の共通処理を追加

以前からモジュール毎のレイアウト指定については
http://developer.unlax.com/2012/11/modulelayout.html
などで、ちょこちょこ調べてたんですが、
今回もモジュール単位の共通処理を追加したくてちょっと調べました。

具体的にやりたかった事は

  • 基本レイアウト指定
  • 404エラー時のレイアウト指定

とりあえずはこんなところでした。

まずどのタイミングで指定するかなんですが、これは MvcEvent クラスの定数を確認。

すると、下記の7つがありました。

  1. MvcEvent::EVENT_BOOTSTRAP
  2. MvcEvent::EVENT_DISPATCH
  3. MvcEvent::EVENT_DISPATCH_ERROR
  4. MvcEvent::EVENT_FINISH
  5. MvcEvent::EVENT_RENDER
  6. MvcEvent::EVENT_RENDER_ERROR
  7. MvcEvent::EVENT_ROUTE
次に順番を確認すると

通常の時

  1. route
  2. dispatch
  3. render
  4. finish

エラー(404)の時

  1. dispatch.error
  2. render
  3. finish
EVENT_RENDER_ERROR はビュー側の処理でエラーの時に通るのかな。。って今回は必要無いの調べてないです。
EVENT_BOOTSTRAP は今回 Module.onBoot() 内で確認したので、取れませんでした。

で、結局どうしたかと言うと1分の画面で違うレイアウトを指定はやっぱり

$this->layout('layout/layout2');
※詳しくは下記などを参考に
http://web-terminal.blogspot.jp/2013/03/layoutpluginzendframework2zf2.html

のよう指定できるようにはしておきたいので、
「基本レイアウト指定」については MvcEvent::EVENT_ROUTE でやりました。
MvcEvent::EVENT_DISPATCH でやってるサンプルも見ましたが、それだと上記の指定時にちょっと処理入れないとダメなので。。

で、「404エラー時のレイアウト指定」については MvcEvent::EVENT_DISPATCH_ERROR でステータスコードをチェックしてやりました。

サンプル

Module.php

<?php
namespace Application;

use Zend\Mvc\MvcEvent;

class Module
{
    public function onBootstrap(MvcEvent $e)
    {
        $eventManager        = $e->getApplication()->getEventManager();
        $moduleRouteListener = new ModuleRouteListener();
        $moduleRouteListener->attach($eventManager);
        $eventManager->attach(MvcEvent::EVENT_ROUTE, array($this, 'setLayout'));
        $eventManager->attach(MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'setErrorLayout'));
    }

    public function setLayout($e)
    {
        $matches    = $e->getRouteMatch();
        $controller = $matches->getParam('controller');
        if (0 !== strpos($controller, __NAMESPACE__ .'\\')) {
            return;
        }
        $e->getViewModel()->setTemplate(strtolower(__NAMESPACE__) . '/layout/layout');
    }

    public function setErrorLayout($e)
    {
        $response = $e->getResponse();
        if ($response->getStatusCode() == 404) {
            $e->getViewModel()->setTemplate(strtolower(__NAMESPACE__) . '/error/404');
            return;
        }
    }

    public function getConfig()
    {
        return include __DIR__ . '/config/module.config.php';
    }

    public function getAutoloaderConfig()
    {
        return array(
            'Zend\Loader\StandardAutoloader' => array(
                'namespaces' => array(
                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
                ),
            ),
        );
    }
}

Application/config/module.config.php

上記修正により 'layout/layout' では通らなくなったので、'application/layout/layout' に変更。

    'view_manager' => array(
        'display_not_found_reason' => true,
        'display_exceptions'       => true,
        'doctype'                  => 'HTML5',
        'not_found_template'       => 'error/404',
        'exception_template'       => 'error/index',
        'template_map' => array(
            'layout/layout'           => __DIR__ . '/../view/layout/layout.phtml',
            'application/index/index' => __DIR__ . '/../view/application/index/index.phtml',
            'error/404'               => __DIR__ . '/../view/error/404.phtml',
            'error/index'             => __DIR__ . '/../view/error/index.phtml',
        ),
        'template_path_stack' => array(
            __DIR__ . '/../view',
        ),
    ),
↓↓↓↓↓↓↓
    'view_manager' => array(
        'display_not_found_reason' => true,
        'display_exceptions'       => true,
        'doctype'                  => 'HTML5',
        'not_found_template'       => 'error/404',
        'exception_template'       => 'error/index',
        'template_map' => array(
            'application/layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
            'application/index/index'   => __DIR__ . '/../view/application/index/index.phtml',
            'application/error/404'     => __DIR__ . '/../view/error/404.phtml',
            'application/error/index'   => __DIR__ . '/../view/error/index.phtml',
        ),
        'template_path_stack' => array(
            __DIR__ . '/../view',
        ),
    ),

Mod2/config/module.config.php

mod2/layout/layout ファイル名はモジュール毎に用意デフォルトを用意するという事で、 mod2 の module.config.php を編集しました。

    'view_manager' => array(
        'template_map' => array(
            'mod2/layout/layout'       => __DIR__ . '/../view/layout/layout.phtml',
            'mod2/error/404'           => __DIR__ . '/../view/error/404.phtml',
        ),
        'template_path_stack' => array(
            'admin' => __DIR__ . '/../view',
        ),
    ),

2013-08-24 追記

上記の方法ダメでした。。
ちょっと各モジュール毎のModule.phpの動きを勘違いしていました。。

という事で config には上記の用に 'mod2/layout/layout' を追記しておきsetTemplateはコントローラー毎に onDispatch を上書きする事にしました。
モジュール毎に共通化するなら継承用のクラスを用意してそこに onDispatch を記述するかですかね。。

ついでに謎になったのが、アクションが無いってエラーとその他の404系は違う扱いなんですね。。

というかアクセスした Module.php だけ読み込んでくれたらいいのにな。。
以下サンプル。 return parent::onDispatch($e); 内でアクション内の処理が実行されるので、それより前に書いておけばアクション内で指定するもので上書きされるので、 一部だけレイアウト指定した時に意識する必要は無いです。

IndexController.php

    public function onDispatch(MvcEvent $e)
    {
        $e->getViewModel()->setTemplate('mod2/layout/layout');
        return parent::onDispatch($e);
    }

Followers