📜 ⬆️ ⬇️

Yii exchange of experience: models (ending)


Continuation of the previous post

The area of ​​responsibility of the model and its place in the project

Models are intended only for handling data (search, saving, deleting), as well as related static files, as they are also an integral part of the data structure (photo, video). Naturally, when deleting a record, the media files associated with it should be deleted, for this it is convenient to use beforeDelete () or afterDelete ().
Simple business logic can be implemented in the model, for complex - it is better to use the service layer (Service Layer) so you save the model from the mass of dependencies and will not inflate the divine object from it.
In models should not appear:

Models should have as few dependencies on other components as possible, so we can make it portable and use it in other projects. In this case, the components on which the model depends should be installed by setters (for example, User :: setEmailComponent ('email')). You can also assign components in User :: init (), but you must also check for its presence. If the component is secondary and unavailable, the model must work without noise, however if the component is paramount, then an exception should be thrown at the initialization stage.
These simple rules will allow your code to be supported by a team of programmers, and it is sufficiently flexible to extend the functionality.

Status check

Usually, checks are done in different places, both in controllers and in views, and checking often looks like this:

//   if($model->status == 1){ ... } //    if($model->getStatus() === Model::STATUS_ACTIVE){ ... } //   if($model->status !== 1 && $model->status !== 2 && $model->status !== 4){ ... } //--    

')
However, if you create an isActive () method that does this check, the code will become more controllable, especially in the context of frequently changing TK. Also sometimes it will be useful to create a method that describes checking for the possibility of transition to a different status status. For example: if a record has the status - “Spam”, then it cannot be transferred to the “Active” status, but it can be transferred to the “To check” status. It is desirable to place all this logic also in models. (This can be useful when building workflow systems)

Use flag fields

To save the size of the table (the number of columns) and to have a more flexible model expansion functionality, use fields with bit flags.
Such fields are usually represented in the database by the type integer (but not necessarily) and are able to place a fairly large number of flags. I already touched flag fields in the previous article. Now I will show practical application. (Bit masks are described in detail in this article ).
Example: There is a user model in which several simultaneous flags can be assigned to a user - “best author”, “phone confirmed”, “email confirmed”, “left a request for moderator post”
Fragment of the model
  public $flags = 0; const FLAG_CONFIRM_EMAIL = 1; // 00000001 const FLAG_CONFIRM_PHONE = 2; // 00000010 const FLAG_BEST_AUTHOR = 4; // 00000100 const FLAG_BECOME_MODERATOR = 8; // 00001000 /** *   * @param integer $flag * @return \User */ public function setFlag($flag) { $this->flag += intval($flag); return $this; } /** *   * @param integer $flag * @return \User */ public function unsetFlag($flag) { $this->flag -= intval($flag); return $this; } /** *    * @param integer $flag * @return boolean */ public function hasFlag($flag) { return ($this->flags & intval($flag)); } /** *     * @return array */ public function getFlagsLabels(){ return array( self::FLAG_CONFIRM_EMAIL => Yii::t('User',"Email "), self::FLAG_CONFIRM_PHONE => Yii::t('User'," "), self::FLAG_BEST_AUTHOR => Yii::t('User'," "), self::FLAG_BECOME_MODERATOR => Yii::t('User',"   "), ); } /** *      * @param integer $flag * @return \User */ public function withFlags($flag=0) { $this->getDbCriteria()->mergeWith(array( 'order'=>'flags & :flag', 'params' => array(':flag' => $flag), )); return $this; } 



In the MySQL query, the check will look like:
  SELECT * FROM `User` WHERE STATUS & 6 


In the example, a named group of conditions is created; this allows searching as shown below:

  User::model()->withFlags(User::FLAG_CONFIRM_EMAIL)->findAll(); 


Relational relations

Relational relationships are well described in the official documentation .
In practice, there are such nuances.


Representations for attributes

HTML code is sometimes found in model code - it does not belong there. If there is a need to display an HTML-formatted attribute for this, use either the widget or create a helper for the model (a class with static methods). examples are shown below.

Helper example
 class UserHelper{ /** *      * @return string */ public static function getProfileLink(User $model, $htmlOptions = array()) { return CHtml::link($model->getUserName(),$model->getProfileUrl(),$htmlOptions); } } 



Widget example
 class UserAvatar extends CWidget { public $emptyPhotoUrl = "/static/images/no-photo.png"; public $model; public $htmlOptions; public function run(){ $avatar = $this->emptyPhotoUrl; if($this->model->hasAvatar()) { $avatar = $this->model->getAvatarUrl(); } echo CHtml::image($avatar,$this->model->getUserName(),$this->htmlOptions); } } 



The widget and helper are conveniently used in views, the helper is convenient when used inside the widget CGridView.

Model journaling

For debugging models, especially for catching a difficult-to-reproduce error, it is sometimes useful to be able to learn the chronology of events.
To do this, you can add logging methods to the model, and keep a log (log file) for all operations performed with data. The implementation of this simple mechanics can be any, but it is useful to recall the CLogRoute component and configure one of the routes for your model, the log can be kept either in the database (caution, decreases performance) or in simple files. It is also useful to write to the log user data on behalf of which the operation is performed, it will simplify the analysis of flights.

Source: https://habr.com/ru/post/212917/


All Articles