How to Program With Yii2: Blameable Behaviors

Final product image
What You'll Be Creating

If you're asking, "What's Yii?" check out my earlier tutorial: Introduction to the Yii Framework, which reviews the benefits of Yii and includes an overview of what's new in Yii 2.0, released in October 2014.

In this Programming With Yii2 series, I'm guiding readers in use of the newly upgraded Yii2 Framework for PHP. In this tutorial, I'll guide you through another of Yii2's interesting behaviors: helping automate the common web development task of assigning created by and updated by user_ids across the models in your web app using DRY coding and Yii2 BlameableBehavior. We'll also create a log that records who updated the Status table for every change made.

For these examples, we'll continue to imagine we're building a framework for posting simple status updates, e.g. our own mini-Twitter.

Just a reminder, I do participate in the comment threads below. I'm especially interested if you have different approaches, additional ideas, or want to suggest topics for future tutorials.

What Is a Behavior?

Yii2 Behaviors are essentially mixins. Wikipedia describes mixins as "a class that contains a combination of methods from other classes. How such a combination is done depends on the language, but it is not by inheritance."

Yii describes them this way:

Attaching a behavior to a component "injects" the behavior's methods and properties into the component, making those methods and properties accessible as if they were defined in the component class itself.

Yii2 offers several built-in behaviors, most of which we'll be documenting, including sluggable (see Programming With Yii2: Sluggable Behavior), blameable, and timestamp (upcoming, check the series page). Behaviors are an easy way to reuse common code across many of your data models without having to repeat the code in many places. Injecting a behavior into a model can often be done with just two lines of code. As the number of models in your application increases, behaviors become more and more useful.

What Is the Blameable Behavior?

Blameable makes it easy for us to implement the frequently needed task of assigning the current logged in user to inserts and updates in an ActiveRecord model, automatically setting the properties for created_by and updated_by.

In Programming With Yii2: Authorization With the Access Control Filter, we implemented our own blameable behavior in two parts. First, we created a migration to add a created_by field to our Status table:

Second, we assigned the created_by field to the the current user_id in the StatusController's create action:

Implementing the Blameable behavior will do this automatically for us and can be easily added to all of the ActiveRecord models in a web application.

Implementing the Blameable Behavior in the Status Model

Extending the Status Table

First, we need to extend the Status table with a migration once more to support an updated_by field.

Here's the migration code we will use:

If you try to run this migration with existing data in your database, you'll get an error when trying to create the foreign key index, because the updated_by is 0 and doesn't exist in the user table. 

We could work around this by updating the data manually in the migration and then adding a foreign key. However, since this is a test platform, it's easiest just to migrate down three steps—dropping the Status table and its test data—and then migrate up again:

Adding the BlameableBehavior to the Status Model

Next, we'll attach the BlameableBehavior to our Status model. In models/Status.php we add the BlameableBehavior after Sluggable:

We also have to include the Blameable behavior at the top of our model:

Then, we remove the required rule for created_by in the model rules:

Like this:

This allows the validation to succeed and continue on to the behaviors.

We can also comment out or delete the StatusController's created_by assignment in the create action:

Once all these changes are complete, we can write a new Status post:

Our Create Status form awaiting implementation of Blameable Behavior

And we can peek into the table view with PHPMyAdmin and see the created_by and updated_by settings:

The Status Table After Blameable Behavior Updates

Logging Updates to the Status Table

When a Status post is created, we'll always know who created the first entry. But, with Blameable Behaviors, we'll only know who last updated the record.

Let's walk through a simple log implementation to record the id of the person who makes every update. Then you could easily see a history of updaters or extend this to be a full revision log.

Creating the Table for StatusLog

First, we need to create a migration for the StatusLog:

Then, we code the migration to include relational fields for the Status table id and User updated_by fields:

Next, we run the migration:

The fastest way to create a model for StatusLog (and CRUD files so we can easily browse the table) is with Yii2's code generator, Gii. You've seen me use it in past tutorials.

Visit http://localhost:8888/hello/gii and create the model with these settings:

Gii Code Generator for Status Log Model

Here are the CRUD settings:

Gii Code Generator for Status Log CRUD Files

Next, we extend the AfterSave event in the Status model:

This method calls the default parent functionality for afterSave but then creates a new StatusLog entry whenever there is an update to a Status row:

Theoretically, we could also extend BlameableBehavior, but since you have to ensure there is a log model for every ActiveRecord model you use it with, it seemed easier to build this functionality into Status.

If you update a couple of Status records, you can then browse the StatusLog using Gii's CRUD. The image below shows two changes made by Status.id 1.

Status Log CRUD Browser - The Update Log

If you want to go further, it should be relatively straightforward to extend this to a revision table complete with previous and new status text to support rollback functionality.

What's Next?

I hope you've enjoyed learning about Yii2 Behaviors and Blameable. Next, we'll explore Timestamp Behaviors, which reduce the amount of code you need to write with each new model for the common operation of creating timestamps for inserts and updates.

Watch for upcoming tutorials in my Programming With Yii2 series as I continue diving into different aspects of the framework. You may also want to check out my Building Your Startup With PHP series which is using Yii2's advanced template as I build a real world application.

I welcome feature and topic requests. You can post them in the comments below or email me at my Lookahead Consulting website.

If you'd like to know when the next Yii2 tutorial arrives, follow me @reifman on Twitter or check my instructor page. My instructor page will include all the articles from this series as soon as they are published. 

Related Links

Tags:

Comments

Related Articles