This is the seventh post in my series on Yii, my favorite PHP framework. In this post, I walk through some basic View edits you’ll make to the code auto-generated by the Yii framework. For some of the code, I’ll be using the employees-departments example I’ve been developing throughout these posts. You may want to reread earlier posts to get a handle on those.
(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.)
When you use the command-line and Gii tools to create a new Web application, the Yii framework generates a series of files and folders for you, from configuration files to controllers to Views. The Views are a series of PHP scripts, organized by folder. The first one you’ll want to edit is protected/views/layouts/main.php (where protected is the root application directory). This is the template for every page within the application. You’ll likely want to change most of the file to create your own look, but I want to highlight a few key points.
To start in the HEAD, you’ll see that external files are linked using
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/main.css" />
Whenever you see Yii::app(), that refers to the Web application as a whole. You can access information about the user viewing a page, about the current or previously-viewed page, etc., there. Yii::app()->request specifically references the current page being accessed (or requested). The ->baseUrl part refers to the root URL for the application, like http://www.example.com. You should use Yii::app()->request->baseUrl for references to external files—CSS, JavaScript, images, and so forth—as the relative path to them can become muddled with the changed Yii URLs (like www.example.com/index.php/site/login).
Next, you’ll see the page’s title set dynamically:
<title><?php echo CHtml::encode($this->pageTitle); ?></title>
By default, the pageTitle value will be the application’s name (defined in the config file) plus something about the current page. Later on, I’ll show you how to change this. The CHtml::encode() method is just used to protect against Cross-Site Scripting (XSS) attacks. You’ll see it used liberally (and appropriately) in the View files.
You’ll also see in the main layout file:
<div id="logo"><?php echo CHtml::encode(Yii::app()->name); ?></div>
Yii::app()->name is the name of the Web application, as established in the config/main.php file. You may or may not want to use it in your Views, but that’s where the value comes from.
Next up, the default layout uses a widget:
<?php $this->widget('zii.widgets.CMenu',array(...Widgets are a way to include a nugget of PHP code in a View using an external file. They’re best for things that aren’t tied to specific Views and that you may want to drop in anywhere. Plus it allows you to further separate out chunks of code for easier management and portability. The above code says that the CMenu widget should be dropped in here. That widget is part of the Zii extension (to the Yii framework). For more on widgets, see the Yii documentation.
Edit for Yii 1.1: Yii 1.1 took a bunch of the best extensions and placed them in their own namespace, zii. Whereas earlier versions of Yii created a MainMenu component, Yii 1.1 uses the CMenu widget. The default layout also makes use of the CBreadcrumbs widget, include in the Zii extensions.
Finally, the layout script has this line, which is the most important:
<?php echo $content; ?>
Now you won’t find a reference to the $content variable anywhere in your code and do note that it’s just $content, not $this->content or $model->content. This is where the page-specific content gets inserted into the layout. All the other HTML and PHP is the template for the entire site; the value of $content is what makes pageX different from pageY. So where does it come from?
Tip: The exact structure of the URLs will depend upon whether you’ve enabled urlManager or not and, if so, how it’s configured. See the post on configuring Yii for more.
If you’re viewing a page like www.example.com/index.php/employee/view/id/1, which is intended to show the employee with an ID of 1, the actionView() method of the EmployeeController class is called. That method loads the Employee Model with a primary key of 1, then renders the view View, passing along the Model in the process. That code is (this is from protected/controllers/EmployeeController.php):
public function actionView($id)
{
$this->render('view',array(
'model'=>$this->loadModel($id),
));
}The loadModel() method of this Controller class does the actual Model retrieval, and I won’t worry about that right now, but the $this->render() part says to render the View to be named, in this case, view. That means that Yii will execute the PHP script protected/views/employee/view.php. That script uses a $model variable (passed in the above code) to display information about the employee within some context (specifically, view.php script uses zii.widgits.CDetailView to list the details) . The result of this executed View script is, behind the scenes, assigned to $content, and therefore dropped into the appropriate place in the layout. That’s how the system works.
One last thing about the layout scripts is that you can easily have different layouts for different sections of the application. To do so, in the Controller method, change the layout value before rendering the view. Provide the name of the layout file, minus the extension. So this line says to use protected/views/layouts/home.php for the index action:
class SiteController extends CController
{...
public function actionIndex()
{...
$this->layout = 'home';In fact, as of Y 1.1.?, the framework creates both one column and two column layouts, each of which use the main.php template file. The Controller then indicates which layout to use for the entire Controller:
class EmployeeController extends Controller
{
public $layout='//layouts/column2';Note: $this->layout within a class method is equivalent to just public $layout outside of any method (as in the above code). The first example changes the layout for a specific action; the second for the Controller as a whole.
Moving on to the View scripts, one of the first things I normally do is change the basic formatting to whatever you’re looking for. For example, the default appearance of a show View is a table of information about the Model: labels and values. Normally you don’t want to show all of the Model data, and you’ll display it in DIVs or paragraphs. These are simple edits. As the above code shows, the Model information will be passed under the name model, so you can use $model->whatever to access the values of the different fields.
Edits for Yii 1.1: There are a number of View file changes, although none that are dramatic: What was previously the list (list.php) View file is now index (index.php). The index page makes use of a CListView widget to list the records. The admin page makes use of a CGridView widget to display all the records. The show file (show.php) is now called view (view.php). It makes use of the CDetailView widget to show the information for a specific record. Multiple View files can make use of the _view.php script, which is a template for showing an individual record. Every view file identifies breadcrumb information at the top, which will tie into the CBreadcrumbs widget referenced in the main layout file.
Tip: If you log into the site (using admin/admin if you haven’t changed the login system) and then go to www.example.com/index.php/department/, you can already create a few department records to make better sense of what I write below.
The index and admin Views both show multiple Model records, using Zii widgets. index.php uses the CListView widget, using the _view.php script as the template. If you edit either _view.php or how CListView is configured (in index.php), you’ll change the listings. The admin page, accessed by clicking on “Manage XXX”, uses the CGridView widget. This widget creates a table of data, with links to view, edit, or delete specific records. The table can be paginated and searched, using Ajax. It’s really sharp and a great demonstration of how much Yii will do for you. This figure shows the departments listing, without having made any changes to what Yii created:
The create and update Views have some page header stuff, then include the form View, using this code:
<?php echo $this->renderPartial('_form', array('model'=>$model)); ?>That code renders a partial View in that place, passing along the Model information to _form.php.
Looking at the generated code, the Department form is fine, as it just provides an input for the department’s name. For the Employee Model, however, there’s some customization you’ll need to do there. You can check it out by heading to www.example.com/index.php/employee/create/.
By default, the forms generated by Gii includes elements for every Model attribute, save for the primary key. But some fields, like the dates created or modified, may be automatically populated with timestamps, and therefore aren’t inputted by the users. And, with related Models, like Employee and Department, you’ll end up needing a drop-down menu in the one to select a value from the other, like choosing what department an employee is in. The Yii-generated code won’t do this for you; the form will just have a text field created by this code:
<?php echo $form->textField($model,'departmentId'); ?>
The $form variable is an object of CActiveForm type. The textField() method creates a text input. The first argument says that the input should be for the $model object (which is the current Model instance, coming from the Controller). The second argument identifies the property in the Model that this element is for.
To create a drop-down associated with another Model, you’d replace that code with:
<?php echo $form->dropDownList($model,'departmentId', CHtml::listData(Department::model()->findAll(), 'id', 'name')); ?>
First, the dropDownList() method of the $form object creates a drop-down list. You need to tie it to the form-associated Model, so the first argument is just $model, the same variable passed to this View when it’s rendered. The second argument is the name of the form field/Model field: here, the departmentId field in the Employee Model. Next, you need to provide the method with the list of values to use for the drop-down menu, which is achieved by calling CHtml::listData(). That method returns a list of values that are usable in drop down menus. Its data source should be the list of Departments. To retrieve those, use Yii’s approach for retrieving all the records in a Model: ModelName::model()->findAll(). So to fetch every department, use Department::model()->findAll(). The final two arguments (to the CHtml::listData() method) are the fields to use for the drop-down menu’s value and displayed text. Those should be id (the department’s ID) and name.
Another thing you’ll want to do in all your View files is remove or edit the links to the different admin features.
Finally, you may decide you want to change the page’s title. To do that, use code like:
<?php $this->pageTitle = $model->something; ?>
Note that you’re assigning a value to $this->pageTitle here, not $model->pageTitle, but you’ll likely use the contents of $model, like a title or name field, as the page title value. You can also still add in the application name, if you want, by concatenating in Yii::app()->name.
Whew! So that’s my whirlwind tour of basic View edits you’ll want to make to a fresh Yii application. In my next post, I’ll discuss basic Controller edits, of which there are surprisingly few, I find. As always, thanks for reading what I have to say and do let me know if you have any questions or comments.


Larry,
Can you please tell me how I might modify Detail View page of the Employee object such that it doesn’t show the DepartmentID but the Department’s name instead (ie, to match your switch from departmentid to department name dropdown in Create)?
Once you’ve established the relationship, you just need to use $model->relationship_name->property, such as $model->department->name.
Will you please elaborate how can use it, with small code example.
Okay. I’ll try to write this up in another post.
Hello Larry, i love this intro to yii,
Can i make label and textfield to appear on the same line on Create view?
thanks in advance.
Thanks for the nice words. In answer to your question, certainly, you just need to edit the HTML and CSS accordingly.
Hell Larry, great work! will definitely buy the book when you publish!
BTW, how would I set up a list view that only displays entries from a single dept?
oops, typo, sorry. Obviously I meant Hello not Hell
If I hadn’t enable SEO friendly urls what should this path look like? http://www.example.com/index.php/employee/view/id/1
If I understand you correctly, the URL without SEO enabled would be http://www.example.com/index.php?r=employee/view&id=1. You can, of course, disable the SEO feature in the configuration file and see for yourself what the results would be.
hello Larry, great work here,
any idea how checkBoxList works coz i need to entrer multiple value into the same field.
Thanks for the nice words. Yes, I do know how the checkBoxList works. If you need help, please use either the Yii forums or my support forums.
Hello Larry excellent post!
Could you help me with this I am trying to use the dropDownList to select the department but is giving me an error.
I wrote this code
dropDownList($model,’departmentId’,CHtml::listData(Department::model()->findAll(‘id’,'name’)))?>
thank you
Thanks for the nice words. The solution largely depends upon the error. If you need help, please use either the Yii forums or my support forums.
Good work !! I feel better when i followed your tutorial from the first one of this series.. A doubt came when i read this section. Consider that i’ve user model and this user model can be used for user and admin as well. so when a user logs in, he should view a profile page whereas when a admin logs in he should view the list of users.. How can i configure different views for a model like this one?
Thanks for the nice words. I’m glad you liked it. As for your question, if there’s only one administrator, you could limit access to that particular user by name. If there may be multiple administrators, then I’d add a user level attribute and restrict access to content based upon the user level.
thanks for the tutorial it really help me,
my question is how to make a date picker for hire_date and leave_date?
and validate the date format?
thank you,
You’d use the jQuery UI date picker and set the formatting in the date picker so that it works with what the Model requires.
I can show Department name in Manage Employee page similar to List Employee page by adding
array(‘header’=>’Dept. Name’, ‘value’=>’$data->department->name’),
below
‘columns’=>array(
‘id’,
‘departmentId’,
in view/employee/admin.php
How can I make this new Dept. Name column filterable like other columns in gridview?
Thank you in advanced.
hi,Larry
In Gridview (employee/admin) i am displaying department name
but in search how can i search for results Department with name?
Department id is the foreign key in employee..
$(‘.search-button’).click(function(){
$(‘.search-form’).toggle();
return false;
});
$(‘.search-form form’).submit(function(){
$.fn.yiiGridView.update(‘employee-grid’, {
data: $(this).serialize()
});
return false;
});
please can u explain me the meaning of the above written code.
Hi: Im new to Gii but maybe I can gve you an explanation to this jquery chunk of code:
. What it does is capture the ´Advanced Search form´ submission, in other words, when you click the ‘Search’ button of that form.
—————————————————————
/*$(‘.search-button’).click(function(){
$(‘.search-form’).toggle();
return false;
});*/
This first code it is an easy one, what it does is handle the ‘clicks’ over the ´Advanced Search´ link, and what it does is: if the ‘advanced search form’ is visible, then it hides. And, if that form is hidden, then it shows it. It is like a show()/hide() function, check jqeury documentation if you want further explanation:
http://api.jquery.com/toggle/
————————————————————————–
$(‘.search-form form’).submit(function(){
$.fn.yiiGridView.update(‘employee-grid’, {
data: $(this).serialize()
});
return false;
});
This is a little more tricky
Then it makes an ajax call that returns the html code needed in order to re-render the whole page, but what it is different is that that returned code is constructed with additional params on the url, that additional params are applied as filters, and also they are written inside their corresponding textfields:
Look an exmaple of how those calls are made. You can copy and paste that urls inside your browser (with your correponding baseUrl) and they will render a page with filled textFields and a filtered table:
-> Looking for a Employee of Department with id =1
http://localhost/yii/ropavirtual/employee/admin?Employeeid=&EmployeedepartmentId=1&EmployeefirstName=&EmployeelastName=&Employeeemail=&Employeeext=&EmployeehireDate=&EmployeeleaveDate=&ajax=employee-grid
I hope it helps you. I strongly recommend you to download and use the firebug plugin to check what is going on behind the curtains. Regards.
Hi, good work.
I got the dropdownlist working only after i changed:
findAll(), ‘id’, ‘name’));
to
findAll(), ‘departmentId’, ‘name’));
That should not be correct. The name of the primary key column in Department is id, not departmentId.
Hi Larry.
Maybe I named it incorrectly somewhere.
Thanx for replying anyway.
Keep up the good work, since the official Yii Class Reference appears to have zero examples.
(I also bought the new cook-book by Alexander Makarov, but still no luck).
For example:
I wondered if it is possible to add a CHtml::submitButton as an item to a menu array?
So, instead of just having:
$this->menu=array(
array(‘label’=>’List Company’, ‘url’=>array(‘index’)),
array(‘label’=>’Create Company’, ‘url’=>array(‘create’)),
);
you have something like this:
$this->menu=array(
array(‘label’=>’List Company’, ‘url’=>array(‘index’)),
array(‘label’=>’Create Company’, ‘url’=>array(‘create’)),
array(CHtml::submitButton(‘Login’)),
);
The menu should thus have 3 buttons: List Company, Create Company and Login (submit button).
I posted this question on Yii forum with plenty of views but no reply. And by scanning the Yii Class References (without examples), I can’t find something that would hold an array of CHtml submit buttons.
I suppose that is the problem with a new framework – so please keep up the good work.
Best regards
Gerhard
I was getting this error when attempting to add an employee record: “SQLSTATE[22007]: Invalid datetime format: 1292 Incorrect datetime value” This article helped clear it up: http://www.yiiframework.com/forum/index.php/topic/12125-problem-with-creating-a-new-project-in-chapter-5/
Thanks for sharing what you figured out, Pedro.
WOW!!!! thanks. I have been using a few various frameworks over the years and randomly ran into your posts about yii. Read them all and am excited to give yii a shot. Funny how we learn all these frameworks, build others sites and end up using wordpress for our own right? Just something i noticed, I do the same.
Thanks for taking the time to write this. it was so very informative.
Thanks, Brandon. I know what you mean about learning frameworks/Web development, but then using WordPress, although I would say it’s part of the same thing: choose the right tool for the job! I could spend a day creating my own blogging software using Yii, and it wouldn’t be nearly as feature-packed as what I’d have by using WordPress in about 5 minutes.