Tuesday, July 3, 2012

Defining multiple layouts in YII Frameworks

Most applications use a single layout for all their views. However, there are situations when
multiple layouts are needed. For example, an application can use different layouts at different
pages: Two additional columns for blog, one additional column for articles, and no additional
columns for portfolio.
Getting ready
Set up a new application using yiic webapp.
How to do it...
1. Create two layouts in protected/views/layouts: blog and articles. Blog will
contain the following code:
<?php $this->beginContent('//layouts/main')?>
<div>
<?php echo $content?>
</div>
<div class="sidebar tags">
<ul>
<li><a href="#php">PHP</a></li>
<li><a href="#yii">Yii</a></li>
</ul>
</div>
<div class="sidebar links">
<ul>
<li><a href="http://yiiframework.com/">Yiiframework</a></li>
<li><a href="http://php.net/">PHP</a></li>
</ul>
</div>
<?php $this->endContent()?>
2. Articles will contain the following code:
<?php $this->beginContent('//layouts/main')?>
<div>
<?php echo $content?>
</div>
<div class="sidebar toc">
<ul>
<li><a href="#intro">1. Introduction</a></li>
<li><a href="#quick-start">2. Quick start</a></li>
</ul>
</div>
<?php $this->endContent()?>
3. Create three controllers named BlogController, ArticleController, and
PortfolioController with index actions in both:
class BlogController extends Controller
{
function actionIndex()
{
$this->layout = 'blog';
$this->render('//site/index');
}
}
class ArticleController extends Controller
{
function actionIndex()
{
$this->layout = 'articles';
$this->render('//site/index');
}
}
class PortfolioController extends Controller
{
function actionIndex()
{
$this->render('//site/index');
}
}
4. Now try http://example.com/blog, http://example.com/article, and
http://example.com/portfolio.
How it works...
We defined two additional layouts for blog and articles. As we don't want to copy-paste
common parts from the main layout, we apply additional layout decorators using $this-
>beginContent and $this->endContent, as shown on the following diagram:
So, we are using a view rendered inside articles layout as main's $content.

Using decorators in YII frameworks

In Yii, we can enclose content into a decorator. The common usage of decorators is
layout. Yes, when you are rendering a view using the render method of your controller, Yii
automatically decorates it with the main layout. Let's create a simple decorator that will
properly format quotes.
Getting ready
Set up a new application using yiic webapp.
How to do it...
1. First, we will create a decorator file protected/views/decorators/quote.php:
<div class="quote">
&ldquo;<?php echo $content?>&rdquo;, <?php echo $author?>
</div>
2. Now in protected/views/site/index.php, we will use our decorator:
<?php $this->beginContent('//decorators/quote', array('author' =>
'Edward A. Murphy'))?>
If anything bad can happen, it probably will
<?php $this->endContent()?>
3. Now, your homepage should include the following markup:
<div class="quote">
&ldquo;If anything bad can happen, it probably will&rdquo;,
Edward A. Murphy
</div>
How it works...
Decorators are pretty simple. Everything between beginContent and endContent
is rendered into a $content variable and passed into a decorator template. Then, the
decorator template is rendered and inserted in the place where endContent was called. We
can pass additional variables into decorator using a second parameter of beginContent,
such as the one we did for the author.

Using clips in YII

One of the Yii features you can use in your views is clips. The basic idea is that you can record
some output and then reuse it later in a view. A good example will be defining additional
content regions for your layout and filling them elsewhere.
Getting ready
Set up a new application using yiic webapp.
How to do it...
1. For our example, we need to define two regions in our layout: beforeContent and
footer. Open protected/views/layouts/main.php and insert the following
just before the content output (<?php echo $content; ?>):
<?php if(!empty($this->clips['beforeContent'])) echo
$this->clips['beforeContent']?>
Then, insert the following into <div id="footer">:
<?php if(!empty($this->clips['footer'])) echo
$this->clips['footer']?>
2. That is it. Now, we need to fill these regions somehow. We will use a controller
action for the beforeContent region. Open protected/controllers/
SiteController.php and add the following to actionIndex:
$this->beginClip('beforeContent');
echo 'Your IP is '.Yii::app()->request->userHostAddress;
$this->endClip();
3. As for footer, we will set its content from a view. Open protected/views/site/
index.php and add the following:
<?php $this->beginClip('footer')?>
This application was built with Yii.
<?php $this->endClip()?>
4. Now, when you open your website's index page, you should get your IP just before the
page content and "built with" note in the footer.
How it works...
We mark regions with the code that just checks for existence of a clip specified and, if
clip exists, the code outputs it. Then, we record content for clips we defined using special
controller methods named beginClip and endClip.

Reusing views with partials in YII frameworks

Yii supports partials, so if you have a block without much logic that you want to reuse or want
to implement e-mail templates, partials are the right way to look.
Getting ready
1. Set up a new application using yiic webapp.
2. Create a WebsiteController as follows:
class WebsiteController extends CController
{
function actionIndex()
{
$this->render('index');
}
}
How to do it...
We will start with a reusable block. For example, we need to embed a YouTube video at
several website pages. Let's implement a reusable template for it.
1. Create a view file named protected/views/common/youtube.php and paste an
embed code from YouTube. You will get something like:
<object width="480" height="385"><param name="movie"
value="http://www.youtube.com/v/S6u7ylr0zIg?fs=1 "></
param><param name="allowFullScreen" value="true"></
param><param name="allowscriptaccess" value="always"></
param><embed src="http://www.youtube.com/v/S6u7ylr0zIg?fs=1"
type="application/x-shockwave-flash" allowscriptaccess="always"
allowfullscreen="true" width="480" height="385"></embed></object>
2. Now, we need to make it reusable. We want to be able to set video ID, width, and
height. Let's make width and height optional, as follows:
<object width="<?php echo!empty($width) ? $width : 480?>"
height="<?php echo!empty($height) ? $height: 385?>"><param
name="movie" value="http://www.youtube.com/v/<?php echo
$id?>?fs=1 "></param><param name="allowFullScreen" value="true"></
param><param name="allowscriptaccess" value="always"></
param><embed src="http://www.youtube.com/v/<?php echo $id?>?fs=1"
type="application/x-shockwave-flash" allowscriptaccess="always"
allowfullscreen="true" width="<?php echo !empty($width) ? $width
: 480?>" height="<?php echo !empty($height) ? $height: 385?>"></
embed></object>
3. Now, you can use it in your protected/views/website/index.php like this:
<?php $this->renderPartial('////common/youtube', array(
'id' => '8Rp-CaIKvQs', // you can get this id by simply looking
at video URL
'width' => 320,
'height' => 256,
))?>
Looks better, right? Note that we have used // to reference a view. This means that
Yii will look for a view starting from protected/views not taking controller name
into account.
4. Now, let's send some e-mails. As we are unable to write unique letters to thousands
of users, we will use a template but will make it customized. Let's add a new method
to protected/controllers/WebsiteController.php as follows:
class WebsiteController extends CController
{
function actionSendmails()
{
$users = User::model->findAll();
foreach($users as $user)
{
$this->sendEmail('welcome', $user->email, 'Welcome to the
website!', array('user' => $user));
}
echo 'Emails were sent.';
}
function sendEmail($template, $to, $subject, $data)
{
mail($to, $subject, $this->renderPartial
('//email/'.$template, $data, true));
}
}
5. Here is our template protected/views/email/welcome.php:
Hello <?php echo $user->name?>,
Welcome to the website!
You can go check our new videos section. There are funny raccoons.
Yours,
Website team.
How it works...
CController::renderPartial does the same template processing as
CController::render except the former does not use layout. As we can access current
controller in a view using $this, we can use its renderPartial to use view within another
view. renderPartial is also useful when dealing with AJAX as you don't need layout
rendered in this case.

yii framework Using controller context in a view

Yii views are pretty powerful and have many features. One of them is that you can use
controller context in a view. So, let's try it.
Getting ready
Set up a new application using yiic webapp.
How to do it...
1. Create a controller as follows:
class WebsiteController extends CController
{
function actionIndex()
{
$this->pageTitle = 'Controller context test';
$this->render('index');
}
function hello()
{
if(!empty($_GET['name']))
echo 'Hello, '.$_GET['name'].'!';
}
}
2. Now, we will create a view showing what we can do:
<h1><?php echo $this->pageTitle?></h1>
<p>Hello call. <?php $this->hello()?></p>
<?php $this->widget('zii.widgets.CMenu',array(
'items'=>array(
array('label'=>'Home', 'url'=>array('index')),
array('label'=>'Yiiframework home',
'url'=>'http://yiiframework.ru/',
),
))?>
How it works...
We are using $this in a view to refer to a currently running controller. When doing it, we can
call a controller method and access its properties. The most useful property is pageTitle
which refers to the current page title and there are many built-in methods that are extremely
useful in views such as renderPartials and widget.