[ Index ]
 

Code source de Symfony 1.0.0

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/doc/ -> 07-Inside-the-View-Layer.txt (source)

   1  Chapter 7 - Inside The View Layer
   2  =================================
   3  
   4  The view is responsible for rendering the output correlated to a particular action. In symfony, the view consists of several parts, with each part designed to be easily modified by the person who usually works with it.
   5  
   6  * Web designers generally work on the templates (the presentation of the current action data) and on the layout (containing the code common to all pages). These are written in HTML with small embedded chunks of PHP, which are mostly calls to helpers.
   7  * For reusability, developers usually package template code fragments into partials or components. They use slots and component slots to affect more than one zone of the layout. Web designers can work on these template fragments as well.
   8  * Developers focus on the YAML view configuration file (setting the properties of the response and other interface elements) and on the response object. When dealing with variables in the templates, the risks of cross-site scripting must not be ignored, and a good comprehension of output escaping techniques is required to safely record user data.
   9  
  10  But whatever your role is, you will find useful tools to speed up the tedious job of presenting the results of the action. This chapter covers all of these tools.
  11  
  12  Templating
  13  ----------
  14  
  15  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.
  16  
  17  Listing 7-1 - A Sample indexSuccess.php Template
  18  
  19      [php]
  20      <h1>Welcome</h1>
  21      <p>Welcome back, <?php echo $name ?>!</p>
  22      <ul>What would you like to do?
  23        <li><?php echo link_to('Read the last articles', 'article/read') ?></li>
  24        <li><?php echo link_to('Start writing a new one', 'article/write') ?></li>
  25      </ul>
  26  
  27  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.
  28  
  29  ### Helpers
  30  
  31  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:
  32  
  33      [php]
  34      <?php echo input_tag('nickname') ?>
  35       => <input type="text" name="nickname" id="nickname" value="" />
  36  
  37  It should look like Listing 7-2.
  38  
  39  Listing 7-2 - Sample Helper Definition
  40  
  41      [php]
  42      function input_tag($name, $value = null)
  43      {
  44        return '<input type="text" name="'.$name.'" id="'.$name.'"value="'.$value.'" />';
  45      }
  46  
  47  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.com/api/symfony.html](http://www.symfony-project.com/api/symfony.html)).
  48  
  49  Most of the time, helpers carry intelligence and save you long and complex coding:
  50  
  51      [php]
  52      <?php echo auto_link_text('Please visit our website www.example.com') ?>
  53       => Please visit our website <a href="http://www.example.com">www.example.com</a>
  54  
  55  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.
  56  
  57  >**TIP**
  58  >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.
  59  
  60  #### Declaring Helpers
  61  
  62  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.
  63  
  64  Listing 7-3 - Declaring the Use of a Helper
  65  
  66      [php]
  67      // Use a specific helper group in this template
  68      <?php echo use_helper('Text') ?>
  69      ...
  70      <h1>Description</h1>
  71      <p><?php echo auto_link_text($description) ?></p>
  72  
  73  >**TIP**
  74  >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 echo ` use_helper('Text', 'Javascript') ?>`.
  75  
  76  A few helpers are available by default in every template, without need for declaration. These are helpers of the following helper groups:
  77  
  78    * `Helper`: Required for helper inclusion (the `use_helper()` function is, in fact, a helper itself)
  79    * `Tag`: Basic tag helper, used by almost every helper
  80    * `Url`: Links and URL management helpers
  81    * `Asset`: Helpers populating the HTML `<head>` section, and providing easy links to external assets (images, JavaScript, and style sheet files)
  82    * `Partial`: Helpers allowing for inclusion of template fragments
  83    * `Cache`: Manipulation of cached code fragments
  84    * `Form`: Form input helpers
  85  
  86  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.
  87  
  88  >**TIP**
  89  >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.
  90  
  91  #### Frequently Used Helpers
  92  
  93  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.
  94  
  95  Listing 7-4 - Common Default Helpers
  96  
  97      [php]
  98      // Helper group
  99      <?php echo use_helper('HelperName') ?>
 100      <?php echo use_helper('HelperName1', 'HelperName2', 'HelperName3') ?>
 101  
 102      // Tag group
 103      <?php echo tag('input', array('name' => 'foo', 'type' => 'text')) ?>
 104      <?php echo tag('input', 'name=foo type=text') ?>  // Alternative options syntax
 105       => <input name="foo" type="text" />
 106      <?php echo content_tag('textarea', 'dummy content', 'name=foo') ?>
 107       => <textarea name="foo">dummy content</textarea>
 108  
 109      // Url group
 110      <?php echo link_to('click me', 'mymodule/myaction') ?>
 111      => <a href="/route/to/myaction">click me</a>  // Depends on the routing settings
 112  
 113      // Asset group
 114      <?php echo image_tag('myimage', 'alt=foo size=200x100') ?>
 115       => <img src="/images/myimage.png" alt="foo" width="200" height="100"/>
 116      <?php echo javascript_include_tag('myscript') ?>
 117       => <script language="JavaScript" type="text/javascript" src="/js/myscript.js"></script>
 118      <?php echo stylesheet_tag('style') ?>
 119       => <link href="/stylesheets/style.css" media="screen" rel="stylesheet"type="text/css" />
 120  
 121  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.com/api/symfony.html](http://www.symfony-project.com/api/symfony.html)), where all the helpers are well documented, with their syntax, options, and examples.
 122  
 123  #### Adding Your Own Helpers
 124  
 125  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.
 126  
 127  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/myapp/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.
 128  
 129  >**TIP**
 130  >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/myapp/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.
 131  
 132  ### Page Layout
 133  
 134  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.
 135  
 136  >**TIP**
 137  >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).
 138  
 139  Figure 7-1 - Decorating a template with a layout
 140  
 141  ![Decorating a template with a layout](/images/book/F0701.png "Decorating a template with a layout")
 142  
 143  Listing 7-5 shows the default page layout, located in the application `templates/` directory.
 144  
 145  Listing 7-5 - Default Layout, in `myproject/apps/myapp/templates/layout.php`
 146  
 147      [php]
 148      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
 149      <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 150      <head>
 151        <?php echo include_http_metas() ?>
 152        <?php echo include_metas() ?>
 153        <?php echo include_title() ?>
 154        <link rel="shortcut icon" href="/favicon.ico" />
 155      </head>
 156      <body>
 157  
 158      <?php echo $sf_data->getRaw('sf_content') ?>
 159  
 160      </body>
 161      </html>
 162  
 163  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.
 164  
 165  Listing 7-6 - The Layout, the View Configuration, and the Template Assembled
 166  
 167      [php]
 168      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
 169      <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 170      <head>
 171        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
 172        <meta name="title" content="symfony project" />
 173        <meta name="robots" content="index, follow" />
 174        <meta name="description" content="symfony project" />
 175        <meta name="keywords" content="symfony, project" />
 176        <title>symfony project</title>
 177        <link rel="stylesheet" type="text/css" href="/css/main.css" />
 178        <link rel="shortcut icon" href="/favicon.ico">
 179      </head>
 180      <body>
 181  
 182      <h1>Welcome</h1>
 183      <p>Welcome back, <?php echo $name ?>!</p>
 184      <ul>What would you like to do?
 185        <li><?php echo link_to('Read the last articles', 'article/read') ?></li>
 186        <li><?php echo link_to('Start writing a new one', 'article/write') ?></li>
 187      </ul>
 188  
 189      </body>
 190      </html>
 191  
 192  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.
 193  
 194  ### Template Shortcuts
 195  
 196  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:
 197  
 198    * `$sf_context`: The whole context object (`instance of sfContext`)
 199    * `$sf_request`: The request object (`instance of` `sfRequest`)
 200    * `$sf_params`: Parameters of the request
 201    * `$sf_user`: The current user session object (`instance of` `sfUser`)
 202  
 203  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:
 204  
 205      [php]
 206      // Long version
 207      <?php echo $sf_request->getParameter('total'); ?>
 208  
 209      // Shorter version
 210      <?php echo $sf_params->get('total'); ?>
 211  
 212      // Equivalent to the following action code
 213      echo $this->getRequestParameter('total');
 214  
 215  Code Fragments
 216  --------------
 217  
 218  You may often need to include some HTML or PHP code in several pages. To avoid repeating that code, the PHP `include()` statement will suffice most of the time.
 219  
 220  For instance, if many of the templates of your application need to use the same fragment of code, save it in a file called `myFragment.php` in the global template directory (`myproject/apps/myapp/templates/`) and include it in your templates as follows:
 221  
 222      [php]
 223      <?php include(sfConfig::get('sf_app_template_dir').'/myFragment.php') ?>
 224  
 225  But this is not a very clean way to package a fragment, mostly because you can have different variable names between the fragment and the various templates including it. In addition, the symfony cache system (described in Chapter 12) has no way to detect an include, so the fragment cannot be cached independently from the template. Symfony provides three alternative types of intelligent code fragments to replace `include`s:
 226  
 227    * 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.
 228    * 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.
 229    * If the fragment is meant to replace a specific part of the layout, for which default content may already exist, you will use a slot.
 230  
 231  >**Note**
 232  >Another code fragment type, called a component slot, is to be used when 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). Component slots are described later in this chapter.
 233  
 234  The inclusion of these fragments is achieved by helpers of the Partial group. These helpers are available from any symfony template, without initial declaration.
 235  
 236  ### Partials
 237  
 238  A partial is a reusable chunk of template code. For instance, in a publication application, the template code displaying an article is used in the article detail page, and also in the list of the best articles and the list of latest articles. This code is a perfect candidate for a partial, as illustrated in Figure 7-2.
 239  
 240  Figure 7-2 - Reusing partials in templates
 241  
 242  ![Reusing partials in templates](/images/book/F0702.png "Reusing partials in templates")
 243  
 244  Just like templates, partials are files located in the `templates/` directory, and they contain HTML code with embedded PHP. A partial file name always starts with an underscore (`_`), and that helps to distinguish partials from templates, since they are located in the same `templates/` folders.
 245  
 246  A template can include partials whether it is in the same module, in another module, or in the global `templates/` directory. Include a partial by using the `include_partial()` helper, and specify the module and partial name as a parameter (but omit the leading underscore and the trailing `.php`), as described in Listing 7-7.
 247  
 248  Listing 7-7 - Including a Partial in a Template of the `mymodule` Module
 249  
 250      [php]
 251      // Include the myapp/modules/mymodule/templates/_mypartial1.php partial
 252      // As the template and the partial are in the same module,
 253      // you can omit the module name
 254      <?php include_partial('mypartial1') ?>
 255  
 256      // Include the myapp/modules/foobar/templates/_mypartial2.php partial
 257      // The module name is compulsory in that case
 258      <?php include_partial('foobar/mypartial2') ?>
 259  
 260      // Include the myapp/templates/_mypartial3.php partial
 261      // It is considered as part of the 'global' module
 262      <?php include_partial('global/mypartial3') ?>
 263  
 264  Partials have access to the usual symfony helpers and template shortcuts. But since partials can be called from anywhere in the application, they do not have automatic access to the variables defined in the action calling the templates that includes them, unless passed explicitly as an argument. For instance, if you want a partial to have access to a `$total` variable, the action must hand it to the template, and then the template to the helper as a second argument of the `include_partial()` call, as shown in Listings 7-8, 7-9, and 7-10.
 265  
 266  Listing 7-8 - The Action Defines a Variable, in `mymodule/actions/actions.class.php`
 267  
 268      [php]
 269      class mymoduleActions extends sfActions
 270      {
 271        public function executeIndex()
 272        {
 273          $this->total = 100;
 274        }
 275      }
 276  
 277  Listing 7-9 - The Template Passes the Variable to the Partial, in mymodule/templates/indexSucc`ess.php`
 278  
 279      [php]
 280      <p>Hello, world!</p>
 281      <?php include_partial('mypartial',
 282      array('mytotal' => $total)
 283      ) ?>
 284  
 285  Listing 7-10 - The Partial Can Now Use the Variable, in `mymodule/templates/_mypartial.php`
 286  
 287      [php]
 288      <p>Total: <?php echo $mytotal ?></p>
 289  
 290  >**TIP**
 291  >All the helpers so far were called by `<?php echo functionName() ?>`. The partial helper, however, is simply called by `<?php include_partial() ?>`, without `echo`, to make it behave similar to the regular PHP `include()` statement. If you ever need a function that returns the content of a partial without actually displaying it, use `get_partial()` instead. All the `include_` helpers described in this chapter have a `get_` counterpart that can be called together with an `echo` statement.
 292  
 293  ### Components
 294  
 295  In Chapter 2, the first sample script was split into two parts to separate the logic from the presentation. Just like the MVC pattern applies to actions and templates, you may need to split a partial into a logic part and a presentation part. In such a case, you should use a component.
 296  
 297  A component is like an action, except it's much faster. The logic of a component is kept in a class inheriting from `sfComponents`, located in an `action/components.class.php` file. Its presentation is kept in a partial. Methods of the `sfComponents` class start with the word `execute`, just like actions, and they can pass variables to their presentation counterpart in the same way that actions can pass variables. Partials that serve as presentation for components are named by the component (without the leading `execute`, but with an underscore instead). Table 7-1 compares the naming conventions for actions and components.
 298  
 299  Table 7-1 - Action and Component Naming Conventions
 300  
 301  Convention               |  Actions              |  Components
 302  ------------------------ | --------------------- | ----------------------
 303  Logic file               | `actions.class.php`   | `components.class.php`
 304  Logic class extends      | `sfActions`           | `sfComponents`
 305  Method naming            | `executeMyAction()`   | `executeMyComponent()`
 306  Presentation file naming | `myActionSuccess.php` | `_myComponent.php`
 307  
 308  >**TIP**
 309  >Just as you can separate actions files, the `sfComponents` class has an `sfComponent` counterpart that allows for single component files with the same type of syntax.
 310  
 311  For instance, suppose you have a sidebar displaying the latest news headlines for a given subject, depending on the user's profile, which is reused in several pages. The queries necessary to get the news headlines are too complex to appear in a simple partial, so they need to be moved to an action-like file--a component. Figure 7-3 illustrates this example.
 312  
 313  For this example, shown in Listings 7-11 and 7-12, the component will be kept in its own module (called `news`), but you can mix components and actions in a single module if it makes sense from a functional point of view.
 314  
 315  Figure 7-3 - Using components in templates
 316  
 317  ![Using components in templates](/images/book/F0703.png "Using components in templates")
 318  
 319  Listing 7-11 - The Components Class, in `modules/news/actions/components.class.php`
 320  
 321      [php]
 322      <?php
 323  
 324      class newsComponents extends sfComponents
 325      {
 326        public function executeHeadlines()
 327        {
 328          $c = new Criteria();
 329          $c->addDescendingOrderByColumn(NewsPeer::PUBLISHED_AT);
 330          $c->setLimit(5);
 331          $this->news = NewsPeer::doSelect($c);
 332        }
 333      }
 334  
 335  Listing 7-12 - The Partial, in `modules/news/templates/_headlines.php`
 336  
 337      [php]
 338      <div>
 339        <h1>Latest news</h1>
 340        <ul>
 341        <?php foreach($news as $headline): ?>
 342          <li>
 343            <?php echo $headline->getPublishedAt() ?>
 344            <?php echo link_to($headline->getTitle(),'news/show?id='.$headline->getId()) ?>
 345          </li>
 346        <?php endforeach ?>
 347        </ul>
 348      </div>
 349  
 350  Now, every time you need the component in a template, just call this:
 351  
 352      [php]
 353      <?php include_component('news', 'headlines') ?>
 354  
 355  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. See Listing 7-13 for an example.
 356  
 357  Listing 7-13 - Passing Parameters to a Component and Its Template
 358  
 359      [php]
 360      // Call to the component
 361      <?php include_component('news', 'headlines', array('foo' => 'bar')) ?>
 362  
 363      // In the component itself
 364      echo $this->foo;
 365       => 'bar'
 366  
 367      // In the _headlines.php partial
 368      echo $foo;
 369       => 'bar'
 370  
 371  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 component doesn't handle security or validation, cannot be called from the Internet (only from the application itself), and doesn't have various return possibilities. That's why a component is faster to execute than an action.
 372  
 373  ### Slots
 374  
 375  Partials and components are great for reusability. But in many cases, code fragments are required to fill a layout with more than one dynamic zone. For instance, suppose that you want to add some custom tags in the `<head>` section of the layout, depending on the content of the action. Or, suppose that the layout has one major dynamic zone, which is filled by the result of the action, plus a lot of other smaller ones, which have a default content defined in the layout but can be overridden at the template level.
 376  
 377  For these situations, the solution is a slot. Basically, a slot is a placeholder that you can put in any of the view elements (in the layout, a template, or a partial). Filling this placeholder is just like setting a variable. The filling code is stored globally in the response, so you can define it anywhere (in the layout, a template, or a partial). Just make sure to define a slot before including it, and remember that the layout is executed after the template (this is the decoration process), and the partials are executed when they are called in a template. Does it sound too abstract? Let's see an example.
 378  
 379  Imagine a layout with one zone for the template and two slots: one for the sidebar and the other for the footer. The slot values are defined in the templates. During the decoration process, the layout code wraps the template code, and the slots are filled with the previously defined values, as illustrated in Figure 7-4. The sidebar and the footer can then be contextual to the main action. This is like having a layout with more than one "hole."
 380  
 381  Figure 7-4 - Layout slots defined in a template
 382  
 383  ![Layout slots defined in a template](/images/book/F0704.png "Layout slots defined in a template")
 384  
 385  Seeing some code will clarify things further. To include a slot, use the `include_slot()` helper. The `has_slot()` helper returns `true` if the slot has been defined before, providing a fallback mechanism as a bonus. For instance, define a placeholder for a `'sidebar'` slot in the layout and its default content as shown in Listing 7-14.
 386  
 387  Listing 7-14 - Including a `'sidebar'` Slot in the Layout
 388  
 389      [php]
 390      <div id="sidebar">
 391      <?php if (has_slot('sidebar')): ?>
 392        <?php include_slot('sidebar') ?>
 393      <?php else: ?>
 394        <!-- default sidebar code -->
 395        <h1>Contextual zone</h1>
 396        <p>This zone contains links and information
 397        relative to the main content of the page.</p>
 398      <?php endif; ?>
 399      </div>
 400  
 401  Each template has the ability to define the contents of a slot (actually, even partials can do it). As slots are meant to hold HTML code, symfony offers a convenient way to define them: just write the slot code between a call to the `slot()` and `end_slot()` helpers, as in Listing 7-15.
 402  
 403  Listing 7-15 - Overriding the `'sidebar'` Slot Content in a Template
 404  
 405      [php]
 406      ...
 407      <?php slot('sidebar') ?>
 408        <!-- custom sidebar code for the current template-->
 409        <h1>User details</h1>
 410        <p>name:  <?php echo $user->getName() ?></p>
 411        <p>email: <?php echo $user->getEmail() ?></p>
 412      <?php end_slot() ?>
 413  
 414  The code between the slot helpers is executed in the context of the template, so it has access to all the variables that were defined in the action. Symfony will automatically put the result of this code in the response object. It will not be displayed in the template, but made available for future `include_slot()` calls, like the one in Listing 7-14.
 415  
 416  Slots are very useful to define zones meant to display contextual content. They can also be used to add HTML code to the layout for certain actions only. For instance, a template displaying the list of the latest news might want to add a link to an RSS feed in the `<head>` part of the layout. This is achieved simply by adding a `'feed'` slot in the layout and overriding it in the template of the list.
 417  
 418  >**SIDEBAR**
 419  >Where to find template fragments
 420  >
 421  >People working on templates are usually web designers, who may not know symfony very well and may have difficulties finding template fragments, since they can be scattered all over the application. These few guidelines will make them more comfortable with the symfony templating system.
 422  >
 423  >First of all, although a symfony project contains many directories, all the layouts, templates, and template fragments files reside in directories named `templates/`. So as far as a web designer is concerned, a project structure can be reduced to something like this:
 424  >
 425  >
 426  >     myproject/
 427  >       apps/
 428  >         application1/
 429  >           templates/       # Layouts for application 1
 430  >           modules/
 431  >             module1/
 432  >               templates/   # Templates and partials for module 1
 433  >             module2/
 434  >               templates/   # Templates and partials for module 2
 435  >             module3/
 436  >               templates/   # Templates and partials for module 3
 437  >
 438  >
 439  >All other directories can be ignored.
 440  >
 441  >When meeting an `include_partial()`, web designers just need to understand that only the first argument is important. This argument's pattern is `module_name/partial_name`, and that means that the presentation code is to be found in `modules/module_name/templates/_partial_name.php`.
 442  >
 443  >For the `include_component()` helper, module name and partial name are the first two arguments. As for the rest, a general idea about what helpers are and which helpers are the most common in templates should be enough to start designing templates for symfony applications.
 444  
 445  View Configuration
 446  ------------------
 447  
 448  In symfony, a view consists of two distinct parts:
 449  
 450    * The HTML presentation of the action result (stored in the template, in the layout, and in the template fragments)
 451    * All the rest, including the following:
 452  
 453      * Meta declarations: Keywords, description, or cache duration.
 454      * Page title: Not only does it help users with several browser windows open to find yours, but it is also very important for search sites' indexing.
 455      * File inclusions: JavaScript and style sheet files.
 456      * Layout: Some actions require a custom layout (pop-ups, ads, and so on) or no layout at all (such as Ajax actions).
 457  
 458  In the view, all that is not HTML is called view configuration, and symfony provides two ways to manipulate it. The usual way is through the `view.yml` configuration file. It can be used whenever the values don't depend on the context or on database queries. When you need to set dynamic values, the alternative method is to set the view configuration via the `sfResponse` object attributes directly in the action.
 459  
 460  >**NOTE**
 461  >If you ever set a view configuration parameter both via the `sfResponse` object and via the `view.yml` file, the `sfResponse` definition takes precedence.
 462  
 463  ### The view.yml File
 464  
 465  Each module can have one `view.yml` file defining the settings of its views. This allows you to define view settings for a whole module and per view in a single file. The first-level keys of the `view.yml` file are the module view names. Listing 7-16 shows an example of view configuration.
 466  
 467  Listing 7-16 - Sample Module-Level `view.yml`
 468  
 469      editSuccess:
 470        metas:
 471          title: Edit your profile
 472  
 473      editError:
 474        metas:
 475          title: Error in the profile edition
 476  
 477      all:
 478        stylesheets: [my_style]
 479        metas:
 480          title: My website
 481  
 482  >**CAUTION**
 483  >Be aware that the main keys in the `view.yml` file are view names, not action names. As a reminder, a view name is composed of an action name and an action termination. For instance, if the `edit` action returns `sfView::SUCCESS` (or returns nothing at all, since it is the default action termination), then the view name is `editSuccess`.
 484  
 485  The default settings for the module are defined under the `all:` key in the module `view.yml`. The default settings for all the application views are defined in the application `view.yml`. Once again, you recognize the configuration cascade principle:
 486  
 487    * In `apps/myapp/modules/mymodule/config/view.yml`, the per-view definitions apply only to one view and override the module-level definitions.
 488    * In `apps/myapp/modules/mymodule/config/view.yml`, the `all:` definitions apply to all the actions of the module and override the application-level definitions.
 489    * In `apps/myapp/config/view.yml`, the `default:` definitions apply to all modules and all actions of the application.
 490  
 491  >**TIP**
 492  >Module-level `view.yml` files don't exist by default. The first time you need to adjust a view configuration parameter for a module, you will have to create an empty `view.yml` in its `config/` directory.
 493  
 494  After seeing the default template in Listing 7-5 and an example of a final response in Listing 7-6, you may wonder where the header values come from. As a matter of fact, they are the default view settings, defined in the application `view.yml` and shown in Listing 7-17.
 495  
 496  Listing 7-17 - Default Application-Level View Configuration, in `apps/myapp/config/view.yml`
 497  
 498      default:
 499        http_metas:
 500          content-type: text/html
 501  
 502        metas:
 503          title:        symfony project
 504          robots:       index, follow
 505          description:  symfony project
 506          keywords:     symfony, project
 507          language:     en
 508  
 509        stylesheets:    [main]
 510  
 511        javascripts:    [ ]
 512  
 513        has_layout:     on
 514        layout:         layout
 515  
 516  Each of these settings will be described in detail in the "View Configuration Settings" section.
 517  
 518  ### The Response Object
 519  
 520  Although part of the view layer, the response object is often modified by the action. Actions can access the symfony response object, called `sfResponse`, via the `getResponse()` method. Listing 7-18 lists some of the `sfResponse` methods often used from within an action.
 521  
 522  Listing 7-18 - Actions Have Access to the `sfResponse` Object Methods
 523  
 524      [php]
 525      class mymoduleActions extends sfActions
 526      {
 527        public function executeIndex()
 528        {
 529          $response = $this->getResponse();
 530  
 531          // HTTP headers
 532          $response->setContentType('text/xml');
 533          $response->setHttpHeader('Content-Language', 'en');
 534          $response->setStatusCode(403);
 535          $response->addVaryHttpHeader('Accept-Language');
 536          $response->addCacheControlHttpHeader('no-cache');
 537  
 538          // Cookies
 539          $response->setCookie($name, $content, $expire, $path, $domain);
 540  
 541          // Metas and page headers
 542          $response->addMeta('robots', 'NONE');
 543          $response->addMeta('keywords', 'foo bar');
 544          $response->setTitle('My FooBar Page');
 545          $response->addStyleSheet('custom_style');
 546          $response->addJavaScript('custom_behavior');
 547        }
 548      }
 549  
 550  In addition to the setter methods shown here, the `sfResponse` class has getters that return the current value of the response attributes.
 551  
 552  The header setters are very powerful in symfony. Headers are sent as late as possible (in the sfRenderingFilter), so you can alter them as much as you want and as late as you want. They also provide very useful shortcuts. For instance, if you don't specify a charset when you call `setContentType()`, symfony automatically adds the default charset defined in the `settings.yml` file.
 553  
 554      [php]
 555      $response->setContentType('text/xml');
 556      echo $response->getContentType();
 557       => 'text/xml; charset=utf-8'
 558  
 559  The status code of responses in symfony is compliant with the HTTP specification. Exceptions return a status 500, pages not found return a status 404, normal pages return a status 200, pages not modified can be reduced to a simple header with status code 304 (see Chapter 12 for details), and so on. But you can override these defaults by setting your own status code in the action with the `setStatusCode()` response method. You can specify a custom code and a custom message, or simply a custom code--in which case, symfony will add the most common message for this code.
 560  
 561      [php]
 562      $response->setStatusCode(404, 'This page no longer exists');
 563  
 564  >**TIP**
 565  >Before sending the headers, symfony normalizes their names. So you don't need to bother about writing `content-language` instead of `Content-Language` in a call to `setHttpHeader()`, as symfony will understand the former and automatically transform it to the latter.
 566  
 567  ### View Configuration Settings
 568  
 569  You may have noticed that there are two kinds of view configuration settings:
 570  
 571    * The ones that have a unique value (the value is a string in the view.yml file and the response uses a `set` method for those)
 572    * The ones with multiple values (for which `view.yml` uses arrays and the response uses an `add` method)
 573  
 574  Keep in mind that the configuration cascade erases the unique value settings but piles up the multiple values settings. This will become more apparent as you progress through this chapter.
 575  
 576  #### Meta Tag Configuration
 577  
 578  The information written in the `<meta>` tags in the response is not displayed in a browser but is useful for robots and search engines. It also controls the cache settings of every page. Define these tags under the `http_metas:` and `metas:` keys in `view.yml`, as in Listing 7-19, or with the `addHttpMeta()` and `addMeta()` response methods in the action, as in Listing 7-20.
 579  
 580  Listing 7-19 - Meta Definition As Key: Value Pairs in `view.yml`
 581  
 582      http_metas:
 583        cache-control: public
 584  
 585      metas:
 586        description:   Finance in France
 587        keywords:      finance, France
 588  
 589  Listing 7-20 - Meta Definition As Response Settings in the Action
 590  
 591      [php]
 592      $this->getResponse()->addHttpMeta('cache-control', 'public');
 593      $this->getResponse()->addMeta('description', 'Finance in France');
 594      $this->getResponse()->addMeta('keywords', 'finance, France');
 595  
 596  Adding an existing key will replace its current content by default. For HTTP meta tags, you can add a third parameter and set it to `false` to have the `addHttpMeta()` method (as well as the `setHttpHeader()`) append the value to the existing one, rather than replacing it.
 597  
 598      [php]
 599      $this->getResponse()->addHttpMeta('accept-language', 'en');
 600      $this->getResponse()->addHttpMeta('accept-language', 'fr', false);
 601      echo $this->getResponse()->getHttpHeader('accept-language');
 602       => 'en, fr'
 603  
 604  In order to have these meta tags appear in the final document, the `include_http_metas()` and `include_metas()` helpers must be called in the `<head>` section (this is the case in the default layout; see Listing 7-5). Symfony automatically aggregates the settings from all the `view.yml` files (including the default one shown in Listing 7-17) and the response attribute to output proper `<meta>` tags. The example in Listing 7-19 ends up as shown in Listing 7-21.
 605  
 606  Listing 7-21 - Meta Tags Output in the Final Page
 607  
 608      [php]
 609      <meta http-equiv="content-type" content="text/html; charset=utf-8" />
 610      <meta http-equiv="cache-control" content="public" />
 611      <meta name="robots" content="index, follow" />
 612      <meta name="description" content="Finance in France" />
 613      <meta name="keywords" content="finance, France" />
 614  
 615  As a bonus, the HTTP header of the response is also impacted by the `http-metas:` definition, even if you don't have any `include_http_metas()` helpers in the layout, or if you have no layout at all. For instance, if you need to send a page as plain text, define the following `view.yml`:
 616  
 617      http_metas:
 618        content-type: text/plain
 619  
 620      has_layout: false
 621  
 622  #### Title Configuration
 623  
 624  The page title is a key part to search engine indexing. It is also very useful with modern browsers that provide tabbed browsing. In HTML, the title is both a tag and meta information of the page, so the `view.yml` file sees the title: key as a child of the `metas:` key. Listing 7-22 shows the title definition in `view.yml`, and Listing 7-23 shows the definition in the action.
 625  
 626  Listing 7-22 - Title Definition in `view.yml`
 627  
 628      indexSuccess:
 629        metas:
 630          title: Three little piggies
 631  
 632  Listing 7-23 - Title Definition in the Action--Allows for Dynamic Titles
 633  
 634      [php]
 635      $this->getResponse()->setTitle(sprintf('%d little piggies', $number));
 636  
 637  In the `<head>` section of the final document, the title definition sets the `<meta name="title">` tag if the `include_metas()` helper is present, and the `<title>` tag if the `include_title()` helper is present. If both are included (as in the default layout of Listing 7-5), the title appears twice in the document source (see Listing 7-6), which is harmless.
 638  
 639  #### File Inclusion Configuration
 640  
 641  Adding a specific style sheet or JavaScript file to a view is easy, as Listings 7-24 and 7-25 demonstrate.
 642  
 643  Listing 7-24 - File Inclusion in `view.yml`
 644  
 645      indexSuccess:
 646        stylesheets: [mystyle1, mystyle2]
 647        javascripts: [myscript]
 648  
 649  Listing 7-25 - File Inclusion in the Action
 650  
 651      [php]
 652      $this->getResponse()->addStylesheet('mystyle1');
 653      $this->getResponse()->addStylesheet('mystyle2');
 654      $this->getResponse()->addJavascript('myscript');
 655  
 656  In each case, the argument is a file name. If the file has a logical extension (`.css` for a style sheet and `.js` for a JavaScript file), you can omit it. If the file has a logical location (`/css/` for a style sheet and `/js/` for a JavaScript file), you can omit it as well. Symfony is smart enough to figure out the correct extension or location.
 657  
 658  Unlike the meta and title definitions, the file inclusion definitions don't require any helper in the template or layout to be included. This means that the previous settings will output the HTML code of Listing 7-26, whatever the content of the template and the layout.
 659  
 660  Listing 7-26 - File Inclusion Result--No Need for a Helper Call in the Layout
 661  
 662      [php]
 663      <head>
 664      ...
 665      <link rel="stylesheet" type="text/css" media="screen" href="/css/mystyle1.css" />
 666      <link rel="stylesheet" type="text/css" media="screen" href="/css/mystyle2.css" />
 667      <script language="javascript" type="text/javascript" src="/js/myscript.js">
 668      </script>
 669      </head>
 670  
 671  >**NOTE**
 672  >Style sheet and JavaScript inclusions in the response are performed by a filter called sfCommonFilter. It looks for a `<head>` tag in the response, and adds the `<link>` and `<script>` just before the closing `</head>`. This means that the inclusion can't take place if there is no `<head>` tag in your layout or templates.
 673  
 674  Remember that the configuration cascade principle applies, so any file inclusion defined in the application `view.yml` makes it appear in every page of the application. Listings 7-27, 7-28, and 7-29 demonstrate this principle.
 675  
 676  Listing 7-27 - Sample Application `view.yml`
 677  
 678      default:
 679        stylesheets: [main]
 680  
 681  Listing 7-28 - Sample Module `view.yml`
 682  
 683      indexSuccess:
 684        stylesheets: [special]
 685  
 686      all:
 687        stylesheets: [additional]
 688  
 689  Listing 7-29 - Resulting `indexSuccess` View
 690  
 691      [php]
 692      <link rel="stylesheet" type="text/css" media="screen" href="/css/main.css" />
 693      <link rel="stylesheet" type="text/css" media="screen" href="/css/additional.css" />
 694      <link rel="stylesheet" type="text/css" media="screen" href="/css/special.css" />
 695  
 696  If you need to remove a file defined at a higher level, just add a minus sign (`-`) in front of the file name in the lower-level definition, as shown in Listing 7-30.
 697  
 698  Listing 7-30 - Sample Module `view.yml` That Removes the Files Defined at the Application Level
 699  
 700      indexSuccess:
 701        stylesheets: [-main, special]
 702  
 703      all:
 704        stylesheets: [additional]
 705  
 706  To remove all style sheets or JavaScript files, use the following syntax:
 707  
 708      indexSuccess:
 709        stylesheets: [-*]
 710        javascripts: [-*]
 711  
 712  You can be more accurate and define an additional parameter to force the position where to include the file (first or last position):
 713  
 714      // In the view.yml
 715      indexSuccess:
 716        stylesheets: [special: { position: first }]
 717  
 718      [php]
 719      // In the action
 720      $this->getResponse()->addStylesheet('special', 'first');
 721  
 722  To specify media for a style sheet inclusion, you can change the default style sheet tag options, as shown in Listings 7-31, 7-32, and 7-33.
 723  
 724  Listing 7-31 - Style Sheet Inclusion with Media in `view.yml`
 725  
 726      indexSuccess:
 727        stylesheets: [main, paper: { media: print }]
 728  
 729  Listing 7-32 - Style Sheet Inclusion with Media in the Action
 730  
 731      [php]
 732      $this->getResponse()->addStylesheet('paper', '', array('media' => 'print'));
 733  
 734  Listing 7-33 - Resulting View
 735  
 736      [php]
 737      <link rel="stylesheet" type="text/css" media="print" href="/css/paper.css" />
 738  
 739  #### Layout Configuration
 740  
 741  According to the graphical charter of your website, you may have several layouts. Classic websites have at least two: the default layout and the pop-up layout.
 742  
 743  You have already seen that the default layout is `myproject/apps/myapp/templates/layout.php`. Additional layouts must be added in the same global `templates/` directory. If you want a view to use a `myapp/templates/my_layout.php` file, use the syntax shown in Listing 7-34 in `view.yml` or in Listing 7-35 in the action.
 744  
 745  Listing 7-34 - Layout Definition in `view.yml`
 746  
 747      indexSuccess:
 748        layout: my_layout
 749  
 750  Listing 7-35 - Layout Definition in the Action
 751  
 752      [php]
 753      $this->setLayout('my_layout');
 754  
 755  Some views don't need any layout at all (for instance, plain text pages or RSS feeds). In that case, set `has_layout` to `false`, as shown in Listings 7-36 and 7-37.
 756  
 757  Listing 7-36 - Layout Removal in `view.yml`
 758  
 759      indexSuccess:
 760        has_layout: false
 761  
 762  Listing 7-37 - Layout Removal in the Action
 763  
 764      [php]
 765      $this->setLayout(false);
 766  
 767  >**NOTE**
 768  >Ajax actions views have no layout by default.
 769  
 770  Component Slots
 771  ---------------
 772  
 773  Combining the power of view components and view configuration brings a new perspective to view development: the component slot system. It is an alternative to slots focusing on reusability and layer separation. So component slots are more structured than slots, but a little slower to execute.
 774  
 775  Just like slots, component slots are named placeholders that you can declare in the view elements. The difference resides in the way the filling code is determined. For a slot, the code is set in another view element; for a component slot, the code results from the execution of a component, and the name of this component comes from the view configuration. You will understand component slots more clearly after seeing them in action.
 776  
 777  To set a component slot placeholder, use the `include_component_slot()` helper. This function expects a label as a parameter. For instance, suppose that the `layout.php` file of the application contains a contextual sidebar. Listing 7-38 shows how the component slot helper would be included.
 778  
 779  Listing 7-38 - Including a Component Slot with the Name `'sidebar'`
 780  
 781      [php]
 782      ...
 783      <div id="sidebar">
 784        <?php include_component_slot('sidebar') ?>
 785      </div>
 786  
 787  Define the correspondence between the component slot label and a component name in the view configuration. For instance, set the default component for the `sidebar` component slot in the application `view.yml`, under the `components` header. The key is the component slot label; the value must be an array containing a module and a component name. Listing 7-39 shows an example.
 788  
 789  Listing 7-39 - Defining the Default `'sidebar'` Slot Component, in `myapp/config/view.yml`
 790  
 791      default:
 792        components:
 793          sidebar:  [bar, default]
 794  
 795  So when the layout is executed, the `sidebar` component slot is filled with the result of 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/`.
 796  
 797  The configuration cascade gives you the ability to 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 that the user published. In that case, specialize the sidebar slot setting in the module `view.yml`, as shown in Listing 7-40.
 798  
 799  Listing 7-40 - Specializing the 'sidebar' Slot Component, in `myapp/modules/user/config/view.yml`
 800  
 801      all:
 802        components:
 803          sidebar:  [bar, user]
 804  
 805  The component definitions to handle this slot should look like the ones in Listing 7-41.
 806  
 807  Listing 7-41 - Components Used by the 'sidebar' Slot, in `modules/bar/actions/components.class.php`
 808  
 809      [php]
 810      class barComponents extends sfComponents
 811      {
 812        public function executeDefault()
 813        {
 814        }
 815  
 816        public function executeUser()
 817        {
 818          $current_user = $this->getUser()->getCurrentUser();
 819          $c = new Criteria();
 820          $c->add(ArticlePeer::AUTHOR_ID, $current_user->getId());
 821          $this->nb_articles = ArticlePeer::doCount($c);
 822          $this->current_user = $current_user;
 823        }
 824      }
 825  
 826  Listing 7-42 shows the views for these two components.
 827  
 828  Listing 7-42 - Partials Used by the `'sidebar'` Slot Components, in `modules/bar/templates/`
 829  
 830      [php]
 831      // _default.php
 832      <p>This zone contains contextual information.</p>
 833  
 834      // _user.php
 835      <p>User name: <?php echo $current_user->getName() ?></p>
 836      <p><?php echo $nb_articles ?> articles published</p>
 837  
 838  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 regular templates, or even in other components. The configuration setting the component of a slot is always taken from the configuration of the last action called.
 839  
 840  If you need to suspend the use of a component slot for a given module, just declare an empty module/component for it, as shown in Listing 7-43.
 841  
 842  Listing 7-43 - Disabling a Component Slot in `view.yml`
 843  
 844      all:
 845        components:
 846          sidebar:  []
 847  
 848  Output Escaping
 849  ---------------
 850  
 851  When you insert dynamic data in a template, you must be sure about the data integrity. For instance, if data comes from forms filled in by anonymous users, there is a risk that it may include malicious scripts intended to launch cross-site scripting (XSS) attacks. You must be able to escape the output data, so that any HTML tag it contains becomes harmless.
 852  
 853  As an example, suppose that a user fills an input field with the following value:
 854  
 855      [php]
 856      <script>alert(document.cookie)</script>
 857  
 858  If you echo this value without caution, the JavaScript will execute on every browser and allow for much more dangerous attacks than just displaying an alert. This is why you must escape the value before displaying it, so that it becomes something like this:
 859  
 860      [php]
 861      &lt;script&gt;alert(document.cookie)&lt;/script&gt;
 862  
 863  You could escape your output manually by enclosing every unsure value in a call to `htmlentities()`, but that approach would be very repetitive and error-prone. Instead, symfony provides a special system, called output escaping, which automatically escapes every variable output in a template. It is activated by a simple parameter in the application `settings.yml`.
 864  
 865  ### Activating Output Escaping
 866  
 867  Output escaping is configured globally for an application in the `settings.yml` file. Two parameters control the way that output escaping works: the strategy determines how the variables are made available to the view, and the method is the default escaping function applied to the data.
 868  
 869  The next sections describe these settings in detail but, basically, all you need to do to activate output escaping is to set the `escaping_strategy` parameter to `both` instead of its default value `bc`, as shown in Listing 7-44.
 870  
 871  Listing 7-44 - Activating Output Escaping, in `myapp/config/settings.yml`
 872  
 873      all:
 874        .settings:
 875          escaping_strategy: both
 876          escaping_method:   ESC_ENTITIES
 877  
 878  This will add `htmlentities()` to all variable output by default. For instance, suppose that you define a `test` variable in an action as follows:
 879  
 880      [php]
 881      $this->test = '<script>alert(document.cookie)</script>';
 882  
 883  With output escaping turned on, echoing this variable in the template will output the escaped data:
 884  
 885      [php]
 886      echo $test;
 887       => &gt;&lt;script&gt;alert(document.cookie)&lt;/script&gt;
 888  
 889  Activating output escaping also gives access to an `$sf_data` variable in every template. It is a container object referencing all the escaped variables. So you can also output the test variable with the following:
 890  
 891      [php]
 892      echo $sf_data->get('test');
 893      => &gt;&lt;script&gt;alert(document.cookie)&lt;/script&gt;
 894  
 895  >**TIP**
 896  >The $sf_data object implements the Array interface, so instead of using the `$sf_data->get('myvariable')`, you can retrieve escaped values by calling `$sf_data['myvariable']`. But it is not a real array, so functions like `print_r()` will not work as expected.
 897  
 898  This object also gives you access to the unescaped, or raw, data. This is useful when a variable stores HTML code meant to be interpreted by the browser, provided that you trust this variable. Call the `getRaw()` method when you need to output the raw data.
 899  
 900      [php]
 901      echo $sf_data->getRaw('test');
 902       => <script>alert(document.cookie)</script>
 903  
 904  You will have to access raw data each time you need variables containing HTML to be really interpreted as HTML. You can now understand why the default layout uses `$sf_data->getRaw('sf_content')` to include the template, rather than a simpler `$sf_content`, which breaks when output escaping is activated.
 905  
 906  ### Escaping Strategy
 907  
 908  The `escaping_strategy` setting determines the way variables are output by default. The following are the possible values:
 909  
 910    * `bc` (backward compatible mode): Variables are not escaped, but an escaped version of each variable is available through the `$sf_data` container. So the data is raw by default, unless you choose to use the escaped value via the `$sf_data` object. This is the default value, and you should be aware that with this strategy, your application is subject to XSS attack risks.
 911    * `both`: All variables are escaped by default. Values are also made available in the `$sf_data` container. This is the recommended strategy, since you will be at risk only if you voluntarily output raw data. In some cases, you will have to use unescaped data--for instance, if you output a variable that contains HTML with the intention that this HTML be rendered as such in the browser. So be aware that if you switch to this strategy with a partially developed application, some features may break. The best choice is to use this setting right from the beginning.
 912    * `on`: Values are available only in the `$sf_data` container. This is the most secure and fastest way to deal with escaping, because each time you output a variable, you must choose if you want to use the escaped version with `get()` or the raw version with `getRaw()`. So you are always aware of the possibility that data may be corrupted.
 913    * `off`: Turns off output escaping. The `$sf_data` container is not available in templates. You can choose to use this strategy rather than `bc` to speed up your application if you are sure that you will never need to access escaped data.
 914  
 915  ### Escaping Helpers
 916  
 917  Escaping helpers are functions returning an escaped version of their input. They can be provided as a default `escaping_method` in the `settings.yml` file or to specify an escaping method for a specific value in the view. The following escaping helpers are available:
 918  
 919    * `ESC_RAW`: Doesn't escape the value.
 920    * `ESC_ENTITIES`: Applies the PHP function `htmlentities()` to the input with `ENT_QUOTES` as the quote style.
 921    * `ESC_JS`: Escapes a value to be put into a JavaScript string that is going to be used as HTML. This is useful for escaping things where HTML is going to be dynamically changed using JavaScript.
 922    * `ESC_JS_NO_ENTITIES`: Escapes a value to be put into a JavaScript string but does not add entities. This is useful if the value is going to be displayed using a dialog box (for example, for a `myString` variable used in `javascript:alert(myString);`).
 923  
 924  ### Escaping Arrays and Objects
 925  
 926  Output escaping not only works for strings, but also for arrays and objects. Any values that are objects or arrays will pass on their escaped state to their children. Assuming your strategy is set to `both`, Listing 7-45 demonstrates the escaping cascade.
 927  
 928  Listing 7-45 - Escaping Also Works for Arrays and Objects
 929  
 930      [php]
 931      // Class definition
 932      class myClass
 933      {
 934        public function testSpecialChars($value = '')
 935        {
 936          return '<'.$value.'>';
 937        }
 938      }
 939  
 940      // In the action
 941      $this->test_array = array('&', '<', '>');
 942      $this->test_array_of_arrays = array(array('&'));
 943      $this->test_object = new myClass();
 944  
 945      // In the template
 946      <?php foreach($test_array as $value): ?>
 947        <?php echo $value ?>
 948      <?php enforeach; ?>
 949       => &amp; &lt; &gt;
 950      <?php echo $test_array_of_arrays[0][0] ?>
 951       => &amp;
 952      <?php echo $test_object->testSpecialChars('&') ?>
 953       => &lt;&amp;&gt;
 954  
 955  As a matter of fact, the variables in the template are not of the type you might expect. The output escaping system "decorates" them and transforms them into special objects:
 956  
 957      [php]
 958      <?php echo get_class($test_array) ?>
 959       => sfOutputEscaperArrayDecorator
 960      <?php echo get_class($test_object) ?>
 961       => sfOutputEscaperObjectDecorator
 962  
 963  This explains why some usual PHP functions (like `array_shift()`, `print_r()`, and so on) don't work on escaped arrays anymore. But they can be still be accessed using `[]`, be traversed using foreach, and they give back the right result with `count()` (`count()` works only with PHP 5.2 or later). And in templates, the data should be read-only anyway, so most access will be through the methods that do work.
 964  
 965  You still have a way to retrieve the raw data through the `$sf_data` object. In addition, methods of escaped objects are altered to accept an additional parameter: an escaping method. So you can choose an alternative escaping method each time you display a variable in a template, or opt for the `ESC_RAW` helper to deactivate escaping. See Listing 7-46 for an example.
 966  
 967  Listing 7-46 - Methods of Escaped Objects Accept an Additional Parameter
 968  
 969      [php]
 970      <?php echo $test_object->testSpecialChars('&') ?>
 971      => &lt;&amp;&gt;
 972      // The three following lines return the same value
 973      <?php echo $test_object->testSpecialChars('&', ESC_RAW) ?>
 974      <?php echo $sf_data->getRaw('test_object')->testSpecialChars('&') ?>
 975      <?php echo $sf_data->get('test_object', ESC_RAW)->testSpecialChars('&') ?>
 976       => <&>
 977  
 978  If you deal with objects in your templates, you will use the additional parameter trick a lot, since it is the fastest way to get raw data on a method call.
 979  
 980  >**CAUTION**
 981  >The usual symfony variables are also escaped when you turn on output escaping. So be aware that `$sf_user`, `$sf_request`, `$sf_param`, and `$sf_context` still work, but their methods return escaped data, unless you add `ESC_RAW` as a final argument to their method calls.
 982  
 983  Summary
 984  -------
 985  
 986  All kinds of tools are available to manipulate the presentation layer. The templates are built in seconds, thanks to helpers. The layouts, partials, components, and component slots bring both modularity and reusability. The view configuration takes advantage of the speed of YAML to handle (mostly) page headers. The configuration cascade exempts you from defining every setting for each view. For every modification of the presentation that depends on dynamic data, the action has access to the `sfResponse` object. And the view is secure from XSS attacks, thanks to the output escaping system.


Généré le : Fri Mar 16 22:42:14 2007 par Balluche grâce à PHPXref 0.7