zz log

zaininnari Blog

(cakephp)コンポーネントの有効無効を行う enabled プロパティ

コントローラーの components プロパティに沿って、コンポーネントが読み込まれますが、コンポーネントの 「startup」「beforeRender」「beforeRedirect」「shutdown」メソッドを実行する際、各コンポーネントの enabled プロパティがチェック($component->enabled === true)され、各メソッドの実行を制御できます。

おさらい:例として、アクセスから Auth コンポーネントの認証まで

  • ソースは cakephp 1.3.2 より
  • projects コントローラーの add アクションは認証が必要な処理

「projects/add」にアクセス、mod_rewrite で「/index.php?url=projects/add」に振り替えが行われます。
[app/webroot/index.php]

  • コアライブラリ等を読み込み、Dispatcher::dispatch() に処理が移ります。

[cake/dispatcher.php]Dispatcher::dispatch

  • ルーティングを行い( $this->params )、projects コントローラーのインスタンス を作成( $controller )します。
  • $this->_invoke($controller, $this->params); に処理が移ります。

[cake/dispatcher.php]

<?php
  function _invoke(&$controller, $params) {
// モデルを読み込みとコンポーネントの読み込みを行います。
    $controller->constructClasses();
// ・コンポーネントの初期化(Component::initialize)、
// ・controller::beforeFilter の実行、
// ・コンポーネントの実行($this->Component->triggerCallback('startup', $this))
// を行います。
    $controller->startupProcess();
//以下略
  }

まずは、
$controller->constructClasses() を詳しく見て、
その後、
$controller->startupProcess() を詳しく見ます。
[cake/libs/controller/controller.php]

<?php
  function constructClasses() {
    $this->__mergeVars();
// ここで、コンポーネントの読み込みが行われます。
    $this->Component->init($this);
// これ以降は、モデルの読み込みのため、略。
  }

$this->Component->init($this); を詳しく見ます。
[cake/libs/controller/component.php]

<?php
  function init(&$controller) {
    if (!is_array($controller->components)) {
      return;
    }
    $this->__controllerVars = array(
      'plugin' => $controller->plugin, 'name' => $controller->name,
      'base' => $controller->base
    );
// ここでコンポーネントの実際の読み込みが行われます。
    $this->_loadComponents($controller);
  }

  function _loadComponents(&$object, $parent = null) {
// ここまで略
      if ($parent === null) {
// $this->_primary は、読み込んだコンポーネント名のリストです。
// 例 : array('Security', 'Auth', 'Session')
        $this->_primary[] = $component;
      }

      if (isset($this->_loaded[$component])) {
// 略
      } else {
        if ($componentCn === 'SessionComponent') {
          $object->{$component} =& new $componentCn($base);
        } else {
          $object->{$component} =& new $componentCn();
        }
// ここで、enabled プロパティが設定されます。
// これの問題点は後述。
        $object->{$component}->enabled = true;
// $this->_loaded は、読み込んだコンポーネントのリストです。
// 例 : 
// array(
//   'Security' => object(SecurityComponent),
//   'Auth' => object(AuthComponent),
//   'Session => object(SessionComponent),
// )
        $this->_loaded[$component] =& $object->{$component};
        if (!empty($config)) {
          $this->__settings[$component] = $config;
        }
      }
  }

[cake/libs/controller/controller.php]

<?php
  function startupProcess() {
// コンポーネントの初期化
// *Controller->components にあるコンポーネントクラスの初期化を実行します。
    $this->Component->initialize($this);
// *Controller::beforeFilter の実行
// ここでは、 ProjectsController::beforeFilter を実行します。
// 「$this->Auth->allow('index', 'view');」 が記述してあるとし、
// Auth コンポーネントに認証を必要としないアクションは、 「index」「view」であることを伝えます。
// つまり、「add」アクションは、認証が必要なアクションとなります。
    $this->beforeFilter();
// コンポーネント startup メソッドを実行します。
// beforeFilter の後、コントローラーアクションの前に呼ばれます。
    $this->Component->triggerCallback('startup', $this);
  }

$this->Component->triggerCallback('startup', $this)) を詳しく見ます。
[cake/libs/controller/component.php]

<?php
// コンポーネントの為の call_user_func() のようなコールバック関数をコールするメソッドです。
  function triggerCallback($callback, &$controller) {
// $this->_primary は、読み込んだコンポーネント名のリストです。
// 例 : array('Security', 'Auth', 'Session')
// $this->_loaded は、読み込んだコンポーネントのリストです。
// 例 : 
// array(
//   'Security' => object(SecurityComponent),
//   'Auth' => object(AuthComponent),
//   'Session => object(SessionComponent),
// )
    foreach ($this->_primary as $name) {
// コンポーネントインスタンスを取得します。
      $component =& $this->_loaded[$name];
// $component->enabled は、
// コンポーネントの読み込み時に、強制的に設定される値(true)です。
// ここでは、
// controller::beforeFilter で、コンポーネントの有効無効を設定できます。

// 問題点 : enabled プロパティの存在が気づきにくい。
// API 集に基本的に記載なし、
// 元々、
// コンポーネントクラスやその親の Object クラスにもプロパティが書かれていないため、気づきにくい。
// ・RequestHandlerComponent には、プロパティがあるので類推する「var $enabled = true;」
// ・[cake/libs/controller/component.php]のソースを読む
// ・英語版 cake book の 3.6.2 Configuring Components の
//   「You can disable the callbacks triggering by setting the enabled property of a component to false.」
//   の1行を見逃さない。(執筆時、日本語版には記載がなかった)
// のいずれかで判別する必要がある。

// $component クラスに 'startup' メソッドがあり、コンポーネントが有効になっている場合、
// startup メソッドを実行する。
// ここで、AuthComponent::startup が呼ばれることになる。
      if (method_exists($component, $callback) && $component->enabled === true) {
        $component->{$callback}($controller);
      }
    }

AuthComponent::startup を詳しく見ます。
[cake/libs/controller/components/auth.php]

<?php
  function startup(&$controller) {
// この中で、認証処理
// 略
  }

その他

enabled プロパティを使って、Authコンポーネントのパスワードハッシュ化回避を行おうと試みるものの、
startup メソッドをトレースすることになるので、 意味なかった(´・ω・`)