Basic Controller Edits in Yii

November 15, 2009
The Yii Book If you like my writing on the Yii framework, you'll love "The Yii Book"!
This entry is part 8 of 8 in the series Learning the Yii Framework

After using Yii‘s command-line and Gii tools to build an application’s base structure, and then to create its Models and crud functionality, there’s still quite a bit of customizing to do (although Yii really does perform the bulk of the work). Previous posts discuss some of the common changes one makes to Models and Views at this point in the development stage; here I’ll discuss Controllers. I have personally found that I don’t make nearly the level of alterations to my auto-generated Controllers as I do to my Models and Views. This makes sense, as the Model should have the bulk of the code, the View is the interface the end user sees, and the Controller is largely an agent between the two (see [intlink id=”453″ type=”post”]my series on the MVC architecture[/intlink] for more on this).

(Note: In October 2010, I’ve updated this entire series to reflect changes in Yii since this series was written, and to take into account feedback provided through the comments. Some outdated material will be crossed out, but left in to reflect how things have changed since the series was begun in June 2009.)


Edit for Yii 1.1: The $defaultAction line is no longer present. Also, the names of some of two of the action methods have changed to match the new names of the corresponding View files: actionView() and actionIndex().


The Controller represents the actions a user takes with a site: views a specific record, updates a record, lists all the records, etc. A user request (i.e., the loading of a URL) is handled by the Yii application, then passed off to the corresponding Controller. It’s the Controller’s duty to perform any necessary work, likely involving the loading or manipulation of some Models, then pass data off to the View. As with any class definition, all of the tasks are performed within methods.

The first thing you’ll encounter within a Controller class is a variable called $layout:

public $layout='//layouts/column2';

As explained in the post on Views, this variable dictates which of the two built-in layouts—one column or two column—the Controller uses. You can change this value to change the layout for the entire Controller, or you can change $this->layout within any of the methods.

Another class variable, which used to be written into the class but now has to be added is:

public $defaultAction='admin';

As just stated, Controllers are the actions one takes, listing information, showing particular records, handling form submissions, and so forth. For each action there is a corresponding method in the Controller class: actionIndex(), actionView(), actionCreate(), etc. The above line dictates which method is called if not otherwise specified. So with that line, the URL www.example.com/index.php/employee calls the actionAdmin() method whereas www.example.com/index.php/employee/create calls actionCreate(). The default value, if you don’t use that line, is to call actionIndex().

Your Controllers should also have several non-action methods, including accessRules(). This method is a key part of the security picture, dictating who can do what. For the “what” options, you have your actions: list, show, create, update, and delete. Your “who” depends upon the situation, but to start there’s at least logged-in and not logged-in users, represented by * (anyone) and @ (logged-in users), accordingly. Depending upon the login system in place, you may also have levels of users, like admins. So the accessRules() method uses all this information and returns an array of values. The values are also arrays, indicating permissions (allow or deny), actions, and users:

public function accessRules()
{
    return array(
        array('allow',  // allow all users to perform 'index' and 'view' actions
            'actions'=>array('index','view'),
            'users'=>array('*'),
        ),
        array('allow', // allow authenticated user to perform 'create' and 'update' actions
            'actions'=>array('create','update'),
            'users'=>array('@'),
        ),
        array('allow', // allow admin user to perform 'admin' and 'delete' actions
            'actions'=>array('admin','delete'),
            'users'=>array('admin'),
        ),
        array('deny',  // deny all users
            'users'=>array('*'),
        ),
    );
}

That’s the default setting, where anyone can perform index and view actions, meaning that anyone can list all records or view individual records in the associated Model. The next section allows any logged-in user to perform create and update actions. Next, only administrators can perform admin and delete actions. Finally, a global deny for all users is added, to cover any situation that wasn’t explicitly defined. This is just a good security practice. Note that these rules just apply to this Controller; each Controller needs its own rules.

You’ll want to customize the rules to each Controller and situation. For example, I did a site with a subscription system, represented by a Contact Model. In that case, anyone had to be allowed to create new Contact records but only the admin was allowed to list or show Contact records. Generally, though, I think most Controllers would allow everyone to perform show and list actions.

You can also create more sophisticated conditionals to create permissions, but that will be a [intlink id=”478″ type=”post”]subject for another post[/intlink]. For example, on one project I did, any logged-in user could create certain types of content but they could only update and delete records that they themselves created. Or you could allow users show permission only on their own Contact record.

Finally, you may need to change your Controllers so that the retrieval of Model records is handled differently. There are a few methods that load records to be used in a View. Some of the methods, like actionView() and actionUpdate(), call a loadModel() method whose job it is to retrieve a single record. Other methods, like actionIndex() and actionAdmin() retrieve every Model record (using a different approach). In these methods, there are a couple of changes you may want to make. For starters, if the Model in question is related to another Model, as defined in the Model class’s relations() method ([intlink id=”657″ type=”post”]see my post on Models[/intlink]), you can invoke that relation when you retrieve the record(s). For example, this code will retrieve an employee, plus the department for that employee:

$model=Employee::model()->with('department')->findByPk((int)$id);

You only want to do this if you’ll use the related records, of course.

You might also tweak the criteria applied to these methods, but that is a big topic. It basically involves adding WHERE SQL conditions to a query. I’ll address it in another post but you can also see the Yii documentation, of course.

So this makes the eighth post in a series on using the Yii framework, from start to kinda-finish. I’ve got a bunch of miscellaneous topics on the subject to post about, but I won’t write those up formally as part of this series. To find those, or any other posting on Yii, use the tags at right.

As always, thanks for reading and let me know if you have any comments or questions.

Larry

Series Navigation

Basic View Edits in Yii