Zend_Controllerを使ったWebアプリケーションで、リクエストを処理し、クライアントにレスポンスを返す一連の流れの主な通過点を理解するため、ログを出力してみます。
Zend_Front_Controllerに追加できるプラグインという機能を利用します。

自前のプラグインの導入

Zend_Controller_Plugin_Abstractを継承して自前のプラグインクラスを作成します。

postDispatchメソッドで、リクエストオブジェクトのディスパッチフラグを強制的にリセット(setDispatched(false))し、別のアクション(testアクション)にディスパッチされるように設定しています。

BASEDIR/webapp02/MyAppPlugin.php
PHP:
  1. <?php
  2.  
  3. class MyAppPlugin extends Zend_Controller_Plugin_Abstract
  4. {
  5.   private $_registry = null;
  6.   private $_logger = null;
  7.   private $_dispatchCount = 0;
  8.  
  9.   function __construct()
  10.   {
  11.     $this->_registry = Zend_Registry::getInstance();
  12.     $this->_logger = $this->_registry['logger'];
  13.   }
  14.  
  15.   public function routeStartup(Zend_Controller_Request_Abstract $request)
  16.   {
  17.     // 一回のリクエストで一回のみ
  18.     $this->_logger->log('MyAppPlugin::routeStartup()',Zend_Log::DEBUG);
  19.   }
  20.  
  21.   public function routeShutdown(Zend_Controller_Request_Abstract $reques)
  22.   {
  23.     // 一回のリクエストで一回のみ
  24.     $this->_logger->log('MyAppPlugin::routeShutdown()',Zend_Log::DEBUG);
  25.   }
  26.  
  27.   public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
  28.   {
  29.     // ここで将来DB接続してみるつもり。
  30.     //$this->_registry['isDbError'] = true;
  31.  
  32.     // 一回のリクエストで一回のみ
  33.     $this->_logger->log('MyAppPlugin::dispatchLoopStartup()',Zend_Log::DEBUG);
  34.   }
  35.  
  36.     public function preDispatch(Zend_Controller_Request_Abstract $request)
  37.   {
  38.     if ($this->_dispatchCount> 10) {
  39.       // 現ソースでは、ここにくることはない(と思う)
  40.       $request->setDispatched(true);
  41.       return;
  42.     }
  43.  
  44.     if (!empty($this->_registry['isDbError'])) {
  45.       // 仮にDBエラーフラグがあった場合、ErrorコントローラーのdbErrorアクションを実行する
  46.       if ($request->getControllerName() != 'default' &&
  47.           $request->getControllerName() != 'error' &&
  48.           $request->getActionName() != 'dbError') {
  49.         $this->getResponse()->clearBody();// 仮に出力したものがあっても、削除
  50.         $request->setControllerName('error');
  51.         $request->setActionName('dbError');
  52.       }
  53.     }
  54.  
  55.     $this->_logger->log('MyAppPlugin::preDispatch()',Zend_Log::DEBUG);
  56.   }
  57.  
  58.   public function postDispatch(Zend_Controller_Request_Abstract $request)
  59.   {
  60.     $this->_dispatchCount++;
  61.     if (empty($this->_registry['isDbError'])) {
  62.       // ---- testアクションを処理するようにしてみるテスト
  63.       static $i = 0;
  64.       if ($i == 0) {
  65.         $request->setDispatched(false);// ディスパッチフラグをリセットしてみる
  66.         $request->setActionName('test');// testアクションを処理するように変更
  67.         $i++;
  68.       }
  69.       // -----
  70.     }
  71.     $this->_logger->log('MyAppPlugin::postDispatch(). count:' . $this->_dispatchCount,Zend_Log::DEBUG);
  72.   }
  73.  
  74.   public function dispatchLoopShutdown()
  75.   {
  76.     // 一回のリクエストで一回のみ
  77.     $this->_logger->log('MyAppPlugin::dispatchLoopShutdown()',Zend_Log::DEBUG);
  78.     $this->_logger->log('*********************',Zend_Log::DEBUG);
  79.   }
  80. }

このプラグインをフロントコントローラに登録します。

BASEDIR/webapp02/bootstrap.php
PHP:
  1. // 略
  2.   require_once $webapp_dir . '/MyAppPlugin.php';
  3.   $front->registerPlugin(new MyAppPlugin());
  4.  
  5.   try {
  6.     $front->dispatch();
  7.   }
  8.   catch (Exception $exception) {
  9.     v($exception);
  10.   }
  11. // 略

アクションコントローラのpreDispatch、postDispatchもオーバーライドして、ログ出力します。

webapp02/modules/default/controllers/IndexController.php
PHP:
  1. class IndexController extends Zend_Controller_Action
  2. {
  3. // 略
  4.   public function preDispatch()
  5.   {
  6.     parent::preDispatch();
  7.  
  8.     $this->_logger->debug('IndexController::preDispatch(). action: ' . $this->getRequest()->getActionName());
  9.   }
  10.  
  11.   public function postDispatch()
  12.   {
  13.     parent::postDispatch();
  14.  
  15.     $this->_logger->debug('IndexController::postDispatch(). action: ' . $this->getRequest()->getActionName());
  16.   }
  17.  }

サンプルの実行

http;//サンプルインストールドメイン/にアクセスすると、defaultモジュール/indexコントローラ/indexアクションが処理された後、強制的にdefaultモジュール/indexコントローラ/testアクションが処理されることがわかります。

DEBUG (7): MyAppPlugin::routeStartup()
DEBUG (7): MyAppPlugin::routeShutdown()
DEBUG (7): MyAppPlugin::dispatchLoopStartup()
DEBUG (7): MyAppPlugin::preDispatch()
DEBUG (7): IndexController::init(). action: index
DEBUG (7): IndexController::preDispatch(). action: index
DEBUG (7): IndexController::indexAction()
DEBUG (7): IndexController::postDispatch(). action: index
DEBUG (7): MyAppPlugin::postDispatch(). count:1
DEBUG (7): MyAppPlugin::preDispatch()
DEBUG (7): IndexController::init(). action: test
DEBUG (7): IndexController::preDispatch(). action: test
DEBUG (7): IndexController::testAction()
DEBUG (7): IndexController::postDispatch(). action: test
DEBUG (7): MyAppPlugin::postDispatch(). count:2
DEBUG (7): MyAppPlugin::dispatchLoopShutdown()

僕は、アプリケーション全体で必要な共通の処理は、プラグインを使用するつもりです。
例えば、プラグインのdispatchLoopStartup()で、DBへの接続を行うことなどを考えています。

プラグインを2個登録してみる

複数のプラグインを登録した場合、デフォルトでは、プラグインの各メソッドは、フロントコントローラに登録(registerPlugin)した順番に起動されます。
(registerPluginの第2引数で順番を指定できます。)

例えば、次のようにプラグインを登録した場合、プラグインのpreDispatchメソッドは、MyAppPlugin::preDispatch()起動された後に、MySecondPlugin::preDispatch()メソッドが起動されます。

PHP:
  1. $front->registerPlugin(new MyAppPlugin());
  2. $front->registerPlugin(new MySecondPlugin());

サンプルで、2個のプラグインを登録した場合のログ出力は、次のようになります。

DEBUG (7): MyAppPlugin::routeStartup()
DEBUG (7): MySecondPlugin::routeStartup()
DEBUG (7): MyAppPlugin::routeShutdown()
DEBUG (7): MySecondPlugin::routeShutdown()
DEBUG (7): MyAppPlugin::dispatchLoopStartup()
DEBUG (7): MySecondPlugin::dispatchLoopStartup()
DEBUG (7): MyAppPlugin::preDispatch()
DEBUG (7): MySecondPlugin::preDispatch()
DEBUG (7): IndexController::init(). action: index
DEBUG (7): IndexController::preDispatch(). action: index
DEBUG (7): IndexController::indexAction()
DEBUG (7): IndexController::postDispatch(). action: index
DEBUG (7): MyAppPlugin::postDispatch(). count:1
DEBUG (7): MySecondPlugin::postDispatch(). count:1
DEBUG (7): MyAppPlugin::preDispatch()
DEBUG (7): MySecondPlugin::preDispatch()
DEBUG (7): IndexController::init(). action: test
DEBUG (7): IndexController::preDispatch(). action: test
DEBUG (7): IndexController::testAction()
DEBUG (7): IndexController::postDispatch(). action: test
DEBUG (7): MyAppPlugin::postDispatch(). count:2
DEBUG (7): MySecondPlugin::postDispatch(). count:2
DEBUG (7): MyAppPlugin::dispatchLoopShutdown()
DEBUG (7): MySecondPlugin::dispatchLoopShutdown()

サンプルダウンロード

ダウンロードページにアーカイブしたファイルを置きました。

実際に動くものを作って、Zend Frameworkのマニュアル(7.2. Zend_Controller の基本)をみると、理解が深まると思います。

Tags:

コメントをどうぞ