Caching in Yii2 and behaviors

Caching in Yii2 and behaviors

What should you do if you need to implement standard functionality (such as data caching) for some default models? In my case, behavior and its powerful capabilities came to the rescue.

In short, behavior in the Yii2 framework allows you to extend controllers and models (or anything inherited from the “Component” class) with additional methods. It works similarly to PHP traits but is not the same. If you’re interested in a more detailed explanation, check the official Yii documentation.

In this article, I’ll describe my experience combining caching, models, and behaviors.

Story: At a certain point in development, I needed to implement caching for four default models:

  • Rubrics
  • Categories
  • Regions
  • Cities

All of them have a standard table structure, except for “categories” and “cities”, which include a parent ID (rubric / region).

The behavior itself looks like this:

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;
	}
}

Where:

public $cache_pref;
	
public $from = 'id';
public $to = 'title';
public $group;

— these are parameters of our behavior, some of which are set by default (for common cases).

Each model has its own prefix for the $cache_pref cache (but you can also use the table name via $this->owner->tableName()).

We define when to clear the cache using events:

public function events()
{
	return [
		ActiveRecord::EVENT_AFTER_INSERT => 'deleteCache',
		ActiveRecord::EVENT_AFTER_UPDATE => 'deleteCache',
		ActiveRecord::EVENT_AFTER_DELETE => 'deleteCache',
	];
}

— that is, on record creation, update, or deletion.

Everything starting with “get” below in the code are methods for working with cache. These can be accessed directly from the model.

Example: attaching our behavior to the city model:

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}}';
	}
}

In the code, you can call behavior methods like this:

//Display as tree
(new TerritoryCityModel()) -> getCacheAsTree();

//Or display as a list
(new TerritoryCityModel()) -> getCacheList()

//Or some other way...

Another great use for behaviors is moving custom validation methods into them.

Are you having problems with your Yii2 framework website? Do you need additional functionality?
>Then write to me via the feedback form, and I will try to help you.

Write a comment

Your email address will not be published. Required fields are marked *