CodeIgniterでRailsライクなbefore/afterフィルターを

CodeIgniterでRailsライクなbefore/afterフィルターを実現するライブラリを見つけたんでメモ。

導入

https://github.com/zackkitzmiller/codeigniter-filter
からファイルをダンロードし、
/config/hooks.phpの中身を/application/config/hooks.phpに追加。
/hooks/Filter.phpを/application/hooks/に移動。
以上で終了。

使い方

コントローラーのメンバ変数として$before_filterと$after_filerを定義する。ここにフィルターとして実行されるアクションとフィルターの適用対象を記述する。
actionだけを指定すればコントローラー内のすべてのpublicメソッドにフィルターが適用される。Railsのようにonly, exceptで適用対象を限定することも可能。
beforeフィルターはコントローラーのコンストラクタが呼ばれた直後に、afterフィルターはアクションが実行された直後に実行される。

<?php
var $before_filter = array( 
     'action' => 'name_of_method_for_before_filter',
     'except' => array('index', 'logout');
);
var $after_filter = array( 
     'action' => 'name_of_method_for_after_filter',
     'except' => array('index', 'logout');
);


フィルターを複数指定することも可能。

<?php
var $before_filter = array();

$before_filter[] = array(
     'action' => 'before1',
     'except' => array('index', 'logout');
);

$before_filter[] = array(
     'action' => 'before2',
     'except' => array('index', 'logout');
);

この時のフィルターの適用順序は、配列の先頭からとなる。

<?php

class Test extends CI_Controller {
    
    var $before_filter = array();
    
    var $after_filter = array();
        
    function __construct() {
        parent::__construct();
        
        $this->load->helper('url');
        
        $this->before_filter[] = array(
            'action' => '_before_filter_run', // 直接実行されないように、フィルタ用アクションはprivateにしておこう
            'except' => array('home')
        );
                
        $this->after_filter[] = array(
            'action' => '_after_filter_run',
            'only' => array('sent_away')
        );
    }
    
    function index() {
        echo 'You made it to the index';
    }
    
    function home() {
        echo 'This is home<br/>';
        echo 'You may try going to the '.anchor('/test/index/', 'index'). ' of this controller.<br/>';
        echo 'The before_filter will execute the before_filter_run method before the controller action is executed.<br/>';
        echo 'It is demonstrated by having before_filter_run redirect to sent_away if the action is "index" <br/>';
    }
    
    function sent_away() {
        echo "You've been sent here by the before_filter_run action, called by the before_filter!<br/>";
        echo anchor('/test/home/', 'Click here to return to the test controller home');
    }
    
    function _before_filter_run() {
        
        $filter = array('index');
        
        if ( in_array($this->router->fetch_method(), $filter) ) {
            redirect('/test/sent_away/');
        } else {
            return true;
        }
    }
    
    function _after_filter_run() {
        echo '<br/>This text is generated from the after_filter_run method';
    }
}