📜 ⬆️ ⬇️

Yii - sharing experience: models


The material in this article is intended for developers who already have skills to work with the YII framework. For experienced programmers, the material may seem uninteresting.
The article is written for the framework version YII 1.1.14. Under the cut there is a lot of text with code fragments.


Let's start


As a rule, the construction of models should begin with the design of tables based on the task. We will leave this fascinating occupation beyond the scope of the article, suppose that we already have requirements for the table. The model is built on the finished table, so you should start with the migration.

Migrations

When building a migration, you should avoid a lot of complex dependent queries, if possible one migration should create a single SQL query. Let's look at why this is so.
')
Suppose that we were tempted and in one migration we created a table and indexes in it. Then, in case of a typo in the index creation function, the migration will be interrupted by the interrupt that was thrown out, and it will not be possible to restart the migration since the table has already been created. Here, if there is a possibility, you should either use the transaction mechanism, or do a lot of small migrations.

Creating a model class

This activity can be trusted to the gii generator, it will do it for you with joy. However, after the generation of the model, as a rule, it is necessary to fine-tune it.

The first thing we do is change the class from which the model is inherited. If you don’t yet have the ActiveRecord.php file in the application.components directory, then it's time to create it, this will be the base class for all our models.

class ActiveRecord extends CActiveRecord { const SCENARIO_CREATE = 'insert'; const SCENARIO_UPDATE = 'update'; const SCENARIO_SEARCH = "search"; /** Return model ID * * @return integer */ public function getId() { return $this->id; } /** * Returns the static ActiveRecord model. * Please note that you should have this exact method in all your CActiveRecord descendants! * @param string $className active record class name. * @return ActiveRecord the static model class */ public static function model($className=__CLASS__) { return parent::model($className); } } 


All duplicate methods from inherited models should be brought into this class in order to comply with the DRY principle. Do not forget to leave comments on methods with the directive return, this is not only for PHPDoc but also for IDE.

Also, for convenience of writing code in the IDE, constants with the names of scripts are created, in this case autocompletion helps to avoid typos, especially when there are a lot of scripts (usually used in validation, but not only).

Basic models

If the model is very large and contains many attributes, such a model is conveniently divided into two. The base model and the main one, inherited from the base one.
For example, the chain of inheritance can be:
User -> BaseUser -> ActiveRecord -> CActiveRecord
In this case, the methods necessary for the work of YII (relational relations, validation rules, attribute labels) are put into the base model, and we place our methods in the main class of the model.
In the base and base class of the model, it is necessary to override the static model () method as shown below. In the comments to the method in the return tag you need to remember to specify your class.

  /** * Returns the static BaseUser model * * @param string $className active record class name. * @return BaseUser */ public static function model($className=__CLASS__) { return parent::model($className); } 


Attribute Name Translation

Good practice is to get used to the development taking into account the international interface, for this we use the method Yii :: t (). As a category, you can specify the class of the module or component to which the model belongs, unfortunately it is undesirable to override this class in the model, since the console parser will not know the category when building dictionaries (however it is possible, but then you will have to call the console command with the additional configuration).

  /** * @return array customized attribute labels (name=>label) */ public function attributeLabels() { return array( 'id' => Yii::t('BaseUser','ID'), 'firstName' => Yii::t('BaseUser','First Name'), 'middleName' => Yii::t('BaseUser','Middle Name'), 'lastName' => Yii::t('BaseUser','Last Name'), 'phone' => Yii::t('BaseUser','Phone Number'), 'email' => Yii::t('BaseUser','E-mail'), // and more... ); } 


Similar to the attributeLabels () method, you also need to create your own, for example, for statusLabels status fields. This is useful when building drop-down lists on a form.

Constants in models

Constants must be used for record status fields, flag fields (bitmasks), progress fields, etc. Namely, for those fields which are being indexed and the value there is compressed and not obvious.

  const STATUS_DRAFT = 1; const STATUS_PUBLIC = 2; const STATUS_TRASH = 3; const FLAG_HAS_CAR = 1; const FLAG_HAS_HOUSE = 2; const FLAG_HAS_CREDIT = 4; const FLAG_HAS_DEPOSIT = 8; 


Obviously, meeting such constants in the source code, they immediately tell us what we are dealing with.

Data access methods

When developing models, it is necessary to use getters and setters and not use attribute reading and assigning values ​​to them directly. This will give developers greater control over the expansion of the project. A setter can do silent filtering when a value is set, or a data type cast, and a getter can format the output in a convenient format. The setter should only assign a value to an attribute, but should not do a model save. If the setter returns $ this, then it is possible to build a fluid interface for the model, which is naturally not applicable for the getter.

  /** * Set user status * * @param int $status * @return \User */ public function setStatus($status){ $this->status = intval($status); return $this; } /** * Return First Name * * @return string */ public function getFirstName() { return (string)$this->upperFirst($this->firstName); } 


Minor operations

Sometimes a model performs small operations on a small number of attributes, such methods can be started with the make prefix, and such methods can save the model inside themselves, and also throw events to hang handlers.
  /** * Make user active * * @return bool */ public function makeActive(){ if($this->hasEventHandler('onBeforeCount')){ $this->onBeforeCount(new CEvent($this)); } $result = $this->setStatus(self::STATUS_ACTIVE) ->save(); if($this->hasEventHandler('onAfterMakeActive')){ $this->onAfterMakeActive(new CEvent($this)); } return $result; } 


On this perhaps interrupt, to get the opinion of the audience.

UPD : Made edits from mitaichik and Fesor .

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


All Articles