Tag Archives: yii 2.0

Yii 2 Create Method on Controller

Greetings to everyone from around the world who follows this blog. Programming knowledge does not recognize borders, which really points to how superficial borders are. I know I’ve said that before, but everytime I get a supportive email from someone on the other side of the planet, it really hits home.

I also appreciate all the positive comments, reviews, and word-of-mouth referrals on my book, Yii 2 For Beginners. Readers of the book have been very helpful in elevating the quality of the book by pointing out typos and bugs. I’m happy to say as of the last update, the code in the book is 100% working. Updates are free for the life of the book and I plan on adding material to the book several times a year.

So for those who are unfamiliar with Yii 2 or have never worked with a PHP framework before, I want to demonstrate just how powerful a single method on the Yii 2 Framework can be. This insight came to me as I was working on an idea for a 2nd book, a book on beginning PHP, for people who have never programmed before.

Anyway, I wanted to simulate a framework to teach PHP fundamentals. I didn’t build an actual framework for the following reasons:

1. That’s too intense for beginning PHP.

2. It would take me a 100 years to write the book.

3. It would be a 100 years of wasted time.

The reason why I say it would be wasted time is because of how great the Yii 2 framework is. It makes the idea of building a framework from scratch a bit silly, unless you have very good reason to do so. Why reinvent the wheel, especially when we have such an amazing wheel to work with in the first place?

Anyway, this was made abundantly clear to me as I was staring at the code I made for my simulated controller code. I used a switch statement to simulate individual actions, and this is what the create action looks like. I’ll explain each section, but to start, here it is in one ugly, proceedural block:


case('/mysong/src/controllers/songcontroller.php/create' == $uri):
                      
            if (isset($_POST)){
                
                $post = Security::sanitizeInput($_POST['form_token']);
                $session = Security::sanitizeInput($_SESSION['form_token']);
            }
            
            if (isset($_POST) && Security::matchTokens($post, $session)){
                       
            $song_name = Security::sanitizeInput($_POST['song_name']);
            $visibility = Security::sanitizeInput($_POST['visibility']);
            $video_source = Security::sanitizeInput($_POST['video_source']);
            $video_is_featured = Security::sanitizeInput(isset($_POST['video_is_featured']));
            $video_is_active_item = Security::sanitizeInput(isset($_POST['video_is_active_item']));

            if ($video_is_active_item == true){
                
                $video_is_active_item = 1;
                
            } else {
                
                $video_is_active_item = 0;
            }
            
            if ($video_is_featured == true){
                
                $video_is_featured = 1;
                
            } else {
                
                $video_is_featured = 0;
                
            }
            
            if (!Validators::validateDropDownOption($visibility)){
                
                $visibility = 'Private';
                
            }                      
          
       $cmd = new Query;
       
       $sql = 'INSERT INTO song (song_name, visibility, video_source, 
               video_is_featured, video_is_active_item) VALUES (:song_name, 
               :visibility, :video_source, :video_is_featured, 
               :video_is_active_item);';
       
       $cmd->query($sql); 
       
       $cmd->bind(':song_name', $song_name);
       $cmd->bind(':visibility', $visibility); 
       $cmd->bind(':video_source', $video_source);
       $cmd->bind(':video_is_featured', $video_is_featured);
       $cmd->bind(':video_is_active_item', $video_is_active_item); 

       $cmd->execute();
       
       $cmd->closeDb();
       
            $url = Url::toSong($song_name);
            return header('Location: ' . $url);
           
            break;
            
        } else {
        
             $url = Url::toSongCreate();
             return header('Location: ' . $url);   
             break;
        }

Anyway, we can step through this quickly. If we have post data, make sure the tokens match to prevent CSRF:


 if (isset($_POST)){
                
     $post = Security::sanitizeInput($_POST['form_token']);
     $session = Security::sanitizeInput($_SESSION['form_token']);
 }

 if (isset($_POST) && Security::matchTokens($post, $session)){

If we pass that test, then we set the variables from the form data:


 $song_name = Security::sanitizeInput($_POST['song_name']);
 $visibility = Security::sanitizeInput($_POST['visibility']);
 $video_source = Security::sanitizeInput($_POST['video_source']);
 $video_is_featured = Security::sanitizeInput(isset($_POST['video_is_featured']));
 $video_is_active_item = Security::sanitizeInput(isset($_POST['video_is_active_item']));

We’re using my homegrown Security class to scrub the input. Then we do a little formatting for the check boxes:


if ($video_is_active_item == true){
                
    $video_is_active_item = 1;
                
} else {
                
    $video_is_active_item = 0;
}
            
if ($video_is_featured == true){
                
    $video_is_featured = 1;
                
} else {
                
    $video_is_featured = 0;
                
}
            
if (!Validators::validateDropDownOption($visibility)){
                
    $visibility = 'Private';
                
}
           

I probably would have used ternary syntax if not for the word wrap issues in creating a book.

Anyway, then I use my custom-built Query class to insert the new record:


 $cmd = new Query;
       
       $sql = 'INSERT INTO song (song_name, visibility, video_source, 
               video_is_featured, video_is_active_item) VALUES (:song_name, 
               :visibility, :video_source, :video_is_featured, 
               :video_is_active_item);';
       
       $cmd->query($sql); 
       
       $cmd->bind(':song_name', $song_name);
       $cmd->bind(':visibility', $visibility); 
       $cmd->bind(':video_source', $video_source);
       $cmd->bind(':video_is_featured', $video_is_featured);
       $cmd->bind(':video_is_active_item', $video_is_active_item); 

       $cmd->execute();
       
       $cmd->closeDb();

My bind method autmatically detects string, int, etc. I had a lot of fun creating that. Then we save via execute and close the DB connection. Then we go to the newly created record or show the form if no post data was sent:


$url = Url::toSong($song_name);
return header('Location: ' . $url);
           
break;
            
} else {
        
$url = Url::toSongCreate();
return header('Location: ' . $url);   
break;
}

This is very simple and clear code, easy for a beginner to digest, but it sure did get procedural in a hurry. So I thought about extracting out the methods to further simulate what a framework like Yii 2 would do, but then I thought, hey, why don’t I just show the reader what the framework actually does instead? How would Yii 2 handle this method?

In Yii 2, we would get a single method on the controller. So I grabbed a controller method for the FAQ model we make in the Yii 2 book:


public function actionCreate()
{
    $model = new Faq();

    if ($model->load(Yii::$app->request->post()) && $model->save()) {
        return $this->redirect(['view', 'id' => $model->id]);
    } else {
        return $this->render('create', [
            'model' => $model,
        ]);
    }
}

9 lines, not counting the white space. Now that’s power. It’s starts by creating a new Faq model, which gives us access to all the model attributes and methods. Then comes:


if ($model->load(Yii::$app->request->post()) && $model->save()) {

So what this is doing is loading the $_POST array, which gets all the fields from the form, validating it, and saving it. All that in one line of code. Wow!

If it successfully saves, it returns the view page of the newly created record:


return $this->redirect(['view', 'id' => $model->id]);

In the above, view is the name of the page we want. Yii 2 knows which model the view belongs to and $model->id is the specific instance. No other routing necessary.

If we can’t successfully save, we get the form:


} else {
     return $this->render('create', [
        'model' => $model,
    ]);
}

And that is essentially one line as well. You could style it like so:


return $this->render('create', ['model' => $model,]);

And that’s pretty much it. 9 lines and all the security, validation and formatting is already handled. It’s so simple!

Hopefully I’ve demonstrated at least one reason why I’m such a Yii 2 enthusiast. I will continue to do my best to make the framework as easy to understand for beginners as possible.

Thanks again to everyone who wrote in with encouragement and corrections, especially to those who took the time to do a review on GoodReads.com. As always, any comments, reviews, word-of-mouth referrals, are greatly appreciated.

Advertisements

Yii 2 Learning Your First PHP Framework

I’d like to start today’s post with a big thanks for the positive reviews I’m getting on GoodReads.com, please add yours if you can.

Also, a big thanks to everyone who has emailed me with supportive comments for the Yii 2 For Beginners book and for the positive comments on this blog.

I’ve made it my mission to help introduce people to the wonderful Yii 2 framework, and I know from first hand experience how hard it is to get up and running on something as big as a PHP framework, especially if you’ve never worked with one before.

The decision to use one framework over another is a personal choice. The major frameworks that I talk about, Yii 2, Laravel, and Symfony, are all great frameworks. You have to pick the one that suits your development style and this can certainly be a challenge when you haven’t worked with them because how are you supposed to know how well it fits?

Well, it’s like expensive clothing, you won’t know if it fits until you try it on. Obviously I’m recommending Yii 2 as the first choice among the frameworks from my point of view. Here’s why:

Top 10 reasons I would start with learning Yii 2:

1. Yii 2’s Advanced Application Template. This template comes with a working user model that includes registration, login, and forgot password functionality right out of the box. It also includes backend and frontend separation, so that you are clear on how to structure your admin area. You can get up and running quickly.

2. Gii. Yii 2 has an amazing code generation tool named Gii, which helps you stand up your models, controllers, and views quickly. The generated code almost always needs refinement, but once you know how to do that, things move along with lightning speed. It takes about 2 minutes to generate 8 files, a model, a search model, controller, and 5 view files. You’ll be amazed how far you can go in so little time.

3. Clear MVC pattern. Yii 2 has folders named models, controllers, and views, so the application structure is just what you would expect from an MVC.

4. No Routing. Most of the other frameworks require you to explicitly name the routes through the site, which can be tedious and at times confusing. Yii 2 handles this automatically. Of course you can set things like pretty URLs and any other customizations that you need, but the basic routing is handled by the framework. This is makes it very easy and intuitive to work with.

5. Widgets. Yii 2 supplies an incredible number of widgets to help develop your application. They cover everything from GridView, Pagination, Forms, DatePicker, etc., it really is impressive what you get out of the box. The widget class is easy to extend, so you can quickly build your own widgets. And once you start using these, you will get spoiled very quickly because you will want to use them for everything.

6. Mobile-First Bootstrap. So right out of the box, Yii 2 incorporates Twitter Bootstrap, which of course is device-responsive, so you can jump into mobile-first design right from the start. Wouldn’t you love to pitch that to your client?

7. Validation Made Easy. Validation in Yii 2 is handled on the model, with a very intuitive Rules method that simply holds an array of settings. The settings include the name of the attribute you wish to validate, the validator, and the options.

For example, do you need to make your email addresses unique so two users can’t have the same email address? It’s one line added to the Rules method.


['email', 'unique'],

It’s that simple.

8. Behaviors. Yii 2 incorporates a method named behaviors in both the models and controllers and this is another intuitive winner. In models, behaviors are used to manage events, like automatically inserting timestamp for creating and updating records, which is a useful behavior for a model to have. You can see how intuitive that sounds.

On Controllers, behaviors help you manage access control, things like restricting pages to logged in users only. Again, very intuitive and easy to work with. You can reference some of the tutorials on this blog for examples.

9. Native ORM. So first, what is ORM? According to wikipedia:

Object-relational mapping is a programming technique for converting data between incompatible type systems in relational databases and object-oriented programming languages. This creates, in effect, a “virtual object database” that can be used from within the programming language.

It’s a perfectly scientific explanation, but I don’t find it particularly helpful. We can break it down to something more digestible.

In the simplest terms, the ORM manages how your application communicates with the database, greatly simplifying the syntax. Example:

return $users = User::find()->asArray()->all();

The above code returns all the users from the user table in an array. No having to open a connection, no SQL, no binding parameters, no specifying fetch mode, etc. It’s just one line that reads like a sentence. Look at how simple that is!

Because Yii 2’s Active Record ORM is native, it is integrated seamlessly into the framework, and this is one of the reasons why Gii is so effective at generating code. The other frameworks use Doctrine, which brings with it the excess baggage of their repository structure etc., and in my view, making it more complicated and less efficient.

10. Enterprise Capability. If you are just starting out with framework development, you are probably not ready to jump into enterprise development. But wouldn’t it be wise to learn the framework that can take you there? Learning Yii 2 ultimate builds value into your career as a programmer.

Ok, so that’s my short list of why I would start with Yii 2 as opposed to some of the other choices out there.

The key to learning a PHP Framework, if you have never done this kind of development before, is patience. Yii 2 hands you an amazing amount of features, but you have to be willing to take the time to learn them.

Another key to success in programming is this: Don’t quit. Just keep going until you get it. You will get it.

Yii 2 has a great community that is willing to help you. Also, I wrote a book that can get anyone with a moderate amount of PHP skills up and running quickly.

I’ve also augmented that with free tutorials on this blog, and I’ve also included bonus material into the book. Everyone who purchases the book gets the free bonus updates for the life of the book. I plan to keep working on it for the foreseeable future.

Working with a PHP framework is a journey, not a destination. It’s hard work but it can also be a lot of fun. I’m very happy to share this journey with you.

Thanks again for all the positive comments and reviews. As always, any comments, reviews, word-of-mouth referrals, are greatly appreciated.

Yii 2 Custom Widgets

I hope everyone’s new year is off to a great start. Special thanks to everyone from around the world who has purchased Yii 2 For Beginners, I really appreciate your support. I also appreciate the positive ratings and reviews I’ve been getting, for example the two I got recently on GoodReads.com.

Your positive feedback keeps me motivated and recently I added over 100 pages of new material to the book. Anyone who purchases the book gets free updates for the life of the book, just log into your leanpub.com account to get the latest.

One of the recent additions to the book had to do with creating your own widgets. For those who are unfamiliar with Yii 2’s widgets, they are very handy for presenting data in the view. Yii 2 ships with a number of time-saving widgets that cover everything from navigation, grid results, pagination etc.

An implementation of a widget could start with a single line of code in the view:

echo GridView::widget(['dataProvider' => $dataProvider,]);

But typically with GridView, you will have a lot of customization of the columns and data-display formats, so the array inside the method signature can grow quite a bit.

Here’s what you might see from a basic user model in a backend admin view:

echo GridViewWidget::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],

'id',
'username',
'email:email',
'status',
'created_at',

['class' => 'yii\grid\ActionColumn'],

],
]);

I’m not going to go into too much detail here, but you can see that the data is provided by the $dataProvider, and I don’t know how it can possibly be more intuitively named, so you have to love that.

The $dataProvider instance is being handed in from the controller, so you don’t have to supply any additional logic in the view. Next you supply it with a filter model, which is again handed in from the controller. Then you simply list the attributes you want to appear in the view.

The format of the email attribute creates a mailto link, and there are many ways to manipulate the appearance of the data.

We are also supplying classes for the look of the columns and a separate class for the ActionColumn, which contains icons and links to view, update, and delete individual records. This is just incredibly powerful out-of-the-box, especially if you are doing rapid prototyping of an admin area. We setup a much more complex version of this in the book, but you get the basic idea here.

One of the big points here is that you don’t need to put a foreach loop in the view, the widget takes care of it for you. So the widget is more of a configuration tool, not really doing much logic, and this helps to make your views incredibly clean. WordPress is chomping the code, so I can’t show you the shortcut echo tags, but you can use the shortcut because this is all really just one line, a bunch of settings handed into the array that sits in the method signature.

You will see very quickly how easy a widget is to place inside of a view, so much so that it spoils you a little. You're going to want a widget for everything.

While that’s not really practical, the good news is that you can easily create your own custom widgets. This article is more of an overview than a tutorial, so I’m not going to cover the complete setup, but I will give you an idea how it works.

Your widgets will extend Widget, with Yii 2 providing the perfect class structure for you to create these wonderful helpers. You start by overwriting your widget's two main methods, init and run.

Init just does the logic you want to perform, the result of which will be stored in the properties that you have named in the class. Then to pass the property values to the widget view, you use the run method, which renders the view with the values you have calculated in the init. The widget view is typically only a partial, which is going to sit inside of another view, making it portable and reusable.

So if you want to create a widget holding a top ten list from your content, and then use it multiple times on your site with just a single line call inside your view, you can do it. This is powerful stuff.

The cool part is how you hand in configuration from your widget call to the widget class itself. The Widget class is already structured to be able to receive an array. So you just set the array as a class property, and when the widget is called, the values of the array get handed in. Then you can use these values in the init to perform the logic you need for formatting the data.

Example:

echo MyWidget::widget(['settings' => ['pageSize' => 3]])

So imagine you wanted to build a widget where you had some results and you wanted to control the page size for pagination. In your MyWidget class, you would have a property declared as $settings = [];

In the code example above, you can see that we created the key/value pair that goes in this array, so this is assigned to the class property when the widget is called. So in your init method, you could perform logic using $this->settings[‘pageSize’] however you want. It’s that simple to move the data in. If this isn’t clear from my description, don’t worry, when you try it for yourself, you will see how it all fits together.

Although your run method need not include a view, it’s better to do it that way if you are creating output that involves html or css, which will most likely be the case. Then you just need to remember that when using the render method from within run, you need to access the properties via keyword $this, because unlike a controller, they will not be available to you otherwise.

The only other slightly tricky part to all this is setting up the application to have visibility on your custom components, which will be in its own components folder, and have its own namespace. I provide a full working example in the book, but that’s too much for here, so consult the Guide for instructions on that. Their widget section is fairly easy to follow.

Once you’ve had a chance to work with Yii 2’s widget architecture, it’s difficult to imagine coding life without it. I see it as yet another huge advantage of selecting Yii 2 as your choice for framework.

Yii 2 MVC

Happy Holidays to everyone around the world, to our wonderful international following, I hope everyone has a great holiday season. I’ve been hard at work on a new writing project, a new book, which I will be releasing details on in the near future. One of the benefits of constantly doing technical writing is that you get to see things from many angles, which often gives you new perspective, even on the most basic things.

Since my blog is oriented towards beginners, I thought I would share some thoughts about the MVC pattern, and why I think Yii 2 does such a great job utilizing and preserving it. And while I’m mentioning Yii 2, a word of thanks to everyone who has bought Yii 2 For Beginners, I really appreciate your encouragement and support, it helps me vigorously pursue this work.

Ok, so jumping into MVC, it’s such a simple idea in many ways, that it quickly gets diluted, or at least our sense of it, depending on how an application is organized. I’m a big fan of an application having folders clearly named models, views, and controllers. in the basic app, these are very easy to find, right there in the root folder.

In the Advanced Application, which is the one I work with, the application has folders for frontend, backend, and common, and within those folders, you find the model, view, and controller folders. I know I’ve mentioned it before, but it bears repeating, the Advanced Application gives you a working user model, with registration, login, and forgot password functionality as well as the frontend/backend separation that I just talked about, so I actually found that easier to work with than the basic app. Just a heads up if you are relatively new to all this.

So from a basic organizational standpoint, Yii 2 is very intuitive and very well defined. Now I know that might sound a little vague, so let me try to be a little more specific and talk about an advantage that Yii 2 has over many other frameworks.

In Yii 2, you do not have to manually define each route. Yii 2 has built-in routing logic that sends the user request to the appropriate controller and view. By itself, that’s pretty cool, it alleviates you from having to keep track of all the different routes moving through the system as well as it relieves you from constantly having to bounce around to a routes file or equivalent. You don’t have to keep track of the path, so no headaches when there is a typo in the route or you forgot to reference something correctly. You can avoid that entirely, so that’s a plus for Yii 2.

But there’s another big plus from Yii 2’s architecture, and this may be a by-product of Yii 2’s built-in route definition, and that is it gives you a sense of a well-defined MVC right out of the box. You get to see how the controllers interact with the views, how they utilize the models, and how it all fits together. In a sense, the framework itself defines the MVC pattern more strongly, and it teaches you a very efficient and effective structure that you can use as you build out your application.

In the advanced application especially, you get enough examples of validation, form models, and the user model, to really see the MVC pattern operating beautifully. You get just the right amount of logic in the controllers to keep them thin. If you were, for example, to extract too much logic out, so you have almost no logic in the controller, you would be constantly drilling dwon into other classes to keep track of what’s going on. If you have too much logic, the core mission of a controller, which is essentially routing, is lost in clutter. Yii 2 finds the perfect balance for you right out of the box.

Another measure of a successful implementation of the MVC pattern is how little PHP ends up in the view file, always a challenge in modern development. If you look at Yii 2’s implementation of a form view, for example, you will be amazed at how clean it is, and how little is actually there. It’s one of many things I love about the framework.

In the MVC pattern, models are supposed to carry the most weight in terms of volume of code, since they do so much. The models in Yii 2 have been consturcted to push a lot of their logic into the parent classes, which you do not have to write, so you get to focus on setting up your validation rules and relationships. For example, when you create a model in Yii 2 from a table, the model knows the attributes, you don’t have to declare them at the top of the class.

Not only is that convenient, but it also keeps the code clean and gives you a great structure that the models will adhere to. Depending on your level of OOP experience, this might not seem as apparent at first, because, as it is with any larger structure, there’s a lot to get used to. Just the sheer size of the framework can be a little overwhelming, expecially for newer programmers or those with less framework experience.

But learning a new framework always involves taking in a lot of new information, and if you think about it, constant learning is one of the defining characteristics of being a programmer, especially given how quickly things can change. Don’t worry, you are not alone in that, and the good news is that is a lot of support out there for Yii 2. A lot of programmers love this framework.

In the months ahead, I hope to be able to bring you more insights and tutorials that will help get the most out of your experience with Yii 2. Once again Happy Holidays to everyone around the world.

And thanks again to everyone who has supported my blog and book. Feel free to contribute with your own comments, links, and reviews, it is greatly appreciated.

Yii 2 FAQ

As part of our ongoing series to build a reusable template in Yii 2, we are going to do a tutorial on our FAQ model. We will focus mostly on our frontend implementation, but we will also be talking about the data structure, differences in the frontend and backend, and we will make use of Yii 2’s ArrayDataProvider, a very handy iterator for use in sending data to the views.

Ok, so if you are just joining the blog, and have not yet gotten started on the basics, I recommend my book, Yii 2 For Beginners, which is a step by step guide to get you installed, up and running, and into development. The book is oriented toward beginning programmers who are just making the transition into frameowrk development and in addition to explaining how things work, we take care to explain why things are done they way they are done.

This blog is meant to be an extension of the book, great for tips and tutorials, which will be included in the quarterly updates of the book. Anyone who purchases the book is entitled to the free quarterly updates for the entire life of the book, so hopefully you can take advantage of that.

One of the other big themes I like to explore is the idea of working for a client and keeping the client satisfied. I’m just going to assume that you will be building applications for a client who is difficult to please.

When we think of FAQs, we think of simplicity, just questions and answers, and simplicity typically serves us well. But if we think about our demanding client and things that are important to them, the order of the questions, for example, might be very important. And obviously, the order they want will most likely not match the ascending or descending timestamp for creation or alphabetical order.

In most cases, the client won’t even know what order they want the questions in until long after the project has been developed. So what we need is a way for them to determine the order via backend UI. Now this is really simple to do of course. We just add a faq_value field, with a data type of int, that we can sort either ascending or desceding depending on our preference.

For example, in an ascending sort, an FAQ with a value of 10 will be higher on the list than an FAQ with a value of 20. And as long as we give the client a method for changing the value of an FAQ from backend UI, the problem is anticipated and solved before it ever becomes an issue.

Yii 2 Test Controller

Welcome back to our beginner’s journey in Yii 2. I’ve made it my mission to help programmers at the beginning stages of framework development to learn about Yii 2, one of the most intuitive and powerful PHP frameworks available.

For those just getting started, I recommend my book, Yii 2 For Beginners, which will take you step by step through setup and onto coding. The book focuses on learning Yii 2 and building a reusable template that can serve as a starting point for your projects. It shows you how to do things, but also explains why we do things the way we do.

This blog serves as an extension of the book, where I share development tips and tutorials that will help you learn more about Yii 2. I also roll out new pieces of the template, which will be incorporated into the book on a quarterly basis. Anyone who purchases the book, gets free updates for the life of the book, so please take advantage of that, if you can.

Today’s tutorial is about implementing a simple test controller to help you with development. This tutorial is for beginning level programmers.

Sometimes in development, you want to isolate a block of code and play with it, without cluttering up your other code. Now version control should always be there if you made a huge mistake, but you really don’t want to be relying on that to step backwards unless you absolutely have to.

So what we’ll do is create a controller named test. We start by navigating to Gii, and clicking on Controller Generator. We don’t have to worry about creating a model first, since we don’t have one, our test controller will be used to play around with different bits of many models, and we will pull in the models via use statements as we need them.

If you don’t know how to use Gii or haven’t started using the framework yet, I would recommend learning that first before moving on to this tutorial. We’re assuming here that you know how to use Gii, which is Yii 2’s built-in code generator.

Ok, so back to the create Controller form on Gii. Pop in test into the first input field to name the controller. We will create just one action for now, Index. Then check to see if the namespace is set to where you want it to go.

In the advanced template, which is what I use because they provide a working user model, I’ve created a test controller for both frontend and backend, though that’s not really necessary. It just helps me when I’m thinking of things to intuitively associate a backend test controller with things I want to try in the backend. Also, sometimes, I leave code in place in the test controller while I’m thinking about whether or not I want to use it.

Ok, so when you hit preview on Gii, it will show two files, the controller and the view file. Once we click generate, it will also create the directory to hold the view file. So let’s do that now.

If all went well, you should have a TestController.php file in frontend\controllers and a frontend\views\test\index.php file.

Yii 2 Behaviors Blameable and Timestamp

One of the things that really made me fall in love with the Yii 2 framework is the intuitiveness of the behaviors method. Behaviors in Yii 2 is a very flexible concept that works on both models and controllers.

On the models, I’ve used two behaviors, timestamp and blameable. Both add a lot of efficiency to the model and prevent code duplication. I’ve talked about timestamp behavior before, I also cover it in my book, so I’ll just cover the basics.

Many times where you create or update a record in the database, you want to keep track of when you did it. This need is so common, that I’m almost tempted to push the behaviors method one layer down by creating my own class extending ActiveRecord and then by having all my models extend from that class. for example:


class MyActiveRecord extends ActiveRecord
{

 public function behaviors()
    {
        return [
            'timestamp' => [
                'class' => 'yii\behaviors\TimestampBehavior',
                'attributes' => [
                    ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
                    ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
                ],
                'value' => new Expression('NOW()'),
            ],
        ];
     }

}

So now, if I built all my models to extend MyActiveRecord instead of ActiveRecord, I get my created_at and updated_at fields updated automatically, assuming I have those fields in my DB table. Of course you would have to include a namespace and the appropriate use statements for it to work.

I generally tend not to use this approach, it’s too much for me because not every model that uses ActiveRecord I create will need it, and I prefer to do things the same way every time when I can, even if that is slightly more procedural. For example, I could extend MyActiveRecord when I want timestamp behavior and extend ActiveRecord when I don’t need the behavior. But then I have to keep track of it. Things like that really depend on the size of the project.

If I find there is a lot of code duplication with the behavior at the end of a project, I can optimize, and put the behavior in its own class as in the example. I would rather do it then because while I’m developing, it’s easier for me to get into the flow of the code by seeing the behavior in the same class as the model.

I’m not saying my way is a best practice, just sharing my particular method of doing it. At least now you are aware of some options and can decide for yourself.

Another pre-built behavior that yii 2 has made for you is the blameable behavior, which, when used in combination with the timestamp behavior, looks like this:


public function behaviors()
    {
        return [
            'timestamp' => [
                'class' => 'yii\behaviors\TimestampBehavior',
                'attributes' => [
                    ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
                    ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
                ],
                'value' => new Expression('NOW()'),
            ],
            'blameable' => [
                'class' => BlameableBehavior::className(),
                'createdByAttribute' => 'created_by',
                'updatedByAttribute' => 'updated_by',
                ],
            
        ];
     }

What blameable does is insert the current user id into the fields created_by and updated_by. This is a super-convient way of doing things. Every time a model gets created or updated, we know who to blame. Don’t you just love the name of the class?

This works out really well for large systems, where multiple users are doing admin and you need to keep track of who is doing what. You can also use this for frontend implementations, for example if you had a posts table and you wanted to use this method to keep track of the author. Alternatively, you could set that in the controller, but the behavior relieves you of having to write any additional code. This is extremely efficient, easy to implement, and easy to understand the benefit.

Now if I were writing a lazy tutorial, I would stop there. However, it’s worth noting that to extract the blameable username and display it, we need 4 additional methods on our model and the Yii 2 guide on behaviors does not mention them. Since this is not from the guide, please keep in mind that this is my way to do it, not necessarily official, and there may be a more concise way to do it that I’m not aware of.

However, until the docs are more complete, I had to come up with my own solution, which I’m pretty happy with at this point. I’m a big fan of these one line methods, which the Yii 2 guide does suggest using for relationships, so that’s how I approached this.

I simply created a get method to map the id field of user to the created_by field of the current model. Then in the next method, getCreateUserName(), we can access the username using the magic get syntax in a ternary statement:


public function getCreateUser()
{
    return $this->hasOne(User::className(), ['id' => 'created_by']);
}

       /**
       * @getCreateUserName
       * 
       */

public function getCreateUserName() 
{
    return $this->createUser ? $this->createUser->username : '- no user -';
}

I put in a condition for – no user – even though the blameable behavior will fire everytime and update to the current user. It doesn’t hurt to code in the possibility that there is no id stored, and in such a case, we return the string ‘- no user -‘. It would help you troubleshoot at the least.

Of course we had to do the same methods for updated_by, so that required 2 more methods.


public function getUpdateUser()
{
   return $this->hasOne(User::className(), ['id' => 'updated_by']);
}
       /**
       * @getUpdateUserName
       * 
       */

public function getUpdateUserName() 
{
    return $this->createUser ? $this->updateUser->username : '- no user -';
} 

I also had to add the following to my attribute labels method on my model:


 'createUserName' => Yii::t('app', 'Created By'),
 'updateUserName' => Yii::t('app', 'Updated By'),

And once you have those labels in place, you can use them in a view like so:


 <?= DetailView::widget([
        'model' => $model,
        'attributes' => [
            'id',
            'question',
            'answer',
            'faqCategory.faq_category_name',
            'faq_value',
            ['attribute'=>'createUserName', 'format'=>'raw'],
            ['attribute'=>'updateUserName', 'format'=>'raw'],
            'created_at',
            'updated_at',
        ],
    ]) ?>

Don’t worry about the rest of the example, that is my Faq model in the DetailView::widget. Ther relevant lines are:


 ['attribute'=>'createUserName', 'format'=>'raw'],
 ['attribute'=>'updateUserName', 'format'=>'raw'],
  

Those labels reference our get methods, using magic syntax, which means the get is implied, not explicit and you have to make the first word lower case. So now, instead of getting an id number displayed, we get the actual username. Cool stuff.

You can see that when we talk about implementing things, we have to jump around a bit. We went from behaviors on the model to calling a get method on the view, so we can return the username instead of user id.

Controllers can also implement the behaviors method, and this is incredibly useful for access control. I did a complete tutorial on RBAC using behaviors on the controllers, you should check that out if you want to continue on to see how you can use behaviors that way. I made implementing RBAC pretty simple, boiling it down to six easy steps.

I also cover this topic more extensively in my book, Yii 2 For Beginners.

Well, that’s it for this tutorial. Thanks for reading and thanks for your support. Feel free to add your comments and thoughts, it’s appreciated, as are links and reviews. Thanks again.