Що робити, якщо вам потрібно впровадити стандартний функціонал (наприклад, кешування даних) у деякі стандартні моделі? У моєму випадку мені на допомогу прийшов behavior і його чудові можливості.
Якщо коротко, то behavior (поведінка) у фреймворку Yii2 дозволяє розширювати контролери та моделі (або все, що успадковано від класу «Component») своїми додатковими методами. Працює за аналогією з трейтами у PHP, але це не те саме. Якщо вас цікавить більш детальне визначення та можливості — зазирніть на офіційний сайт фреймворку.
У цій статті я опишу свій невеликий досвід спільної роботи кешування, моделей та поведінок.
Історія. На певному етапі розробки знадобилося впровадити кешування до чотирьох стандартних моделей:
- Рубрики
- Категорії
- Регіони
- Міста
Усі вони мають стандартну структуру таблиць, за винятком таблиць «категорій» та «міст». У них присутній батьківський ID (рубрики / регіону).
Наша поведінка має наступний код:
class CachedBehavior extends Behavior
{
public $cache_pref;
public $from = 'id';
public $to = 'title';
public $group;
public function events()
{
return [
ActiveRecord::EVENT_AFTER_INSERT => 'deleteCache',
ActiveRecord::EVENT_AFTER_UPDATE => 'deleteCache',
ActiveRecord::EVENT_AFTER_DELETE => 'deleteCache',
];
}
public function deleteCache()
{
Yii::$app -> cache -> delete($this -> cache_pref);
}
public function getCacheAsTree()
{
return ArrayHelper::map($this -> getCache(), $this -> from, $this -> to, $this -> group);
}
public function getCacheList()
{
return ArrayHelper::map($this -> getCache(), $this -> from, $this -> to);
}
public function getCacheById($id)
{
$a = $this -> getCache();
if(isset($a[$id]))
{
return $a[$id];
}
return [];
}
public function getCache()
{
$Cache = Yii::$app -> cache;
$a = $Cache -> get($this -> cache_pref);
if($a === false)
{
$a_ = (new Query())
-> select('*')
-> from($this -> owner -> tableName())
-> orderBy('`order` ASC, `title` ASC')
-> all();
$a = [];
foreach ($a_ as $v)
{
$a[$v[$this -> from]] = $v;
}
$Cache -> set($this -> cache_pref, $a, HelperDate::WEEK);
}
return $a;
}
}Де:
public $cache_pref; public $from = 'id'; public $to = 'title'; public $group;
— параметри нашої поведінки, деякі (стандартні для всіх випадків) встановлені за замовчуванням.
Кожна модель має свій префікс для $cache_pref кешу (але можна використовувати й назву таблиці, звернувшись до неї як $this->owner->tableName()).
Через події вказуємо, коли потрібно видалити кеш:
public function events()
{
return [
ActiveRecord::EVENT_AFTER_INSERT => 'deleteCache',
ActiveRecord::EVENT_AFTER_UPDATE => 'deleteCache',
ActiveRecord::EVENT_AFTER_DELETE => 'deleteCache',
];
}— а саме при створенні нового запису, редагуванні існуючого або видаленні якогось.
Усе, що починається з «get» нижче в коді — це методи роботи з кешем. Їх можна викликати безпосередньо через метод моделі.
Наприклад, підключаємо нашу поведінку до моделі міст:
class TerritoryCityModel extends ActiveRecord
{
public function behaviors()
{
return [
'CachedBehavior' => [
'class' => CachedBehavior::className(),
'cache_pref' => 'territory-city',
'group' => 'territory_region_id',
],
];
}
public static function tableName()
{
return '{{%territory_city}}';
}
}У коді до методів нашої поведінки можна буде звернутись так:
//Відобразити деревом (new TerritoryCityModel()) -> getCacheAsTree(); //Або відобразити списком (new TerritoryCityModel()) -> getCacheList() //Або якось інакше...
Ще одна чудова ідея використання поведінок — це винесення нестандартних методів валідації.
