Behavior の適用範囲を広げる $mapMethods

(CakePHP 1.2.5)
ビヘイビアに定義されたメソッドは、モデル自身のメソッドであるかのように呼び出すことができます。

class FooBehavior extends ModelBehavior {
  function foo($model){ /* ... */ }
}
 
class Bar extends AppModel {
  var $actsAs = array('Foo');
}
 
// in Controllers
$this->Bar->foo();

しかしこの方法では Dynamic Finder のように動的に名前が変化するメソッドは実装できません。

ModelBehavior クラスの $mapMethods プロパティを使用すると、この制約を乗り越えることができます。$mapMethods は配列で、次のような構造をしています:

array( '/メソッド名に対する正規表現/' => '実際に呼び出されるメソッド'  )

例えば '/^list/' => '_genericList' という設定を行った場合、listから始まる全てのメソッド呼び出しが、ビヘイビアの _genericList メソッドの呼び出しに変換されます。このとき _genericList メソッドの引数には元のメソッド名と引数が渡されます。ちょうど __call によるメソッドのオーバーロードと同じです。

この機能を活用して、あるカラムの値を配列として取得するための listColumn メソッドを作ってみます(Column はカラム名)。このメソッドは ListingBehavior に実装することにしましょう。

class ListingBehavior extends ModelBehavior {
  var $mapMethods = array('/^list[a-zA-z0-9]+$/' => '_listColumn');
 
  function _listColumn($model, $methodName, $query=array()) {
    $column = substr($methodName, 4);
    $query = am($query, array('fields' => array($model->alias.".".$column)));
    $arr = $model->find('all', $query);
    if(is_array($arr)) {
      return Set::extract("/{$model->alias}/{$column}", $arr);
    }
    return $arr;
  }
}

モデルにこのビヘイビアを組み込むと、任意のカラムに対して listXXX メソッドを呼び出すことができるようになります。

class User extends AppModel {
  var $actsAs = array('Listing');
}
 
// in Controllers
$this->User->listId();
$this->User->listUsername(array('conditions' => 'active = 1'));
$this->User->listGroup_id();

メソッド名は小文字に変換されて渡されるので(これが仕様なのかバグなのか微妙なところです)、残念ながら Inflector::underscore を使うことはできません。

Leave a Reply