Development

Documentation/fr_FR/book/1.0/trunk/07-Inside-the-View-Layer

You must first sign up to be able to contribute.

Version 79 (modified by Geoff, 10 years ago)
application r6118 (adresse symfony-project de .com à .org)

Cette partie de la documentation est en cours de traduction. Cela signifie qu'elle est traduite de manière soit incomplète, soit inexacte. En attendant que cette traduction soit terminée, vous pouvez consulter la version en anglais pour des informations plus fiables.

Chapitre 7 – La vue

Le rôle de la vue est de restituer graphiquement les résultats que retourne le contrôleur. Dans Symfony, la vue se compose de trois parties et chaque partie est faite pour être facilement modifiée par celui qui en a la charge.

  • Les graphistes travailleront généralement sur les gabarits des actions (les templates) et sur le gabarit principal du site (le layout) qui contient le matériel graphique commun à l'ensembles des pages. Ces gabarits contiennent du code HTML, entrecoupé de courtes instructions PHP : les helpers.

  • Pour permettre la réusabilité de leur code, les développeurs le regroupe en composants (les components) ou composants partiels (les partials). Lorsqu'il s'agira de modifier une ou plusieurs zones entières du gabarit, ils utiliseront ce qu'on appelle dans Symfony un slot. Les graphistes pourront travailler sur ces éléments également.

  • Les développeurs travaillent sur les fichiers YAML de configurations de la vue (gérer la réponse du controleur et les éléments de l'interface) et sur l'objet Response. Avec les variables dans les gabarits, il faut toujours considérer le risque potentiel de cross-site-scripting. De la même façon, bien comprendre les techniques d'échappement de chaînes est nécessaire, si l'on veut enregistrer de façon sûre des données utilisateurs.

En somme, quel que soit votre rôle, si vous souhaitez disposer d'outils vous permettant d'accélérer le travail de présentation, ce chapitre est pour vous.

Les gabarits

La figure 7.1 représente un gabarit Symfony des plus classiques. On y trouve du HTML, du PHP de base avec essentiellement des appels aux variables définies par l'action (grâce à $this->name = 'foo';) et des helpers.

Figure 7.1 - Exemple d'un gabarit indexSuccess.php

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

Comme déjà évoqué au chapitre 4, la syntaxe PHP alternative dans les gabarits est préférable, car elle offre une meilleure compréhension aux non-spécialistes PHP. Dans la mesure où les gabarits sont la représentation graphique de l'interface, et sont amenés à être manipulés par d'autres équipes, spécialisées en graphisme mais pas nécessairement en programmation, il est sage de limiter l'usage de PHP dans ces fichiers. Ne pas déporter la logique hors de l'action permet aussi de disposer de plusieurs gabarits pour une même action, sans pour autant tomber dans la duplication de code.

Les helpers

Les helpers sont des fonctions PHP qui génèrent du code HTML et que l'on peut utiliser dans les gabarits. Dans la figure 7-1, la fonction link_to() est un helper. Les helpers ne sont parfois que de simples raccourcis, mais qui permettent en embarquant du code fréquemment utilisé dans les gabarits, de gagner un temps précieux. On peut aisément imaginer la fonction d'un helper :

Figure 7-1 - Un helper

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

Elle ressemblerait à peu de choses près à la figure 7-2

Figure 7-2 - Exemple de définition d'un helper

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

En réalité la fonction input_tag() de Symfony est un peu plus compliquée dans la mesure où elle accepte en troisième argument, d'autres attributs pour la balise <input>. Les paramètres optionnels et la syntaxe complète sont disponibles dans l'API en ligne.

Dans la majorité des cas, les helpers sont intelligents et vous épargneront du code long et complexe :

[php]
<?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>

Les helpers facilitent l'écriture des gabarits et génèrent le meilleur HTML possible en termes de performances et d'accessibilité. Il est toujours possible d'utiliser du HTML brut, mais les helpers sont généralement plus rapides à écrire.

NOTE Vous vous êtes peut-être demandé pourquoi le nommage des helpers suivaient une syntaxe à underscore et non la convention camelCase partout présente dans Symfony ? C'est parce-que les helpers sont des fonctions, et que les fonctions PHP natives utilisent cette convention de syntaxe à underscore.

Déclarer les helpers

Les fichiers symfony qui contiennent les définitions des helpers ne sont pas chargés automatiquement (ce sont des fonctions, pas des classes). Les helpers sont classés selon leur finalité. Par exemple, tous les helpers liés à la gestion du texte sont définis dans le fichier TextHelper.php, appelé le groupe des helpers Text.

Figure 7-3 - Déclarer les helpers

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

NOTE Si vous devez déclarer plusieurs groupes de helpers, ajoutez des arguments supplémentaires lors de l'appel à la fonction use_helper(). Par exemple, pour charger dans le gabarit à la fois le groupe des helpers Text et les Javascript, écrivez <?php echo use_helper('Text', 'Javascript') ?>.

Certains helpers sont par défaut disponibles dans tous les gabarits, sans déclaration préalable. Ce sont les helpers des groupes suivants :

  • Helper: nécessaires pour l'inclusion des helpers (la fonction use_helper() est en réalité un helper elle-même)
  • Tag : helpers pour les balises de base, utilisés par presque tous les helpers
  • Url : helpers de gestion de liens et d'URL
  • Asset : helpers permettant de remplir la section HTML , et permettant un accès facile aux ressources externes (images, javascripts, feuilles de style).
  • Partial : helpers permettant l'inclusion d'éléments de gabarits
  • Cache : manipulation du cache
  • Form : helpers pour les champs de formulaires

La liste des helpers standards, chargés par défaut dans tous les gabarits est paramétrable dans le fichier settings.yml. Ainsi, si vous savez que vous n'utiliserez jamais les helpers du groupe Cache ou que vous utiliserez toujours ceux du groupe Text, configurez les helpers standards en conséquence. Cela accélérera sensiblement votre application. Il n'est pas possible de retirer un des quatre premiers groupes de la liste (Helper, Tag, Url et Asset) car ils sont indispensables au bon fonctionnement du moteur de gabarits. C'est pour cette raison qu'ils n'apparaissent même pas dans la liste des helpers standards.

NOTE Si vous deviez utiliser un helper en dehors des gabarits, il est toujours possible de charger un groupe de helper depuis n'importe où dans le projet en appelant sfLoader::loadHelpers($helpers), en considérant que $helpers est le nom d'un groupe de helper, ou du tableau associatif qui en contiendrait plusieurs. Si par exemple vous souhaitez utiliser la fonction auto_link_text()dans une action, vous devez commencer par appeler sfLoader::loadHelpers('Text').

Helpers couramment utilisés

Certains helpers seront étudiés en détail dans les prochains chapitres liés à la fonction remplie par le helper. La figure 7-4 présente une courte liste des helpers de bases fréquemment utilisés, associés au code HTML qu'ils génèrent.

Figure 7-4 - Helpers communément utilisés

[php]
// Helper group
<?php echo use_helper('HelperName') ?>
<?php echo 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" />
[/php]

Il y a beaucoup d'autres helpers dans Symfony, et cela prendrait un livre entier pour en faire le tour. La meilleur référence pour les helpers est la documentation de l'API en ligne, où l'ensemble des helpers sont largement documentés, avec la syntaxe, les options et des exemples.

Créer vos propres helpers

Symfony est distribué avec de nombreux helpers, à des fins variées, mais si vous ne trouvez pas votre bonheur dans la documentation de l'API, vous souhaiterez certainement créer le vôtre. C'est très facile.

Les fonctions de helpers (fonctions en PHP natif générant du code HTML) doivent être enregistrées dans un fichier nommé FooBarHelper.php, Foobar étant le nom du groupe de helpers. Placez le fichier dans le répertoire apps/myapp/lib/helper/ (ou dans n'importe quel répertoire helper/crée dans un des dossiers lib/de votre projet) de façon à ce qu'il soit trouvé et automatiquement inclus par le helper use_helper('FooBar').

NOTE Ce système vous permet même de surcharger les helpers symfony existants. Par exemple, pour redéfinir tous les helpers du groupe Text, créez simplement un fichier TextHelper.php dans votre répertoire apps/myapp/lib/helper/. Lorsque vous appelerez use_helper('Text'), symfony utilisera alors votre groupe de helpers plutôt que le sien. Mais attention, car dans la mesure où le fichier orginal n'est pas chargé, ce sont toutes les fonctions du groupe de helpers qu'il faut redéfinir pour surcharger. Sinon, certains helpers d'origine ne seront pas disponibles.

Le gabarit principal

Le gabarit de la figure 7-1 n'est pas une document XHTML valide. Il manque la définition du DOCTYPE et les balises <html>et <body>. La raison en est qu'elles sont stockées à un autre endroit de l'application, dans un fichier nommé layout.php, qui contient le layout de la page. Ce fichier, également template global, contient le code HTML commun à l'ensemble des pages de l'application, ce qui évite sa répétion dans chacun des gabarits. Le contenu du gabarit est intégré au layout, ou si l'on de point de vue, le layout vient décorer le gabarit. C'est une mise en pratique du modèle de conception decorator illustré en 7-1.

NOTE Pour plus d'informations sur le decorator et les autres modèles de conceptions, consultez l'ouvrage Patterns of Enterprise Application Architecture écrit par Martin Fowler (Addison-Wesley, ISBN: 0-32112-742-0).

Illustration 7-1 - Décorer le gabarit avec le layout

Image : http://www.symfony-project.org/images/book/trunk/F0701.png

La figure 7-5 montre le layout par défault d'une page, stocké dans le répertoire templates/ de l'application.

_Figure 7-5 - Layout par défaut, dans myproject/apps/myapp/templates/layout.php_

[php]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/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 $sf_data->getRaw('sf_content') ?>

</body>
</html>
[/php]

Les helpers appelés dans la section <head> puisent l'information dans l'objet response et dans la configuration de la vue. La balise <body> affiche le gabarit. Avec précisemment ce layout, cette configuration par défaut et le gabarit donné en exemple à la figure 7-1, la vue traitera l'ensemble tel qu'llustré dans la figure 7-6.

Figure 7-6 - Le layout, la vue et le template une fois assemblés

[php]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/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>
[/php]

Le template général à la possibilité d'être complétement personnalié pour chaque application. Vous pouvez y placer tout le code HTML dont vous avez besoin. Le layout est souvent utilisé pour la navigation du site, le logo etc. Il est même possible d'avoir plusieurs layout et décider de celui à utiliser pour chaque action. Pour l'instant, ne vous souciez pas des Javascripts et des feuilles de styles à intégrer. La section "Configuration de la vue" de ce chapitre montrera comment gérer cela.

Les gabarits et les raccourcis

Dans les gabarits, certaines variables symfony sont toujours disponibles. Ces raccourcis permettent grâce aux objets natif de symfony d'accéder aux informations dont on a le plus souvent besoin dans les gabarits.

  • $sf_context: l'intégralité de l'objet context (instance de sfContext)
  • $sf_request: l'objet request (instance de sfRequest)
  • $sf_params : les paramètres de la requête
  • $sf_user: l'objet user lié à la session utilisateur en cours (instance de sfUser)

Le chapitre précédent a présenté des méthodes utiles liées aux objets sfRequest et sfUser. Vous pouvez appeler ces méthodes depuis les gabarits grâce aux variables $sf_requestet $sf_user. Si par exemple la requête contient un paramètre total, sa valeur est accessible dans les gabarits de la façons suivante :

[php]
// Version longue
<?php echo $sf_request->getParameter('total'); ?>

// Version courte
<?php echo $sf_params->get('total'); ?>

// Identique au code suivant pour une action
echo $this->getRequestParameter('total');
[/php]

La factorisation du code

Il est courant de de devoir inclure du code HTML ou PHP dans plusieurs pages. Pour éviter la répétition de code, l'instruction PHP include() est souvent suffisante.

Par exemple, si dans plusieurs des gabarits de l'application vous devez utiliser le même morceau de code, enregistrez-le dans le répertoire général des gabarits (myproject/apps/myapp/templates/)dans un fichier myFragment.php et incluez-le dans votre gabarit de la façon suivante :

[php]
<?php include(sfConfig::get('sf_app_template_dir').'/myFragment.php') ?>
[/php]

Seulement voilà, ce n'est pas une façon très propre de gérer ce morceau de code. Essentiellement parce-que vous pouvez avoir des noms de variables différents entre le code factorisé et les différents gabarits qui l'incluent. De plus, le système de cache de Symfony (décrit au chapitre 12) n'est pas en mesure de détecter un include() et le morceau de code ne peut pas être mis en cache indépendamment du gabarit. Symfony dispose de trois autres solutions intelligentes de fatorisation de code pour remplacer les include() :

  • Si la logique est limitée, vous inclurez simplement un gabarit qui accèdera aux paramètres que vous lui passerez. Vous utiliserez un partiel.
  • Si la logique est plus lourde (vous avez par exemple besoin d'accèder au modèle de données et/ou de modifier le contenu selon la session), séparer la présentation de la logique sera préférable. Vous utiliserez dans ce cas un composant.
  • Si l'objectif du gabarit est de remplacer une partie spécifique de la page, pour laquelle il peut exister un contenu par défaut, vous utiliserez un slot.

TIP Un autre type de code, appelé un slot de composant est utilisé lorsque la nature de la découpe dépend du contexte (par exemple lorsque que le morceau de code diffère selon les différentes actions d'un même module). Les slots de composants seront décrits plus tard dans ce chapitre.

L'inclusion de fragments est possible grâce aux helpers du groupe Partial. Ces helpers sont accessibles depuis n'importe quel gabarit Symfony, sans déclaration préalable.

Les partiels

Un partiel est un morceau de code réutilisable au sein du gabarit. Par exemple, dans une application de publication, le gabarit permettant l'affichage de l'article est utilisé dans le détail de l'article, mais aussi dans la liste des meilleurs articles et dans la liste des articles les plus récents. C'est une situation parfaite pour un partiel, comme on peut le voir dans l'illustration 7-2.

Illustration 7-2 - Reutiliser les partiels dans les gabarits

Image : http://www.symfony-project.org/images/book/trunk/F0702.png

De la même façon que pour les gabarits, les partiels sont des fichiers situés dans le répertoire /templates. Ils contiennent le code HTML et PHP. Le nom d'un partiel commence toujours par un underscore (_). Cela permet de distinguer les partiels des gabarits, dans la mesure ils se trouvent dans le même répertoire /templates.

Un gabarit peut intégrer un partiel s'il s'agit du même module, d'un un autre module, ou du répertoire global templates/. On inclut un partiel en utilisant le helper include_partial() et en spécifiant le nom du module et du partiel en paramètre (en retirant toutefois le underscore au début, et le .php à la fin), comme décrit au listing 7-7.

Listing 7-7 - Inclure un partiel dans un gabarit du module mymodule

[php]
// Include the myapp/modules/mymodule/templates/_mypartial1.php partial
// As the template and the partial are in the same module,
// you can omit the module name
<?php include_partial('mypartial1') ?>

// Include the myapp/modules/foobar/templates/_mypartial2.php partial
// The module name is compulsory in that case
<?php include_partial('foobar/mypartial2') ?>

// Include the myapp/templates/_mypartial3.php partial
// It is considered as part of the 'global' module
<?php include_partial('global/mypartial3') ?>
[/php]

Les partiels ont accès à l'ensemble des raccourcis et helpers Symfony habituels. Mais dans la mesure où les partiels peuvent être appelés depuis n'importe où dans l'application, ils n'ont pas automatiquement accès aux variables définies dans l'action qui a appelé leur gabarit, à moins qu'elles soient explicitement passées en argument. Si par exemple vous voulez que votre partiel ait accès à la variable $total, l'action doit la passer au template et le template au helper, en deuxième argument de include_partial(), comme illustré dans les listings 7-8, 7-9, 7-10.

Listing 7-8 - L'action définit une variable dans mymodule/actions/actions.class.php

[php]
class mymoduleActions extends sfActions
{
  public function executeIndex()
  {
    $this->total = 100;
  }
}
[/php]

Listing 7-9 - Le gabarit passe la variable au partiel dans mymodule/templates/indexSuccess.php

[php]
<p>Hello, world!</p>
<?php include_partial('mypartial',
array('mytotal' => $total)
) ?>
[/php]

Listing 7-10 - Le partiel peut maintenant utiliser la variable dans mymodule/templates/_mypartial.php

[php]
<p>Total: <?php echo $mytotal ?></p>
[/php]

NOTE Jusqu'à présent, tous les helpers ont été appelés à l'aide de <?php echo functionName() ?>. Cependant, le helper du partiel a été appelé par <?php include_partial() ?>, sans echo, pour qu'elle se comporte comme la fonction PHP native include(). Si vous avez besoin d'une fonction qui retourne le contenu du partiel sans l'afficher, utilisez get_partial() à la place. Tous les helpers de type include_ évoqués dans ce chapitre ont un équivalent en _get que l'on peut joindre à echo.

Les composants

Au chapitre 2, le premier script d'exemple avait été coupé en deux pour séparer la logique de la présentation. De la même façon que le modèle MVC s'applique aux actions et aux gabarits, vous aurez peut-être besoin de scinder un partiel en deux parties : logique et présentation. Dans ce cas, c'est un composant que vous devrez utiliser.

Un composant se présente comme une action, en beaucoup plus rapide. La logique d'un composant est stockée dans un classe héritée de sfComponents, qui se trouve dans le fichier action/components.class.php. La présentation est stockée dans un partiel. Les méthodes de la classe sfComponents commencent par le mot execute, tout comme les actions, et ils peuvent passer des variables à leur pendant côté présentation, de la même façon que les actions peuvent passer des variables. Les partiels qui servent à des fins de présentation pour des composants sont nommés par le composant (sans le executeinitial, mais avec un underscore à la place). Le tableau 7-1 compare les conventions de nommage pour les actions et les composants.

Tableau 7-1 - Conventions de nommage pour les actions et les composants Convention Actions Composants Logic file actions.class.php components.class.php Logic class extends sfActions sfComponents Method naming executeMyAction() executeMyComponent() Presentation file naming myActionSuccess.php _myComponent.php

NOTE De la même façon que vous pouvez séparer les fichiers d'actions, la classe sfComponents a un équivalent sdComponent qui permet des fichiers de composant uniques avec le même type de syntaxe

Imaginez par exemple que vous ayez une barre latérale qui affiche les dernières actualités d'un sujet donné, lié au profil de l'utilisateur, réutilisé dans plusieurs pages. Les requêtes nécessaires pour récupérer les derniers titres sont trop complexes pour un simple partiel. Il est alors judicieux de les déplacer dans un fichier se comportant comme une action : un composant. La figure 7-3 illustre cet exemple.

Pour l'exemple des listings 7-11 et 7-12, on gardera le composant dans son propre module news, mais il est possible de faire cohabiter composants et actions dans un module unique si cela a un sens d'un point de vue fonctionnel.

Figure 7-3 - Utiliser des composants dans les gabarits

Image : http://www.symfony-project.org/images/book/1_0/F0703.png

Listing 7-11 - La classe Components, dans modules/news/actions/components.class.php

[php]
<?php

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

Listing 7-12 - Le partiel, dans modules/news/templates/_headlines.php

[php]
<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>
[/php]

Dès lors, lorsque vous avez besoin du composant dans le gabarit, faites simplement :

[php]
<?php include_component('news', 'headlines') ?>
[/php]

Tout comme les partiels, les composants acceptent des paramètres traditionnels sous forme de tableau associatif. Les paramètres sont accessibles au partiel par leurs noms, et le composant par l'objet $this. Voyez le listing 7-13 pour un exemple.

Listing 7-13 - Passer des paramètres à un composant et à son gabarit

[php]
// On appelle le composant
<?php include_component('news', 'headlines', array('foo' => 'bar')) ?>

// A l'intérieur du composant
echo $this->foo;
 => 'bar'

// Dans le partiel _headlines.php
echo $foo;
 => 'bar'
[/php]

Il est possible d'inclure des composants au sein d'autres composants ou dans le gabarit principal, comme dans n'importe quel gabarit. Comme les actions, les méthodes execute des composants peuvent transmettre des variables au partiel concerné et avoir accès aux même raccourcis. Toutefois, les similitudes s'arrêtent là. Un composant ne traite pas de la sécurité ou de la validation, ne peut pas être appelé en dehors de l'application web, et ne dispose pas des diverses possibilité de retour. C'est pourquoi un composant s'execute plus rapidement qu'une action.

Les slots

Les partiels et les composants sont parfaits en terme de réusabilité. Mais dans beaucoup de cas, des morceaux de code sont nécessaires à un gabarit qui comporte plus d'une zone dynamique. Imaginez par exemple que vous souhaitiez intégrer dans la section du gabarit des tags personnalisés, selon le contenu de l'action. Ou imaginez que le gabarit principal a une zone dynamique majeure, qui affiche le résultat d'une action, et quelques autres plus petites, avec un contenu défini par défaut dans le gabarit mais qui peuvent être surchargés au niveau du gabarit.

Dans ces situations, la solution est le slot. A la base, un slot est un conteneur que l'on peut placer dans n'importe quel élément de la vue (dans le gabarit principal, dans un template ou dans un partiel). Remplir ce conteneur est comme intialiser une variable. Le code généré est stocké dans la réponse de façon globale et vous pouvez la définir n'importe où (dans le gabarit principal, dans un template ou dans un partiel). Il faut juste s'assurer de définir un slot avant de l'inclure, et de ne pas oublier que le gabarit principal est exécuté après le gabarit (principe de décoration), et que les partiels sont exécutés lorsqu'ils sont appelés dans le gabarit. Est-ce que cela vous paraît trop abstrait ? Voyons un exemple.

Imaginez un gabarit principal avec une zone pour le gabarit et deux slots : un pour la barre latérale and l'autre pour le pied-de-page. Les valeurs du slot sont définies dans les gabarits. Pendant le processus de décoration, le code du gabarit principal enveloppe le code du gabarit, et les slots sont générés avec les valeurs définies précdemment comme illustré dans la Figure 7-4. La barre latérale et le pied de page peuvent ainsi être contextualisés en fonction de l'action principal. C'est comme avoir un gabarit principal avec plus d'un "trou".

Figure 7-4 - Slots du gabarit pricipal défini dans un gabarit

Image : http://www.symfony-project.org/images/book/1_0/F0704.png

Un peu de code va permettre de clarifier les choses. Pour inclure un slot utilisez le helper include_slot(). Le helper has-slot() retournera une valeur positive si le slot a été défini auparavant, offrant ainsi par la même occasion un mécanisme de fallback. Définissez par exemple un conteneur pour un slot de barre latérale dans le gabarit principal et son contenu par défault comme dans le Listing 7-14.

Listing 7-14 - Inlcure un slot de barre latérale dans le gabarit principal

[php]
<div id="sidebar">
<?php if (has_slot('sidebar')): ?>
<?php include_slot('sidebar') ?>
<?php else: ?>
<!-- default sidebar code -->
<h1>Contextual zone</h1>
<p>Cette zone contient des liens et de l'information
relative au contenu principal de la page.</p>
<?php endif; ?>
</div>
[/php]

Chaque gabarit est capable de définir du contenu comme un slot (en fait, même les partiels peuvent le faire). Dans la mesure où les slots sont pensés pour contenir code HTML, Symfony offre une manière bien pratique de les définir : il suffit d'écrire le code du slot entre les deux appels aux helpers slot() et end_slot(), comme dans le Listing 7-15.

Listing 7-15 - Surcharger le slot 'barre latérale' dans un gabarit

[php]
...
<?php slot('sidebar') ?>
  <!-- custom sidebar code for the current template-->
  <h1>User details</h1>
  <p>name:  <?php echo $user->getName() ?></p>
  <p>email: <?php echo $user->getEmail() ?></p>
<?php end_slot() ?>
[/php]

Le code contenu entre les helpers du slot est executé dans le contexte du gabarit et a donc accès à toutes les variables définies dans l'action. Symfony va automatiquement placer le résultat du code dans l'objet réponse. Il ne sera pas affiché dans le gabarit mais est rendu accessible pour les prochains appels include_slot(), comme celui du Listing 7-14. 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.

Les slots sont très utiles pour définir des zones destinées à du contenu contextuel. Ils peuvent aussi être utilisés pour ajouter du code HTML au gabarit pirncipal pour certaines actions seulement. Par exemple, un gabarit qui affiche la liste des dernières infos doit également proposer un lien vers un fil RSS dans la partie <head>du gabarit principal. Cela est réalisable en ajoutant simplement un slot 'feed' dans le gabarit principal et en le surchargeant dans le gabarit de la liste.


Où se trouve le code des gabarits ?

Les personnes qui travaillent sur les gabarits sont généralement des webdesigners qui ne connaissant pas forcément Symfony très bien et qui peuvent éprouver quelques difficultés à trouver le code des templates, dans la mesure où ils peuvent éclatés en différentes parties de l'application. Les lignes qui vont suivre devraient leur offrir une vision plus simple et plus claire du système de gabarits Symfony.

Première chose, bien qu'un projet Symfony contienne beaucoup de répertoires, tous les gabarits principaux, gabarits et sous-gabarits se situent dans les répertoires nommés templates/. Ainsi, pour autant qu'est concerné le webdesigner, la structure d'un projet peut être réduit à quelque chose de ce type :

myproject/
  apps/
    application1/
      templates/       # Gabarits principaux pour l'application 1
      modules/
        module1/
          templates/   # Gabarits et partiels pour le module 1
        module2/
          templates/   # Gabarits et partiels pour le module 2
        module3/
          templates/   # Gabarits et partiels pour le module 3

Tous les autres répertoires peuvent être ignorés.

Lorsqu'ils sont en présence d'un include_partial(), les webdesigners doivent comprendre que seul le premier argument est important. Cet argument fonctionne selon le modèle nom_du_module/nom_du_partiel, et cela signifie que le code lié à la présentation se trouve dans modules/nom_du_module/templates/_nom_du_partiel.php.

Pour le helper include_component(), les noms du module et du partiel sont les deux premiers arguments. Pour le reste, avoir une idée générale de ce que sont les helpers et des helpers les plus utilisés dans les gabarits devrait suffir pour commencer à créer des gabarits destinés à des applications Symfony.


Configurer la vue

Dans Symfony, la vue consiste en deux parties distinctes :

  • La présentation HTML du résultat de l'action (stocké dans le gabarit, dans le gabarit principal et dans les différentes découpes du gabarits)
  • Tout le reste, c'est-à-dire :
    • Les meta-déclarations : keywords, description et gestion du cache
    • Le titre de la page, qui ne sert d'ailleurs pas qu'à se repérer entre toutes les fenêtres, mais qui influe largement sur l'indexation et le référencement du site
    • Les fichiers inclus : Javascript et feuilles de styles
    • Le gabarit principal : certaines actions nécessitent une gabarit particulier (les pop-up, les pubs etc.) ou au contraire aucun (comme les actions Ajax)

Dans la vue, tout ce qui n'est pas HTML est considéré comme la configuration de la vue et Symfony offre deux façons de la manipuler. La méthode classique passe par le fichier de configuration view.yml. Il peut être utilisé tant que les valeurs ne dépendent ni du contexte ni des requêtes en base. Lorsque vous avez besoin de placer des valeurs dynamiques, la deuxième méthode est de configurer la vue à l'aide des attributs de l'objet sfResponsedirectement dans l'action.

NOTE Si vous deviez configurer la vue à la fois à l'aide de l'objet sfResponse et du fichier view.yml, ce qui est défini par sfResponse prévaudra.

The view.yml file

Chaque module peut dispose de son propre fichier view.yml avec ses propres réglages de vues. Cela permet de paramétrer la vue pour tout un module et par vue dans un seul fichier. Les clés de premier niveau du fichier view.yml sont les noms de vues des modules. Le listing 7-16 montre un exemple de configuration de la vue.

Listing 7-16 - Exemple d'un view.yml au niveau du module

[php]
editSuccess:
  metas:
    title: Modifier votre profil
editError:
  metas:
    title: Erreur dans la modification du profil

all:
  stylesheets: [my_style]
  metas:
    title: Mon site web
[/php]

CAUTION Notez bien que les clés principales du fichier view.yml sont les noms des vues et non des actions. Petit rappel, le nom d'une vue est composé du nom de l'action et du résultat de l'action. Par exemple, si l'action edit retourne sfView::SUCCESS (ou ne retourne rien du tout puisque c'est le résultat de l'action par défaut), le nom de la vue sera donc editSucess.

Les réglages par défaut pour le module sont définis dans la clé all: du view.yml du module. Les réglages par défaut pour toute l'application sont définis dans la clé all: du view.yml de l'application. Une fois encore, vous observez le principe de configuration en casacade :

  • In apps/myapp/modules/mymodule/config/view.yml, the per-view definitions apply only to one view and override the module-level definitions.
  • 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.
  • In apps/myapp/config/view.yml, the default: definitions apply to all modules and all actions of the application.

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

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.

Listing 7-17 - Default Application-Level View Configuration, in apps/myapp/config/view.yml

[php]
default:
  http_metas:
    content-type: text/html

  metas:
    title:        symfony project
    robots:       index, follow
    description:  symfony project
    keywords:     symfony, project
    language:     en

  stylesheets:    [main]

  javascripts:    [ ]

  has_layout:     on
  layout:         layout
[/php]

Each of these settings will be described in detail in the "View Configuration Settings" section.

The Response Object

View Configuration Settings

Meta Tag Configuration

Title Configuration

File Inclusion Configuration

Layout Configuration

Component Slots

Output Escaping

Activating Output Escaping

Escaping Strategy

Escaping Helpers

Escaping Arrays and Objects

Summary