とあるプログラマの備忘録

都内某所に住むプログラマが自分用に備忘録を残すという趣旨のブログです。はてなダイアリーから移動しました!

自作フィルターの作成

詳しくは本家のサイトを参照してもらいたいのですが、
今まではSessionフィルターとかDIContainerフィルターとかを散々使って実装していたわけですが、
既存のフィルターだけではカバーしきれない箇所(ユーザー認証とか)を
毎回クラスので呼び出していたらきりがないので、
「action」が実行される前に「必ず動くフィルター」を今回実装する方法を教えてもらったので覚書

まずはフィルタークラスを作成します。

$ samurai add-filter kakeibo

今回は覚えるように家計簿を使ってるので、名前はkakeibo実際何でもOKっす。


そしたら、ドキュメントルートのsamurai.ymlファイルに以下のように作ったフィルターを追加します。

kakeibo : 

これで下位層のすべてのactionに反映されるようになります。

そしたらさっき作ったフィルターを作成に入ります。
パスは/kakeibo/component/filter/ここにできているはず。

<?php
/**
 * [[機能説明]]
 * 
 * @package    Package
 * @subpackage Filter
 * @copyright  Foo Project
 * @author     Foo Bar <foo@bar.jp>
 */
class Filter_Kakeibo extends Samurai_Filter
{

    /**
     * コンストラクタ
     *
     * @access     public
     */
    public function __construct()
    {
        
    }


    /**
     * @override
     */
    protected function _prefilter()
    {
        parent::_prefilter();
        /*これがaction実行前に動くフィルター*/
        
    }

    /**
     * @override
     */
    protected function _postfilter()
    {
        parent::_postfilter();
        
        /*これがaction実行後に動くフィルター*/
    }
}

こんな感じで作成されているはず。コメントはちょっと追加してみました。
ここのaction実行前に動くフィルターに今回authフィルターを実装します。

はい、できました。
以下はちょっと例ですけど

仕様としては認証はログイン時には名前とパスワードを入力して、
ユーザーテーブルに存在しているかを確認。

そしたらユーザーテーブルのIDをセッションに持たせる。
これがログイン認証。

その続きに、URLを直接打たれても表示できないように
セッションにIDがあるかを確認し、ない場合は認証失敗。

<?php
/**
 * [[機能説明]]
 * 
 * @package    Package
 * @subpackage Filter
 * @copyright  Foo Project
 * @author     Foo Bar <foo@bar.jp>
 */
class Filter_Kakeibo extends Samurai_Filter
{


    /*
    *セッションとアクションチェインは後で使うのでここで定義
    */
    public $Session;
    public $ActionChain;
    
    /*ユーザーマネージャー(自分で作成してください)*/
    public $UserManager;

    /*
    *ユーザーidとuser(obj)はpublicで一応持っておく
    */
    public $userid;
    public $user;

    /**
     * コンストラクタ
     *
     * @access     public
     */
    public function __construct()
    {
        
    }


    /**
     * @override
     */
    protected function _prefilter()
    {
        parent::_prefilter();
        
        /*すべてのアクションの実行前に行いたい処理を書く*/
        
        //もしもauthがtrueならユーザー認証を行う(デフォルト値はtrue)
        if($this->getAttribute('auth',true)){
            //ユーザー認証
            $this->_auth();
        }
        
    }
    
    /*
    *ユーザー認証を行うメソッド
    */
    private function _auth(){
    
        //セッション取得(セッションにuseridが入る予定)
        $this->userid =$this->Session->get('userid');
        $this->_errorView($this->userid);
    
        //テーブルから取得
        $this->user = $this->UserManager->get($this->userid);
        $this->_errorView($this->user);
        
    }
    
    /*
    * エラーハンドリング
    */
    private function _errorView($user){
        
        //取得できなかった場合
        if(!$user){
        
            /*ここでエラーリストを作成して、authErrorという名前でset*/
            $errorList = $this->ActionChain->getCurrentErrorList();
            $errorList->setType('authError');
        }
    }


    /**
     * @override
     */
    protected function _postfilter()
    {
        parent::_postfilter();
        
        /*すべてのアクションの実行後に行いたい処理を書く*/
    }
}


これでフィルターの作成は終わりましたが、
今のままではすべてのactionで認証が起きてログイン画面でも認証が動いて
無限ループにはまってしまいます。

なので、ログイン画面では認証を動かさないようにしたいので、login.ymlに以下のように
記述します。

#
# login.yml
#

Kakeibo : 
    auth : false

これでフィルターに作成した値が初期値ではなくfalseを返すようになり、
認証が動かないようになります。

要点としては
フィルターを作成>ymlファイルにフィルターを定義>実装
という感じです。