OxyScripts.com
Menu spacer Home Tutorials Articles Code Forums irc.freenode.net #oxyscripts
Main (PHP)
Home Forums PHP News PHP Tutorials Articles PHP Code Snippets Contact Us Sysadmin Resources Books Template Shop
3rd Party Streams
SlashDot PHPDeveloper.org PHP.Net
Resources
PHP Manual MySQL Manual Smarty Manual PEAR Manual PHP-GTK Manual Symfony Manual
Code Snippets
Authentication Database Graphics HTTP Miscellaneous Time/Date
Affiliates
Scripts TutorialMan TutorialGuide CodingForums.com PHP Scripts Cheap Web Hosting Affordable Web Hosting Dreamweaver Templates

Search This Site :     PHP Function Reference :
 

Symfony View: templates, layouts, partials and components

Overview

The implementation of the MVC View paradigm in symfony uses templates, possibly included in a Layout. Reusable parts of code are available in slots, when they result of an action, or in fragments, when they don't need applicative logic. The naming conventions and the tight integration with the symfony Controller implementation make template management an easy task.

Templating

The result of an action execution is a View. In symfony, a View is the combination of a template described by a classic PHP file, and a configuration file describing the way this template will fit with other interface elements.

Here is a typical template, typically named indexSuccess.php:

<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>

It contains some HTML code and some basic PHP code, usually calls to variables defined in the action and helpers.

The variables called in the templates must be either one of the usual shortcuts (see below) or attributes of the action object defined in the related action file. For instance, to define a value for the $name variable used here, the action must contain such a line:

$this->name = 'myvalue';

Developers like to keep as little PHP code as possible 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.

Shortcuts

Symfony provides the templates with a few useful pre-defined variables, or shortcuts, allowing it to access the most commonly needed information:

$sf_context        //the whole context object
$sf_request        //the origin request 
$sf_params         //parameters of the origin request
$sf_user           //the current sfUser object
$sf_view           //the calling sfView object

For instance, if the action call included a parameter total, the value of the parameter is available in the template with:

<?php echo $sf_params->get('total'); ?>
// equivalent to the following action code:
echo $this->getRequestParameter('total');

This is true whether the parameter was sent to the action with POST or GET methods, or using the symfony routing system:

index.php/test/index&total=123   //GET
index.php/test/index/total/123   //routed action call

And since the first action call can lead to other action calls (for instance if there is a forward), you may need to access the action stack. A few additional shortcuts will make it easy for you:

$sf_first_module   //first module called
$sf_last_module    //last module called
$sf_first_action   //first action called
$sf_last_action    //last action called

Helpers

Helpers (like the link_to() function in the template example above) are PHP functions that facilitate the process of writing templates and produce the best possible HTML code in terms of performance and accessibility. Three types of helpers are available:

  • The standard compulsory helpers, that must be used instead of the corresponding HTML code because they allow internal symfony mechanisms (like routing, automated form management, internationalization, etc.) to work.

    This includes all the HTML tags that handle URLs: they are replaced by symfony shortcuts to allow the routing.

  • The standard optional helpers, that use less code than classic HTML for the same purpose.

    In addition, they take advantage of the symfony architecture : by using these helpers, you make sure that your code will even work after any subsequent change in the file tree structure.

  • The helpers defined specifically for an application (learn more about that feature in the custom helper creation chapter).

Using helpers speeds up the template development; they are described in detail in the following chapters.

In order to use helper functions, the file that contains this helper has to be loaded.

A few helpers are loaded for every application:

  • Helper: defines the use_helper() helpers, needed for helper inclusion
  • Tag: defines the basic tag operations
  • Url: link and URL management helpers
  • Asset: head, include, images and javascript call helpers

By default, the application configuration specifies additional helpers to be loaded for all requests in the settings.yml:

default:
  .settings:
    standard_helpers:    [Partial, Cache, Form]

You can define the helpers that need to be included in your application in addition to those ones. For instance, if you know that your application will use a lot of text and internationalization functions, you can write in the settings.yml:

all:
  .settings:
    standard_helpers:    [Partial, Cache, Form, Text, I18N]

If you need to use a helper that is not loaded by default, the template that will use it has to call the use_helper() function:

// use a specific in this template
<?php echo use_helper('Date') ?>
...
<?php echo format_date($date, 'd', 'en') ?>
 
// you can call more than one helper at once
<?php echo use_helpers('Date', 'I18N') ?>

Global template

All the templates can be included into a global template, or layout, located in myproject/apps/myapp/templates/layout.php. Here is its default content:

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

The content of the <head> tag might be a little cryptic for now, but if will be explained in detail in the next chapter. Just keep in mind that with the default configuration, and our previous template, the processed view should look like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-200000126/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="robots" content="index, follow" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<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>

This is an application of the decorator design pattern: The content of the template called by the action is integrated into the global template with the help of the $content variable.

The global template can be entirely customized for each application.

Naming conventions

Now you may wonder how symfony links actions with templates. To avoid repeated explicit call of templates when the name of the template can be easily deduced from the one of the action, symfony has a few naming conventions.

A template name is made of two parts: the first part is related to the action, the second to is result. For instance, the typical template of an action called index that executed successfully is indexSuccess.php.

This is an implicit rule in symfony: if the value returned by the action is sfView::SUCCESS, then the name of the template called will be the name of the action concatenated with Success.php.

For instance, with two actions index and list in a product module :

class productActions extends sfActions
{
  public function executeIndex()
  {
    ...
    return sfView::SUCCESS;
  }
  public function executeList()
  {
    ...
    return sfView::SUCCESS;
  }
}

The templates called at the end of the execution of each action will be located in myproject/apps/myapp/modules/product/templates/ and named:

indexSuccess.php
listSuccess.php

Because this is the default behavior, if an action returns nothing, the framework considers that the success view has to be called as if the return sfView::SUCCESS; was implied.

For any other return value (different from sfView::NONE), the template called will have a name ending with this value. For instance, if the action returns sfView::ERROR, the template name must end with Error.php.

An action can also set an alternate template:

$this->setTemplate('myCustomTemplate');

According to the value returned by the action, the template called can be myCustomTemplateSuccess.php or myCustomTemplateError.php.

Now let's see all these possibilities in action:

class productActions extends sfActions
{
  public function executeIndex()
  {
    if ($test == 1) 
    {
      ...
      return sfView::SUCCESS;
    } 
    else if ($test == 2)
    {
      ...
      return 'MyResult';
    }
    else if ($test == 3)
    {
      ...
      $this->setTemplate('myCustomTemplate');
      return sfView::SUCCESS;
    }
    else 
    {
      return sfView::ERROR;
    }
  }
}

The templates called in myapp/modules/product/templates/, according to the value of $test, are named:

indexSuccess.php
indexMyResult.php
myCustomTemplateSuccess.php
indexError.php

View configuration

Applications and modules can have a view.yml configuration file describing how the templates are integrated with other interface components (layouts, slots, stylesheets, etc.) in the module and each of its actions.

So the view.yml file is an alternative solution to the function calls concerning the view from within the action:

template:     $this->setTemplate();

Read more about the view.yml files in the next chapter.

Code fragments

You may often need to include some HTML or PHP code into several pages, to avoid repeating it, or to display the same piece of content throughout more that one page. The PHP include() statement will suffice most of the time for that purpose. But what if you need to access the symfony objects and helpers, or pass parameters to this code fragment? Symfony provides three helpers for that:

  • If the logic is lightweight, you will just want to include a template file having access to some data you pass to it. For that, you will use a partial.
  • If the logic is heavier (for instance if you need to access the data model and/or modify the content according to the session), you will prefer to separate the presentation from the logic. For that, you will use a component
  • If the nature of the fragment depends on the context (for instance if the fragment needs to be different for the actions of a given module), you will use a component slot.

In addition, symfony provides a technique to define a zone in the layout that can be overridden by a template, and it's called a slot. It is an alternative to component slots for when you have no heavy logic.

These helpers are available from any symfony template.

Include

If the content type is static HTML, you can use a classic include() PHP statement:

// include some HTML code into the current template
<?php include('myfile.html') ?>

The most common need is to include a piece of PHP code. If this code doesn't require the symfony objects and methods, the include() statement is still enough. For instance, if many of the templates of your test module use a fragment of code showing the current time, save this piece of code in a file called time.php in the global template directory (myproject/apps/myapp/templates). Now, when you need this piece of code in a template, just call the include() function:

// include some PHP code into the current template
<?php include(sfConfig::get('sf_app_template_dir').'/time.php') ?>

Partial

Partials are template fragments that can be called from different modules throughout an application. A partial has access to the usual symfony helpers and template shorcuts, but not to the variables defined in the action calling it, unless passed explicitly as an argument.

Let's imagine an application where the user has a selection of items in a shopping cart. In some pages of the application, a block displays the number of items in the cart and a link to it. The shopping cart object is provided by the action. First, let's see what the template partial would look like:

<div>
  <h1>Selected items</h1>
  <?php echo $cart->getCount() ?><br />
  <?php echo link_to('Modify', 'cart/edit?cart_id='.$cart->getId()) ?>
</div>

This template partial is saved in a cart module, in a file called templates/_sidebar.php.

Now, let's go back to the templates using this partial. For each of them, the action defines a $myShoppingCart object containing the current selection of items. To pass this value to a partial, the templates will use the include_partial() helper:

<?php echo include_partial('cart/sidebar', array('cart' => $myShoppingCart )) ?>

The first argument is the module/template name, the second is an array of variables that are needed by the partial. Notice the '_' difference between partial name in the include_partial() call and the actual file name in the templates/ directory. This helps to keep your code clean and to show the fragments ahead of the other templates in a file explorer.

If your need is not restricted to one module, save your fragment in the main template directory (in myproject/apps/myapp/templates). To call it from any module template, you now need:

<?php echo include_partial('global/sidebar', array('cart' => $myShoppingCart )) ?>

Components

In the previous example, the logic of the partial is light and doesn't require an action. If you need a partial with a logic behind, you should use a component. A component is like an action, it can pass variables to a template partial - except it's much faster than an action. The logic is kept in a components.class.php file in the actions/ directory, and the template is a regular partial.

For instance, a news component could display in a sidebar the latest news headlines for a given subject, depending on the user's profile. The queries necessary to get the news headlines are too complex to appear in a simple partial, so they have to be moved to an action-like file.

In a news module, create a file called components.class.php in the actions/ folder with the following content:

<?php
 
class newsComponents extends sfComponents
{
  public function executeHeadlines()
  {
    $c = new Criteria();
    $c->addDescendingOrderByColumn(NewsPeer::PUBLISHED_AT);
    $c->setLimit(5);
    $this->news = NewsPeer::doSelect($c);
  }
}
 
?>

In the same news module, create a _headlines.php partial in the templates/ directory:

<div>
  <h1>Latest news</h1>
  <ul>
  <?php foreach($news as $headline): ?>
    <li>
      <?php echo $headline->getPublishedAt() ?>
      <?php echo link_to($headline->getTitle(), 'news/show?id='.$headline->getId()) ?>
    </li>
  <?php endforeach ?>
  </ul>
</div>

Now, every time you need the component in a template, just call it by:

<?php include_component('news', 'headlines') ?>

Just like the partials, components accept additional parameters in the shape of an associative array. The parameters are available to the partial under their name, and in the component via the $this object:

// call to the component
<?php include_component('news', 'headlines', array('foo' => 'bar')) ?>
 
// in the component itself,
echo $this->foo;          => 'bar'
 
// in the _headlines.php partial,
echo $foo;                => 'bar'

You can include components in components, or in the global layout, as in any regular template. Like actions, components execute methods can pass variables to the related partial and have access to the same shortcuts. But the similarities stop there: A partial doesn't handle security, doesn't have various return possibilities, and is much faster than an action to execute.

Component slots

You sometimes need to include a component which varies according to the module calling it. For instance, the main layout of an application can display in the right part of the window a set of contextual information and links.

Symfony makes it easy to handle with the include_component_slot() helper. This function expects a label as parameter, and this label will be used to define a component for each module, using the view.yml configuration file.

For instance, let's imagine that the layout.php of the application contains:

...
<div id="sidebar">
  <?php include_component_slot('sidebar') ?>
</div>

In the main view.yml configuration file (located in the myapp/config/ directory), you define the default value for this slot:

default:
  components:
    sidebar:  [bar, default]

By default, this sidebar will call the executeDefault() method of the barComponents class located in the bar module, and this method will display the _default.php partial located in modules/bar/templates/. But you can override this setting for a given module. For instance, in a user module, you may want the contextual component to display the user name, and the number of articles he/she published. In that case, add to the view.yml of the modules/user/config/ directory:

all:
  components:
    sidebar:  [bar, user]

Note: The config/view.yml file for your module is not automatically generated by the module initialization. You will need to create this file manually.

In the modules/bar/actions/components.class.php, add this new method:

class barComponents extends sfComponents
{
  ...
  public function executeUser()
  {
    $current_user = $this->getUser()->getCurrentUser();
    $c = new Criteria();
    $c->add(ArticlePeer::AUTHOR_ID, $current_user->getId());
    $this->nb_articles = ArticlePeer::doCount($c);
    $this->current_user = $current_user;
  }
}

Then, create the following modules/bar/templates/_user.php:

User name: <?php echo $current_user->getName() ?><br />
(already published <?php echo $nb_articles ?> articles)

Component slots can be used for breadcrumbs, contextual navigations, and dynamic insertions of all kinds. As components, they can be used in the global layout and in regular templates, or even in other components. The configuration setting the component of a slot is always the one of the last action called.

Note: If you need to suspend the use of a component slot for a given module, just declare an empty module/component for it:

all:
  components:
    sidebar:  [ ]

Slots

Managing a component slot obliges you to create a component, a partial, and a configuration file. It is really useful when you want reusability. If your need is to define an additional zone in the layout that can be overriden action by action, then there is a faster solution: the slots.

A slot is a code chunk stored globally in the response. It can be defined anywhere (in the layout, in a template, in a partial) and can be included anywhere as well. Just remember that the layout is executed after the template, and that the partials are executed when they are called in a template, to be sure to define a slot before including it.

To define a slot, use the slot() and end_slot() helpers. For instance, a template will define the content of a 'sidebar' slot as follows:

...
<?php slot('sidebar') ?>
  <h1>User <?php echo $user ?>'s details</h1>
  <p>email: <?php echo $user->getEmail() ?></p>
  <p><?php echo link_to('do things', 'user/dothings?id='.$user->getId()) ?>
<?php end_slot() ?>
 

The code between the slot() and end_slot() helpers is not output in the template, but in a placeholder in the response, waiting to be included somewhere else.

To include a slot, use the include_slot() helper. Using the has_slot() helper, you can even manage default slot values. For instance, the layout can display the 'sidebar' slot in a <div>. If the slot has been defined earlier (by a template, as in the previous example), then it is displayed. If not, the default content takes its place. Note that since include_slot() returns nothing if the slot is not defined, the use of has_slot() is not compulsory.

...
<div id="sidebar">
  <?php if(has_slot('sidebar')): ?>
    <?php include_slot('sidebar') ?>
  <?php else: ?>
    <!-- default sidebar code -->
    <h1>Contextual zone</h1>
    <p>This zone contains links and information relative to the main content of the page.</p>
  <?php endif; ?>
</div>

One common usage of slots is the addition of special tags in the <head> section, for instance when you want to include RSS links in the header for some specific actions. A layout with more than one dynamic zone, for instance the main content plus the secondary navigation, is another commun use. As they can be included anywhere, with fallback mechanisms, slots are very powerful and allow for a very modular conception of layouts and templates. Eventually, slots are much faster than component slots, so feel free to use them extensively.

Note: Slots were present in earlier versions of symfony, but with a slightly different meaning.

 
   Print this page

Top Sponsor
Symantec\'s Norton SystemWorks 2006
Sponsors
CA
Sponsors
AdWords Dominator 125*125
Advertisting

Affiliates
VertexTemplates PHPFreaks CodeWalkers StarGeek DevScripts CGI & PHP Scripts PHP CMS

Shopping Rebates   Sell It 4 You   Flash Page Counters   Get Insured
GPS Tracking Service   Charity Donate Info   Web Site Hosting   VOIP Service

Privacy Policy | Links | Site Map | Advertising

All content on OxyScripts.com is (©)2002-2007

 
Powered by Adrastea - Version 1.0.0. Copyright © Rune Solutions, 2004-2005