Listing 7-1 shows a typical symfony template. It contains some HTML code and some basic PHP code, usually calls to variables defined in the action (via $this->name = 'foo';) and helpers.

Listing 7-1 - A Sample indexSuccess.php Template

<h1>Welcome</h1>
<p>Welcome back, <?php echo $name ?>!</p>
<ul>What would you like to do?
  <li><?php echo link_to('Read the last articles', 'article/read') ?></li>
  <li><?php echo link_to('Start writing a new one', 'article/write') ?></li>
</ul>

As explained in Chapter 4, the alternative PHP syntax is preferable for templates to make them readable for non-PHP developers. You should keep PHP code to a minimum in templates, since these files are the ones used to design the GUI of the application, and are sometimes created and maintained by another team, specialized in presentation but not in application logic. Keeping the logic inside the action also makes it easier to have several templates for a single action, without any code duplication.

7.1.1. Helpers

Helpers are PHP functions that return HTML code and can be used in templates. In Listing 7-1, the link_to() function is a helper. Sometimes, helpers are just time-savers, packaging code snippets frequently used in templates. For instance, you can easily imagine the function definition for this helper:

<?php echo input_tag('nickname') ?>
 => <input type="text" name="nickname" id="nickname" value="" />

It should look like Listing 7-2.

Listing 7-2 - Sample Helper Definition

function input_tag($name, $value = null)
{
  return '<input type="text" name="'.$name.'" id="'.$name.'"value="'.$value.'" />';
}

As a matter of fact, the input_tag() function built into symfony is a little more complicated than that, as it accepts a third parameter to add other attributes to the <input> tag. You can check its complete syntax and options in the online API documentation (http://www.symfony-project.org/api/1_2/).

Most of the time, helpers carry intelligence and save you long and complex coding:

<?php echo auto_link_text('Please visit our website www.example.com') ?>
 => Please visit our website <a href="http://www.example.com">www.example.com</a>

Helpers facilitate the process of writing templates and produce the best possible HTML code in terms of performance and accessibility. You can always use plain HTML, but helpers are usually faster to write.

Tip You may wonder why the helpers are named according to the underscore syntax rather than the camelCase convention, used everywhere else in symfony. This is because helpers are functions, and all the core PHP functions use the underscore syntax convention.

7.1.1.1. Declaring Helpers

The symfony files containing helper definitions are not autoloaded (since they contain functions, not classes). Helpers are grouped by purpose. For instance, all the helper functions dealing with text are defined in a file called TextHelper.php, called the Text helper group. So if you need to use a helper in a template, you must load the related helper group earlier in the template by declaring it with the use_helper() function. Listing 7-3 shows a template using the auto_link_text() helper, which is part of the Text helper group.

Listing 7-3 - Declaring the Use of a Helper

// Use a specific helper group in this template
<?php use_helper('Text') ?>
...
<h1>Description</h1>
<p><?php echo auto_link_text($description) ?></p>

Tip If you need to declare more than one helper group, add more arguments to the use_helper() call. For instance, to load both the Text and the Javascript helper groups in a template, call <?php use_helper('Text', 'Javascript') ?>.

A few helpers are available by default in every template, without need for declaration. These are helpers of the following helper groups:

  • Helper: Required for helper inclusion (the use_helper() function is, in fact, a helper itself)
  • Tag: Basic tag helper, used by almost every helper
  • Url: Links and URL management helpers
  • Asset: Helpers populating the HTML <head> section, and providing easy links to external assets (images, JavaScript, and style sheet files)
  • Partial: Helpers allowing for inclusion of template fragments
  • Cache: Manipulation of cached code fragments
  • Form: Form input helpers

The list of the standard helpers, loaded by default for every template, is configurable in the settings.yml file. So if you know that you will not use the helpers of the Cache group, or that you will always use the ones of the Text group, modify the standard_helpers setting accordingly. This will speed up your application a bit. You cannot remove the first four helper groups in the preceding list (Helper, Tag, Url, and Asset), because they are compulsory for the templating engine to work properly. Consequently, they don't even appear in the list of standard helpers.

Tip If you ever need to use a helper outside a template, you can still load a helper group from anywhere by calling sfLoader::loadHelpers($helpers), where $helpers is a helper group name or an array of helper group names. For instance, if you want to use auto_link_text() in an action, you need to call sfLoader::loadHelpers('Text') first.

7.1.1.2. Frequently Used Helpers

You will learn about some helpers in detail in later chapters, in relation with the feature they are helping. Listing 7-4 gives a brief list of the default helpers that are used a lot, together with the HTML code they return.

Listing 7-4 - Common Default Helpers

// Helper group
<?php use_helper('HelperName') ?>
<?php use_helper('HelperName1', 'HelperName2', 'HelperName3') ?>

// Tag group
<?php echo tag('input', array('name' => 'foo', 'type' => 'text')) ?>
<?php echo tag('input', 'name=foo type=text') ?>  // Alternative options syntax
 => <input name="foo" type="text" />
<?php echo content_tag('textarea', 'dummy content', 'name=foo') ?>
 => <textarea name="foo">dummy content</textarea>

// Url group
<?php echo link_to('click me', 'mymodule/myaction') ?>
=> <a href="/route/to/myaction">click me</a>  // Depends on the routing settings

// Asset group
<?php echo image_tag('myimage', 'alt=foo size=200x100') ?>
 => <img src="/images/myimage.png" alt="foo" width="200" height="100"/>
<?php echo javascript_include_tag('myscript') ?>
 => <script language="JavaScript" type="text/javascript" src="/js/myscript.js"></script>
<?php echo stylesheet_tag('style') ?>
 => <link href="/stylesheets/style.css" media="screen" rel="stylesheet"type="text/css" />

There are many other helpers in symfony, and it would take a full book to describe all of them. The best reference for helpers is the online API documentation (http:// www.symfony-project.org/api/1_2/), where all the helpers are well documented, with their syntax, options, and examples.

7.1.1.3. Adding Your Own Helpers

Symfony ships with a lot of helpers for various purposes, but if you don't find what you need in the API documentation, you will probably want to create a new helper. This is very easy to do.

Helper functions (regular PHP functions returning HTML code) should be saved in a file called FooBarHelper.php, where FooBar is the name of the helper group. Store the file in the apps/frontend/lib/helper/ directory (or in any helper/ directory created under one of the lib/ folders of your project) so it can be found automatically by the use_helper('FooBar') helper for inclusion.

Tip This system even allows you to override the existing symfony helpers. For instance, to redefine all the helpers of the Text helper group, just create a TextHelper.php file in your apps/frontend/lib/helper/ directory. Whenever you call use_helper('Text'), symfony will use your helper group rather than its own. But be careful: as the original file is not even loaded, you must redefine all the functions of a helper group to override it; otherwise, some of the original helpers will not be available at all.

7.1.2. Page Layout

The template shown in Listing 7-1 is not a valid XHTML document. The DOCTYPE definition and the <html> and <body> tags are missing. That's because they are stored somewhere else in the application, in a file called layout.php, which contains the page layout. This file, also called the global template, stores the HTML code that is common to all pages of the application to avoid repeating it in every template. The content of the template is integrated into the layout, or, if you change the point of view, the layout "decorates" the template. This is an application of the decorator design pattern, illustrated in Figure 7-1.

Tip For more information about the decorator and other design patterns, see Patterns of Enterprise Application Architecture by Martin Fowler (Addison-Wesley, ISBN: 0-32112-742-0).

Decorating a template with a layout

Figure 7.1 Decorating a template with a layout

Listing 7-5 shows the default page layout, located in the application templates/ directory.

Listing 7-5 - Default Layout, in myproject/apps/frontend/templates/layout.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <?php include_http_metas() ?>
    <?php include_metas() ?>
    <?php include_title() ?>
    <link rel="shortcut icon" href="/favicon.ico" />
  </head>
  <body>
    <?php echo $sf_content ?>
  </body>
</html>

The helpers called in the <head> section grab information from the response object and the view configuration. The <body> tag outputs the result of the template. With this layout, the default configuration, and the sample template in Listing 7-1, the processed view looks like Listing 7-6.

Listing 7-6 - The Layout, the View Configuration, and the Template Assembled

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <meta name="title" content="symfony project" />
    <meta name="robots" content="index, follow" />
    <meta name="description" content="symfony project" />
    <meta name="keywords" content="symfony, project" />
    <title>symfony project</title>
    <link rel="stylesheet" type="text/css" href="/css/main.css" />
    <link rel="shortcut icon" href="/favicon.ico">
  </head>
  <body>
    <h1>Welcome</h1>
    <p>Welcome back, <?php echo $name ?>!</p>
    <ul>What would you like to do?
      <li><?php echo link_to('Read the last articles', 'article/read') ?></li>
      <li><?php echo link_to('Start writing a new one', 'article/write') ?></li>
    </ul>
  </body>
</html>

The global template can be entirely customized for each application. Add in any HTML code you need. This layout is often used to hold the site navigation, logo, and so on. You can even have more than one layout, and decide which layout should be used for each action. Don't worry about JavaScript and style sheet inclusion for now; the "View Configuration" section later in this chapter shows how to handle that.

7.1.3. Template Shortcuts

In templates, a few symfony variables are always available. These shortcuts give access to the most commonly needed information in templates, through the core symfony objects:

  • $sf_context: The whole context object (instance of sfContext)
  • $sf_request: The request object (instance of sfRequest)
  • $sf_params : The parameters of the request object
  • $sf_user : The current user session object (instance of sfUser)

The previous chapter detailed useful methods of the sfRequest and sfUser objects. You can actually call these methods in templates through the $sf_request and $sf_user variables. For instance, if the request includes a total parameter, its value is available in the template with the following:

// Long version
<?php echo $sf_request->getParameter('total') ?>

// Shorter version
<?php echo $sf_params->get('total') ?>

// Equivalent to the following action code
echo $request->getParameter('total')