Я люблю выносить обработку данных в модели. При этом у меня часто получаются модели со схожими функциями, как в одном проекте так и в разных. А меня очень удручает, когда надо писать один и тот же код по несколько раз, а от копирования кода меня просто передёргивает, потому что я уже вижу как через полгода буду себя проклинать. До CakePHP я в таких случаях просто создавал общего потомка и там реализовал общую функциональность. Недостаток этого метода — это то, что в PHP можно наследовать можно только один класс.
К счастью, разработчики CakePHP придумали как удобнее выносить одинаковую функциональность из моделей. Эта возможность появилась в Cake PHP 1.2 и называется behaviors.
Возьмём, нашу модель Word. У меня часто бывают такие таблицы, которые состоят из id и name. Я покажу как сделать так, чтобы к другим моделям такого типа можно было применять общую функциональность. Но при этом мы можем указать в каждой конкретной модели, какие behaviors к ней подключать. Самое удобное, что можно подключать их несколько, а не только одну.
Модель выглядела так
app/models/word.php
<?phpclass Word extends AppModel { var
$name = 'Word'; var
$validate = array(
'id' => VALID_NUMBER,
'name' => VALID_NOT_EMPTY, );
/** * Adds a word and returns id
*
* @param string $name
* @return integer If failed to save returns false
*/
function add($name) {
$item = array(
'name' => $name, );
$this->create(); if (
$this->save($item)) { return
$this->getInsertId(); } else {
return
false; }
}
/** * Generates list of lowercase names and its ids
*
* @return array (a(name=>id), ...)
*/
function generateListFlipLow(&$model) {
$items = $this->generateList(); foreach (
$items as $id=>$name) {
$items[$id] = low($name); }
return
array_flip($items); }
}
?>
С применением behavior этот же класс будет выглядеть так
<?class Word extends AppModel { var
$name = 'Word'; var
$validate = array(
'id' => VALID_NUMBER,
'name' => VALID_NOT_EMPTY, );
var
$actsAs = array('NameList');}
?>
И всё. Через запятую можно указать несколько behaviors. Если надо передать настройки в behavior, то надо писать
var $actsAs = array('NameList'=>array('setting1'=>'value1', 'setting2'=>'value2'));
Сами behaviors находятся в app/models/behaviors. Для нашей модели — это app/models/behaviors/name_list.php
<?class NameListBehavior extends ModelBehavior { var
$settings = array(); function
setup(&$model, $config = array()) {
$this->settings = $config; }
/** * Adds a word and returns id
*
* @param string $name
* @return integer If failed to save returns false
*/
function add(&$model, $name) {
$item = array(
'name' => $name, );
$model->create(); if (
$model->save($item)) { return
$model->getInsertId(); } else {
return
false; }
}
/** * Generates list of lowercase names and its ids
*
* @return array (a(name=>id), ...)
*/
function generateListFlipLow(&$model) {
$items = $model->generateList(); foreach (
$items as $id=>$name) {
$items[$id] = low($name); }
return
array_flip($items); }
}
?>
В методе setup мы настраиваем behavior. В $config передаются настройки, которые можно указать в модели.
Во всех методах добавляется первый параметр $model. Если вы переносите методы из модели, то надо не забыть все $this поменять на $model.
Как видите, создавать behaviors очень просто. Особенно, если мы заранее создали тест и можем автоматически убедиться, что всё по-прежнему работает.