Yii 1.1: How to implement multiple page layouts in an application

25 followers

In this tutorial, we describe how to implement multiple layouts for action views in an application. As an example, we assume that the pages in our application will use three different layouts:

  • one-column layout: contains only the main content area;
  • two-column layout: contains a left sidebar displaying portlets, and the main content area;
  • three-column layout: contains a left sidebar displaying portlets, the main content area, and the right sidebar displaying some context information.

Designing Layouts

To simplify the CSS design, we use the 960 Grid System.

Because all layouts have the similar header and footer sections, we first develop the main layout which will serve as the parent of the three layouts. We store all these layout files under the same folder protected/views/layouts. Below is the code for the main layout (stored as the file main.php):

<html>
<head>
<?php echo CHtml::cssFile(Yii::app()->baseUrl.'/css/reset.css'); ?>
<?php echo CHtml::cssFile(Yii::app()->baseUrl.'/css/text.css'); ?>
<?php echo CHtml::cssFile(Yii::app()->baseUrl.'/css/960.css'); ?>
<?php echo CHtml::cssFile(Yii::app()->baseUrl.'/css/main.css'); ?>
</head>
<body>
<div class="container_16">
    <div class="grid_16">
        <div id="header">
        ...site logo and other header content...
        </div>
    </div>
 
    <div class="clear">&nbsp;</div>
 
    <div class="grid_16">
    ...main menu...
    </div>
 
    <div class="clear">&nbsp;</div>
 
    <div class="grid_16">
        <?php echo $content; ?>
    </div>
 
    <div class="clear">&nbsp;</div>
 
    <div class="grid_16" id="footer">
    ...footer content...
    </div><!-- footer -->
 
</div><!-- container -->
 
</body>
</html>

Next, we will develop those column-based layouts.

We start with the simplest one-column layout which is stored as the file column1.php:

<?php $this->beginContent(); ?>
 
<?php $this->widget('Breadcrumbs', array('crumbs'=>$this->crumbs)); ?>
 
<div id="content">
    <?php echo $content; ?>
</div>
 
<?php $this->endContent(); ?>

In this layout, we enclose the view content in a pair of CController::beginContent and CController::endContent method calls. Because we do not pass any parameter to the CController::beginContent, it means the default layout (which is main we just developed) will be applied to this view.

Notice also that we include a BreadCrumbs widget at the beginning of the view. The widget is a customly developed to display breadcrumbs (navigation path) of the current page. The reference $this stands for the current controller, and we use its crumbs property to store the breadcrumbs data.

We now develop the two-column layout which is stored as the file column2.php.

<?php $this->beginContent(); ?>
 
<div class="grid_4 alpha">
    <div class="sidebar">&nbsp;
    <?php foreach($this->portlets as $class=>$properties)
        $this->widget($class,$properties); ?>
    </div>
</div>
 
<div class="grid_12 omega">
    <?php $this->widget('Breadcrumbs', array('crumbs'=>$this->crumbs)); ?>
 
    <div id="content">
        <?php echo $content; ?>
    </div>
</div>
 
<?php $this->endContent(); ?>

Compared with the one-column layout, this layout adds a sidebar column in which we render a list of portlets. The specification of portlets are stored in the portlets property of the current controller.

And finally, we create the three-column layout and save it as column3.php.

<?php $this->beginContent(); ?>
 
<div class="grid_4 alpha">
    <div class="sidebar">&nbsp;
    <?php foreach($this->portlets as $class=>$properties)
        $this->widget($class,$properties); ?>
    </div>
</div>
 
<div class="grid_9">
    <?php $this->widget('Breadcrumbs', array('crumbs'=>$this->crumbs)); ?>
 
    <div id="content">
        <?php echo $content; ?>
    </div>
</div>
 
<div class="grid_3 omega">
    <div class="sidebar">&nbsp;
    <?php foreach($this->portlets2 as $class=>$properties)
        $this->widget($class,$properties); ?>
    </div>
</div>
 
<?php $this->endContent(); ?>

Nothing special here. We add yet another extra sidebar column and display a list of portlets whose specification comes from the portlets2 property of the current controller.

Using Layouts

As we know that the layout of a page (generated by calling CController::render) is mainly determined by two properties: CWebApplication::layout and CController::layout. The former sets the global layout that applies to all pages in the application, while the latter can be used to override the former to specify an individual layout for a particular page.

In order to use the above column-based layouts, we need to configure the CController::layout property in each action view. We can configure this property in the controller or action class, but a better place would be in the view script since this is related with rendering. For example, if a post list page needs to use three-column layout, we can have the following code for the list view:

<?php
$this->layout='column3';
?>
...render the post list...

Similarly, we can set layout to be column1 or column2 based on requirements.

One thing we are missing here is how to specify the breadcrumbs and portlets since they may vary among different views. Because in all these layouts, we are assuming the current controller has crumbs, portlets and portlets2 properties, it is natural that we use a base controller class to define these common properties, and then we can derive from this base class each individual concrete controller class. We may store this base class in the file protected/components/BaseController.php.

abstract class BaseController extends CController
{
    public $crumbs=array();
    public $portlets=array();
    public $portlets2=array();
}

Now, if we want to display in the list view two portlets: one showing the post categories, the other showing the recent comments, we can modify the list view as follows:

<?php
$this->layout='column3';
$this->portlets['PostCategoryPortlet']=array();
$this->portlets['RecentCommentPortlet']=array('count'=>5);
?>
...render the post list...

In the above, we also need to configure the breadcrumbs of the view. We will leave this as an exercise for you.

Total 2 comments

#4019 report it
Aabbid at 2011/05/28 02:21am
Continue study...

Don't know I am right or not.

To create PostCategoryPortlet.php, you may need to study this. Creating User Menu Portlet

#1764 report it
jonah at 2009/04/13 01:39am
bug

This seems to go into an endless loop unless I change the line

<?php $this->beginContent(); ?>

to

<?php $this->beginContent('/layouts/main'); ?>

Leave a comment

Please to leave your comment.

Write new article
  • Written by: qiang
  • Updated by: wei
  • Category: Tutorials
  • Yii Version: 1.1
  • Votes: +24
  • Viewed: 83,413 times
  • Created on: Apr 8, 2009
  • Last updated: Oct 25, 2010
  • Tags: layout