Tagging caching is a tool that allows point-to-refresh cache when certain dependencies change.
Unfortunately, the Yii developers did not consider it necessary to implement this tool in ActiveRecord, but it would be worth it. However, they gave us the opportunity to do it ourselves.
The implementation of tagging to dependency-based models has already been discussed at
habrahabr.ru/post/159079 . Author separate thanks. I will use it as a basis, and I will add functions for automatic generation of tags.
Let us highlight the tasks that we will have to solve:
Generating tags according to predefined rules. (standardization)
Since there are many different entities in the project, and the binding keys are formed without definite standards, we need a way to use one tag for columns whose names are different. For example, in one table we have the user_id field, and in the other we have the customer_id field, both columns refer to the user entity. It is logical that they should depend on the same tag - user_id.
')
Automatic tag generation
Tritely overload certain methods in a CActiveRecord.
Tags must be generated for relationships, when selecting several models at the same time and when selecting a model by the master key (and the master key can be composite)
Ability to add tags manually
No matter how much we want to automate the process to the maximum, all the same, there will be enough situations where you need to specify the tags manually.
For example, when a model is sampled using a complex query (using CDbCriteria). To do this, we will expand the CDbCriteria class by adding the $ tags property to it, according to which the tag generator will understand that there are tags added “manually”.
Implementation:
In order to satisfy all the above requirements, we need a functional that allows us to define standards.
The next problem is the definition of which tag should be removed when changing a particular model. When reading, we create / check all tags on which the model depends. When recording, we need to remove only individual tags. You can not remove tags on which other models depend.
To solve this problem, unfortunately, I was forced to divide the rules into two groups corresponding to the “read” and “write” modes. This allows us to determine which tags will be used when reading and which need to be removed when writing. It is necessary to manually determine these points.
The rules will be stored in the model method cacheTags ($ mode = 'read'). Which should return an array. Also, we define that if cacheTags is not declared in the model or returns an empty array, automatic caching will not be activated.
Each tag will have a prefix consisting of a lowercase model name, i.e. user_id is the tag for the id property in the User model.
Going forward, I will say that during the implementation I had to define several types of rules:
- Static
- Constant
- Link
- Composite
Static - linear element of the array, the value of which corresponds to a particular column of the table. The tag will consist of a prefix and the current name of the rule.
Constant - value, with the leading character ':', which will be used instead of the tag name, after removing the ':' character. In other words, the global prefix will not be added to the tag name.
A link is an associative element of an array, the key of which corresponds to a table column. The rule value will be used to name the tag. In this case, the value of the rule can be represented as other rules.
Composition is an array of rules. The corresponding composite tag will be created.
Example:
public function cacheTags($mode='read'){ switch ($mode) { case 'read': return array( 'id',
In the above example, we see that the model depends on the id tags, user_id tags, the composite one, which consists of id and user_email, but only the id tags and the composite one will be deleted during the recording. Thus, the user_id tag will remain untouched and other models depending on it will not be affected.
All of the above is implemented as a library and posted on github:
github.com/yiix/Cache .
To install, you can use the composer or just copy the repository. Models must inherit from the \ Yiix \ Cache \ Tagging \ CActiveRecord class. Just do not forget to add the method cacheTags to each model with a description of the rules for generating tags, as all the automation in it.
I do not see much point in cluttering up the post with the code from the library, I will give only some illustrative examples.
The codes given in the examples should not be used directly. I present them in order to describe the technique used in Yiix / Cache / Tagging / CActiveRecord.
Suppose we have the following models:
class User extends \Yiix\Cache\Tagged\CActiveRecord { ... public function cacheTags($mode = 'read') { switch ($mode) { case 'write': return array( 'id','email','username'=>':user_name', array('id','email') ); break; case 'read': return array( 'id','email','username'=>':user_name', array('id','email') ); default: break; } } ... } class Post extends \Yiix\Cache\Tagged\CActiveRecord { ... public function cacheTags($mode = 'read') { switch ($mode) { case 'write': return array( 'id', ); break; case 'read': return array( 'id', 'authorId'=>':user_id', ); default: break; } } ... } class Tag extends \Yiix\Cache\Tagged\CActiveRecord { ... public function cacheTags($mode = 'read') { switch ($mode) { case 'write': return array( 'id', 'name', ); break; case 'read': return array( 'id', 'name', ); default: break; } } ... }
Logically, it suffices to define rules for key properties.
Example 1
The tag will be created by the primary key.
$model = User::model()->findByPk(1); $tags = \Yiix\Cache\Tagged\Helper::generateTags($model); dump($tags);
result:
array ( 0 => 'user_id=1' )
Example 2
Tags are created by this array of parameters.
$tags = \Yiix\Cache\Tagged\Helper::generateTags(User::model(),array( 'id'=>'1', 'email'=>'webmaster@example.com', 'username'=>'demo' )); dump($tags);
result:
array ( 0 => 'user_id=1' 1 => 'user_email=webmaster@example.com' 2 => 'user_name=demo', 3 => 'user:user_id=1,user_email=webmaster@example.com' )
As a result, there is a tag (array element with index 3) created by a composite rule.
Example 3
Analogously to example 2.
$tags = \Yiix\Cache\Tagged\Helper::generateTags($Tag::model(),array('name'=>'blog')); dump($tags);
result:
array ( 0 => 'tag_name=blog' )
Example 4
Add tags manually.
$criteria = new \Yiix\Cache\Tagged\CDbCriteria(); $criteria->addInCondition('authorId', array('1','2')); $criteria->tags = array( 'authorId'=>array('1','2'), ); $tags = \Yiix\Cache\Tagged\Helper::generateTags(Post::model(),$criteria); dump($tags);
result:
array ( 0 => 'user_id=1' 1 => 'user_id=2' )
here we see that the “link” rule has worked and the tag name matches the User entity
The library uses a namespace. Information on setting up the namespace is described here:
yiiframework.ru/doc/guide/ru/basics.namespaceThanks for attention.