When creating web based software applications we sometimes want to have a standard way of populating a variety of database table columns which we intend to appear in multiple database tables within our software application. These columns may generally include the following …
- userID – for storing the user ID of the user who owns the record
- createdDate – for storing the date the record was created
- createdBy – for storing the ID of the user who created the record
- updatedDate – for storing the date the record was updated
- updatedBy – for storing the ID of the user who updated the record
The above are the standard columns I normally use within my database tables when creating web applications. I deliberately separate the userID from the createdBy and updatedBy. As I look at the createdBy and updatedBy as more of a audit trail and the userID as the actual owner of the record and the foreign key which connects that record to the users table.
In this article I am going to show you a method to populate these values automatically. These fields will be populated whenever you save a record within the web application.
As I presume you are going to want this method exposed to more than 1 Model within the web application I advise you first read the earlier article I wrote about creating master Models and Controllers …
Create a master Model and Controller in Yii2
Master Model and Controller classes are Model and Controller classes which are a parent class to all Model and Controller classes within your web application. All of the methods within the master Model and Controller classes are exposed to the Model and Controller classes within your web application that extend from those master Model and Controller classes.
Now that you have created a master Model make sure you have the following use statements within your master Model …
|
use Yii; use yii\behaviors\TimestampBehavior; use yii\db\Expression; |
Now put the following method in your master Model …
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public function beforeSave($insert) { if(parent::beforeSave($insert)) { if($this->hasAttribute("userID") && $insert && !Yii::$app->user->isGuest && $this->userID == null) $this->userID = Yii::$app->user->id; if($this->hasAttribute("createdDate") && $insert) $this->createdDate = new Expression("now()"); if($this->hasAttribute("createdBy") && $insert && !Yii::$app->user->isGuest) $this->createdBy = Yii::$app->user->id; if($this->hasAttribute("updatedDate")) $this->updatedDate = new Expression("now()"); if($this->hasAttribute("updatedBy") && !Yii::$app->user->isGuest) $this->updatedBy = Yii::$app->user->id; return true; } } |
The Yii2 beforeSave method will fire whenever a Model is saved within your web application. As the beforeSave method is used in our master Model, the beforeSave method will fire whenever a Model is saved providing that Model extends from our master Model.
The method above is made up of 5 IF statements each setting a variable on the Model. The variables on the Model are those 5 database table columns discussed at the beginning of the article. The above code can summarized as follows …
- Line 1 – beforeSave method, $insert variable is true or false depending on whether this is inserting a new record or updating an existing record. Yii2 sets the $insert automatically
- Line 3 – IF statement checks to see … userID column exists in table, this record is a new record being inserted, the user is logged in and hence has a userID, the userID variable has not already been set on the Model
- Line 4 – Set the userID variable on the Model to be the logged in users user ID
- Line 6 – IF statement checks to see … createdDate column exists in table, this record is a new record being inserted
- Line 7 – Set the createdDate variable on the Model to be the current datetime
- Line 9 – IF statement checks to see … createdBy column exists in table, this record is a new record being inserted, the user is logged in and hence has a userID
- Line 10 – Set the createdBy variable on the Model to be the logged in users user ID
- Line 12 – IF statement checks to see … updatedDate column exists in table
- Line 13 – Set the updatedDate variable on the Model to be the current datetime
- Line 15 – IF statement checks to see … updatedBy column exists in table, the user is logged in and hence has a userID
- Line 16 – Set the updatedBy variable on the Model to be the logged in users user ID
- Line 18 – beforeSave return true, the Model will not save unless this method returns true
If you need to use the beforeSave method in a Model that extends from the master Model and you want to retain the functionality of the beforeSave in the parent model you will need to call the parent beforeSave as follows …
|
public function beforeSave($insert) { if(parent::beforeSave($insert)) { // your code here return true; } return false; } |
Please note you do not have to use the beforeSave method in a Model that extends from the master Model for the beforeSave method in the Master Model to work. The above example is only shown in case you want to run further code in the extended Model that happens on the beforeSave whilst still retaining the functionality in the master Model. If the extended Model has no beforeSave method that is fine, the code will still run in the master Model and populate the database columns with the data.
It is also worth noting that you can also use the afterFind to format the data when finding Model records …
|
public function afterFind() { if($this->hasAttribute("createdDate")) $this->createdDateFormatted = Yii::$app->formatter->asDatetime($this->createdDate, "short"); if($this->hasAttribute("updatedDate")) $this->updatedDateFormatted = Yii::$app->formatter->asDatetime($this->updatedDate, "short"); return true; } |
The above example shows the automatic formatting of the created and updated dates for user interface display purposes within our web application. The examples in this article can be extended to include any data or code you like in the beforeSave and afterFind methods. I personally use these methods in the web software applications to save and format general data that is used through many of the database tables within the web software application.
This method reduces code duplication, reduces chance for errors as the code is not in multiple places, keeps the code neat and tidy by only being in one place. This method frees you up to concentrate on other areas of the web software application.
Please also note Yii 2 does incorporate code to automatically fill in the “createdBy” user ID and “updatedBy” user ID using the following behaviour …
http://www.yiiframework.com/doc-2.0/yii-behaviors-blameablebehavior.html
However the above code I wrote can be used to automatically fill in more fields than just “createdBy” user ID and “updatedBy” user ID.