Subscribe

Subscribe to our newsletter or follow us on Twitter and receive big discounts when new books are available!


Buy the first edition of this e-book (includes 3+ hours of companion video) for just $15 and you will receive the forthcoming second edition for free!


Beta Chapters

Chapter 00. Introduction

Chapter 01. Introducing Framework-Driven Development

Chapter 02. Creating Your First Zend Framework Application

Chapter 03. Managing Layouts, Views, CSS, Images and JavaScript


To add a comment, click on the desired paragraph! I'll add more features in coming releases. I have tested the beta site using Google Chrome and Firefox 3.6.8. Opera is currently buggy.

Easy PHP Websites with the Zend Framework, 2E

Chapter 3. Managing Layouts, Views, CSS, Images and JavaScript

Much attention is devoted to sexier features such as web services integration, yet for the majority of developers the true productivity boosts come from frameworks' ability to manage more mundane details such as configuration data and website assets such as templates, CSS, images, and JavaScript. The lack of focus upon these features is ironic given the enormous amount of time and effort you and your team will spend organizing these resources over the course of a project's lifecycle. Because understanding how to maximize the Zend Framework's ability to manage these assets is almost certainly going to have a dramatic effect on your efficiency, I've opted to devote an early chapter to the topic.

In this chapter I'll introduce you to quite a few of the Zend Framework's asset management features, beginning with showing you how to effectively manage your website templates (referred to as layouts in Zend Framework vernacular), as well as override the default behaviors of layouts and views. You'll also learn about the framework's view helpers, and even learn how to create custom view helpers, which can go a long way towards keeping your code DRY. Next, we'll talk about several native features which can help you manage your website images, CSS, and JavaScript. Finally, the chapter concludes with several examples demonstrating how to construct tests capable of helping you identify any errors which may arise when implementing the aforementioned features.

Managing Your Website Layout

One common approach to managing website templates (layouts) involves creating a series of files with each containing a significant portion of the site, including the header and footer. Several require_once statements are used within each page to include the header and footer, thereby assembling the page in its entirety. However maintaining these page components in separate files quickly becomes tedious, particularly for web designers who prefer to use WYSIWYG (What-You-See-Is-What-You-Get) tools to create and maintain page elements.

The Zend Framework offers a far more convenient solution which allows you to manage a web site template within a single file. This file contains the site's header, footer, and any other data which should be made available within every page. Each time a page is requested, the framework will render the layout, injecting the action's corresponding view into the layout at a specific location. I'll talk about precisely what that location is in a moment, however first enable the framework's layout feature for your application by executing the following command from the application's root directory:

%>zf enable layout
Layouts have been enabled, and a default layout created at 
/var/www/dev.gamenomad.com/application/layouts/scripts/layout.phtml
A layout entry has been added to the application config file.

As the command output indicates, this file is named layout.phtml and it resides in the directory application/layouts/scripts/. Open this file and you'll see a single line:

<?php echo $this?>layout()->content; ?>

This is the location where the action's view will be injected into the layout. Therefore you can add your site's global page elements simply by building around this command. For instance, one of the first things you'll probably want to do is add the standard HTML header and closing tags:

<html>
<head>
<title>GameNomad</title>
</head>
<body>
<h1>Welcome to GameNomad</h1>
<?php echo $this?>layout()->content; ?>
<p>
Questions? Contact the GameNomad team at team@gamenomad.com!
</p>
</body>
</html>

Once saved, navigate to any page within your site and you'll see that the header and footer are now automatically added, as depicted in Figure 3-1.

Figure 3.1. Using the Zend Framework's layout feature

Using the Zend Framework's layout feature

Using Alternative Layouts

Although the typical web site embraces a particular design theme, it's often desirable to use multiple layouts in order to accomodate the organization of different data sets. Consider for instance the layout of any major media web site such as The Wall Street Journal (http://www.wsj.com). The site's home page and several of the category home page use a three-column layout, whereas those pages which display an article employ a two-column layout. You can change an action's layout setting by retrieving an instance of the layout by way of a feature known as the helper broker, and then calling the setLayout() method, passing in the name of the alternative layout:

$layout = $this->_helper->layout();
$layout->setLayout('three-column');

Like the default layout, any alternative layout should also reside in the application/layouts/scripts/ directory, and should use the .phtml extension.

If you wanted to change the layout for all actions in a particular controller, just insert the above two lines into the controller's init() method, which will execute prior to the invocation of any action found in the controller. The init() method was introduced in the last chapter if you're not familiar with this feature.

Disabling the Layout

To prevent the layout from rendering, call the disableLayout() helper at the top of the action:

$this->_helper->layout()->disableLayout();

Keep in mind that disabling the layout will not disable the action's corresponding view. Therefore if you want to create an action which neither renders a layout nor a view, you'll also need to explicitly disable the view. You'll learn how to disable an action's view in the later section "Disabling the View".

Tip

If your reason for disabling the layout and view is due to the desire to use an action to process an AJAX request, then chances are you won't need to call either of these helpers because the framework's encodeJson() helper will automatically disable rendering for you. See Chapter 9 for more information about processing AJAX requests.

Managing Views

When a controller action is invoked, the Zend Framework's default behavior is to look for an appropriately named action to return as the response. However, there are situations which you might wish to override this default behavior, either by using a different view or by disabling view rendering altogether.

Overriding the Default Action View

By default the framework will search for a view script named identically to the action being invoked. For instance, if the About controller's contact action is called, then the framework will expect an action named contact.phtml to exist and reside in the application/views/scripts/about directory, producing an error if this expectation isn't met. You can override this behavior by passing the name of a different controller into the render() helper:

$this->view->render('alternate.phtml');

If the view script resides in a directory different than that where the currently executing controller's views reside, you can change the view script path using the setScriptPath() method:

$this->view->setScriptPath('/application/scripts/mobile/about/');
$this->view->render('contact.phtml');

Disabling the View

Should you need to prevent an action's view from being rendered, add the following line to the top of the action body:

$this->_helper->viewRenderer->setNoRender(true);

Presumably you'll also want to disable the layout, therefore you'll also need to call the disableLayout() helper as introduced earlier in this chapter:

$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender();

View Helpers

The Zend Framework relies heavily on a concept known as a view helper which can be used to manage the placement and formatting of a wide variety of site assets and other data, including page titles, CSS and JavaScript files, images, and even URLs. You can even create custom view helpers which can be immensely useful for minimizing the amount of repetitive logic which would otherwise be spread throughout the view templates. In this section I'll introduce you to one of the framework's most commonly used view helpers, and even show you how to create your own. Later in the chapter I'll introduce other native view helpers relevant to managing your site's CSS, JavaScript, and other key page elements.

Managing URLs

The framework supports a URL view helper which can be used to programmatically insert URLs into a page. For instance, suppose you wanted to create a hyperlink which points to http://dev.gamenomad.com/games/list/console/ps3. Using the URL view helper within your view, you'll identify the controller, action, and lone parameter like this:

<a href="<?= $this->url(array(
    'controller' => 'games', 
    'action' => 'list', 
    'console' => 'ps3')); ?>">View PS3 games</a>

Executing this code will result in a hyperlink being added to the page which looks like this:

<a href="/games/list/console/ps3">View PS3 games</a>

But isn't this more trouble than its worth? After all, writing the hyperlink will actually require less keystrokes than using the URL view helper. The primary reason you should use the URL view helper is for reasons of maintainability. What if you created a site which when first deployed was placed within the web server's root document directory, but as the organization grew needed to be moved into a subdirectory? This location change would require you to modify every link on the site to accommodate the new location. Yet if you were using the URL view helper, no changes would be necessary because the framework is capable of detecting any changes to the base URL.

The secondary reason for using the URL view helper is that it's possible to reference a custom named route within the helper instead of referring to a controller and action at all, allowing for maximum flexibility should you later decide to point the custom route elsewhere. For instance, you might recall the custom route created in the last chapter which allowed us to use a more succinct URL when viewing information about a specific game. This was accomplished by eliminating the inclusion of the action within the URL, allowing us to use URLs such as http://dev.gamenomad.com/games/title/ms_pac_man rather than http://dev.gamenomad.com/games/view/title/ms_pac_man. To refresh your memory, the custom route definition is included here:

$route = new Zend_Controller_Router_Route (
    'games/title/:title',
    array('controller' => 'Games',
          'action'     => 'view',
          'title'       => 'ms_pac_man'
         )
);

$router->addRoute('game-title-view', $route);

Notice how the name game-title-view is associated with this custom route when it's added to the framework's router instance. You can pass this unique name to the URL view helper to create URLs:

<a href="<?= $this->url(array(
    'title' => 'call_of_duty_world_at_war'), 
    'game-title-view'); ?>">Call of Duty: World at War</a>

Executing this code will produce the following hyperlink:

http://dev.gamenomad.com/games/title/call_of_duty_world_at_war

Table 3-1 highlights some of the Zend Framework's other useful view helpers. Keep in mind that this is only a partial listing. You should consult the documentation for a complete breakdown.

Table 3.1. Other Useful View Helpers

NameDescription
CurrencyDisplays currency using a localized format
CycleAlternates the background color for a set of values
DoctypeSimplifies the placement of a DOCTYPE definition within an HTML document
HeadLinkLinks to external CSS files and other resources, such as favicons and RSS feeds
HeadMetaDefines meta tags and setting client-side caching rules
HeadScriptAdds client-side scripting elements and links to remote scripting resources. You'll learn more about this helper later in the chapter
HeadStyleAdds CSS declarations inline

Creating Custom View Helpers

You'll often want to repeatedly perform complex logic within your code, such as formatting a user's birthday in a certain manner, or rendering a certain icon based on a preset value. To eliminate the redundant insertion of this code, you can package it within classes known as custom view helpers, and then call each view helper as necessary.

To create a custom view helper, you'll create a new class which extends the framework's Zend_View_Helper_Abstract class. For instance, I use the following helper on the GameNomad web site so I can easily associate the appropriate gender with the user's gender designation:

01 <?php 02
03   class Zend_View_Helper_Gender extends Zend_View_Helper_Abstract
04   { 
05          
06     /** 
07      * Produces string based on whether value is
08      * masculine or feminine 
09      *  
10      * @param string $gender 
11      * @return string 
12      */ 
13     public function Gender($gender)  
14     { 
15              
16       if ($gender == "m") { 
17         return "he"; 
18       } else { 
19         return "she"; 
20       } 
21  
22     } 
23          
24   } 
25  
26 ?>

The code breakdown follows:

  1. Line 03 defines the helper class. Notice the naming convention and format used in the class name.
  2. Line 13 defines the class method, Gender(). This method must be named identically to the concluding part of your class name Gender, in this case). Likewise, the helper's file name must be named identically to the method, include the .php extension Gender.php, and be saved to the application/views/helpers directory.

Once created, you can execute the helper from within your views like so:

Jason owns 14 games, and <?= $this->Gender("m"); ?> is 
currently playing Call of Duty: World at War.

Partial Views

Many web pages are built from snippets which are found repeatedly throughout the Web site. For instance, you might insert information about the best selling video game title within a number of different pages. The HTML might look like this:

<p> 
 Best-selling game this hour:<br /> 
 <a href="/games/title/call_of_duty_black_ops">Call of Duty: Black Ops</a> 
</p>

So how can we organize these templates for easy reuse? The Zend Framework makes it easy to do so, calling them partials. A partial is a template which can be retrieved and rendered within a page, meaning you can use it repeatedly throughout the site. If you later decide to modify the partial to include for instance the current Amazon sales rank, the change will immediately occur within each location the partial is referenced.

However partials have an additional useful feature in that they can contain their own variables and logic without having to worry about potential clashing of variable names. This is useful because the variables $this->permalink and $this->title may already exist in the page calling the partial, but because of this behavior, we won't have to worry about odd side effects.

For organizational purposes, I prefix partial filenames with an underscore, and store them within the application/views/scripts directory. For instance, the above partial might be named _hottestgame.phtml. To insert a partial into a view, use the following call:

<?= $this->partial('_hottestgame.phtml',  
    array('asin' => $hottestASIN, 'title' => $hottestTitle)); ?>

Notice how each key in the array corresponds to a variable found in the referenced partial.

The Partial Loop

The Zend Framework offers a variation of the partial statement useful for looping purposes. Revising the hottest game partial, suppose you instead wanted to provide a list containing several of the hottest selling games. You can create a partial which represents just one entry in the list, and use the PartialLoop construct to iterate through the games and format them accordingly. The revised partial might look like this:

<a href="/games/title/<?= $this->permalink; ?>"><?= $this->title; ?>
</a>

Using the PartialLoop construct, you can pass along a partial and a multi-dimensional array, prompting the loop to iterate until the array values have been exhausted:

<ul> 
<li><?= $this->partialLoop('_hottestgames.phtml', 
    array(
      array('permalink' => 'call_of_duty_black_ops', 'title' => 'Call of Duty: Black Ops'), 
      array('permalink' => 'halo_reach', 'title' => 'Halo Reach'), 
      array('permalink' => 'metroid_other_m', 'title' => 'Metroid: Other M')
    )
  ) 
</li>
</ul>

Executing this partial loop within a view produces the following output:

<ul>
  <li><a href="/games/title/call_of_duty_black_ops">Call of Duty: Black Ops</a></li>
  <li><a href="/games/title/halo_reach">Halo Reach</a></li>
  <li><a href="/games/title/metroid_other_m">Metroid: Other M</a></li>
</ul>

Managing Images

There really isn't much to say regarding the integration of images into your web site views, as no special knowledge is required other than to understand that the framework will serve images from the public directory. However, the Zend_Tool utility does not generate a directory intended to host your site images when the application structure is created, so I suggest creating a directory named images or similar within your public directory. After moving the site images into this directory, you can reference them using the typical img tag:

<img src="/images/logo.png" alt="Welcome to GameNomad" />

Managing CSS

As is the case with images, no special knowledge is required to begin integrating Cascading Style Sheets (CSS) into your Zend Framework-powered web site, other than the understanding that the CSS files should be placed somewhere within the public directory. For organizational purposes I suggest creating a directory named css or similar, and placing the CSS files within it.

With the files in place, you'll typically use the link tag within your site layout in order to make the CSS styles available. For instance:

<link href="/css/screen.css" rel="stylesheet" media="screen, projection" type="text/css">
</link>

There are however a few view helpers which I STOPPED HERE

Managing JavaScript

Managing Other Page Elements

Testing Your Work

Verifying Image Existence

Test Your Knowledge

Test your understanding of the concepts introduced in this chapter by answering the following questions. You can find the answers in the back of the book.

Please wait...