CakePHP 簡単なビヘイビアを作ってみる

前回の記事、『CakePHP サニタイズでエスケープされた改行コードを元に戻す簡単なコンポーネントを作ってみる』で簡単なコンポーネントを作成したのですが、色々考えた結果「データの加工などの処理はモデルで行うべきだ」との考えに至ったので、前回作成したコンポーネントと同じ処理をするビヘイビアを作成してみたいと思います。

作成するビヘイビアのメソッドとしては、『サニタイズでエスケープされた改行コードを元に戻す』『HTMLエンティティを特殊文字に置き換える』です。

ビヘイビアは、『ModelBehavior』クラスを継承して作成します。

▼『ModelBehavior』クラスを継承

class HtmlDecodeBehavior extends ModelBehavior {
    public $name = 'HtmlDecode';
}

CakePHPの命名規則に則り、『/app/models/behaviors』に保存します。

ビヘイビアの準備ができたので、メソッドを追加していきます。

コンポーネントの作成との違いは、モデルから呼び出せるメソッドの『第1引数がモデルの参照になる』ことです。
private宣言やprotected宣言のメソッドは『第1引数がモデルの参照になる』ことはありません。

▼作成したビヘイビアにメソッドを追加

class HtmlDecodeBehavior extends ModelBehavior {
    public $name = 'HtmlDecode';

    // 置き換え対象のHTMLエンティティ
    protected $_patterns = array(
        'before' => array(
            "/¥&/",    // 『&』
            "/¥&lt;/",     // 『<』
            "/¥&gt;/",     // 『>』
            "/¥&quot;/",   // 『'』
            "/¥&#39;/",    // 『"』
        ),

        'after' => array(
            "&",        // 『&amp;』
            "<",        // 『&lt;』
            ">",        // 『&gt;』
            "'",        // 『&quot;』
            '"',        // 『&#39;』
        )
    );

    /**
     *    HTMLエンティティを特殊文字に置き換える
     *
     *    @param     string or array    $data      HTMLエンティティを特殊文字に置き換えたい配列、または文字列
     *    @param     pool               $script    置き換え後の特殊文字がScriptタグになった場合、削除するなら『true』を指定
     *    @param     pool               $space     置き換え後の文字列からスペースを削除するなら『true』を指定
     *
     *    @return    string or array    処理後、引数に指定された形式で返す。
     */
    public function htmlCheck(&$model, $data, $script = true, $image = true, $space = true) {
        if(is_array($data)) {
            $cnvData = array();

            foreach($data as $key => $item) {
                if(isset($item)) {
                    // 特殊文字へ置き換え
                    $cnvData[$key] = $this->_htmlDecode($item);

                    // スクリプトタグの削除
                    if($script) $cnvData[$key] = Sanitize::stripScripts($cnvData[$key]);

                    // 画像の削除
                    if($image) $cnvData[$key] = Sanitize::stripImages($cnvData[$key]);

                    // スペースの削除
                    if($space) $cnvData[$key] = Sanitize::stripWhitespace($cnvData[$key]);
                }
            }
        } else {
            if(isset($data)) {
                // 特殊文字へ置き換え
                $cnvData = $this->_htmlDecode($data);

                // スクリプトタグの削除
                if($script) $cnvData = Sanitize::stripScripts($cnvData);

                // 画像の削除
                if($image) $cnvData = Sanitize::stripImages($cnvData);

                // スペースの削除
                if($space) $cnvData = Sanitize::stripWhitespace($cnvData);
            }
        }

        return $cnvData;
    }

    /**
     *    配列、または文字列に含まれる『///n』を『/n』に置き換える
     *
     *    @param     string or array     $data         『///n』を『/n』に置き換えたい配列、または文字列
     *    @param     pool                $conversion    置き換え後の『/n』を『
』タグに変更する場合、trueを指定 * * @return string or array 処理後、引数に指定された形式で返す。 * */
public function nlCheck(&$model, $data, $conversion = false) { if(is_array($data)) { $cnvData = array(); foreach($data as $key => $item) { if(isset($item)) { // 『/n』へ置き換え $cnvData[$key] = $this->_nlDecode($item); // 『
』へ置き換え
if($conversion) $cnvData[$key] = nl2br($cnvData[$key]); } } } else { if(isset($data)) { // 『/n』へ置き換え $cnvData = $this->_nlDecode($data); // 『
』へ置き換え
if($conversion) $cnvData = nl2br($cnvData); } } return $cnvData; } /** * HTMLエンティティを特殊文字に置き換える * * @param string $data 置き換えたい文字列 * * @return string 置き換え後の文字列 */ protected function _htmlDecode($data) { return preg_replace($this->_patterns['before'], $this->_patterns['after'], $data); } /** * 『///n』を『/n』に置き換える * * @param string $data 置き換えたい文字列 * * @return string 置き換え後の文字列 */ protected function _nlDecode($data) { return preg_replace('/\\\n/', "\n", $data); } }

内容は、前回作成したコンポーネントと同じで、『preg_replace』関数を使用し文字を置き換えていくだけです。

後は、モデルから作成したビヘイビアを読み込み処理をしていきます。
ビヘイビアを読み込む場合は、メンバ変数『$actsAs』に使用したいビヘイビア名を指定します。

注意しなければならないのが、ビヘイビア側の第1引数はモデルの参照になっていますが、モデル側では第1引数を省略し第2引数から指定していくことです。
また、コンポーネントの『$this->コンポーネント名->コンポーネントのメソッド名』とは違い、『$this->ビヘイビアのメソッド名』となります。

class HtmlDecodeBehavior extends ModelBehavior {
    public function nlCheck(&$model, $data, $conversion = false) {
        /*
         *    処理は省略します
         */
    }
}
class Post extends AppModel {
    public $name   = 'Post';
    public $actsAs = 'HtmlDecode';

    public function find($type, $options = array()) {
        /*
         *    処理は省略します
         */

        $data = $this->nlCheck($data, true);
    }

このことに注意しながら、実装していきます。

▼モデル

class Post extends AppModel {
    public $name   = 'Post';
    public $actsAs = 'HtmlDecode';

    public function find($type, $options = array()) {
        switch($type) {
            case 'show':
                // データの取得
                $data = parent::find('first', $options);

                $data['Post'] = $this->nlCheck($data['Post'], true);

                return $data;
            break;

            default:
                return parent::find($type, $options);
            break;
        }
    }
}

▼コントローラー

class PostsController extends AppController {
    public $name  = 'Posts';
    public $users = array('Post');

    public function show($id = null) {
        if (!$id) $this->referer($this->referer());

        // データの取得
        $post = $this->Post->find('show', array('conditions' => array('Post.id = ?' => $id)));

        $this->set('post', $post);
    }
}

これでビヘイビアの作成は終了です。
いくつか注意点はありますが、基本的には簡単に作成することができました。