Что делать, если Вам потребовалось внедрить стандартный функционал (к примеру кэширование данных) к некоторым стандартным моделям? Мне в данном случае, на помощь пришел 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() //Или как-то иначе...
Еще одна замечательная идея использования поведений, это вынесение в них не стандартных методов валидации.
