2noの日記

メモ用

CakePHP 2.x でバリデート前にまとめてデータを加工する

最近業務で CakePHP を使い始めたので備忘録的な。

FuelPHP などに慣れていると、バリデートのルールと一緒にフィルタ処理したい衝動に駆られる。
こういった機構は CodeIgniter や Phalcon など実装されてたと思う(Phalcon はうろ覚え)

CakePHP においてバリデート時にフィルタを掛けるなら、beforeValidate というコールバックメソッドを用意してあげれば良いみたい。

汎用的に使おうと思ったらこんな感じ?

テスト環境:
CakePHP 2.6.2
PHP 5.6.6

▼ AppModel.php

<?php
/**
 * Application model for Cake.
 *
 * This file is application-wide model file. You can put all
 * application-wide model-related methods here.
 *
 * @link          http://cakephp.org CakePHP(tm) Project
 * @package       app.Model
 * @since         CakePHP(tm) v 0.2.9
 */

App::uses('Model', 'Model');

/**
 * Application model for Cake.
 *
 * Add your application-wide methods in the class below, your models
 * will inherit them.
 *
 * @package       app.Model
 */
class AppModel extends Model {

/**
 * バリデート前に実行するフィルタ一覧
 *
 * @var array
 */
    public $filters = [];

/**
 * バリデート前に実行するイベント
 *
 * @param array $options オプション
 * @return bool
 */
    public function beforeValidate($options = []) {
        $result = parent::beforeValidate($options);
        if ($result && $this->filters) {
            array_walk($this->data[$this->name], function (&$value, $key) {
                if (!isset($this->filters[$key])) {
                    return;
                }
                foreach ($this->filters[$key] as $filter) {
                    if (is_string($filter)) {
                        $value = call_user_func($filter, $value);
                    } elseif (is_array($filter)) {
                        $callback = array_shift($filter);
                        array_unshift($filter, $value);
                        $value = call_user_func_array($callback, $filter);
                    }
                }
            });
        }
        return $result;
    }
}

あとは継承先で、$filters プロパティを用意して指定してあげるだけ。

<?php
class Hoge extends AppModel {
    public $filters = [
        'title' => ['trim', [['self', 'upper']]],
    ];

/**
 * 小文字を大文字に変換します。
 *
 * @param string $str 対象の文字列
 * @return string 変換後の文字列
 */
    public static function upper($str) {
        return strtoupper($str);
    }
}

この場合、title というデータにビルトイン関数 trim と、Hoge#upper を実行することになる。