Development

Documentation/de_DE/book/1.0/07-Inside-the-View-Layer (diff)

You must first sign up to be able to contribute.

Changes between Version 41 and Version 42 of Documentation/de_DE/book/1.0/07-Inside-the-View-Layer

Show
Ignore:
Author:
Jan.Kunzmann (IP: 87.158.172.131)
Timestamp:
02/08/08 04:09:26 (10 years ago)
Comment:

Nach Markdown umgesetzt, kleinere Typos korrigiert

Legend:

Unmodified
Added
Removed
Modified
  • Documentation/de_DE/book/1.0/07-Inside-the-View-Layer

    v41 v42  
     1'''ARBEITSENTWURF ROHÜBERSETZUNG / TRANSLATION WORKING DRAFT'''[[BR]] 
     2Originaldokument: http://svn.symfony-project.com/doc/trunk/book/07-Inside-the-View-Layer.txt, Version 3526 vom 2007-02-21[[BR]] 
     3Übersetzungsfortschritt: 100%[[BR]] 
     4Übersetzung: SK[[BR]] 
     5Korrekturfortschritt: 0%[[BR]] 
     6 
     7{{{ 
     8#!WikiMarkdown 
     9Kapitel 7 - Die View-Ebene 
     10========================== 
     11 
    112Die Sicht (View) ist dafür verantwortlich, den korrekten Output einer bestimmten Aktion anzuzeigen. In symfony besteht die Sicht aus mehreren Teilen, wobei jeder Teil so konzipiert wurde, dass er sich möglichst einfach verändern lässt von den Personen, die ihn normalerweise benutzen. 
    213 
    3     * Webdesigner arbeiten normalerweise mit den Templates (die Präsentation der Daten der aktuellen Aktion) und mit dem Layout (das den gemeinsamen Code aller Seiten enthält). Diese sind in HTML geschrieben, das kleine PHP-Snippets enthält (meistens Helfer-Aufrufe). 
    4     * Um der Wiederbenutzbarkeit willen stecken Entwickler normalerweise Templatecodefragmente in sogenannte Partials oder Komponenten. Sie benutzen Slots und Komponentenslots, um mehrere Bereiche des Layouts abzudecken. Webdesigner können ebenfalls an diesen Templatefragmenten arbeiten. 
    5     * Entwickler konzentrieren sich auf die YAML-Sicht-Konfigurations-Datei (um die Eigenschaften der Antwort und anderer Interface-Elemente zu bearbeiten) und auf das Antwortobject. Beim Arbeiten mit Variablen in einem Template darf das Risiko von Cross-Site-Scripting (XSS) nicht ausser Acht gelasen werden – um für die Sicherheit der Benutzerdaten garantieren zu können, ist ein gutes Verständnis von Escaping-Verfahren nötig. 
     14  * Webdesigner arbeiten normalerweise mit den Templates (die Präsentation der Daten der aktuellen Aktion) und mit dem Layout (das den gemeinsamen Code aller Seiten enthält). Diese sind in HTML geschrieben, das kleine PHP-Snippets enthält (meistens Helfer-Aufrufe). 
     15  * Um der Wiederbenutzbarkeit willen stecken Entwickler normalerweise Templatecodefragmente in sogenannte Partials oder Komponenten. Sie benutzen Slots und Komponentenslots, um mehrere Bereiche des Layouts abzudecken. Webdesigner können ebenfalls an diesen Templatefragmenten arbeiten. 
     16  * Entwickler konzentrieren sich auf die YAML-Sicht-Konfigurations-Datei (um die Eigenschaften der Antwort und anderer Interface-Elemente zu bearbeiten) und auf das Antwortobject. Beim Arbeiten mit Variablen in einem Template darf das Risiko von Cross-Site-Scripting (XSS) nicht ausser Acht gelasen werden – um für die Sicherheit der Benutzerdaten garantieren zu können, ist ein gutes Verständnis von Escaping-Verfahren nötig. 
    617 
    718Aber welche Rolle auch immer Sie dabei spielen, Sie werden hilfreiche Werkzeuge finden, die Ihnen bei der mühsamen Präsentation der Resultate einer Aktion behilflich sein können. Dieses Kapitel erläutert all diese Werkzeuge. 
    819 
    9 = Templates = 
    10  
    11 Codeabschnitt 7-1 zeigt ein typisches symfony-Template. Es enthält HTML-Code und ein wenig PHP-Code, normalerweise, um auf Variablen zuzugreifen, die in der Aktion definiert wurden (mit {{{$this->name = 'foo';}}}) und auf Helfer. 
    12  
    13 ''Codeabschnitt 7-1 - Ein beispielhaftes indexSuccess.php-Template'' 
    14 {{{ 
    15 #!php 
    16 <h1>Willkommen</h1> 
    17 <p>Willkommen zurück, <?php echo $name ?>!</p> 
    18 <ul>Was möchten Sie tun? 
    19   <li><?php echo link_to('Die neusten Artikel lesen', 'article/read') ?></li> 
    20   <li><?php echo link_to('Einen neuen Artikel schreiben', 'article/write') ?></li> 
    21 </ul> 
     20Templates 
     21--------- 
     22 
     23Codeabschnitt 7-1 zeigt ein typisches symfony-Template. Es enthält HTML-Code und ein wenig PHP-Code, normalerweise, um auf Variablen zuzugreifen, die in der Aktion definiert wurden (mit `$this->name = 'foo';`) und auf Helfer. 
     24 
     25Codeabschnitt 7-1 - Ein beispielhaftes indexSuccess.php-Template 
     26 
     27    [php] 
     28    <h1>Willkommen</h1> 
     29    <p>Willkommen zurück, <?php echo $name ?>!</p> 
     30    <ul>Was möchten Sie tun? 
     31      <li><?php echo link_to('Die neusten Artikel lesen', 'article/read') ?></li> 
     32      <li><?php echo link_to('Einen neuen Artikel schreiben', 'article/write') ?></li> 
     33    </ul> 
     34 
     35Wie in Kapitel 4 erklärt ist diese alternative PHP-Syntax vorzuziehen, da sie die Templates für Nicht-PHP-Entwickler lesbarer macht. Sie sollten den PHP-Code in den Templates auf ein Minimum reduzieren, da diese Dateien diejenigen sind, die das GUI Ihrer Applikation darstellen und deshalb manchmal von einem anderen Team bearbeitet werden, das sich auf Präsentation spezialisiert hat und nicht auf Applikationslogik. Wenn also die Logik in der Aktion bleibt, ist es auch einfacher, mehrere Templates für eine einzige Aktion zu haben, ohne Codewiederholungen. 
     36 
     37### Helfer 
     38 
     39Helfer sind PHP-Funktionen, die HTML-Code zurückgeben und in Templates benutzt werden können. Beispielsweise ist in Codeabschnitt 7-1 die `link_to()`-Funktion so ein Helfer. Manchmal ersparen einem Helfer einfach nur etwas Zeit, indem sie in Templates häufig benutzte Codeschnipsel bequem verpacken. Beispielsweise ist es sehr einfach, sich die Funktionsdefinition dieses Helfers zu überlegen: 
     40 
     41    [php] 
     42    <?php echo input_tag('nickname') ?> 
     43     => <input type="text" name="nickname" id="nickname" value="" /> 
     44 
     45Er ist in Codeabschnitt 7-2 zu sehen. 
     46 
     47Codeabschnitt 7-2 - Beispielhafte Helfer-Definition 
     48 
     49    [php] 
     50    <?php 
     51    function input_tag($name, $value = null) 
     52    { 
     53      return '<input type="text" name="'.$name.'" id="'.$name.'"value="'.$value.'" />'; 
     54    } 
     55    ?> 
     56 
     57In Wirklichkeit ist die `input_tag()`-Funktion von symfony etwas komplizierter, da sie einen dritten Parameter akzeptiert, um dem `<input>`-Tag weitere Attribute hinzuzufügen. Sie können die komplette Syntax und alle Möglichkeiten in der Online-API-Dokumentation (http://www.symfony-project.com/api/symfony.html) einsehen. 
     58 
     59Meistens beinhalten Helfer aber eine gewisse Intelligenz und ersparen es Ihnen somit, langen und komplizierten Code zu tippen: 
     60 
     61    [php] 
     62    <?php echo auto_link_text('Bitte besuchen Sie unsere Website www.beispiel.de') ?> 
     63     => Bitte besuchen Sie unsere Website <a href="http://www.beispiel.de">www.beispiel.de</a> 
     64 
     65Helfer vereinfachen das Schreiben von Templates und produzieren den bestmöglichen HTML-Code hinsichtlich Performance und Zugänglichkeit. Sie können immer noch reines HTML verwenden, aber mit Helfern geht es normalerweise schneller. 
     66 
     67>**TIP** 
     68>Möglicherweise wundern Sie sich darüber, dass die Helfer nach der Unterstrich-Syntax benannt sind und nicht nach der camelCase-Konvention, die sonst überall in symfony verwendet wird. Das ist deshalb so, weil Helfer Funktionen sind, und alle Kern-PHP-Funktionen benutzen die Unterstrich-Syntaxkonvention. 
     69 
     70#### Helfer deklarieren 
     71 
     72Die symfony-Dateien mit den Helferdefinitionen werden nicht automatisch geladen (weil sie Funktionen enthalten, und keine Klassen). Helfer sind nach Einsatzzweck sortiert. Beispielsweise sind alle Helferfunktionen, die mit Text zu tun haben, in einer Datei `TextHelper.php` enthalten, die `Text`-Helfergruppe. Wenn Sie also in einem Template einen Helfer benötigen, müssen Sie zuvor im Template die entsprechende Helfergruppe laden mit der `use_helper()`-Funktion. Codeabschnitt 7-3 zeigt ein Template, das den `auto_link_text()`-Helfer benutzt, der Teil der Texthelfer-Gruppe ist. 
     73 
     74Codeabschnitt 7-3 - Die Benutzung eines Helfers deklarieren 
     75 
     76    [php] 
     77    // Benutze eine bestimmte Helfergruppe in diesem Template 
     78    <?php echo use_helper('Text') ?> 
     79    ... 
     80    <h1>Beschreibung</h1> 
     81    <p><?php echo auto_link_text($description) ?></p> 
     82 
     83    Wenn Sie mehr als eine Helfergruppe deklarieren müssen, fügen Sie entsprechend mehr Argumente zum `use_helper()`-Funktionsaufruf hinzu. Um etwa die `Text`- und die `Javascript`-Helfergruppen in einem Template zu laden, rufen Sie `<?php echo use_helper('Text', 'Javascript') ?>` auf. 
     84 
     85Einige Helfer sind standardmässig in jedem Template verfügbar, ohne entsprechende Deklaration. Es sind dies die Helfer der folgenden Gruppen: 
     86 
     87  * `Helfer`: Benötigt für das Einbinden anderer Helfer (die `use_helper()`-Funktion ist selbst auch ein Helfer) 
     88  * `Tag`: Grundsätzlicher Taghelfer, wird von beinahe jedem anderen Helfer benötigt 
     89  * `Url`: Link- und URL-Management-Helfer 
     90  * `Asset`: Helfer, die sich um den HTML-`<head>`-Teil kümmern und auf einfache Art und Weise Links zu externen Dateien bereitstellen. (Bilder, JavaScript, CSS-Dateien) 
     91  * `Partial`: Helfer, die das Einbinden von Templatefragmenten ermöglichen 
     92  * `Cache`: Manipulation gecacheter Codefragmente 
     93  * `Form`: Formularhelfer 
     94 
     95Die Liste der standardmässig geladenen Helfer kann in der `settings.yml`-Datei eingestellt werden. Wenn Sie also wissen, dass Sie die Helfer der Gruppe `Cache` nicht benötigen oder dass Sie immer diejenigen der Textgruppe benötigen, verändern sie die `standard_helpers`-Einstellung entsprechend. Das wird Ihre Applikation etwas beschleunigen. Die ersten vier Helfer in der obigen Liste (`Helper`, `Tag`, `Url` und `Asset`) können Sie nicht entfernen, da Sie zwingend notwendig sind für das Funktionieren der Templateengine. Deshalb erscheinen sie auch nicht in der Liste der Standardhelfer. 
     96 
     97>**TIP** 
     98>Sollten Sie einmal einen Helfer ausserhalb eines Templates benötigen, können Sie eine Helfergruppe von überall aus mit `sfLoader::loadHelpers($helpers)` laden, wobei `$helpers` ein Helfergruppenname oder ein Array aus Helfergruppennamen ist. Wenn Sie etwa den `auto_link_text()`-Helfer in einer Aktion benutzen wollen, müssen Sie zuerst `sfLoader::loadHelpers('Text')` aufrufen. 
     99 
     100#### Häufig benutzte Helfer 
     101 
     102Sie werden in späteren Kapiteln mehr über einige Helfer erfahren und wie sie Ihnen helfen können. Codeabschnitt 7-4 gibt einen kurzen Überblick über die Standardhelfer, die häufig benutzt werden, zusammen mit dem HTML-Code, den sie zurückgeben. 
     103 
     104Codeabschnitt 7-4 - Gängige Standardhelfer 
     105 
     106    [php] 
     107    // Helper-Gruppe 
     108    <?php echo use_helper('Helfername') ?> 
     109    <?php echo use_helper('Helfername1', 'Helfername2', 'Helfername3') ?> 
     110     
     111    // Tag-Gruppe 
     112    <?php echo tag('input', array('name' => 'foo', 'type' => 'text')) ?> 
     113    <?php echo tag('input', 'name=foo type=text') ?>  // alternative Syntax für die Optionen 
     114     => <input name="foo" type="text" /> 
     115    <?php echo content_tag('textarea', 'Beispieltext', 'name=foo') ?> 
     116     => <textarea name="foo">Beispieltext</textarea> 
     117     
     118    // Url-Gruppe 
     119    <?php echo link_to('klick mich', 'modul/aktion') ?> 
     120    => <a href="/pfad/zur/aktion">klick mich</a>  // hängt von den Routing-Einstellungen ab 
     121     
     122    // Asset-Gruppe 
     123    <?php echo image_tag('bild', 'alt=foo size=200x100') ?> 
     124     => <img src="/images/bild.png" alt="foo" width="200" height="100"/> 
     125    <?php echo javascript_include_tag('meinscript') ?> 
     126     => <script language="JavaScript" type="text/javascript" src="/js/meinscript.js"></script> 
     127    <?php echo stylesheet_tag('style') ?> 
     128     => <link href="/stylesheets/style.css" media="screen" rel="stylesheet" type="text/css" /> 
     129 
     130Es gibt viele weitere Helfer in symfony, und es bräuchte eine ganzes Buch, um sie alle zu beschreiben. Die beste Referenz für die Helfer ist die Online-API-Dokumentation (http://www.symfony-project.com/api/symfony.html), wo für alle Helfer ausführlich Syntax, Optionen und Beispiele dokumentiert sind. 
     131 
     132#### Eigene Helfer hinzufügen 
     133 
     134symfony bringt viele Helfer für verschiedenste Zwecke mit, aber wenn Sie in der API-Dokumentation nicht das finden, was Sie benötigen, wollen Sie möglicherweise einen neuen Helfer erstellen. Das ist wirklich sehr einfach. 
     135 
     136Helferfunktionen (normale PHP-Funktionen, die HTML-Code zurückgeben) sollten in einer Datei `FoobarHelper.php` gespeichert werden, wobei `Foobar` der Name der Helfergruppe ist. Speichern Sie die Datei im `apps/meineapp/lib/helper/`-Verzeichnis (oder in irgendeinem `helper/`-Verzeichnis erstellt in einem der `lib/`-Verzeichnisse Ihres Projekts), und es kann automatisch mit `use_helper('Foobar')` eingebunden werden. 
     137 
     138>**TIP** 
     139>Das System erlaubt Ihnen sogar, die existierenden symfony-Helfer zu überschreiben. Um etwa alle Helfer aus der Helfergruppe `Text` neu zu definieren, erzeugen Sie einfach eine Datei `TextHelper.php` in Ihrem `apps/meineapp/lib/helper/`-Verzeichnis. Jedesmal, wenn Sie `use_helper('Text')` aufrufen, wird symfony Ihre `Text`-Helfergruppe statt seine eigene benutzen. Aber Vorsicht: Da die Originaldatei gar nicht mehr beachtet wird, müssen Sie alle Funktionen der Helfergruppe neu definieren; andernfalls werden einige der Originalhelfer nicht mehr verfügbar sein. 
     140 
     141### Seitenlayout 
     142 
     143Das Template in Codeabschnitt 7-1 ist kein gültiges XHTML-Dokument. Die `DOCTYPE`-Definition und die `<html>`- und `<body>`-Tags fehlen. Das liegt darain, dass sie anderswo in der Applikation gespeichert sind, in einer Datei `layout.php`, die das Seitenlayout enthält. Diese Datei, das globale Template, speichert den HTML-Code, der allen Seiten der Applikation gemeinsam ist, um zu verhindern, dass er in jedem Template wiederholt werden muss. Der Inhalt eines Templates wird ins Layout eingebettet oder, andersherum betrachtet, das Layout "dekoriert" das Template. Das ist eine Anwendung des Decorator-Design-Patterns, zu sehen in Abbildung 7-1. 
     144 
     145>**TIP** 
     146>Für weitere Informationen über das Decorator- und anderen Design-Pattern, siehe *Patterns of Enterprise Application Architecture* von Martin Fowler (Addison-Wesley, ISBN: 0-32112-742-0). 
     147 
     148Abbildung 7-1 - Ein Template mit dem Layout dekorieren 
     149 
     150[[Image(http://www.symfony-project.com/images/book/trunk/F0701.png)]] 
     151 
     152Codeabschnitt 7-5 zeigt das Standard-Seitenlayout, zu finden im `templates/`-Verzeichnis der Applikation. 
     153 
     154Codeabschnitt 7-5 - Standardlayout in `meinprojekt/apps/meineapp/templates/layout.php` 
     155 
     156    [php] 
     157    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd"> 
     158    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de"> 
     159    <head> 
     160    <?php echo include_http_metas() ?> 
     161    <?php echo include_metas() ?> 
     162    <?php echo include_title() ?> 
     163    <link rel="shortcut icon" href="/favicon.ico" /> 
     164    </head> 
     165    <body> 
     166     
     167    <?php echo $sf_data->getRaw('sf_content') ?> 
     168     
     169    </body> 
     170    </html> 
     171 
     172Die Helfer im `<head>`-Bereich holsen sich Informationen aus dem Response-Objekt und der View-Konfiguration. Der `<body>`-Tag zeigt das fertige Template an. Mit diesem Layout, der Standardkonfiguration, und dem Beispieltemplate aus Codeabschnitt 7-1, sieht das Ganze am Schluss dann so aus wie in Codeabschnitt 7-6. 
     173 
     174Codeabschnitt 7-6 - Das Layout, die View-Konfiguration und das Template 
     175 
     176    [php] 
     177    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd"> 
     178    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de"> 
     179    <head> 
     180      <meta http-equiv="content-type" content="text/html; charset=utf-8" /> 
     181      <meta name="title" content="Symfony-Projekt" /> 
     182      <meta name="robots" content="index, follow" /> 
     183      <meta name="description" content="Symfony-Projekt" /> 
     184      <meta name="keywords" content="symfony, projekt" /> 
     185      <title>Symfony-Projekt</title> 
     186      <link rel="stylesheet" type="text/css" href="/css/main.css" /> 
     187      <link rel="shortcut icon" href="/favicon.ico"> 
     188    </head> 
     189    <body> 
     190     
     191    <h1>Willkommen</h1> 
     192    <p>Willkommen zurück, <?php echo $name ?>!</p> 
     193    <ul>Was möchten Sie tun? 
     194      <li><?php echo link_to('Die neusten Artikel lesen', 'article/read') ?></li> 
     195      <li><?php echo link_to('Einen neuen Artikel schreiben', 'article/write') ?></li> 
     196    </ul> 
     197     
     198    </body> 
     199    </html> 
     200 
     201Das globale Template kann vollständig an Ihre Applikation angepasst werden. Fügen Sie beliebigen HTML-Code hinzu. Dieses Layout wird oft dazu benutzt, die Navigation, das Logo usw. darzustellen. Sie können sogar mehrere Layouts haben und entscheiden, welches Layout für welche Aktion benutzt werden soll. Machen Sie sich um die Einbindung von JavaScript und CSS-Dateien keine Sorgen; der Abschnitt "View-Konfiguration" später in diesem Kapitel erklärt diese ausführlich. 
     202 
     203### Template-Shortcuts 
     204 
     205In den Templates sind einige symfony-Variablen immer verfügbar. Diese Shortcuts ermöglichen den Zugriff auf die wichtigsten Informationen über die symfony-Kern-Objekte: 
     206 
     207  * `$sf_context`: Das Context-Object (Instanz von `sfContext`) 
     208  * `$sf_request`: Das Request-Objekt (Instanz von `sfRequest`) 
     209  * `$sf_params`: Parameter des Requests 
     210  * `$sf_user`: Das aktuelle User-Session-Objekt (Instanz von `sfUser`) 
     211 
     212Das vorherige Kapitel hat hilfreiche Methoden des `sfRequest`- und des `sfUser`-Objekts beschrieben. Sie können diese Methoden in Templates durch die `$sf_request`- und `$sf_user`-Variablen aufrufen. Wenn zum Beispiel der Request einen `total`-Parameter enthält, ist sein Wert im Template folgendermassen verfügbar: 
     213 
     214    [php] 
     215    // lange Version 
     216    <?php echo $sf_request->getParameter('total'); ?> 
     217     
     218    // kürzere Version 
     219    <?php echo $sf_params->get('total'); ?> 
     220     
     221    // gleichwertig mit dem folgenden Code in einer Aktion 
     222    <?php echo $this->getRequestParameter('total'); ?> 
     223 
     224Codefragmente 
     225------------- 
     226 
     227Oft müssen Sie HTML- oder PHP-Code in mehrere Seiten einbinden. Die PHP-`include()`-Funktion hilft Ihnen dabei, dass Sie den Code nicht jedesmal wiederholen müssen. 
     228 
     229Wenn zum Beispiel viele Templates Ihrer Applikation das gleiche Codefragment benötigen, speichern Sie es in einer Datei `meinFragment.php` im globalen Template-Verzeichns (`meinprojekt/apps/meineapp/templates/`) und binden es in Ihr Template wie folgt ein: 
     230 
     231    [php] 
     232    <?php include(sfConfig::get('sf_app_template_dir').'/meinFragment.php') ?> 
     233 
     234Aber das ist keine sehr saubere Art, ein Fragment zu verpacken, vor allem deshalb, weil sie verschiedene Variablennamen im Fragment und den verschiedenen Templates haben können, die es einbinden. Ausserdem hat das symfony-Cachesystem (näheres dazu in Kapitel 12) keine Möglichkeit, includes zu erkennen, das Codefragment kann also nicht uanbhängig vom Template im Cache abgelegt werden. symfony bietet drei Alternativen zu gewöhnlichen `include`s: 
     235 
     236  * Wenn die Logik simpel ist, können Sie einfach eine Templatedatei nehmen, der Sie einige Daten übergeben. Dazu verwenden Sie ein Partial. 
     237  * Wenn die Logik komlizierter ist (zum Beispiel wenn sie aufs Datenmodell zugreift oder den Inhalt entsprechend der Session ändert), sollten Sie die Präsentation von der Logik trennen. Dazu benötigen Sie eine Component. 
     238  * Wenn das Fragment einen bestimmten Teil des Layouts ersetzen soll, für den möglicherweise bereits Standardinhalt definiert wurde, brauchen Sie ein Slot. 
     239 
     240    Ein weiterer Codefragment-Typ, ein Component Slot, wird benutzt, wenn der Inhalt des Fragments vom Kontext abhäng (z.B. wenn das Fragment für verschiedene Aktionen eines Moduls unterschiedlichen Inhalt hat). Component Slots werden später in diesem Kapitel noch genauer beschrieben. 
     241 
     242Die Einbindung dieser Fragmente geschieht durch Helfer der Partial-Gruppe. Diese Helfer sind in jedem symfony-Template ohne Deklaration verfügbar. 
     243 
     244### Partials 
     245 
     246Ein Partial ist ein wiederbenutzbares Stück Template-Code. In einer Publikationsapplikation wird der Templatecode zum Anzeigen eines Artikels sowohl in der Artikel-Detailseite verwendet als auch in der Liste der besten und derjenigen der neusten Artikel. Solcher Code ist ein perfekter Kandidat für ein Partial, wie in Abbildung 7-2 dargestellt. 
     247 
     248Abbildung 7-2 - Partials in Templates wiederverwenden 
     249 
     250[[Image(http://www.symfony-project.com/images/book/trunk/F0702.png)]] 
     251 
     252Genau wie Templates sind Partials Dateien im `templates/`-Verzeichnis, die HTML-Code mit etwas PHP enthalten. Der Dateiname eines Partials beginnt immer mit einem Unterstrich (`_`), um sie gut von Templates unterscheiden zu können, die ja in den gleichen `templates/`-Verzeichnissen gespeichert sind. 
     253 
     254Ein Template kann Partials einbinden, egal, ob sie aus dem gleichen Modul stammen, einem anderen oder aus dem globalen `templates/`-Verzeichnis. Sie können ein Partial mit dem `include_partial()`-Helfer einbinden und dabei das Modul und den Partialnamen wie in Codeabschnitt 7-7 gezeigt als Parameter angeben (ohne den führenden Unterstrich und die Dateiendung `.php`). 
     255 
     256Codeabschnitt 7-7 - Ein Partial in ein Template des `meinmodul`-Moduls einbinden 
     257 
     258    [php] 
     259    // Binde das meineapp/modules/meinmodul/templates/_meinpartial1.php-Partial ein 
     260    // Da das Template und das Partial im gleichen Modul sind, 
     261    // können Sie den Modulnamen weglassen 
     262    <?php include_partial('meinpartial1') ?> 
     263     
     264    // Binde das meineapp/modules/foobar/templates/_meinpartial2.php-Partial ein 
     265    // Hier muss der Modulname angegeben werden 
     266    <?php include_partial('foobar/meinpartial2') ?> 
     267     
     268    // Binde das meineapp/templates/_meinpartial3.php-Partial ein 
     269    // Es wird als Teil des 'global'-Moduls betrachtet 
     270    <?php include_partial('global/meinpartial3') ?> 
     271 
     272Partials haben Zugriff auf die üblichen symfony-Helfer und Template-Shortcuts. Aber weil Partials überall in der Applikation aufgerufen werden können, haben sie nicht automatisch Zugriff auf die Variablen der Aktion, die das Template aufruft, in dem sie sich befinden - ausser, wenn die Variablen explizit als Argument übergeben werden. Wenn etwa ein Partial Zugriff auf eine Variable `$total` haben soll, muss die Aktion diese dem Template übergeben und das Template sie dann dem Helfer als zweites Argument des `include_partial()`-Aufrufs, siehe Codeabschnitte 7-8, 7-9 und 7-10. 
     273 
     274Codeabschnitt 7-8 - Die Aktion definiert eine Variable in `meinmodul/actions/actions.class.php` 
     275 
     276    [php] 
     277    class meinmodulActions extends sfActions 
     278    { 
     279      public function executeIndex() 
     280      { 
     281        $this->total = 100; 
     282      } 
     283    } 
     284 
     285Codeabschnitt 7-9 - Das Template übergibt die Variable dem Partial, in `meinmodul/templates/indexSuccess.php` 
     286 
     287    [php] 
     288    <p>Hallo Welt!</p> 
     289    <?php include_partial('meinpartial', 
     290    array('meintotal' => $total) 
     291    ) ?> 
     292 
     293Codeabschnitt 7-10 - Das Partial kann die Variable jetzt verwenden, in `meinmodul/templates/_meinpartial.php` 
     294 
     295    [php] 
     296    <p>Total: <?php echo $meintotal ?></p> 
     297 
     298>**TIP** 
     299>Bisher wurden alle Helfer mit `<?php echo functionName() ?>` aufgerufen. Der Partial-Helper hingegen wird einfach nur mit `<?php include_partial() ?>` aufgerufen - ohne `echo`, so verhält es sich ähnlich dem normalen PHP-`include()`-Befehl. Sollten Sie jemals eine Funktion benötigen, die den Inhalt eines Partials zurückgibt ohne ihn anzuzeigen, verwenden Sie `get_partial()`. Alle in diesem Kapitel beschriebenen `include_`-Helfer haben ein `get_`-Pendant, das zusammen mit einem `echo` verwendet werden kann. 
     300 
     301### Komponenten 
     302 
     303Das erste Beispielskript in Kapitel 2 war in zwei Teile aufgeteilt, um die Logik von der Präsentation zu trennen. Genau wie das MVC-Pattern auf Aktionen und Templates zutrifft, müssen Sie möglicherweise ein Partial in einen Logik- und einen Präsentationsteil aufteilen. In so einem Fall sollten sie eine Komponente benutzen. 
     304 
     305Eine Komponente ist wie eine Aktion, nur viel schneller. Die Logik einer Komponente befindet sich in einer Klasse, die von `sfComponents` erbt, sie befindet sich in der Datei `action/components.class.php`. Die Präsentation befindet sich in einem Partial. Methoden der `sfComponents`-Klasse beginnen mit `execute`, genau wie Aktionen, und genau wie Aktionen können sie Variablen an den Präsentationsteil übergeben. Partials, die zusammen mit einer Komponente verwendet werden, werden nach dieser benannt (ohne das führende `execute`, aber dafür mit einem Unterstrich). Tabelle 7-1 vergleich die Namenskonventionen von Aktionen und Komponenten. 
     306 
     307Tabelle 7-1 - Aktions- und Komponenten-Namenskonventionen 
     308 
     309Konvention            | Aktionen                 | Komponenten 
     310--------------------- | ------------------------ | -------------------------- 
     311Logikdatei            | `actions.class.php`      | `components.class.php` 
     312Logikklasse erweitert | `sfActions`              | `sfComponents` 
     313Methodennamen         | `executeMeineAktion()`   | `executeMeineKomponente()` 
     314Präsentationsdatei    | `meineAktionSuccess.php` | `_meineKomponente.php` 
     315 
     316>**TIP** 
     317>Genau wie Sie Sie Aktionsdateien aufspalten können, hat die `sfComponents`-Klasse ein `sfComponent`-Pendant, das einzelne Komponentendateien mit der gleichen Syntax erlaubt. 
     318 
     319Ein Beispiel: Nehmen wir an, Sie haben eine Sidebar, in der Sie die neusten Nachrichten eines bestimmten Themas anzeigen, abhängig vom Benutzerprofil; diese Sidebar wird auf verschiedenen Seiten verwendet. Die benötigten Querys, um die Headlines zu holen, sind zu kompliziert für ein einzelnes Partial, also müssen sie in eine aktionsartige Datei verschoben werden – eine Komponente. Abbildung 7-3 illustriert dieses Beispiel. 
     320 
     321Für dieses Beispiel (siehe Codeabschnitte 7-11 und 7-12) befindet sich die Komponente in ihrem eigenen Modul `news`, aber Sie können Komponenten und Aktionen auch in einem einzigen Modul mischen, wenn es Sinn macht. 
     322 
     323Abbildung 7-3 - Komponenten in Templates verwenden 
     324 
     325[[Image(http://www.symfony-project.com/images/book/trunk/F0703.png)]] 
     326 
     327Codeabschnitt 7-11 - Die Komponentenklasse in `modules/news/actions/components.class.php` 
     328 
     329    [php] 
     330    <?php 
     331     
     332    class newsKomponenten extends sfComponents 
     333    { 
     334      public function executeHeadlines() 
     335      { 
     336        $c = new Criteria(); 
     337        $c->addDescendingOrderByColumn(NewsPeer::EINGETRAGEN_AM); 
     338        $c->setLimit(5); 
     339        $this->news = NewsPeer::doSelect($c); 
     340      } 
     341    } 
     342 
     343Codeabschnitt 7-12 - Das Partial in `modules/news/templates/_headlines.php` 
     344 
     345    [php] 
     346    <div> 
     347      <h1>Neuste Nachrichten</h1> 
     348      <ul> 
     349      <?php foreach($news as $headline): ?> 
     350        <li> 
     351          <?php echo $headline->getEingetragenAm() ?> 
     352          <?php echo link_to($headline->getTitel(),'news/show?id='.$headline->getId()) ?> 
     353        </li> 
     354      <?php endforeach ?> 
     355      </ul> 
     356    </div> 
     357 
     358Jetzt können Sie jedesmal, wenn Sie die Komponente in einem Template benötigen, einfach diesen Code einbinden: 
     359 
     360    [php] 
     361    <?php include_component('news', 'headlines') ?> 
     362 
     363Genau wie Partials akzeptieren Komponenten als zusätzliche Parameter assoziative Arrays. Die Parameter sind in den Partials unter ihrem eigenen Namen verfügbar, und in Komponenten über das `$this`-Objekt (siehe Codeabschnitt 7-13). 
     364 
     365Codeabschnitt 7-13 - Parameter an eine Komponente und das dazugehörige Template übergeben 
     366 
     367    [php] 
     368    // Komponente einbinden 
     369    <?php include_component('news', 'headlines', array('foo' => 'bar')) ?> 
     370     
     371    // In der Komponente selbst 
     372    echo $this->foo; 
     373     => 'bar' 
     374     
     375    // Im _headlines.php-Partial 
     376    echo $foo; 
     377     => 'bar' 
     378 
     379Sie können sogar Komponenten in andere Komponenten einbinden, oder auch im globalen Layout, wie jedes normale Template. Wie Aktionen führen Komponenten Methoden aus, die Variablen an das zugehörige Partial übergeben und Zugriff auf die gleichen Shortcuts haben. Aber die Ähnlichkeiten enden hier. Eine Komponente kümmert sich nicht um Sicherheit oder Validation, kann nicht vom Internet aus aufgerufen werden (nur von der Applikation selbst) und hat nicht mehrere Rückgabemöglichkeiten. Darum ist die Ausführung einer Komponente schneller als die einer Aktion. 
     380 
     381### Slots 
     382 
     383Partials und Komponenten dienen der Wiederbenutzbarkeit. Aber oft sollen Codefragmente ein Layout mit verschiedenen dynamischen Bereichen ausfüllen. Beispielsweise möchten Sie einige individuelle Tags in den `<head>`-Bereich Ihres Layouts einbinden, abhängig von der aufgerufenen Aktion. Oder die Aktion füllt verschiedene grössere dynamische Bereiche auf der Seite und zusätzlich viele kleinere, für die ein Standardinhalt im Layout festgelegt ist, der aber von Templates überschrieben werden kann. 
     384 
     385In solchen Situationen ist die Lösung ein Slot. Ein Slot ist ein Platzhalter, den man in einem beliebigen View-Element einsetzen kann. (Layout, Template, Partial) Diesen Platzhalter ausfüllen ist genau wie eine Variable setzen. Der Code, mit dem der Slot gefüllt wird, wird im Response-Objekt gespeichert, Sie können es also in jedem View-Element definieren. Nur sollten Sie sicherstellen, dass ein Slot definiert ist, bevor er eingebunden wird; und denken Sie daran: Das Layout wird nach dem Template gerendert (das ist der Dekorationsprozess), und die Partials werden dann gerendert, wenn sie von einem Template aus aufgerufen werden. Klingt zu kompliziert? Sehen wir uns ein Beispiel an. 
     386 
     387Nehmen wir ein Layout mit einem Bereich fürs Template und zwei Slots: Einen für die Sidebar und den anderen für den Footer. Die Slotwerte werden in den Templates definiert. Während dem Dekorationsprozesses enthält das Layout den Templatecode, und die Slots werden mit den vorher definierten Werten gefüllt, wie in Abbildung 7-4 zu sehen. Die Sidebar und der Footer können dann abhängig von der Aktion geändert werden. Das ist so, als ob Sie ein Layout mit mehreren "Löchern" haben. 
     388 
     389Abbildung 7-4 - Layoutslots in einem Template 
     390 
     391[[Image(http://www.symfony-project.com/images/book/trunk/F0704.png)]] 
     392 
     393Wenn wir uns etwas Code ansehen, wird die Sache schnell verständlicher. Um einen Slot einzubinden, verwenden Sie den `include_slot()`-Helfer. Der `has_slot()`-Helfer gibt `true` zurück, wenn der Slot bereits definiert wurde. Um einen Platzhalter für den Slot `'sidebar'` im Layout mitsamt seinem Standardinhalt zu definieren, verwenden Sie den Code aus Codeabschnitt 7-14. 
     394 
     395Codeabschnitt 7-14 - Den Slot `'sidebar'` ins Layout einbinden 
     396 
     397    [php] 
     398    <div id="sidebar"> 
     399    <?php if (has_slot('sidebar')): ?> 
     400      <?php include_slot('sidebar') ?> 
     401    <?php else: ?> 
     402      <!-- Standard-Sidebar-Inhalt --> 
     403      <h1>Individuellelr Bereich</h1> 
     404      <p>Dieser Bereich enthält Links und Informationen 
     405      abhängig vom Hauptbereich der Seite.</p> 
     406    <?php endif; ?> 
     407    </div> 
     408 
     409Jedes Template kann die Inhalt eines Slots definieren (sogar Partials können das). Da Slots dazu gedacht sind, HTML-Code zu beinhalten, bietet symfony einen komfortablen Weg, sie zu definieren: Schreiben Sie den Slot-Code einfach zwischen einen Aufruf des `slot()`- und des `end_slot()`-Helfer, so wie in Codeabschnitt 7-15. 
     410 
     411Codeabschnitt 7-15 - Den Inhalt von Slot `'sidebar'` in einem Template überschreiben 
     412 
     413    [php] 
     414    ... 
     415    <?php slot('sidebar') ?> 
     416      <!-- Individueller Sidebar-Inhalt für das aktuelle Template --> 
     417      <h1>Benutzerinformationen</h1> 
     418      <p>Name:  <?php echo $user->getName() ?></p> 
     419      <p>E-Mail-Adresse: <?php echo $user->getEmail() ?></p> 
     420    <?php end_slot() ?> 
     421 
     422Der Code zwischen den Slothelfern wird im Kontext des Templates ausgeführt, es hat also keinen Zugriff auf die Variablen der Aktion. symfony fügt diesen Code automatisch dem Response-Objekt hinzu. Es wird nicht im Template angezeigt, aber ist für künftige `include_slot()`-Aufrufe verfügbar, wie in Codeabschnitt 7-14  zu sehen. 
     423 
     424Slots sind sehr nützlich für Bereiche mit individuellem Inhalt. Sie können auch benutzt werden, wenn HTML-Code nur von gewissen Aktionen angezeigt werden soll. Zum Beispiel hat es in einem Template, das die Liste der neusten Nachrichten anzeigt, im `<head>`-Bereich des Layouts einen Link zu einem RSS-Feed. Das kann man mit einem `'feed'`-Slot im Layout lösen, den man dann im Template der Liste setzt. 
     425 
     426>**SIDEBAR** 
     427>Wo die Templatefragmente zu finden sind 
     428
     429>Leute, die mit Templates arbeiten, sind normalerweise Webdesigner, die symfony möglicherweise nicht gut kennen und Schiwerigkeiten haben, Templatefragmente zu finden, da diese überall in der Applikation verteilt sein können. Diese Richtlinien wird ihnen die Arbeit mit dem symfony-Templatingsystem erleichtern. 
     430
     431>Obwohl ein symfony-Projekt viele Verzeichnisse enthält, befinden sich alle Layouts, Templates und Templatefragmente in Verzeichnissen mit dem Namen `templates/`. Was also den Webdesigner angeht, kann eine Projektstruktur auf das folgende vereinfacht werden: 
     432
     433>    meinproject/ 
     434>      apps/ 
     435>        applikation1/ 
     436>          templates/       # Layouts für Applikation 1 
     437>          modules/ 
     438>            modul1/ 
     439>              templates/   # Templates und Partials für Modul 1 
     440>            modul2/ 
     441>              templates/   # Templates und Partials für Modul 2 
     442>            modul3/ 
     443>              templates/   # Templates und Partials für Modul 3 
     444
     445>Alle anderen Verzeichnisse können ignoriert werden. 
     446
     447>Wenn sie auf ein `include_partial()` treffen, müssen Webdesigner lediglich verstehen, dass nur das erste Argument wichtig ist. Dieses Argument ist immer von der Form `modul_name/partial_name`, und das heisst, dass sich der Präsentationscode in `modules/modul_name/templates/_partial_name.php` befindet. 
     448
     449>Beim `include_component()`-Helfer ist es so, dass Modulname und Partialname die ersten beiden Argumente sind. Für den Rest genügt es eigentlich, eine grundsätzliche Idee davon zu haben, was Helfer sind und welche Helfer am häufigsten in Templates verwendet werden. 
     450 
     451View-Konfiguration 
     452------------------ 
     453 
     454In symfony besteht eine View aus zwei unabhängigen Teilen: 
     455 
     456  * Die HTML-Darstellung des Ergebnisses einer Aktion (gespeichert in einem Template, im Layout und in den verschiedenen Templatefragmenten) 
     457  * Der ganze Rest, darunter folgendes: 
     458    * Metadeklarationen: Stichwörter, Beschreibung, Cache-Dauer usw. 
     459    * Seitentitel: Hilft nicht nur beim Tabbed Browsing, Ihre Seite zu finden, sondern ist auch für Suchmaschinen sehr wichtig. 
     460    * Dateieinbindungen: JavaScripts und CSS-Dateien 
     461    * Layout: Gewisse Aktionen benötigen ein individuelles Layout (Pop-Ups, Werbungen usw.) oder überhaupt kein Layout (z.B. Ajax-Aktionen). 
     462 
     463In der View wird alles, das nicht HTML ist, als View-Konfiguration bezeichnet, und symfony bietet zwei Möglichkeiten, diese zu bearbeiten. Der normale Weg geht über die `view.yml`-Konfigurationsdatei. Sie kann immer dann benutzt werden, wenn Werte nicht vom Kontext oder von Datenbank-Querys abhängen. Wenn Sie jedoch dynamische Werte setzen müssen, sollten Sie die alternative Möglichkeit verwenden und die Konfiguration direkt über das `sfResponse`-Objekt in der Aktion selbst bearbeiten. 
     464 
     465>**NOTE** 
     466>Wenn Sie einen View-Konfigurationsparameter sowohl über das `sfResponse`-Objekt wie auch über die `view.yml` setzen, hat der Wert im `sfResponse`-Objekt Vorrang. 
     467 
     468### Die `view.yml`-Datei 
     469 
     470Jedes Modul kann eine `view.yml`-Datei haben, die die Einstellungen seiner Views definiert. So können Sie Vieweinstellungen für ein ganzes Modul in einer einzigen Datei verwalten. Die Schlüssel in der `view.yml` sind die Modul-View-Namen. Codeabschnitt 7-16 zeigt ein Beispiel einer Viewkonfiguration. 
     471 
     472Codeabschnitt 7-16 - Beispielhafte `view.yml` 
     473 
     474    editSuccess: 
     475      metas: 
     476        title: Bearbeiten Sie ihr Profil 
     477     
     478    editError: 
     479      metas: 
     480        title: Fehler bei der Bearbeitung des Profils 
     481     
     482    all: 
     483      stylesheets: [mein_style] 
     484      metas: 
     485        title: Meine Website 
     486 
     487>**ACHTUNG** 
     488>Achten Sie darauf, dass die Hauptschlüssel in der `view.yml` Viewnamen sind und keine Aktionsnamen. Zur Erinnerung: Ein Viewname setzt sich zusammen aus einem Aktionsnamen und einem Aktions-Beende-Namen. Wenn die `edit`-Aktion `sfView::SUCCESS` zurückgibt (oder gar nichts, da dies die standardmässige Rückgabe ist), dann ist der Viewname `editSuccess`. 
     489 
     490Die Standardeinstellungen für ein Modul sind unter dem `all:`-Schlüssel in der Modul-`view.yml` definiert. Die Standardeinstellungen für alle Applilkationsviews befinden sich in der Applikations-`view.yml`. Wieder einmal erkennen Sie hier die Verschachtelung der Konfiguration: 
     491 
     492  * In `apps/meineapp/modules/meinmodul/config/view.yml` können Sie Definitionen für einzelne Views festlegen, die die modulweiten Definitionen überschreiben 
     493  * In `apps/meineapp/modules/meinmodul/config/view.yml` können Sie unter dem `all:`-Schlüssel Viewdefinitionen für alle Aktionen des Moduls festlegen, die die applikationsweiten Definitionen überschreiben. 
     494  * In `apps/meineapp/config/view.yml` können Sie applikationsweite Definitionen festlegen, die für alle Module und alle Aktionen der Applikation gelten. 
     495 
     496Modulweite `view.yml`-Dateien existieren standardmässig überhaupt nicht. Sie müssen also, wenn Sie das erste Mal eine Viewkonfiguration für ein bestimmtes Modul anpassen wollen, eine `view.yml` im `config/`-Verzeichnis dieses Moduls anlegen. 
     497 
     498Nachdem Sie das Standardtemplate in Codeabschnitt 7-5 und ein Beispiel der fertigen Antwort in Codeabschnitt 7-6 gesehen haben, fragen Sie sich vielleicht, wo die Header-Werte herkommen. Die kommen schlicht und einfach aus den Standard-Vieweinstellungen, definiert in der Applikations-`view.yml`, zu sehen in Codeabschnitt 7-17. 
     499 
     500Codeabschnitt 7-17 - Standard-Applikations-Viewkonfiguration in `apps/meineapp/config/view.yml` 
     501 
     502    default: 
     503      http_metas: 
     504        content-type: text/html 
     505     
     506      metas: 
     507        title:        Symfony-Projekt 
     508        robots:       index, follow 
     509        description:  Symfony-Projekt 
     510        keywords:     symfony, projekt 
     511        language:     de 
     512     
     513      stylesheets:    [main] 
     514     
     515      javascripts:    [ ] 
     516     
     517      has_layout:     on 
     518      layout:         layout 
     519 
     520Jede dieser Einstellungen wird im Abschnitt "View-Konfigurationseinstellungen" deatilliert beschrieben. 
     521 
     522### Das Response-Objekt 
     523 
     524Obwohl es eigentlich Bestandteil der View-Ebene ist, wird das Response-Objekt oft von der Aktion selbst verändert. Aktionen können auf das symfony-Response-Objekt, `sfResponse`, mittels der `getResponse()`-Methode zugreifen. Codeabschnitt 7-18 zeigt einige der häufig verwendeten `sfResponse`-Methoden. 
     525 
     526Codeabschnitt 7-18 - Aktionen haben Zugriff auf die `sfResponse`-Objektmethoden 
     527 
     528    [php] 
     529    <?php 
     530    class meinmodulActions extends sfActions 
     531    { 
     532      public function executeIndex() 
     533      { 
     534        $response = $this->getResponse(); 
     535     
     536        // HTTP-Header 
     537        $response->setContentType('text/xml'); 
     538        $response->setHttpHeader('Content-Language', 'de'); 
     539        $response->setStatusCode(403); 
     540        $response->addVaryHttpHeader('Accept-Language'); 
     541        $response->addCacheControlHttpHeader('no-cache'); 
     542     
     543        // Cookies 
     544        $response->setCookie($name, $content, $expire, $path, $domain); 
     545     
     546        // Metadaten und Titel 
     547        $response->addMeta('robots', 'NONE'); 
     548        $response->addMeta('keywords', 'foo bar'); 
     549        $response->setTitle('Meine Seite'); 
     550        $response->addStyleSheet('custom_style'); 
     551        $response->addJavaScript('custom_behavior'); 
     552      } 
     553    } 
     554    ?> 
     555 
     556Zusätzlich zu den setter-Methoden, die Sie hier sehen können, hat die `sfResponse`-Klasse auch getter, die den aktuellen Wert eines Response-Attributes zurückgeben. 
     557 
     558Die Header-Setter in symfony sind sehr hilfreich. Header werden erst so spät wie möglich geschickt (im `sfRenderingFilter`), Sie können Sie also so oft und so stark ändern, wie Sie wollen. Die Setter bieten Ihnen auch sehr nützliche Shortcuts. Wenn Sie beispielsweise keinen Zeichensatz spezifizieren beim Aufruf von `setContentType()`, dann fügt symfony automatisch den Standard-Zeichensatz aus der `settings.yml` hinzu. 
     559 
     560    [php] 
     561    $response->setContentType('text/xml'); 
     562    echo $response->getContentType(); 
     563     => 'text/xml; charset=utf-8' 
     564 
     565Der Statuscode von Antworten in symfony entspricht der HTTP-Spezifikation. Exceptions liefern einen Status 500, nicht gefundene Seiten 404, normale Seiten 200, nicht veränderte Seiten können Status 304 zurückgeben (siehe Kapitel 12 für Details) usw. Aber Sie können diese Standards überschreiben, indem Sie Ihren eigenen Statuscode in der Aktion mit der `setStatusCode()`-Response-Methode definieren. Sie können Ihren eigenen Code und Ihre eigene Nachricht definieren, oder auch nur Ihren eigenen Code -- in diesem Fall wird symfony die passende Nachricht zu diesem Code automatisch hinzufügen. 
     566 
     567    [php] 
     568    $response->setStatusCode(404, 'This page no longer exists'); 
     569 
     570>**TIP** 
     571>Bevor die Header geschickt werden, normalisiert symfony ihre Namen. Sie müssen sich also nicht darum kümmern, ob Sie in einem `setHttpHeader()`-Aufruf `content-language` anstatt `Content-Language` schreiben, symfony versteht auch ersteres und wandelt es automatisch in die korrekte Schreibweise um. 
     572 
     573### View-Konfigurationseinstellungen 
     574 
     575Vielleicht haben Sie bemerkt, dass es zwei Arten von View-Konfigurationseinstellungen gibt: 
     576 
     577  * Diejenigen, die einen eindeutigen Wert haben (der Wert ist ein String in der `view.yml`-Datei und das Response-Objekt benutzt eine `set`-Methode dafür) 
     578  * Diejenigen mit mehreren Werten (für die die `view.yml` Arrays benutzt und das Response-Objekt eine `add`-Methode) 
     579 
     580Denken Sie daran, dass eine Konfigurationenfolge die eindeutigen Werte löscht, sie aber zu den Einstellungen mit mehreren Werten hinzufügt. Das wird im Verlauf dieses Kapitels noch klarer werden. 
     581 
     582#### Meta-Tag-Konfiguration 
     583 
     584Die Informationen in den `<meta>`-Tags der Antwort werden im Browser nicht angezeigt, sind aber nützlich für Robots und Suchmaschinen. Sie kontrollieren auch das Cache-Verhalten einer Seite. Definieren Sie diese Tags unter den `http_metas:`- und `metas:`-Schlüsseln in der `view.yml` wie in Codeabschnitt 7-19 oder mit den `addHttpMeta()`- und `addMeta()`-Antwortmethoden in der Aktion wie in Codeabschnitt 7-20. 
     585 
     586Codeabschnitt 7-20 - Metadefinitionen als Schlüssel-Wert-Paare in der `view.yml` 
     587 
     588    http_metas: 
     589      cache-control: public 
     590     
     591    metas: 
     592      description:   Finanzen in Frankreich 
     593      keywords:      finanzen, frankreich 
     594 
     595Codeabschnitt 7-20 - Metadefinitionen als Antworteinstellungen in der Aktion 
     596 
     597    [php] 
     598    $this->getResponse()->addHttpMeta('cache-control', 'public'); 
     599    $this->getResponse()->addMeta('description', 'Finanzen in Frankreich'); 
     600    $this->getResponse()->addMeta('keywords', 'finanzen, frankreich'); 
     601 
     602Einen existierenden Schlüssel hinzufügen ersetzt standardmässig seinen aktuellen Inhalt. Für HTTP-Meta-Tags können Sie einen dritten Parameter übergeben – ist dieser auf `false` gesetzt, hängt die `addHttpMeta()`-Methode (genau wie die `setHttpHeader()`-Methode) den Wert an den existierenden an, statt ihn zu ersetzen. 
     603 
     604    [php] 
     605    $this->getResponse()->addHttpMeta('accept-language', 'en'); 
     606    $this->getResponse()->addHttpMeta('accept-language', 'fr', false); 
     607    echo $this->getResponse()->getHttpHeader('accept-language'); 
     608     => 'en, fr' 
     609 
     610Damit diese Metatags im fertigen Dokument erscheinen, müssen der `include_http_metas()`- und der `include_metas()`-Helfer im `<head>`-Bereich aufgerufen werden. (Das wird im Standardlayout automatisch gemacht; siehe Codeabschnitt 7-5.) symfony sammelt automatisch die Einstellungen aus allen `view.yml`-Dateien (inklusive derjenigen in Codeabschnitt 7-17) und wandelt sie in `meta`-Tags um. Das Beispiel aus Codeabschnitt 7-19 verwandelt sich also in Codeabschnitt 7-21. 
     611 
     612Codeabschnitt 7-21 - Ausgegebene Metatags auf der fertigen Seite 
     613 
     614    [php] 
     615    <meta http-equiv="content-type" content="text/html; charset=utf-8" /> 
     616    <meta http-equiv="cache-control" content="public" /> 
     617    <meta name="robots" content="index, follow" /> 
     618    <meta name="description" content="Finanzen in Frankreich" /> 
     619    <meta name="keywords" content="finanzen, frankreich" /> 
     620 
     621Zusätzlich wird der HTTP-Header der Antwort von der `http-metas:`-Definition beeinflusst, selbst wenn Sie gar keine `include_http_metas()`-Helfer in Ihrem Layout haben, oder wenn Sie überhaupt kein Layout haben – zum Beispiel, wenn Sie eine Datein als Plaintext senden müssen. Dann definieren Sie einfach folgende `view.yml`: 
     622 
     623    http_metas: 
     624      content-type: text/plain 
     625     
     626    has_layout: false 
     627 
     628#### Titelkonfiguration 
     629 
     630Der Seitentitel ist ein integraler Bestandteil der Suchmaschinenoptimierung. Auch bei modernen, tabbed-browsing-fähigen Browsern trägt der zum Überblick bei. Im HTML-Code ist der Titel sowohl ein Tag als auch Metainformation über die Seite, deshalb ist in der `view.yml` der `title:`-Schlüssel ein Kind des `metas:`-Schlüssels. Codeabschnitt 7-22 zeigt die Titeldefinition in der `view.yml`, und Codeabschnitt 7-23 zeigt die Definition in einer Aktion. 
     631 
     632Codeabschnitt 7-22 - Titeldefinition in der `view.yml` 
     633 
     634    indexSuccess: 
     635      metas: 
     636        title: Drei kleine Ferkel 
     637 
     638Codeabschnitt 7-23 - Titeldefinition in der Aktion – ermöglicht dynamische Titel 
     639 
     640    $this->getResponse()->setTitle(sprintf('%d kleine Ferkel', $anzahl)); 
     641 
     642Im `<head>`-Bereich der fertigen Seite erzeugt die Titeldefinition einen `<meta name="title">`-Tag, wenn der `include_metas()`-Helfer verwendet wird, und einen `<title>`-Tag, wenn der `include_title()`-Helfer verwendet wird. Wenn beide verwendet werden (was im Standardlayout der Fall ist, s. Codeabschnitt 7-5), erscheint der Titel zweimal im Quelltext (siehe Codeabschnitt 7-6). 
     643 
     644#### Konfigurieren der einzubindenden Dateien 
     645 
     646Eine CSS- oder JavaScript-Datei zu einer View hinzufügen ist sehr einfach, wie in Codeabschnitt 7-24 und 7-25 zu sehen. 
     647 
     648Codeabschnitt 7-24 - Dateieinbindung in `view.yml` 
     649 
     650    indexSuccess: 
     651      stylesheets: [meinstyle1, meinstyle2] 
     652      javascripts: [meinscript] 
     653 
     654Codeabschnitt 7-25 - Dateieinbindung in der Aktion 
     655 
     656    [php] 
     657    <?php 
     658    $this->getResponse()->addStylesheet('meinstyle1'); 
     659    $this->getResponse()->addStylesheet('meinstyle2'); 
     660    $this->getResponse()->addJavascript('meinscript'); 
     661    ?> 
     662 
     663In jedem Fall ist das Argument ein Dateiname. Wenn die Datei eine logische Endung hat (`.css` für ein Stylesheet und `.js` für ein JavaScript), können Sie es auch weglassen. Wenn die Datei in einem logischen Verzeichnis liegt (`/css/` für ein Stylesheet, `/js/` für ein JavaScript), können Sie das ebenfalls weglassen. symfony ist so schlau und findet die korrekte Dateiendung und das korrekte Verzeichnis selbst heraus. 
     664 
     665Anders als die Meta- und Titel-Definitionen benötigen die Datei-Einbindungen keine Helfer im Template oder Layout. Das heisst, die obigen Einstellungen geben den HTML-Code aus Codeabschnittt 7-26 zurück, egal, was im Template und/Oder im Layout steht. 
     666 
     667Codeabschnitt 7-26 - Datei-Einbindung – Im Layout wird kein Helfer benötigt 
     668    [php] 
     669    <head> 
     670    ... 
     671    <link rel="stylesheet" type="text/css" media="screen" href="/css/mystyle1.css" /> 
     672    <link rel="stylesheet" type="text/css" media="screen" href="/css/mystyle2.css" /> 
     673    <script language="javascript" type="text/javascript" src="/js/myscript.js"> 
     674    </script> 
     675    </head> 
     676 
     677>**NOTE** 
     678>Die Einbindung von CSS und JavaScript in der Antwort wird vom Filter `sfCommonFilter` übernommen. Dieser sucht in der Antwort nach einem `<head>`-Tag und fügt die `<link>`s und `<script>`s direkt vor dem schliessenden `</head>` ein. Wenn kein `<head>`-Tag vorhanden ist, funktioniert die Einbindung nicht. 
     679 
     680Denken Sie daran: Auch hier findet die Konfigurationskaskade wieder Anwendung: Jede Datei, die in der Applikations-`view.yml` definiert wurde, wird in jeder Seite der Applikation eingebunden. Die Codeabschnitte 7-27, 7-28 und 7-29 demonstrieren dies. 
     681 
     682Codeabschnitt 7-27 - Beispiel-Applikations-`view.yml` 
     683 
     684    default: 
     685      stylesheets: [main] 
     686 
     687Codeabschnitt 7-28 - Beispiel-Modul-`view.yml` 
     688 
     689    indexSuccess: 
     690      stylesheets: [special] 
     691     
     692    all: 
     693      stylesheets: [additional] 
     694 
     695Codeabschnitt 7-29 - Der View `indexSuccess` als Ergebnis 
     696 
     697    [php] 
     698    <link rel="stylesheet" type="text/css" media="screen" href="/css/main.css" /> 
     699    <link rel="stylesheet" type="text/css" media="screen" href="/css/additional.css" /> 
     700    <link rel="stylesheet" type="text/css" media="screen" href="/css/special.css" /> 
     701 
     702Wenn Sie eine Datei entfernen möchten, die auf einer höheren Stufe definiert wurde, häängen Sie einfach ein Minuszeichen (`-`) vor dem Dateinamen, wie in Codeabschnitt 7-30. 
     703 
     704Codeabschnitt 7-30 - Beispiel-Modul-`view.yml`, die eine Datei entfernt, die auf der Applikationsstufe definiert wurde 
     705 
     706    indexSuccess: 
     707      stylesheets: [-main, special] 
     708     
     709    all: 
     710      stylesheets: [additional] 
     711 
     712Um alle CSS- oder JavaScript-Dateien zu entfernen, verwenden Sie folgende Syntax: 
     713 
     714    indexSuccess: 
     715      stylesheets: [-*] 
     716      javascripts: [-*] 
     717 
     718Sie können auch weiter ins Detail gehen und in einem zusätzlichen Parameter angeben, wo genau die Datei eingebunden werden soll (an der ersten oder letzten Stelle): 
     719 
     720    // In der view.yml 
     721    indexSuccess: 
     722      stylesheets: [special: { position: first }] 
     723 
     724    [php] 
     725    // In der Aktion 
     726    $this->getResponse()->addStylesheet('special', 'first'); 
     727 
     728Um Medientypen für CSS-Dateien hinzuzufügen, können Sie die Standard-CSS-Tag-Optionen ändern, zu sehen in den Codeabschnitten 7-31, 7-32 und 7-33. 
     729 
     730Codeabschnitt 7-31 - CSS-Einbindung mit Medientyp in der `view.yml` 
     731 
     732    indexSuccess: 
     733      stylesheets: [main, paper: { media: print }] 
     734 
     735Codeabschnitt 7-32 - CSS-Einbindung mit Medientyp in der Aktion 
     736 
     737    [php] 
     738    <?php 
     739    $this->getResponse()->addStylesheet('paper', '', array('media' => 'print')); 
     740    ?> 
     741 
     742Codeabschnitt 7-33 - Das Ergebnis 
     743 
     744    [php] 
     745    <link rel="stylesheet" type="text/css" media="print" href="/css/paper.css" /> 
     746 
     747#### Layout-Konfiguration 
     748 
     749Abhängig vom gestalterischen Aufbau Ihrer Website haben Sie möglicherweise mehrere Layouts. Klassische Websites haben mindestens zwei: Das Standardlayout und das Pop-up-Layout. 
     750 
     751Sie wissen bereits, dass das Standardlayout sich in `meinprojekt/apps/meineapp/templates/layout.php` befindet. Zusätzliche Layouts müssen im gleichen globalen `templates/`-Verzeichnis hinzugefügt werden. Wenn Sie möchten, dass eine View die Datei `meineapp/templates/mein_layout.php` verwendet, benutzen Sie die Syntax aus Codeabschnitt 7-34 in der `view.yml` oder den Code aus Codeabschnitt 7-35 in der Aktion. 
     752 
     753Codeabschnitt 7-34 - Layoutdefinition in `view.yml` 
     754 
     755    indexSuccess: 
     756      layout: my_layout 
     757 
     758Codeabschnitt 7-35 - Layoutdefinition in der Aktion 
     759 
     760    [php] 
     761    <?php 
     762    $this->setLayout('my_layout'); 
     763    ?> 
     764 
     765Einige Views benötigen überhaupt kein Layout (z.B. Plain-Text-Seiten oder RSS-Feeds). In diesem Fall setzen Sie `has_layout` auf `false` wie in den Codeabschnitten 7-36 und 7-37. 
     766 
     767Codeabschnitt 7-36 - Layout-Entfernung in `view.yml` 
     768 
     769    indexSuccess: 
     770      has_layout: false 
     771 
     772Codeabschnitt 7-37 - Layoutentfernung in der Aktion 
     773    [php] 
     774    <?php 
     775    $this->setLayout(false); 
     776    ?> 
     777 
     778>**NOTE** 
     779>Ajax-Aktions-Views haben standardmässig kein Layout. 
     780 
     781Komponentenslots 
     782---------------- 
     783 
     784Um die Vielseitigkeit von Viewkomponenten und Viewkonfiguration zu vereinigen, gibt es das Komponentenslot-System. Es ist eine Alternative zu Slots, speziell zugeschnitten auf Wiederverwendbarkeit und Layer-Trennung. Komponentenslots sind strukturierter aufgebaut als normale Slots, brauchen aber in der Ausführung etwas länger. 
     785 
     786Genau wie Slots sind auch Komponentenslots benannte Platzhalter, die Sie in den View-Elementen definieren können. Der Unterschied besteht darin, wie der ersetzende Code bestimmt wird. Bei einem Slot befindet sich der Code in einem anderen View-Element; bei einem Komponentenslot ist der Code das Ergebnis der Ausführung einer Komponente, und der Name dieser Komponente kommt aus der Viewkonfiguration. Sie werden Komponentenslots besser verstehen, wenn Sie sie erst einmal in Aktion erlebt haben. 
     787 
     788Um einen Komponentenslot-Platzhalter zu setzen, verwenden Sie den `include_component_slot()`-Helfer. Diese Funktion erwartet ein Label als Parameter. Nehmen Sie an, die `layout.php` Ihrer Applikation enthält eine kontextabhängige Sidebar. Codeabschnitt 7-38 zeigt, wie der Komponentslot-HElfer eingebunden wird. 
     789 
     790Codeabschnitt 7-38 - Einen Komponentenslot mit dem Namen `'sidebar'` einbinden 
     791 
     792    [php] 
     793    ... 
     794    <div id="sidebar"> 
     795      <?php include_component_slot('sidebar') ?> 
     796    </div> 
     797 
     798Definieren Sie die Verbindung von Komponentenslot-Labe und Komponentenname in der Viewkonfiguration. Setzen Sie die Standardkomponente für den Komponentenslot `'sidebar'` in der Applikations-`view.yml`, unter dem `components`-Header. Der Schlüssel ist das Komponentenslot-Label; der Wert muss ein Array sein, der ein Modul und einen Komponentennamen beinhaltet. Ein Beispiel ist in Codeabschnitt 7-39 zu sehen. 
     799 
     800Codeabschnitt 7-39 - Den Standard-`'Sidebar'`-Komponentenslot in der `meineapp/config/view.yml` definieren 
     801 
     802    default: 
     803      components: 
     804        sidebar:  [bar, default] 
     805 
     806Wenn das Layout ausgeführt wird, wird der Komponentenslot `'sidebar'` mit dem Ergebnis der `executeDefault()`-Methode der `barComponents`-Klasse innerhalb des `bar`-Moduls gefüllt, und diese Methode wird das `_default.php`-Partial anzeigen, das sich in `modules/bar/templates/` befindet. 
     807 
     808Die Konfigurationskaskade ermöglicht Ihnen, diese Einstellung für ein bestimmtes Modul zu überschreiben. In einem Benutzermodul möchten Sie vielleicht, dass in der Sidebar der Benutzername und die Anzahl Artikel stehen, die dieser Benutzer veröffentlicht hat. In diesem Fall können Sie die Sidebar-Slot-Einstellung in der Modul-`view.yml` ändern wie in Codeabschnitt 7-40. 
     809 
     810Codeabschnitt 7-40 - Den Komponentenslot `'sidebar'` spezialisieren in `meineapp/modules/user/config/view.yml` 
     811 
     812    all: 
     813      components: 
     814        sidebar:  [bar, user] 
     815 
     816Die Komponentendefinitionen, die diesen Slot behandeln sollen, sehen so aus wie in Codeabschnitt 7-41. 
     817 
     818Codeabschnitt 7-41 - Vom Slot `'sidebar'` verwendete Komponenten in `modules/bar/actions/components.class.php` 
     819 
     820    [php] 
     821    <?php 
     822    class barComponents extends sfComponents 
     823    { 
     824      public function executeDefault() 
     825      { 
     826      } 
     827     
     828      public function executeUser() 
     829      { 
     830        $current_user = $this->getUser()->getCurrentUser(); 
     831        $c = new Criteria(); 
     832        $c->add(ArticlePeer::AUTHOR_ID, $current_user->getId()); 
     833        $this->nb_articles = ArticlePeer::doCount($c); 
     834        $this->current_user = $current_user; 
     835      } 
     836    } 
     837    ?> 
     838 
     839Codeabschnitt 7-42 zeigt die Views für diese zwei Komponenten. 
     840 
     841Codeabschnitt 7-42 - Vom Komponentenslot `'sidebar'` verwendete Partials in `modules/bar/templates/` 
     842 
     843    [php] 
     844    // _default.php 
     845    <p>This zone contains contextual information.</p> 
     846     
     847    // _user.php 
     848    <p>User name: <?php echo $current_user->getName() ?></p> 
     849    <p><?php echo $nb_articles ?> articles published</p> 
     850 
     851Komponentenslots können Sie unter anderem einsezten für: Breadcrumb-Navigationen, kontextsensitive Navigationen sowie dynamische Einbindungen aller Art. Sie können im globalen Layout und in Templates verwendet werden, und sogar in anderen Komponenten. Die Konfigurationseinstellung eines Komponentenslots ist immer diejenige der Konfiguration der letzten aufgerufenen Aktion. 
     852 
     853Wenn der Komponentenslot für ein bestimmtes Modul leer bleiben soll, definieren Sie ihn einfach als leer, wie in Codeabschnitt 7-43. 
     854 
     855Codeabschnitt 7-43 - Einen Komponentenslot in der `view.yml` deaktivieren 
     856 
     857    all: 
     858      components: 
     859        sidebar:  [] 
     860 
     861Output Escaping 
     862--------------- 
     863 
     864Wenn Sie dynamische Daten in ein Template einfügen, müssen Sie die Datenintegrität sicherstellen. Wenn Daten aus einem Formular kommen, besteht die Gefahr, dass sie bösartige Scripte enthalten, die versuchen, Cross-Site-Scripting-Attacken (XSS) auszuführen. Sie müssen den Output maskieren (escapen), so dass allfälliger darin enthaltener HTML-Code wirkungslos wird. 
     865 
     866Nehmen Sie an, ein Benutzer füllt ein Eingabefeld mit dem folgenden Wert: 
     867 
     868    [php] 
     869    <script>alert(document.cookie)</script> 
     870 
     871Wenn Sie diesen Wert unvorsichtigerweise einfach ausgeben, wird das JavaScript in jedem Browser ausgeführt und erlaubt so noch wesentlich gefährlichere Angriffe als nur ein `alert`. Darum müssen Sie den Output maskieren, bevor Sie ihn anzeigen. Dann sieht er so aus: 
     872 
     873    [php] 
     874    &lt;script&gt;alert(document.cookie)&lt;/script&gt; 
     875 
     876Sie könnten den Output manuell maskieren, indem Sie ihn jedesmal mit `htmlentities()` umschliessen, aber das wäre sehr fehleranfällig. Symfony bietet stattdessen ein spezielles System, genannt Output Escaping, das automatisch jeden dynamischen Output in einem Template maskiert. Es wird durch einen einfachen Parameter in der Applikations-`settings.yml` aktiviert. 
     877 
     878### Output Escaping aktivieren 
     879 
     880Output Escaping wird global für eine Applikation in der `settings.yml` konfiguriert. Zwei Parameter bestimmen, wie Output Escaping arbeitet: Die Strategie bestimmt, wie die Variablen der View zur Verfügung gestellt werden, und die Methode ist die Standard-Maskierfunktion, die auf die Daten angewendet wird. 
     881 
     882Die nächsten Abschnitte beschreiben diese Einstellungen detailliert, aber grundsätzlich ist das einzige, was Sie tun müssen, um Output Escaping zu aktivieren, den `escaping_strategy`-Parameter von seinem Standardwert `bc` auf `both` zu ändern wie in Codeabschnitt 7-44. 
     883 
     884Codeabschnitt 7-44 - Output Escaping aktivieren in `meineapp/config/settings.yml` 
     885 
     886    all: 
     887      .settings: 
     888        escaping_strategy: both 
     889        escaping_method:   ESC_ENTITIES 
     890 
     891Jetzt wird `htmlentities()` standardmässig auf alle Ausgabevariablen angewandt. Wenn Sie in einer Aktion eine `test`-Variable wie folgt definieren: 
     892 
     893    [php] 
     894    <?php 
     895    $this->test = '<script>alert(document.cookie)</script>'; 
     896    ?> 
     897 
     898Dann wird diese Variable im Template wie folgt ausgegeben: 
     899 
     900    [php] 
     901    echo $test; 
     902     => &gt;&lt;script&gt;alert(document.cookie)&lt;/script&gt; 
     903 
     904Wenn Sie Output Escaping aktiviert haben, haben Sie in jedem Template Zugriff auf die Variable `$sf_data`. Es handelt sich dabei um ein Containerobjekt, das all die maskierten Variablen enthält. Sie können die Testvariable also auch so ausgeben: 
     905 
     906    [php] 
     907    echo $sf_data->get('test'); 
     908    => &gt;&lt;script&gt;alert(document.cookie)&lt;/script&gt; 
     909 
     910>**TIP** 
     911>Das `$sf_data`-Objekt verwendet Array-Syntax, Sie können also anstatt `$sf_data->get('meinevariable')` die maskierten Parameter über `$sf_data['meinevariable']` erreichen. Es handelt sich aber eigentlich nicht um ein Array, weshalb Funktionen wie `print_r()` nicht funktionieren werden. 
     912 
     913Dieses Objekt bietet Ihnen auch Zugriff zu den unmaskierten Rohdaten. Das ist hilfreich, wenn eine Variable HTML-Code enthält, der vom Browser interpretiert werden sollen, vorausgesetzt, Sie vertrauen dieser Variablen. Rufen Sie die `getRaw()`-Methode auf, wenn Sie die Rohdaten ausgeben möchten. 
     914 
     915    [php] 
     916    echo $sf_data->getRaw('test'); 
     917     => <script>alert(document.cookie)</script> 
     918 
     919Jedesmal, wenn Sie möchten, dass HTML-Variablen vom Browser interpretiert werden sollen, benötigen Sie die Rohdaten. Das ist auch der Grund, weshalb das Standardlayout `$sf_data->getRaw('sf_content')` verwendet, um ein Template einzubinden. Nur `$sf_content` funktioniert nämlich nicht, wenn Output Escaping aktiviert ist.. 
     920 
     921### Escaping-Strategie 
     922 
     923Die `escaping_strategy`-Einstellung bestimmt, wie Variablen standardmässig ausgegeben werden. Die folgenden Werte sind möglich: 
     924 
     925  * `bc` (backward compatible, rückwärts-kompatibel): Variablen werden nicht maskiert, aber eine maskierte Version jeder Variablen ist im `$sf_data`-Container verfügbar. Die Daten sind also standardmässig im Rohformat, ausser wenn Sie über das `$sf_data`-Objekt auf die maskierten Daten zugreifen. `bc` ist die Standardeinstellung und Sie sollten sich bewusst sein, dass mit dieser Strategie Ihre Seite anfällig für XSS-Attacken ist. 
     926  * `both`: Alle Variablen werden standardmässig maskiert. Die Werte sind auch im `$sf_data`-Container verfügbar. Das ist die empfohlene Strategie, da Sie nur ein Risiko eingehen, wenn Sie absichtlich die Rohdaten ausgeben. Manchmal werden Sie unmaskierte Daten verwenden müssen – beispielsweise, wenn eine Variable HTML-Code enthält, der gerendert werden soll. Passen Sie also auf: Wenn Sie während der Entwicklung einer Applikation zu dieser Strategie wechseln, funktionieren gewisse Dinge womöglich nicht mehr. Die beste Idee ist es daher, diese Einstellung gleich von Beginn an zu verwenden. 
     927  * `on`: Werte sind nur im `$sf_data`-Container verfügbar. Das ist der sicherste und schnellste Weg, da Sie bei jedem Ausgeben einer Variablen auswählen müssen, ob Sie die maskierte Version mit `get()` oder die Rohdaten mit `getRaw()` ausgeben. Sie sind sich also jederzeit der Möglichkeit bewusst, dass die Daten korrumpiert sein könnten. 
     928  * `off`: Schaltet Output Escaping vollständig ab. Der `$sf_data`-Container ist in den Templates nicht verfügbar. Sie können diese Strategie anstelle von `bc` verwenden, um Ihre Applikation zu beschleunigen, wenn Sie sich sicher sind, dass Sie niemals maskierte Daten benötigen. 
     929 
     930### Escaping-Helfer 
     931 
     932Escaping-Helfer sind Funktionen, die eine maskierte Version ihrer Eingabe zurückgeben. Sie können als Standard-`escaping_method` in der `setting.yml` verwendet werden oder für einen bestimmten Wert in der View. Die folgenden Escaping-Helfer sind verfügbar: 
     933 
     934  * `ESC_RAW`: Maskiert den Wert nicht. 
     935  * `ESC_ENTITIES`: Wendet die PHP-Funktion `htmlentities()` mit `ENT_QUOTES` als zweitem Parameter auf die Eingabe an. 
     936  * `ESC_JS`: Maskiert einen Wert, der in einem JavaScript-String als HTML verwendet wird. Hilfreich, wenn HTML dynamisch mit JavaScript verändert wird. 
     937  * `ESC_JS_NO_ENTITIES`: Maskiert einen Wert, der in einen JavaScript-String gehört, aber fügt keine Entities hinzu. Das ist hilfreich, wenn der Wert z.B. in einer Dialogbox angezeigt wird. (Eine `meinString`-Variable wird angezeigt mit `javascript:alert(meinString)`.) 
     938 
     939### Arrays und Objekte maskieren 
     940 
     941Output Escaping funktioniert nicht nur bei Strings, sondern auch bei Arrays und Objekten. Jeder Wert in einem Objekt oder Array wird seinen maskierten Zustand an seine Kinder weitergeben. Nehmen wir an, Ihre Strategie sei `both`. Dann zeigt Codeabschnitt 7-45 die Maskierungskaskade. 
     942 
     943Codeabschnitt 7-45 - Escaping funktioniert auch bei Arrays und Objekten 
     944 
     945    [php] 
     946    <?php 
     947    // Klassendefinition 
     948    class meineKlasse 
     949    { 
     950      public function testeSpezialZeichen($wert = '') 
     951      { 
     952        return '<'.$wert.'>'; 
     953      } 
     954    } 
     955     
     956    // In der Aktion 
     957    $this->test_array = array('&', '<', '>'); 
     958    $this->test_array_of_arrays = array(array('&')); 
     959    $this->test_objekt = new meineKlasse(); 
     960     
     961    // Im Template 
     962    <?php foreach($test_array as $wert): ?> 
     963      <?php echo $wert ?> 
     964    <?php endforeach; ?> 
     965     => &amp; &lt; &gt; 
     966    <?php echo $test_array_of_arrays[0][0] ?> 
     967     => &amp; 
     968    <?php echo $test_objekt->testeSpezialZeichen('&') ?> 
     969     => &lt;&amp;&gt; 
     970 
     971Die Variablen im Template sind jedoch nicht von dem Typ, den Sie womöglich erwarten. Das Output-Escaping-System "dekoriert" sie und verwandelt sie in spezielle Objekte: 
     972 
     973    [php] 
     974    <?php echo get_class($test_array) ?> 
     975     => sfOutputEscaperArrayDecorator 
     976    <?php echo get_class($test_objekt) ?> 
     977     => sfOutputEscaperObjectDecorator 
     978 
     979Das erklärt auch, warum einige Standard-PHP-Funktionen (wie `array_shift()`, `print_r()` usw.) bei maskierten Arrays nicht mehr funktionieren. Aber Sie können darauf immer noch mit `[]` zugreifen, sie mit `foreach` traversieren, und die Anzahl mit `count()` zurückgeben (wobei letzteres nur mit PHP 5.2 oder neuer funktioniert). Und in Templates sollten die Daten ohnehin schreibgeschützt sein, die meisten Zugriffe werden also auf Arten geschehen, die funktionieren. 
     980 
     981Sie haben immer noch eine Möglichkeit, über das `$sf_data`-Objekt an die Rohdaten zu gelangen. Zusätzlich werden Methoden von maskierten Objekten so verändert, dass sie einen zusätzlichen Parameter akzeptieren: Eine Maskierungsmethode. Sie können also eine andere Maskierungsmethode wählen jedesmal, wenn Sie eine Variable in einem Template anzeigen, oder Sie können mit dem `ESC_RAW`-Helfer die Maskierung komplett abschalten. Codeabschnitt 7-46 zeigt ein Beispiel. 
     982 
     983Codeabschnitt 7-46 - Methoden von maskierten Objekten akzeptieren einen zusätzlichen Parameter 
     984 
     985    [php] 
     986    <?php echo $test_object->testeSpezialZeichen('&') ?> 
     987    => &lt;&amp;&gt; 
     988    // Die drei folgenden Zeilen geben den gleichen Wert zurück 
     989    <?php echo $test_object->testeSpezialZeichen('&', ESC_RAW) ?> 
     990    <?php echo $sf_data->getRaw('test_object')->testeSpezialZeichen('&') ?> 
     991    <?php echo $sf_data->get('test_object', ESC_RAW)->testeSpezialZeichen('&') ?> 
     992     => <&> 
     993 
     994Wenn Sie in Ihren Templates mit Objekten arbeiten, werden Sie den Trick mit dem zusätzlichen Parameter häufig verwenden, da er die schnellste Möglichkeit bietet, Rohdaten direkt aus einem Methodenaufruf zu bekommen. 
     995 
     996>**ACHTUNG** 
     997>Die üblichen symfony-Variablen werden ebenfalls maskiert, wenn Sie Output Escaping aktivieren. Achten Sie also darauf: `$sf_user`, `$sf_request`, `$sf_param` und `$sf_context` funktionieren immer noch, aber ihre Methoden geben maskierte Daten zurück – es sei denn, Sie geben `ESC_RAW` als letzten Parameter bei den Methodenaufrufen an. 
     998 
     999Zusammenfassung 
     1000--------------- 
     1001 
     1002Viele verschiedene Tools stehen Ihnen zur Verfügung, um die Präsentationsschicht zu bearbeiten. Template erstellen Sie dank der Helfer innert Sekunden. Layouts, Partials, Komponenten und Komponentenslots bringen sowohl Modularität als auch Wiederverwendbarkeit. Die Viewkonfiguration bedient sich der Geschwindigkeitvorteile von YAML, um die (meisten) Seitenheader zu verwalten. Die Konfigurationskaskade bewahrt Sie davor, jede Einstellung für jede View zu definieren. Für jede Änderung der Präsentation, die von dynamischen Daten abhängt, hat die Aktion Zugriff auf das `sfResponse`-Objekt. Und die Sicht ist dank dem Output-Escaping-System sicher vor XSS-Angriffen. 
    221003}}} 
    23  
    24 Wie in [http://trac.symfony-project.com/trac/wiki/Documentation/de_DE/book/1.0/04-The-Basics-of-Page-Creation Kapitel 4] erklärt ist diese alternative PHP-Syntax vorzuziehen, da sie die Templates für Nicht-PHP-Entwickler lesbarer macht. Sie sollten den PHP-Code in den Templates auf ein Minimum reduzieren, da diese Dateien diejenigen sind, die das GUI Ihrer Applikation darstellen und deshalb manchmal von einem anderen Team bearbeitet werden, das sich auf Präsentation spezialisiert hat und nicht auf Applikationslogik. Wenn also die Logik in der Aktion bleibt, ist es auch einfacher, mehrere Templates für eine einzige Aktion zu haben, ohne Codewiederholungen. 
    25  
    26 === Helfer === 
    27  
    28 Helfer sind PHP-Funktionen, die HTML-Code zurückgeben und in Templates benutzt werden können. Beispielsweise ist in Codeabschnitt 7-1 die {{{link_to()}}}-Funktion so ein Helfer. Manchmal ersparen einem Helfer einfach nur etwas Zeit, indem sie in Templates häufig benutzte Codeschnipsel bequem verpacken. Beispielsweise ist es sehr einfach, sich die Funktionsdefinition dieses Helfers zu überlegen: 
    29  
    30 {{{ 
    31 #!php 
    32 <?php echo input_tag('nickname') ?> 
    33  => <input type="text" name="nickname" id="nickname" value="" /> 
    34 }}} 
    35  
    36 Er ist in Codeabschnitt 7-2 zu sehen. 
    37  
    38 ''Codeabschnitt 7-2 - Beispielhafte Helfer-Definition'' 
    39 {{{ 
    40 #!php 
    41 <?php 
    42 function input_tag($name, $value = null) 
    43 { 
    44   return '<input type="text" name="'.$name.'" id="'.$name.'"value="'.$value.'" />'; 
    45 } 
    46 ?> 
    47 }}} 
    48  
    49 In Wirklichkeit ist die {{{input_tag()}}}-Funktion von symfony etwas komplizierter, da sie einen dritten Parameter akzeptiert, um dem {{{<input>}}}-Tag weitere Attribute hinzuzufügen. Sie können die komplette Syntax und alle Möglichkeiten in der Online-API-Dokumentation (http://www.symfony-project.com/api/symfony.html) einsehen. 
    50  
    51 Meistens beinhalten Helfer aber eine gewisse Intelligenz und ersparen es Ihnen somit, langen und komplizierten Code zu tippen: 
    52  
    53 {{{ 
    54 #!php 
    55 <?php echo auto_link_text('Bitte besuchen Sie unsere Website www.beispiel.de') ?> 
    56  => Bitte besuchen Sie unsere Website <a href="http://www.beispiel.de">www.beispiel.de</a> 
    57 }}} 
    58  
    59 Helfer vereinfachen das Schreiben von Templates und produzieren den bestmöglichen HTML-Code hinsichtlich Performance und Zugänglichkeit. Sie können immer noch reines HTML verwenden, aber mit Helfern geht es normalerweise schneller. 
    60  
    61     Möglicherweise wundern Sie sich darüber, dass die Helfer nach der Unterstrich-Syntax benannt sind und nicht nach der camelCase-Konvention, die sonst überall in symfony verwendet wird. Das ist deshalb so, weil Helfer Funktionen sind, und alle Kern-PHP-Funktionen benutzen die Unterstrich-Syntaxkonvention. 
    62  
    63 === Helfer deklarieren === 
    64  
    65 Die symfony-Dateien mit den Helferdefinitionen werden nicht automatisch geladen (weil sie Funktionen enthalten, und keine Klassen). Helfer sind nach Einsatzzweck sortiert. Beispielsweise sind alle Helferfunktionen, die mit Text zu tun haben, in einer Datei {{{TextHelper.php}}} enthalten, die {{{Text}}}-Helfergruppe. Wenn Sie also in einem Template einen Helfer benötigen, müssen Sie zuvor im Template die entsprechende Helfergruppe laden mit der {{{use_helper()}}}-Funktion. Codeabschnitt 7-3 zeigt ein Template, das den {{{auto_link_text()}}}-Helfer benutzt, der Teil der Texthelfer-Gruppe ist. 
    66  
    67 ''Codeabschnitt 7-3 - Die Benutzung eines Helfers deklarieren'' 
    68 {{{ 
    69 #!php 
    70 // Benutze eine bestimmte Helfergruppe in diesem Template 
    71 <?php echo use_helper('Text') ?> 
    72 ... 
    73 <h1>Beschreibung</h1> 
    74 <p><?php echo auto_link_text($description) ?></p> 
    75 }}} 
    76  
    77     Wenn Sie mehr als eine Helfergruppe deklarieren müssen, fügen Sie entsprechend mehr Argumente zum {{{use_helper()}}}-Funktionsaufruf hinzu. Um etwa die {{{Text}}}- und die {{{Javascript}}}-Helfergruppen in einem Template zu laden, rufen Sie {{{<?php echo use_helper('Text', 'Javascript') ?>}}} auf. 
    78  
    79 Einige Helfer sind standardmässig in jedem Template verfügbar, ohne entsprechende Deklaration. Es sind dies die Helfer der folgenden Gruppen: 
    80  
    81     * {{{Helfer}}}: Benötigt für das Einbinden anderer Helfer (die {{{use_helper()}}}-Funktion ist selbst auch ein Helfer) 
    82     * {{{Tag}}}: Grundsätzlicher Taghelfer, wird von beinahe jedem anderen Helfer benötigt 
    83     * {{{Url}}}: Link- und URL-Management-Helfer 
    84     * {{{Asset}}}: Helfer, die sich um den HTML-{{{<head>}}}-Teil kümmern und auf einfache Art und Weise Links zu externen Dateien bereitstellen. (Bilder, JavaScript, CSS-Dateien) 
    85     * {{{Partial}}}: Helfer, die das Einbinden von Templatefragmenten ermöglichen 
    86     * {{{Cache}}}: Manipulation gecacheter Codefragmente 
    87     * {{{Form}}}: Formularhelfer 
    88  
    89 Die Liste der standardmässig geladenen Helfer kann in der {{{settings.yml}}}-Datei eingestellt werden. Wenn Sie also wissen, dass Sie die Helfer der Cachegruppe nicht benötigen oder dass Sie immer diejenigen der Textgruppe benötigen, verändern sie die {{{standard_helpers}}}-Einstellung entsprechend. Das wird Ihre Applikation etwas beschleunigen. Die ersten vier Helfer in der obigen Liste ({{{Helper}}}, {{{Tag}}}, {{{Url}}} und {{{Asset}}}) können Sie nicht entfernen, da Sie zwingend notwendig sind für das Funktionieren der Templateengine. Deshalb erscheinen sie auch nicht in der Liste der Standardhelfer. 
    90  
    91     Sollten Sie einmal einen Helfer ausserhalb eines Templates benötigen, können Sie eine Helfergruppe von überall aus mit {{{sfLoader::loadHelpers($helpers)}}} laden, wobei {{{$helpers}}} ein Helfergruppenname oder ein Array aus Helfergruppennamen ist. Wenn Sie etwa den {{{auto_link_text()}}}-Helfer in einer Aktion benutzen wollen, müssen Sie zuerst {{{sfLoader::loadHelpers('Text')}}} aufrufen. 
    92  
    93 === Häufig benutzte Helfer === 
    94  
    95 Sie werden in späteren Kapiteln mehr über einige Helfer erfahren und wie sie Ihnen helfen können. Codeabschnitt 7-4 gibt einen kurzen Überblick über die Standardhelfer, die häufig benutzt werden, zusammen mit dem HTML-Code, den sie zurückgeben. 
    96  
    97 ''Codeabschnitt 7-4 - Gängige Standardhelfer'' 
    98 {{{ 
    99 #!php 
    100 // Helper-Gruppe 
    101 <?php echo use_helper('Helfername') ?> 
    102 <?php echo use_helper('Helfername1', 'Helfername2', 'Helfername3') ?> 
    103   
    104 // Tag-Gruppe 
    105 <?php echo tag('input', array('name' => 'foo', 'type' => 'text')) ?> 
    106 <?php echo tag('input', 'name=foo type=text') ?>  // alternative Syntax für die Optionen 
    107  => <input name="foo" type="text" /> 
    108 <?php echo content_tag('textarea', 'Beispieltext', 'name=foo') ?> 
    109  => <textarea name="foo">Beispieltext</textarea> 
    110   
    111 // Url-Gruppe 
    112 <?php echo link_to('klick mich', 'modul/aktion') ?> 
    113 => <a href="/pfad/zur/aktion">klick mich</a>  // hängt von den Routing-Einstellungen ab 
    114   
    115 // Asset-Gruppe 
    116 <?php echo image_tag('bild', 'alt=foo size=200x100') ?> 
    117  => <img src="/images/bild.png" alt="foo" width="200" height="100"/> 
    118 <?php echo javascript_include_tag('meinscript') ?> 
    119  => <script language="JavaScript" type="text/javascript" src="/js/meinscript.js"></script> 
    120 <?php echo stylesheet_tag('style') ?> 
    121  => <link href="/stylesheets/style.css" media="screen" rel="stylesheet" type="text/css" /> 
    122 }}} 
    123  
    124 Es gibt viele weitere Helfer in symfony, und es bräuchte eine ganzes Buch, um sie alle zu beschreiben. Die beste Referenz für die Helfer ist die Online-API-Dokumentation (http://www.symfony-project.com/api/symfony.html), wo für alle Helfer ausführlich Syntax, Optionen und Beispiele dokumentiert sind. 
    125  
    126 === Eigene Helfer hinzufügen === 
    127  
    128 symfony bringt viele Helfer für verschiedenste Zwecke mit, aber wenn Sie in der API-Dokumentation nicht das finden, was Sie benötigen, wollen Sie möglicherweise einen neuen Helfer erstellen. Das ist wirklich sehr einfach. 
    129  
    130 Helferfunktionen (normale PHP-Funktionen, die HTML-Code zurückgeben) sollten in einer Datei {{{FoobarHelper.php}}} gespeichert werden, wobei {{{Foobar}}} der Name der Helfergruppe ist. Speichern Sie die Datei im {{{apps/meineapp/lib/helper/}}}-Verzeichnis (oder in irgendeinem {{{helper/}}}-Verzeichnis erstellt in einem der {{{lib/}}}-Verzeichnisse Ihres Projekts), und es kann automatisch mit {{{use_helper('Foobar')}}} eingebunden werden. 
    131  
    132     Das System erlaubt Ihnen sogar, die existierenden symfony-Helfer zu überschreiben. Um etwa alle Helfer aus der Texthelfergruppe neu zu definieren, erzeugen Sie einfach eine Datei {{{TextHelper.php}}} in Ihrem {{{apps/meineapp/lib/helper/}}}-Verzeichnis. Jedesmal, wenn Sie {{{use_helper('Text')}}} aufrufen, wird symfony Ihre {{{Text}}}-Helfergruppe statt seine eigene benutzen. Aber Vorsicht: Da die Originaldatei gar nicht mehr beachtet wird, müssen Sie alle Funktionen der Helfergruppe neu definieren; andernfalls werden einige der Originalhelfer nicht mehr verfügbar sein. 
    133  
    134 == Seitenlayout == 
    135  
    136 Das Template in Codeabschnitt 7-1 ist kein gültiges XHTML-Dokument. Die {{{DOCTYPE}}}-Definition und die {{{<html>}}}- und {{{<body>}}}-Tags fehlen. Das liegt darain, dass sie anderswo in der Applikation gespeichert sind, in einer Datei layout.php, die das Seitenlayout enthält. Diese Datei, das globale Template, speichert den HTML-Code, der allen Seiten der Applikation gemeinsam ist, um zu verhindern, dass er in jedem Template wiederholt werden muss. Der Inhalt eines Templates wird ins Layout eingebettet oder, andersherum betrachtet, das Layout "dekoriert" das Template. Das ist eine Anwendung des Decorator-Design-Patterns, zu sehen in Abbildung 7-1. 
    137  
    138    Für weitere Informationen über das Decorator- und anderen Design-Pattern, siehe ''Patterns of Enterprise Application Architecture'' von Martin Fowler (Addison-Wesley, ISBN: 0-32112-742-0). 
    139  
    140 ''Abbildung 7-1 - Ein Template mit dem Layout dekorieren 
    141  
    142 [[Image(http://www.symfony-project.com/images/book/trunk/F0701.png)]] 
    143  
    144 Codeabschnitt 7-5 zeigt das Standard-Seitenlayout, zu finden im {{{templates/}}}-Verzeichnis der Applikation. 
    145  
    146 ''Codeabschnitt 7-5 - Standardlayout in {{{meinprojekt/apps/meineapp/templates/layout.php}}}'' 
    147  
    148 {{{ 
    149 #!php 
    150 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd"> 
    151 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de"> 
    152 <head> 
    153   <?php echo include_http_metas() ?> 
    154   <?php echo include_metas() ?> 
    155   <?php echo include_title() ?> 
    156   <link rel="shortcut icon" href="/favicon.ico" /> 
    157 </head> 
    158 <body> 
    159   
    160 <?php echo $sf_data->getRaw('sf_content') ?> 
    161   
    162 </body> 
    163 </html> 
    164 }}} 
    165  
    166 Die Helfer im {{{<head>}}}-Bereich holsen sich Informationen aus dem Response-Objekt und der View-Konfiguration. Der {{{<body>}}}-Tag zeigt das fertige Template an. Mit diesem Layout, der Standardkonfiguration, und dem Beispieltemplate aus Codeabschnitt 7-1, sieht das Ganze am Schluss dann so aus wie in Codeabschnitt 7-6. 
    167  
    168 ''Codeabschnitt 7-6 - Das Layout, die View-Konfiguration und das Template'' 
    169  
    170 {{{ 
    171 #!php 
    172 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd"> 
    173 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de"> 
    174 <head> 
    175   <meta http-equiv="content-type" content="text/html; charset=utf-8" /> 
    176   <meta name="title" content="Symfony-Projekt" /> 
    177   <meta name="robots" content="index, follow" /> 
    178   <meta name="description" content="Symfony-Projekt" /> 
    179   <meta name="keywords" content="symfony, projekt" /> 
    180   <title>Symfony-Projekt</title> 
    181   <link rel="stylesheet" type="text/css" href="/css/main.css" /> 
    182   <link rel="shortcut icon" href="/favicon.ico"> 
    183 </head> 
    184 <body> 
    185   
    186 <h1>Willkommen</h1> 
    187 <p>Willkommen zurück, <?php echo $name ?>!</p> 
    188 <ul>Was möchten Sie tun? 
    189   <li><?php echo link_to('Die neusten Artikel lesen', 'article/read') ?></li> 
    190   <li><?php echo link_to('Einen neuen Artikel schreiben', 'article/write') ?></li> 
    191 </ul> 
    192   
    193 </body> 
    194 </html> 
    195 }}} 
    196  
    197 Das globale Template kann vollständig an Ihre Applikation angepasst werden. Fügen Sie beliebigen HTML-Code hinzu. Dieses Layout wird oft dazu benutzt, die Navigation, das Logo usw. darzustellen. Sie können sogar mehrere Layouts haben und entscheiden, welches Layout für welche Aktion benutzt werden soll. Machen Sie sich um die Einbindung von JavaScript und CSS-Dateien keine Sorgen; der Abschnitt "View-Konfiguration" später in diesem Kapitel erklärt diese ausführlich. 
    198  
    199 == Template-Shortcuts == 
    200  
    201 In den Templates sind einige symfony-Variablen immer verfügbar. Diese Shortcuts ermöglichen den Zugriff auf die wichtigsten Informationen über die symfony-Kern-Objekte: 
    202  
    203     * {{{$sf_context}}}: Das Context-Object (Instanz von {{{sfContext}}}) 
    204     * {{{$sf_request}}}: Das Request-Objekt (Instanz von {{{sfRequest}}}) 
    205     * {{{$sf_params}}}: Parameter des Requests 
    206     * {{{$sf_user}}}: Das aktuelle User-Session-Objekt (Instanz von {{{sfUser}}}) 
    207  
    208 Das vorherige Kapitel hat hilfreiche Methoden des {{{sfRequest}}}- und des {{{sfUser}}}-Objekts beschrieben. Sie können diese Methoden in Templates durch die {{{$sf_request}}}- und {{{$sf_user}}}-Variablen aufrufen. Wenn zum Beispiel der Request einen {{{total}}}-Parameter enthält, ist sein Wert im Template folgendermassen verfügbar: 
    209  
    210 {{{ 
    211 #!php 
    212 // lange Version 
    213 <?php echo $sf_request->getParameter('total'); ?> 
    214   
    215 // kürzere Version 
    216 <?php echo $sf_params->get('total'); ?> 
    217   
    218 // gleichwertig mit dem folgenden Code in einer Aktion 
    219 <?php echo $this->getRequestParameter('total'); ?> 
    220 }}} 
    221  
    222 = Codefragmente = 
    223  
    224 Oft müssen Sie HTML- oder PHP-Code in mehrere Seiten einbinden. Die PHP-{{{include()}}}-Funktion hilft Ihnen dabei, dass Sie den Code nicht jedesmal wiederholen müssen. 
    225  
    226 Wenn zum Beispiel viele Templates Ihrer Applikation das gleiche Codefragment benötigen, speichern Sie es in einer Datei meinFragment.php im globalen Template-Verzeichns ({{{meinprojekt/apps/meineapp/templates/}}}) und binden es in Ihr Template wie folgt ein: 
    227  
    228 {{{ 
    229 #!php 
    230 <?php include(sfConfig::get('sf_app_template_dir').'/meinFragment.php') ?> 
    231 }}} 
    232  
    233 Aber das ist keine sehr saubere Art, ein Fragment zu verpacken, vor allem deshalb, weil sie verschiedene Variablennamen im Fragment und den verschiedenen Templates haben können, die es einbinden. Ausserdem hat das symfony-Cachesystem (näheres dazu in Kapitel 12) keine Möglichkeit, includes zu erkennen, das Codefragment kann also nicht uanbhängig vom Template im Cache abgelegt werden. symfony bietet drei Alternativen zu gewöhnlichen includes: 
    234  
    235     * Wenn die Logik simpel ist, können Sie einfach eine Templatedatei nehmen, der Sie einige Daten übergeben. Dazu verwenden Sie ein Partial. 
    236     * Wenn die Logik komlizierter ist (zum Beispiel wenn sie aufs Datenmodell zugreift oder den Inhalt entsprechend der Session ändert), sollten Sie die Präsentation von der Logik trennen. Dazu benötigen Sie eine Component. 
    237     * Wenn das Fragment einen bestimmten Teil des Layouts ersetzen soll, für den möglicherweise bereits Standardinhalt definiert wurde, brauchen Sie ein Slot. 
    238  
    239     Ein weiterer Codefragment-Typ, ein Component Slot, wird benutzt, wenn der Inhalt des Fragments vom Kontext abhäng (z.B. wenn das Fragment für verschiedene Aktionen eines Moduls unterschiedlichen Inhalt hat). Component Slots werden später in diesem Kapitel noch genauer beschrieben. 
    240  
    241 Die Einbindung dieser Fragmente geschieht durch Helfer der Partial-Gruppe. Diese Helfer sind in jedem symfony-Template ohne Deklaration verfügbar. 
    242  
    243 == Partials == 
    244  
    245 Ein Partial ist ein wiederbenutzbares Stück Template-Code. In einer Publikationsapplikation wird der Templatecode zum Anzeigen eines Artikels sowohl in der Artikel-Detailseite verwendet als auch in der Liste der besten und derjenigen der neusten Artikel. Solcher Code ist ein perfekter Kandidat für ein Partial, wie in Abbildung 7-2 dargestellt. 
    246  
    247 ''Abbildung 7-2 - Partials in Templates wiederverwenden'' 
    248  
    249 [[Image(http://www.symfony-project.com/images/book/trunk/F0702.png)]] 
    250  
    251 Genau wie Templates sind Partials Dateien im {{{templates/}}}-Verzeichnis, die HTML-Code mit etwas PHP enthalten. Der Dateiname eines Partials beginnt immer mit einem Unterstrich (_), um sie gut von Templates unterscheiden zu können, die ja in den gleichen {{{templates/}}}-Verzeichnissen gespeichert sind. 
    252  
    253 Ein Template kann Partials einbinden, egal, ob sie aus dem gleichen Modul stammen, einem anderen oder aus dem globalen {{{templates/}}}-Verzeichnis. Sie können ein Partial mit dem {{{include_partial()}}}-Helfer einbinden und dabei das Modul und den Partialnamen wie in Codeabschnitt 7-7 gezeigt als Parameter angeben (ohne den führenden Unterstrich und die Dateiendung .php). 
    254  
    255 ''Codeabschnitt 7-7 - Ein Partial in ein Template des meinmodul-Moduls einbinden'' 
    256  
    257 {{{ 
    258 #!php 
    259 // Binde das meineapp/modules/meinmodul/templates/_meinpartial1.php-Partial ein 
    260 // Da das Template und das Partial im gleichen Modul sind, 
    261 // können Sie den Modulnamen weglassen 
    262 <?php include_partial('meinpartial1') ?> 
    263   
    264 // Binde das meineapp/modules/foobar/templates/_meinpartial2.php-Partial ein 
    265 // Hier muss der Modulname angegeben werden 
    266 <?php include_partial('foobar/meinpartial2') ?> 
    267   
    268 // Binde das meineapp/templates/_meinpartial3.php-Partial ein 
    269 // Es wird als Teil des 'global'-Moduls betrachtet 
    270 <?php include_partial('global/meinpartial3') ?> 
    271 }}} 
    272  
    273 Partials haben Zugriff auf die üblichen symfony-Helfer und Template-Shortcuts. Aber weil Partials überall in der Applikation aufgerufen werden können, haben sie nicht automatisch Zugriff auf die Variablen der Aktion, die das Template aufruft, in dem sie sich befinden - ausser, wenn die Variablen explizit als Argument übergeben werden. Wenn etwa ein Partial Zugriff auf eine Variable {{{$total}}} haben soll, muss die Aktion diese dem Template übergeben und das Template sie dann dem Helfer als zweites Argument des {{{include_partial()}}}-Aufrufs, siehe Codeabschnitte 7-8, 7-9 und 7-10. 
    274  
    275 ''Codeabschnitt 7-8 - Die Aktion definiert eine Variable in meinmodul/actions/actions.class.php'' 
    276  
    277 {{{ 
    278 #!php 
    279 class meinmodulActions extends sfActions 
    280 { 
    281   public function executeIndex() 
    282   { 
    283     $this->total = 100; 
    284   } 
    285 } 
    286 }}} 
    287  
    288 ''Codeabschnitt 7-9 - Das Template übergibt die Variable dem Partial in meinmodul/templates/indexSuccess.php'' 
    289  
    290 {{{ 
    291 #!php 
    292 <p>Hallo Welt!</p> 
    293 <?php include_partial('meinpartial', 
    294 array('meintotal' => $total) 
    295 ) ?> 
    296 }}} 
    297  
    298 ''Codeabschnitt 7-10 - Das Partial kann die Variable jetzt verwenden in meinmodul/templates/_meinpartial.php'' 
    299  
    300 {{{ 
    301 #!php 
    302 <p>Total: <?php echo $meintotal ?></p> 
    303 }}} 
    304  
    305     Bisher wurden alle Helfer mit {{{<?php echo functionName() ?>}}} aufgerufen. Der Partial-Helper hingegen wird einfach nur mit {{{<?php include_partial() ?>}}} aufgerufen - ohne {{{echo}}}, so verhält es sich ähnlich dem normalen PHP-{{{include()}}}-Befehl. Sollten Sie jemals eine Funktion benötigen, die den Inhalt eines Partials zurückgibt ohne ihn anzuzeigen, verwenden Sie {{{get_partial()}}}. Alle in diesem Kapitel beschriebenen {{{include_}}}-Helfer haben ein {{{get_}}}-Pendant, das zusammen mit einem {{{echo}}} verwendet werden kann. 
    306  
    307 == Komponenten == 
    308  
    309 Das erste Beispielskript in Kapitel 2 war in zwei Teile aufgeteilt, um die Logik von der Präsentation zu trennen. Genau wie das MVC-Pattern auf Aktionen und Templates zutrifft, müssen Sie möglicherweise ein Partial in einen Logik- und einen Präsentationsteil aufteilen. In so einem Fall sollten sie eine Komponente benutzen. 
    310  
    311 Eine Komponente ist wie eine Aktion, nur viel schneller. Die Logik einer Komponente befindet sich in einer Klasse, die von {{{sfComponents}}} erbt, sie befindet sich in der Datei {{{action/components.class.php}}}. Die Präsentation befindet sich in einem Partial. Methoden der {{{sfComponents}}}-Klasse beginnen mit {{{execute}}}, genau wie Aktionen, und genau wie Aktionen können sie Variablen an den Präsentationsteil übergeben. Partials, die zusammen mit einer Komponente verwendet werden, werden nach dieser benannt (ohne das führende {{{execute}}}, aber dafür mit einem Unterstrich). Tabelle 7-1 vergleich die Namenskonventionen von Aktionen und Komponenten. 
    312  
    313 ''Tabelle 7-1 - Aktions- und Komponenten-Namenskonventionen'' 
    314  
    315 ||'''Konvention'''||'''Aktionen'''||'''Komponenten'''|| 
    316 ||Logikdatei||{{{actions.class.php}}}||{{{components.class.php}}}|| 
    317 ||Logikklasse erweitert||{{{sfActions}}}||{{{sfComponents}}}|| 
    318 ||Methodennamen||{{{executeMeineAktion()}}}||{{{executeMeineKomponente()}}}|| 
    319 ||Präsentationsdatei||{{{meineAktionSuccess.php}}}||{{{_meineKomponente.php}}}|| 
    320  
    321     Genau wie Sie Sie Aktionsdateien aufspalten können, hat die {{{sfComponents}}}-Klasse ein {{{sfComponent}}}-Pendant, das einzelne Komponentendateien mit der gleichen Syntax erlaubt. 
    322  
    323 Ein Beispiel: Nehmen wir an, Sie haben eine Sidebar, in der Sie die neusten Nachrichten eines bestimmten Themas anzeigen, abhängig vom Benutzerprofil; diese Sidebar wird auf verschiedenen Seiten verwendet. Die benötigten Querys, um die Headlines zu holen, sind zu kompliziert für ein einzelnes Partial, also müssen sie in eine aktionsartige Datei verschoben werden – eine Komponente. Abbildung 7-3 illustriert dieses Beispiel. 
    324  
    325 Für dieses Beispiel (siehe Codeabschnitte 7-11 und 7-12) befindet sich die Komponente in ihrem eigenen Modul {{{news}}}, aber Sie können Komponenten und Aktionen auch in einem einzigen Modul mischen, wenn es Sinn macht. 
    326  
    327 ''Abbildung 7-3 - Komponenten in Templates verwenden'' 
    328  
    329 [[Image(http://www.symfony-project.com/images/book/trunk/F0703.png)]] 
    330  
    331 ''Codeabschnitt 7-11 - Die Komponentenklasse in {{{modules/news/actions/components.class.php'' 
    332  
    333 {{{ 
    334 #!php 
    335 <?php 
    336   
    337 class newsKomponenten extends sfComponents 
    338 { 
    339   public function executeHeadlines() 
    340   { 
    341     $c = new Criteria(); 
    342     $c->addDescendingOrderByColumn(NewsPeer::EINGETRAGEN_AM); 
    343     $c->setLimit(5); 
    344     $this->news = NewsPeer::doSelect($c); 
    345   } 
    346 } 
    347 }}} 
    348  
    349 ''Codeabschnitt 7-12 - Das Partial in {{{modules/news/templates/_headlines.php}}}'' 
    350  
    351 {{{ 
    352 #!php 
    353 <div> 
    354   <h1>Neuste Nachrichten</h1> 
    355   <ul> 
    356   <?php foreach($news as $headline): ?> 
    357     <li> 
    358       <?php echo $headline->getEingetragenAm() ?> 
    359       <?php echo link_to($headline->getTitel(),'news/show?id='.$headline->getId()) ?> 
    360     </li> 
    361   <?php endforeach ?> 
    362   </ul> 
    363 </div> 
    364 }}} 
    365  
    366 Jetzt können Sie jedesmal, wenn Sie die Komponente in einem Template benötigen, einfach diesen Code einbinden: 
    367  
    368 {{{#!php<?php include_component('news', 'headlines') ?>}}} 
    369  
    370 Genau wie Partials akzeptieren Komponenten als zusätzliche Parameter assoziative Arrays. Die Parameter sind in den Partials unter ihrem eigenen Namen verfügbar, und in Komponenten über das {{{$this}}}-Objekt (siehe Codeabschnitt 7-13). 
    371  
    372 ''Codeabschnitt 7-13 - Parameter an eine Komponente und das dazugehörige Template übergeben'' 
    373  
    374 {{{ 
    375 #!php 
    376 // Komponente einbinden 
    377 <?php include_component('news', 'headlines', array('foo' => 'bar')) ?> 
    378   
    379 // In der Komponente selbst 
    380 echo $this->foo; 
    381  => 'bar' 
    382   
    383 // Im _headlines.php-Partial 
    384 echo $foo; 
    385  => 'bar' 
    386 }}} 
    387  
    388 Sie können sogar Komponenten in andere Komponenten einbinden, oder auch im globalen Layout, wie jedes normale Template. Wie Aktionen führen Komponenten Methoden aus, die Variablen an das zugehörige Partial übergeben und Zugriff auf die gleichen Shortcuts haben. Aber die Ähnlichkeiten enden hier. Eine Komponente kümmert sich nicht um Sicherheit oder Validation, kann nicht vom Internet aus aufgerufen werden (nur von der Applikation selbst) und hat nicht mehrere Rückgabemöglichkeiten. Darum ist die Ausführung einer Komponente schneller als die einer Aktion. 
    389  
    390 == Slots == 
    391  
    392 Partials und Komponenten dienen der Wiederbenutzbarkeit. Aber oft sollen Codefragmente ein Layout mit verschiedenen dynamischen Bereichen ausfüllen. Beispielsweise möchten Sie einige individuelle Tags in den {{{<head>}}}-Bereich Ihres Layouts einbinden, abhängig von der aufgerufenen Aktion. Oder die Aktion füllt verschiedene grössere dynamische Bereiche auf der Seite und zusätzlich viele kleinere, für die ein Standardinhalt im Layout festgelegt ist, der aber von Templates überschrieben werden kann. 
    393  
    394 In solchen Situationen ist die Lösung ein Slot. Ein Slot ist ein Platzhalter, den man in einem beliebigen View-Element einsetzen kann. (Layout, Template, Partial) Diesen Platzhalter ausfüllen ist genau wie eine Variable setzen. Der Code, mit dem der Slot gefüllt wird, wird im Response-Objekt gespeichert, Sie können es also in jedem View-Element definieren. Nur sollten Sie sicherstellen, dass ein Slot definiert ist, bevor er eingebunden wird; und denken Sie daran: Das Layout wird nach dem Template gerendert (das ist der Dekorationsprozess), und die Partials werden dann gerendert, wenn sie von einem Template aus aufgerufen werden. Klingt zu kompliziert? Sehen wir uns ein Beispiel an. 
    395  
    396 Nehmen wir ein Layout mit einem Bereich fürs Template und zwei Slots: Einen für die Sidebar und den anderen für den Footer. Die Slotwerte werden in den Templates definiert. Während dem Dekorationsprozesses enthält das Layout den Templatecode, und die Slots werden mit den vorher definierten Werten gefüllt, wie in Abbildung 7-4 zu sehen. Die Sidebar und der Footer können dann abhängig von der Aktion geändert werden. Das ist so, als ob Sie ein Layout mit mehreren "Löchern" haben. 
    397  
    398 ''Abbildung 7-4 - Layoutslots in einem Template 
    399  
    400 [[Image(http://www.symfony-project.com/images/book/trunk/F0704.png)]] 
    401  
    402 Wenn wir uns etwas Code ansehen, wird die Sache schnell verständlicher. Um einen Slot einzubinden, verwenden Sie den {{{include_slot()}}}-Helfer. Der {{{has_slot()}}}-Helfer gibt {{{true}}} zurück, wenn der Slot bereits definiert wurde. Um einen Platzhalter dür den "Sidebar"-Slot im Layout mitsamt seinem Standardinhalt zu definieren, verwenden Sie den Code aus Codeabschnitt 7-14. 
    403  
    404 ''Codeabschnitt 7-14 - Einen "Sidebar"-Slot ins Layout einbinden'' 
    405  
    406 {{{ 
    407 #!php 
    408 <div id="sidebar"> 
    409 <?php if (has_slot('sidebar')): ?> 
    410   <?php include_slot('sidebar') ?> 
    411 <?php else: ?> 
    412   <!-- Standard-Sidebar-Inhalt --> 
    413   <h1>Individuellelr Bereich</h1> 
    414   <p>Dieser Bereich enthält Links und Informationen 
    415   abhängig vom Hauptbereich der Seite.</p> 
    416 <?php endif; ?> 
    417 </div> 
    418 }}} 
    419  
    420 Jedes Template kann die Inhalt eines Slots definieren (sogar Partials können das). Da Slots dazu gedacht sind, HTML-Code zu beinhalten, bietet symfony einen komfortablen Weg, sie zu definieren: Schreiben Sie den Slot-Code einfach zwischen einen Aufruf des {{{slot()}}}- und des {{{end_slot()}}}-Helfer, so wie in Codeabschnitt 7-15. 
    421  
    422 ''Codeabschnitt 7-15 - Den "Sidebar"-Slotinhalt in einem Template überschreiben'' 
    423  
    424 {{{ 
    425 #!php 
    426 ... 
    427 <?php slot('sidebar') ?> 
    428   <!-- Individueller Sidebar-Inhalt für das aktuelle Template --> 
    429   <h1>Benutzerinformationen</h1> 
    430   <p>Name:  <?php echo $user->getName() ?></p> 
    431   <p>E-Mail-Adresse: <?php echo $user->getEmail() ?></p> 
    432 <?php end_slot() ?> 
    433 }}} 
    434  
    435 Der Code zwischen den Slothelfern wird im Kontext des Templates ausgeführt, es hat also keinen Zugriff auf die Variablen der Aktion. symfony fügt diesen Code automatisch dem Response-Objekt hinzu. Es wird nicht im Template angezeigt, aber ist für künftige {{{include_slot()}}}-Aufrufe verfügbar, wie in Codeabschnitt 7-14  zu sehen. 
    436  
    437 Slots sind sehr nützlich für Bereiche mit individuellem Inhalt. Sie können auch benutzt werden, wenn HTML-Code nur von gewissen Aktionen angezeigt werden soll. Zum Beispiel hat es in einem Template, das die Liste der neusten Nachrichten anzeigt, im {{{<head>}}}-Bereich des Layouts einen Link zu einem RSS-Feed. Das kann man mit einem "Feed"-Slot im Layout lösen, den man dann im Template der Liste setzt. 
    438  
    439 == Wo die Templatefragmente zu finden sind == 
    440  
    441 Leute, die mit Templates arbeiten, sind normalerweise Webdesigner, die symfony möglicherweise nicht gut kennen und Schiwerigkeiten haben, Templatefragmente zu finden, da diese überall in der Applikation verteilt sein können. Diese Richtlinien wird ihnen die Arbeit mit dem symfony-Templatingsystem erleichtern. 
    442  
    443 Obwohl ein symfony-Projekt viele Verzeichnisse enthält, befinden sich alle Layouts, Templates und Templatefragmente in Verzeichnissen mit dem Namen {{{templates/}}}. Was also den Webdesigner angeht, kann eine Projektstruktur auf das folgende vereinfacht werden: 
    444  
    445 {{{ 
    446 meinproject/ 
    447   apps/ 
    448     applikation1/ 
    449       templates/       # Layouts für Applikation 1 
    450       modules/ 
    451         modul1/ 
    452           templates/   # Templates und Partials für Modul 1 
    453         modul2/ 
    454           templates/   # Templates und Partials für Modul 2 
    455         modul3/ 
    456           templates/   # Templates und Partials für Modul 3 
    457 }}} 
    458  
    459 Alle anderen Verzeichnisse können ignoriert werden. 
    460  
    461 Wenn sie auf ein {{{include_partial()}}} treffen, müssen Webdesigner lediglich verstehen, dass nur das erste Argument wichtig ist. Dieses Argument ist immer von der Form ModulName/PartialName, und das heisst, dass sich der Präsentationscode in {{{modules/ModulName/templates/_PartialName.php}}} befindet. 
    462  
    463 Beim {{{include_component()}}}-Helfer ist es so, dass Modulname und Partialname die ersten beiden Argumente sind. Für den Rest genügt es eigentlich, eine grundsätzliche Idee davon zu haben, was Helfer sind und welche Helfer am häufigsten in Templates verwendet werden. 
    464  
    465 = View-Konfiguration = 
    466  
    467 In symfony besteht eine View aus zwei unabhängigen Teilen: 
    468  
    469     * Die HTML-Darstellung des Ergebnisses einer Aktion (gespeichert in einem Template, im Layout und in den verschiedenen Templatefragmenten) 
    470     * Der ganze Rest, darunter folgendes: 
    471          * Metadeklarationen: Stichwörter, Beschreibung, Cache-Dauer usw. 
    472          * Seitentitel: Hilft nicht nur beim Tabbed Browsing, Ihre Seite zu finden, sondern ist auch für Suchmaschinen sehr wichtig. 
    473          * Dateieinbindungen: JavaScripts und CSS-Dateien 
    474          * Layout: Gewisse Aktionen benötigen ein individuelles Layout (Pop-Ups, Werbungen usw.) oder überhaupt kein Layout (z.B. Ajax-Aktionen). 
    475  
    476 In der View wird alles, das nicht HTML ist, als View-Konfiguration bezeichnet, und symfony bietet zwei Möglichkeiten, diese zu bearbeiten. Der normale Weg geht über die {{{view.yml}}}-Konfigurationsdatei. Sie kann immer dann benutzt werden, wenn Werte nicht vom Kontext oder von Datenbank-Querys abhängen. Wenn Sie jedoch dynamische Werte setzen müssen, sollten Sie die alternative Möglichkeit verwenden und die Konfiguration direkt über das {{{sfResponse}}}-Objekt in der Aktion selbst bearbeiten. 
    477  
    478     Wenn Sie einen View-Konfigurationsparameter sowohl über das {{{sfResponse}}}-Objekt wie auch über die {{{view.yml}}} setzen, hat der Wert im {{{sfResponse}}}-Objekt Vorrang. 
    479  
    480 == Die {{{view.yml}}}-Datei == 
    481  
    482 Jedes Modul kann eine {{{view.yml}}}-Datei haben, die die Einstellungen seiner Views definiert. So können Sie Vieweinstellungen für ein ganzes Modul in einer einzigen Datei verwalten. Die Schlüssel in der {{{view.yml}}} sind die Modul-View-Namen. Codeabschnitt 7-16 zeigt ein Beispiel einer Viewkonfiguration. 
    483  
    484 ''Codeabschnitt 7-16 - Beispielhafte {{{view.yml}}} 
    485  
    486 {{{ 
    487 editSuccess: 
    488   metas: 
    489     title: Bearbeiten Sie ihr Profil 
    490  
    491 editError: 
    492   metas: 
    493     title: Fehler bei der Bearbeitung des Profils 
    494  
    495 all: 
    496   stylesheets: [mein_style] 
    497   metas: 
    498     title: Meine Website 
    499 }}} 
    500  
    501     Achten Sie darauf, dass die Hauptschlüssel in der {{{view.yml}}} Viewnamen sind und keine Aktionsnamen. Zur Erinnerung: Ein Viewname setzt sich zusammen aus einem Aktionsnamen und einem Aktions-Beende-Namen. Wenn die {{{edit}}}-Aktion {{{sfView::SUCCESS}}} zurückgibt (oder gar nichts, da dies die standardmässige Rückgabe ist), dann ist der Viewname {{{editSuccess}}}. 
    502  
    503 Die Standardeinstellungen für ein Modul sind unter dem {{{all:}}}-Schlüssel in der Modul-{{{view.yml}}} definiert. Die Standardeinstellungen für alle Applilkationsviews befinden sich in der Applikations-{{{view.yml}}}. Wieder einmal erkennen Sie hier die Verschachtelung der Konfiguration: 
    504  
    505     * In apps/meineapp/modules/meinmodul/config/view.yml können Sie Definitionen für einzelne Views festlegen, die die modulweiten Definitionen überschreiben 
    506     * In apps/meineapp/modules/meinmodul/config/view.yml können Sie unter dem {{{all:}}}-Schlüssel Viewdefinitionen für alle Aktionen des Moduls festlegen, die die applikationsweiten Definitionen überschreiben. 
    507     * In apps/meineapp/config/view.yml können Sie applikationsweite Definitionen festlegen, die für alle Module und alle Aktionen der Applikation gelten. 
    508  
    509 Modulweite {{{view.yml}}}-Dateien existieren standardmässig überhaupt nicht. Sie müssen also, wenn Sie das erste Mal eine Viewkonfiguration für ein bestimmtes Modul anpassen wollen, eine {{{view.yml}}} im {{{config/}}}-Verzeichnis dieses Moduls anlegen. 
    510  
    511 Nachdem Sie das Standardtemplate in Codeabschnitt 7-5 und ein Beispiel der fertigen Antwort in Codeabschnitt 7-6 gesehen haben, fragen Sie sich vielleicht, wo die Header-Werte herkommen. Die kommen schlicht und einfach aus den Standard-Vieweinstellungen, definiert in der Applikations-{{{view.yml}}}, zu sehen in Codeabschnitt 7-17. 
    512  
    513 ''Codeabschnitt 7-17 - Standard-Applikations-Viewkonfiguration in {{{apps/meineapp/config/view.yml}}}'' 
    514  
    515 {{{ 
    516 default: 
    517   http_metas: 
    518     content-type: text/html 
    519  
    520   metas: 
    521     title:        Symfony-Projekt 
    522     robots:       index, follow 
    523     description:  Symfony-Projekt 
    524     keywords:     symfony, projekt 
    525     language:     de 
    526  
    527   stylesheets:    [main] 
    528  
    529   javascripts:    [ ] 
    530  
    531   has_layout:     on 
    532   layout:         layout 
    533 }}} 
    534  
    535 Jede dieser Einstlelungen wird im Abschnitt "View-Konfigurationseinstellungen" deatilliert beschrieben. 
    536  
    537 == Das Response-Objekt == 
    538  
    539 Obwohl es eigentlich Bestandteil der View-Ebene ist, wird das Response-Objekt oft von der Aktion selbst verändert. Aktionen können auf das symfony-Response-Objekt, {{{sfResponse}}}, mittels der {{{getResponse()}}}-Methode zugreifen. Codeabschnitt 7-18 zeigt einige der häufig verwendeten {{{sfResponse}}}-Methoden. 
    540  
    541 ''Codeabschnitt 7-18 - Aktionen haben Zugriff auf die {{{sfResponse}}}-Objektmethoden'' 
    542  
    543 {{{ 
    544 #!php 
    545 <?php 
    546 class meinmodulActions extends sfActions 
    547 { 
    548   public function executeIndex() 
    549   { 
    550     $response = $this->getResponse(); 
    551   
    552     // HTTP-Header 
    553     $response->setContentType('text/xml'); 
    554     $response->setHttpHeader('Content-Language', 'de'); 
    555     $response->setStatusCode(403); 
    556     $response->addVaryHttpHeader('Accept-Language'); 
    557     $response->addCacheControlHttpHeader('no-cache'); 
    558   
    559     // Cookies 
    560     $response->setCookie($name, $content, $expire, $path, $domain); 
    561   
    562     // Metadaten und Titel 
    563     $response->addMeta('robots', 'NONE'); 
    564     $response->addMeta('keywords', 'foo bar'); 
    565     $response->setTitle('Meine Seite'); 
    566     $response->addStyleSheet('custom_style'); 
    567     $response->addJavaScript('custom_behavior'); 
    568   } 
    569 } 
    570 ?> 
    571 }}} 
    572  
    573 Zusätzlich zu den setter-Methoden, die Sie hier sehen können, hat die {{{sfResponse}}}-Klasse auch getter, die den aktuellen Wert eines Response-Attributes zurückgeben. 
    574  
    575 Die Header-Setter in symfony sind sehr hilfreich. Header werden erst so spät wie möglich geschickt (im {{{sfRenderingFilter}}}), Sie können Sie also so oft und so stark ändern, wie Sie wollen. Die Setter bieten Ihnen auch sehr nützliche Shortcuts. Wenn Sie beispielsweise keinen Zeichensatz spezifizieren beim Aufruf von {{{setContentType()}}}, dann fügt symfony automatisch den Standard-Zeichensatz aus der {{{settings.yml}}} hinzu. 
    576  
    577 {{{ 
    578 #!php 
    579 $response->setContentType('text/xml'); 
    580 echo $response->getContentType(); 
    581  => 'text/xml; charset=utf-8' 
    582 }}} 
    583  
    584 Der Statuscode von Antworten in symfony entspricht der HTTP-Spezifikation. Exceptions liefern einen Status 500, nicht gefundene Seiten 404, normale Seiten 200, nicht veränderte Seiten können Status 304 zurückgeben (siehe Kapitel 12 für Details) usw. Aber Sie können diese Standards überschreiben, indem Sie Ihren eigenen Statuscode in der Aktion mit der {{{setStatusCode()}}}-Response-Methode definieren. Sie können Ihren eigenen Code und Ihre eigene Nachricht definieren, oder auch nur Ihren eigenen Code -- in diesem Fall wird symfony die passende Nachricht zu diesem Code automatisch hinzufügen. 
    585  
    586 {{{ 
    587 #!php 
    588 $response->setStatusCode(404, 'This page no longer exists'); 
    589 }}} 
    590  
    591     Bevor die Header geschickt werden, normalisiert symfony ihre Namen. Sie müssen sich also nicht darum kümmern, ob Sie in einem {{{setHttpHeader()}}}-Aufruf {{{content-language}}} anstatt {{{Content-Language}}} schreiben, symfony versteht auch ersteres und wandelt es automatisch in die korrekte Schreibweise um. 
    592  
    593 == View-Konfigurationseinstellungen == 
    594  
    595 Vielleicht haben Sie bemerkt, dass es zwei Arten von View-Konfigurationseinstellungen gibt: 
    596  
    597     * Diejenigen, die einen eindeutigen Wert haben (der Wert ist ein String in der {{{view.yml}}}-Datei und das Response-Objekt benutzt eine {{{set}}}-Methode dafür) 
    598     * Diejenigen mit mehreren Werten (für die die {{{view.yml}}} Arrays benutzt und das Response-Objekt eine {{{add}}}-Methode) 
    599  
    600 Denken Sie daran, dass eine Konfigurationenfolge die eindeutigen Werte löscht, sie aber zu den Einstellungen mit mehreren Werten hinzufügt. Das wird im Verlauf dieses Kapitels noch klarer werden. 
    601  
    602 === Meta-Tag-Konfiguration === 
    603  
    604 Die Informationen in den {{{<meta>}}}-Tags der Antwort werden im Browser nicht angezeigt, sind aber nützlich für Robots und Suchmaschinen. Sie kontrollieren auch das Cache-Verhalten einer Seite. Definieren Sie diese Tags unter den {{{http_metas:}}}- und {{{metas:}}}-Schlüsseln in der {{{view.yml} wie in Codeabschnitt 7-19 oder mit den {{{addHttpMeta()}}}- und {{{addMeta()}}}-Antwortmethoden in der Aktion wie in Codeabschnitt 7-20. 
    605  
    606 ''Codeabschnitt 7-20 - Metadefinitionen als Schlüssel-Wert-Paare in der {{{view.yml}}}'' 
    607  
    608 {{{ 
    609 http_metas: 
    610   cache-control: public 
    611  
    612 metas: 
    613   description:   Finanzen in Frankreich 
    614   keywords:      finanzen, frankreich 
    615 }}} 
    616  
    617 ''Codeabschnitt 7-20 - Metadefinitionen als Antworteinstellungen in der Aktion'' 
    618  
    619 {{{ 
    620 #!php 
    621 $this->getResponse()->addHttpMeta('cache-control', 'public'); 
    622 $this->getResponse()->addMeta('description', 'Finanzen in Frankreich'); 
    623 $this->getResponse()->addMeta('keywords', 'finanzen, frankreich'); 
    624 }}} 
    625  
    626 Einen existierenden Schlüssel hinzufügen ersetzt standardmässig seinen aktuellen Inhalt. Für HTTP-Meta-Tags können Sie einen dritten Parameter übergeben – ist dieser auf {{{false}}} gesetzt, hängt die {{{addHttpMeta()}}}-Methode (genau wie die {{{setHttpHeader()}}}-Methode) den Wert an den existierenden an, statt ihn zu ersetzen. 
    627  
    628 {{{ 
    629 #!php 
    630 $this->getResponse()->addHttpMeta('accept-language', 'en'); 
    631 $this->getResponse()->addHttpMeta('accept-language', 'fr', false); 
    632 echo $this->getResponse()->getHttpHeader('accept-language'); 
    633  => 'en, fr' 
    634 }}} 
    635  
    636 Damit diese Metatags im fertigen Dokument erscheinen, müssen der {{{include_http_metas()}}}- und der {{{include_metas()}}}-Helfer im {{{<head>}}}-Bereich aufgerufen werden. (Das wird im Standardlayout automatisch gemacht; siehe Codeabschnitt 7-5.) symfony sammelt automatisch die Einstellungen aus allen {{{view.yml}}}-Dateien (inklusive derjenigen in Codeabschnitt 7-17) und wandelt sie in {{{meta}}}-Tags um. Das Beispiel aus Codeabschnitt 7-19 verwandelt sich also in Codeabschnitt 7-21. 
    637  
    638 ''Codeabschnitt 7-21 - Ausgegebene Metatags auf der fertigen Seite'' 
    639  
    640 {{{ 
    641 #!php 
    642 <meta http-equiv="content-type" content="text/html; charset=utf-8" /> 
    643 <meta http-equiv="cache-control" content="public" /> 
    644 <meta name="robots" content="index, follow" /> 
    645 <meta name="description" content="Finanzen in Frankreich" /> 
    646 <meta name="keywords" content="finanzen, frankreich" /> 
    647 }}} 
    648  
    649 Zusätzlich wird der HTTP-Header der Antwort von der {{{http-metas:}}}-Definition beeinflusst, selbst wenn Sie gar keine {{{include_http_metas()}}}-Helfer in Ihrem Layout haben, oder wenn Sie überhaupt kein Layout haben – zum Beispiel, wenn Sie eine Datein als Plaintext senden müssen. Dann definieren Sie einfach folgende {{{view.yml}}}: 
    650  
    651 {{{ 
    652 http_metas: 
    653   content-type: text/plain 
    654  
    655 has_layout: false 
    656 }}} 
    657  
    658 === Titelkonfiguration === 
    659 Der Seitentitel ist ein integraler Bestandteil der Suchmaschinenoptimierung. Auch bei modernen, tabbed-browsing-fähigen Browsern trägt der zum Überblick bei. Im HTML-Code ist der Titel sowohl ein Tag als auch Metainformation über die Seite, deshalb ist in der {{{view.yml}}} der {{{title:}}}-Schlüssel ein Kind des {{{metas:}}}-Schlüssels. Codeabschnitt 7-22 zeigt die Titeldefinition in der {{{view.yml}}}, und Codeabschnitt 7-23 zeigt die Definition in einer Aktion. 
    660  
    661 ''Codeabschnitt 7-22 - Titeldefinition in der {{{view.yml}}}'' 
    662 {{{ 
    663 indexSuccess: 
    664   metas: 
    665     title: Drei kleine Ferkel 
    666 }}} 
    667  
    668 ''Codeabschnitt 7-23 - Titeldefinition in der Aktion – ermöglicht dynamische Titel'' 
    669  
    670  
    671 Listing 7-23 - Title Definition in the Action--Allows for Dynamic Titles 
    672 {{{ 
    673 #!php 
    674 $this->getResponse()->setTitle(sprintf('%d kleine Ferkel', $anzahl)); 
    675 }}} 
    676  
    677 Im {{{<head>}}}-Bereich der fertigen Seite erzeugt die Titeldefinition einen {{{<meta name="title">}}}-Tag, wenn der {{{include_metas()}}}-Helfer verwendet wird, und einen {{{<title>}}}-Tag, wenn der {{{include_title()}}}-Helfer verwendet wird. Wenn beide verwendet werden (was im Standardlayout der Fall ist, s. Codeabschnitt 7-5), erscheint der Titel zweimal im Quelltext (siehe Codeabschnitt 7-6). 
    678  
    679 == Konfigurieren der einzubindenden Dateien == 
    680 Eine CSS- oder JavaScript-Datei zu einer View hinzufügen ist sehr einfach, wie in Codeabschnitt 7-24 und 7-25 zu sehen. 
    681  
    682 ''Codeabschnitt 7-24 - Dateieinbindung in {{{view.yml}}}'' 
    683 {{{ 
    684 indexSuccess: 
    685   stylesheets: [meinstyle1, meinstyle2] 
    686   javascripts: [meinscript] 
    687 }}} 
    688  
    689 ''Codeabschnitt 7-25 - Dateieinbindung in der Aktion'' 
    690 {{{ 
    691 #!php 
    692 <?php 
    693 $this->getResponse()->addStylesheet('meinstyle1'); 
    694 $this->getResponse()->addStylesheet('meinstyle2'); 
    695 $this->getResponse()->addJavascript('meinscript'); 
    696 ?> 
    697 }}} 
    698  
    699 In jedem Fall ist das Argument ein Dateiname. Wenn die Datei eine logische Endung hat ({{{.css}}} für ein Stylesheet und {{{.js}}} für ein JavaScript), können Sie es auch weglassen. Wenn die Datei in einem logischen Verzeichnis liegt ({{{/css/} für ein Stylesheet, {{{/js/}}} für ein JavaScript), können Sie das ebenfalls weglassen. symfony ist so schlau und findet die korrekte Dateiendung und das korrekte Verzeichnis selbst heraus. 
    700  
    701 Anders als die Meta- und Titel-Definitionen benötigen die Datei-Einbindungen keine Helfer im Template oder Layout. Das heisst, die obigen Einstellungen geben den HTML-Code aus Codeabschnittt 7-26 zurück, egal, was im Template und/Oder im Layout steht. 
    702  
    703 ''Codeabschnitt 7-26 - Datei-Einbindung – Im Layout wird kein Helfer benötigt'' 
    704 {{{ 
    705 #!html 
    706 <head> 
    707 ... 
    708 <link rel="stylesheet" type="text/css" media="screen" href="/css/mystyle1.css" /> 
    709 <link rel="stylesheet" type="text/css" media="screen" href="/css/mystyle2.css" /> 
    710 <script language="javascript" type="text/javascript" src="/js/myscript.js"> 
    711 </script> 
    712 </head> 
    713 }}} 
    714  
    715     Die Einbindung von CSS und JavaScript in der Antwort wird vom Filter {{{sfCommonFilter}}} übernommen. Dieser sucht in der Antwort nach einem {{{<head>}}}-Tag und fügt die {{{<link>}}}s und {{{<script>}}}s direkt vor dem schliessenden {{{</head>}}} ein. Wenn kein {{{<head>}}}-Tag vorhanden ist, funktioniert die Einbindung nicht. 
    716      
    717 Denken Sie daran: Auch hier findet die Konfigurationskaskade wieder Anwendung: Jede Datei, die in der Applikations-{{{view.yml}}} definiert wurde, wird in jeder Seite der Applikation eingebunden. Die Codeabschnitte 7-27, 7-28 und 7-29 demonstrieren dies. 
    718  
    719 ''Codeabschnitt 7-27 - Beispiel-Applikations-{{{view.yml}}}'' 
    720 {{{ 
    721 default: 
    722   stylesheets: [main] 
    723 }}} 
    724  
    725 ''Codeabschnitt 7-28 - Beispiel-Modul-{{{view.yml}}}'' 
    726 {{{ 
    727 indexSuccess: 
    728   stylesheets: [special] 
    729  
    730 all: 
    731   stylesheets: [additional] 
    732 }}} 
    733  
    734 '''Codeabschnitt 7-29 - Das Ergebnis''' 
    735 {{{ 
    736 #!html 
    737 <link rel="stylesheet" type="text/css" media="screen" href="/css/main.css" /> 
    738 <link rel="stylesheet" type="text/css" media="screen" href="/css/additional.css" /> 
    739 <link rel="stylesheet" type="text/css" media="screen" href="/css/special.css" /> 
    740 }}} 
    741  
    742 Wenn Sie eine Datei entfernen möchten, die auf einer höheren Stufe definiert wurde, häängen Sie einfach ein Minuszeichen (-) vor dem Dateinamen, wie in Codeabschnitt 7-30. 
    743  
    744 ''Codeabschnitt 7-30 - Beispiel-Modul-{{{view.yml}}}, die eine Datei entfernt, die auf der Applikationsstufe definiert wurde'' 
    745 {{{ 
    746 indexSuccess: 
    747   stylesheets: [-main, special] 
    748  
    749 all: 
    750   stylesheets: [additional] 
    751 }}} 
    752  
    753 Um alle CSS- oder JavaScript-Dateien zu entfernen, verwenden Sie folgende SYntax: 
    754  
    755 {{{ 
    756 indexSuccess: 
    757   stylesheets: [-*] 
    758   javascripts: [-*] 
    759 }}} 
    760  
    761 Sie können auch weiter ins Detail gehen und in einem zusätzlichen PArameter angeben, wo genau die Datei eingebunden werden soll (an der ersten oder letzten Stelle): 
    762  
    763 {{{ 
    764 // In der view.yml 
    765 indexSuccess: 
    766   stylesheets: [special: { position: first }] 
    767 }}} 
    768  
    769 {{{ 
    770 #!php 
    771 // In der Aktion 
    772 $this->getResponse()->addStylesheet('special', 'first'); 
    773 }}} 
    774  
    775 Um Medientypen für CSS-Dateien hinzuzufügen, können Sie die Standard-CSS-Tag-Optionen ändern, zu sehen in den Codeabschnitten 7-31, 7-32 und 7-33. 
    776  
    777 ''Codeabschnitt 7-31 - CSS-Einbindung mit Medientyp in der {{{view.yml}}}'' 
    778 {{{ 
    779 indexSuccess: 
    780   stylesheets: [main, paper: { media: print }] 
    781 }}} 
    782  
    783 ''Codeabschnitt 7-32 - CSS-Einbindung mit Medientyp in der Aktion'' 
    784 {{{ 
    785 #!php 
    786 <?php 
    787 $this->getResponse()->addStylesheet('paper', '', array('media' => 'print')); 
    788 ?> 
    789 }}} 
    790  
    791 ''Codeabschnitt 7-33 - Das Ergebnis'' 
    792 {{{ 
    793 #!html 
    794 <link rel="stylesheet" type="text/css" media="print" href="/css/paper.css" /> 
    795 }}} 
    796  
    797 == Layout-Konfiguration == 
    798  
    799 Abhängig vom gestalterischen Aufbau Ihrer Website haben Sie möglicherweise mehrere Layouts. Klassische Websites haben mindestens zwei: Das Standardlayout und das Pop-up-Layout. 
    800  
    801 Sie wissen bereits, dass das Standardlayout sich in {{{meinprojekt/apps/meineapp/templates/layout.php}}} befindet. Zusätzliche Layouts müssen im gleichen globalen {{{templates/}}}-Verzeichnis hinzugefügt werden. Wenn Sie möchten, dass eine View die Datei {{{meineapp/templates/mein_layout.php}}} verwendet, benutzen Sie die Syntax aus Codeabschnitt 7-34 in der {{{view.yml}}} oder den Code aus Codeabschnitt 7-35 in der Aktion. 
    802  
    803 ''Codeabschnitt 7-34 - Layoutdefinition in {{{view.yml}}}'' 
    804 {{{ 
    805 indexSuccess: 
    806   layout: my_layout 
    807 }}} 
    808  
    809 ''Codeabschnitt 7-35 - Layoutdefinition in der Aktion'' 
    810 {{{ 
    811 #!php 
    812 <?php 
    813 $this->setLayout('my_layout'); 
    814 ?> 
    815 }}} 
    816  
    817 Einige Views benötigen überhaupt kein Layout (z.B. Plain-Text-Seiten oder RSS-Feeds). In diesem Fall setzen Sie {{{has_layout}}} auf {{{false}}} wie in den Codeabschnitten 7-36 und 7-37. 
    818  
    819 ''Codeabschnitt 7-36 - Layout-Entfernung in {{{view.yml}}}'' 
    820 {{{ 
    821 indexSuccess: 
    822   has_layout: false 
    823 }}} 
    824  
    825 ''Codeabschnitt 7-37 - Layoutentfernung in der Aktion'' 
    826 {{{ 
    827 #!php 
    828 <?php 
    829 $this->setLayout(false); 
    830 ?> 
    831 }}} 
    832  
    833     Ajax-Aktions-Views haben standardmässig kein Layout. 
    834  
    835 = Komponentenslots = 
    836 Um die Vielseitigkeit von Viewkomponenten und Viewkonfiguration zu vereinigen, gibt es das Komponentenslot-System. Es ist eine Alternative zu Slots, speziell zugeschnitten auf Wiederverwendbarkeit und Layer-Trennung. Komponentenslots sind strukturierter aufgebaut als normale Slots, brauchen aber in der Ausführung etwas länger. 
    837  
    838 Genau wie Slots sind auch Komponentenslots benannte Platzhalter, die Sie in den View-Elementen definieren können. Der Unterschied besteht darin, wie der ersetzende Code bestimmt wird. Bei einem Slot befindet sich der Code in einem anderen View-Element; bei einem Komponentenslot ist der Code das Ergebnis der Ausführung einer Komponente, und der Name dieser Komponente kommt aus der Viewkonfiguration. Sie werden Komponentenslots besser verstehen, wenn Sie sie erst einmal in Aktion erlebt haben. 
    839  
    840 Um einen Komponentenslot-Platzhalter zu setzen, verwenden Sie den {{{include_component_slot()}}}-Helfer. Diese Funktion erwartet ein Label als Parameter. Nehmen Sie an, die {{{layout.php}}} Ihrer Applikation enthält eine kontextabhängige Sidebar. Codeabschnitt 7-38 zeigt, wie der Komponentslot-HElfer eingebunden wird. 
    841  
    842 ''Codeabschnitt 7-38 - Einen Komponentenslot einbinden mit dem Namen ›sidebar‹'' 
    843 {{{ 
    844 #!php 
    845  
    846 <div id="sidebar"> 
    847   <?php include_component_slot('sidebar') ?> 
    848 </div> 
    849 }}} 
    850  
    851 Definieren Sie die Verbindung von Komponentenslot-Labe und Komponentenname in der Viewkonfiguration. Setzen Sie die Standardkomponente für den Sidebar-Komponentenslot in der Applikations-{{{view.yml}}}, unter dem {{{components}}}-Header. Der Schlüssel ist das Komponentenslot-Label; der Wert muss ein Array sein, der ein Modul und einen Komponentennamen beinhaltet. Ein Beispiel ist in Codeabschnitt 7-39 zu sehen. 
    852  
    853 ''Codeabschnitt 7-39 - Den Standard-›Sidebar‹-Komponentenslot in der {{{meineapp/config/view.yml}}} definieren'' 
    854 {{{ 
    855 default: 
    856   components: 
    857     sidebar:  [bar, default] 
    858 }}} 
    859  
    860 Wenn das Layout ausgeführt wird, wird der Sidebar-Komponentenslot mit dem Ergebnis der {{{executeDefault()}}}-Methode der {{{barComponents}}}-Klasse innerhalb des {{{bar}}}-Moduls gefüllt, und diese Methode wird das {{{_default.php}}}-Partial anzeigen, das sich in {{{modules/bar/templates/}}} befindet. 
    861  
    862 Die Konfigurationskaskade ermöglicht Ihnen, diese Einstellung für ein bestimmtes Modul zu überschreiben. In einem Benutzermodul möchten Sie vielleicht, dass in der Sidebar der Benutzername und die Anzahl Artikel stehen, die dieser Benutzer veröffentlicht hat. In diesem Fall können Sie die Sidebar-Slot-Einstellung in der Modul-{{{view.yml}}} ändern wie in Codeabschnitt 7-40. 
    863  
    864 ''Codeabschnitt 7-40 - Den Sidebar-Komponentenslot spezialisieren in {{{meineapp/modules/user/config/view.yml}}}'' 
    865  
    866 {{{ 
    867 all: 
    868   components: 
    869     sidebar:  [bar, user] 
    870 }}} 
    871  
    872 Die Komponentendefinitionen, die diesen Slot behandeln sollen, sehen so aus wie in Codeabschnitt 7-41. 
    873  
    874 ''Codeabschnitt 7-41 - Vom Sidebar-Slot verwendete Komponenten in {{{modules/bar/actions/components.class.php}}}'' 
    875  
    876 {{{ 
    877 #!php 
    878 <?php 
    879 class barComponents extends sfComponents 
    880 { 
    881   public function executeDefault() 
    882   { 
    883   } 
    884   
    885   public function executeUser() 
    886   { 
    887     $current_user = $this->getUser()->getCurrentUser(); 
    888     $c = new Criteria(); 
    889     $c->add(ArticlePeer::AUTHOR_ID, $current_user->getId()); 
    890     $this->nb_articles = ArticlePeer::doCount($c); 
    891     $this->current_user = $current_user; 
    892   } 
    893 } 
    894 ?> 
    895 }}} 
    896  
    897 Codeabschnitt 7-42 zeigt die Views für diese zwei Komponenten. 
    898  
    899 ''Codeabschnitt 7-42 - Vom Sidebar-Komponentenslot verwendete Partials in {{{modules/bar/templates/}}}'' 
    900  
    901 {{{ 
    902 #!php 
    903 // _default.php 
    904 <p>This zone contains contextual information.</p> 
    905   
    906 // _user.php 
    907 <p>User name: <?php echo $current_user->getName() ?></p> 
    908 <p><?php echo $nb_articles ?> articles published</p> 
    909 }}} 
    910  
    911 Komponentenslots können Sie unter anderem einsezten für: Breadcrumb-Navigationen, kontextsensitive Navigationen sowie dynamische Einbindungen aller Art. Sie können im globalen Layout und in Templates verwendet werden, und sogar in anderen Komponenten. Die Konfigurationseinstellung eines Komponentenslots ist immer diejenige der Konfiguration der letzten aufgerufenen Aktion. 
    912  
    913 Wenn der Komponentenslot für ein bestimmtes Modul leer bleiben soll, definieren Sie ihn einfach als leer, wie in Codeabschnitt 7-43. 
    914  
    915 ''Codeabschnitt 7-43 - Einen Komponentenslot in der {{{view.yml}}} deaktivieren'' 
    916  
    917 {{{ 
    918 all: 
    919   components: 
    920     sidebar:  [] 
    921 }}} 
    922  
    923 = Output Escaping = 
    924  
    925 Wenn Sie dynamische Daten in ein Template einfügen, müssen Sie die Datenintegrität sicherstellen. Wenn Daten aus einem Formular kommen, besteht die Gefahr, dass sie bösartige Scripte enthalten, die versuchen, Cross-Site-Scripting-Attacken (XSS) auszuführen. Sie müssen den Output maskieren (escapen), so dass allfälliger darin enthaltener HTML-Code wirkungslos wird. 
    926  
    927 Nehmen Sie an, ein Benutzer füllt ein Eingabefeld mit dem folgenden Wert: 
    928  
    929 {{{ 
    930 <script>alert(document.cookie)</script> 
    931 }}} 
    932  
    933 Wenn Sie diesen Wert unvorsichtigerweise einfach ausgeben, wird das JavaScript in jedem Browser ausgeführt und erlaubt so noch wesentlich gefährlichere Angriffe als nur ein {{{alert}}}. Darum müssen Sie den Output maskieren, bevor Sie ihn anzeigen. Dann sieht er so aus: 
    934  
    935 {{{ 
    936 &lt;script&gt;alert(document.cookie)&lt;/script&gt; 
    937 }}} 
    938  
    939 Sie könnten den Output manuell maskieren, indem Sie ihn jedesmal mit {{{htmlentities()}}} umschliessen, aber das wäre sehr fehleranfällig. symfony bietet stattdessen ein spezielles System, genannt Output Escaping, das automatisch jeden dynamischen Output in einem Template maskiert. Es wird durch einen einfachen Parameter in der Applikations-{{{settings.yml}}} aktiviert. 
    940  
    941 == Output Escaping aktivieren == 
    942  
    943 Output Escaping wird global für eine Applikation in der {{{settings.yml}}} konfiguriert. Zwei Parameter bestimmen, wie Output Escaping arbeitet: Die Strategie bestimmt, wie die Variablen der View zur Verfügung gestellt werden, und die Methode ist die Standard-Maskierfunktion, die auf die Daten angewendet wird. 
    944  
    945 Die nächsten Abschnitte beschreiben diese Einstellungen detailliert, aber grundsätzlich ist das einzige, was Sie tun müssen, um Output Escaping zu aktivieren, den {{{escaping_strategy}}}-Parameter von seinem Standardwert {{{bc}}} auf {{{both}}} zu ändern wie in Codeabschnitt 7-44. 
    946  
    947 ''Codeabschnitt 7-44 - Output Escaping aktivieren in {{{meineapp/config/settings.yml}}}'' 
    948  
    949 {{{ 
    950 all: 
    951   .settings: 
    952     escaping_strategy: both 
    953     escaping_method:   ESC_ENTITIES 
    954 }}} 
    955  
    956 Jetzt wird {{{htmlentities()}}} standardmässig auf alle Ausgabevariablen angewandt. Wenn Sie in einer Aktion eine Testvariable wie folgt definieren: 
    957  
    958 {{{ 
    959 #!php 
    960 <?php 
    961 $this->test = '<script>alert(document.cookie)</script>'; 
    962 ?> 
    963 }}} 
    964  
    965 Dann wird diese Variable im Template wie folgt ausgegeben: 
    966  
    967 {{{ 
    968 echo $test; 
    969  => &gt;&lt;script&gt;alert(document.cookie)&lt;/script&gt; 
    970 }}} 
    971  
    972 Wenn Sie Output Escaping aktiviert haben, haben Sie in jedem Template Zugriff auf die Variable {{{$sf_data}}}. Es handelt sich dabei um ein Containerobjekt, das all die maskierten Variablen enthält. Sie können die Testvariable also auch so ausgeben: 
    973  
    974 {{{ 
    975 echo $sf_data->get('test'); 
    976 => &gt;&lt;script&gt;alert(document.cookie)&lt;/script&gt; 
    977 }}} 
    978  
    979     Das {{{$sf_data}}}-Objekt verwendet Array-Syntax, Sie können also anstatt {{{$sf_data->get('meinevariable')}}} die maskierten Parameter über {{{$sf_data['meinevariable']}}} erreichen. Es handelt sich aber eigentlich nicht um ein Array, weshalb Funktionen wie {{{print_r()}}} nicht funktionieren werden. 
    980  
    981 Dieses Objekt bietet Ihnen auch Zugriff zu den unmaskierten Rohdaten. Das ist hilfreich, wenn eine Variable HTML-Code enthält, der vom Browser interpretiert werden sollen, vorausgesetzt, Sie vertrauen dieser Variablen. Rufen Sie die {{{getRaw()}}}-Methode auf, wenn Sie die Rohdaten ausgeben möchten. 
    982  
    983 {{{ 
    984 echo $sf_data->getRaw('test'); 
    985  => <script>alert(document.cookie)</script> 
    986 }}} 
    987  
    988 Jedesmal, wenn Sie möchten, dass HTML-Variablen vom Browser interpretiert werden sollen, benötigen Sie die Rohdaten. Das ist auch der Grund, weshalb das Standardlayout {{{$sf_data->getRaw('sf_content')}}} verwendet, um ein Template einzubinden. Nur {{{$sf_content}}} funktioniert nämlich nicht, wenn Output Escaping aktiviert ist.. 
    989  
    990 == Escaping-Strategie == 
    991 Die {{{escaping_strategy}}}-Einstellung bestimmt, wie Variablen standardmässig ausgegeben werden. Die folgenden Werte sind möglich: 
    992  
    993     * {{{bc}}} (''backward compatible'', rückwärts-kompatibel): Variablen werden nicht maskiert, aber eine maskierte Version jeder Variablen ist im {{{$sf_data}}}-Container verfügbar. Die Daten sind also standardmässig im Rohformat, ausser wenn Sie über das {{{$sf_data}}}-Objekt auf die maskierten Daten zugreifen. {{{bc}}} ist die Standardeinstellung und Sie sollten sich bewusst sein, dass mit dieser Strategie Ihre Seite anfällig für XSS-Attacken ist. 
    994     * {{{both}}}: Alle Variablen werden standardmässig maskiert. Die Werte sind auch im {{{$sf_data}}}-Container verfügbar. Das ist die empfohlene Strategie, da Sie nur ein Risiko eingehen, wenn Sie absichtlich die Rohdaten ausgeben. Manchmal werden Sie unmaskierte Daten verwenden müssen – beispielsweise, wenn eine Variable HTML-Code enthält, der gerendert werden soll. Passen Sie also auf: Wenn Sie während der Entwicklung einer Applikation zu dieser Strategie wechseln, funktionieren gewisse Dinge womöglich nicht mehr. Die beste Idee ist es daher, diese Einstellung gleich von Beginn an zu verwenden. 
    995     * on: Werte sind nur im {{{$sf_data}}}-Container verfügbar. Das ist der sicherste und schnellste Weg, da Sie bei jedem Ausgeben einer Variablen auswählen müssen, ob Sie die maskierte Version mit {{{get()}}} oder die Rohdaten mit {{{getRaw()}}} ausgeben. Sie sind sich also jederzeit der Möglichkeit bewusst, dass die Daten korrumpiert sein könnten. 
    996     * off: Schaltet Output Escaping vollständig ab. Der {{{$sf_data}}}-Container ist in den Templates nicht verfügbar. Sie können diese Strategie anstelle von {{{bc}}} verwenden, um Ihre Applikation zu beschleunigen, wenn Sie sich sicher sind, dass Sie niemals maskierte Daten benötigen. 
    997  
    998 == Escaping-Helfer == 
    999  
    1000 Escaping-Helfer sind Funktionen, die eine maskierte Version ihrer Eingabe zurückgeben. Sie können als Standard-{{{escaping_method}}} in der {{{setting.yml}}} verwendet werden oder für einen bestimmten Wert in der View. Die folgenden Escaping-Helfer sind verfügbar: 
    1001  
    1002     * {{{ESC_RAW}}}: Maskiert den Wert nicht. 
    1003     * {{{ESC_ENTITIES}}}: Wendet die PHP-Funktion {{{htmlentities()}}} mit {{{ENT_QUOTES}}} als zweitem Parameter auf die Eingabe an 
    1004     * {{{ESC_JS}}}: Maskiert einen Wert, der in einem JavaScript-String als HTML verwendet wird. Hilfreich, wenn HTML dynamisch mit JavaScript verändert wird. 
    1005     * {{{ESC_JS_NO_ENTITIES}}}: Maskiert einen Wert, der in einen JavaScript-String gehört, aber fügt keine Entities hinzu. Das ist hilfreich, wenn der Wert z.B. in einer Dialogbox angezeigt wird. (Eine {{{meinString}}}-Variable wird angezeigt mit {{{javascript:alert(meinString)}}}.) 
    1006  
    1007 == Arrays und Objekte maskieren == 
    1008  
    1009 Output Escaping funktioniert nicht nur bei Strings, sondern auch bei Arrays und Objekten. Jeder Wert in einem Objekt oder Array wird seinen maskierten Zustand an seine Kinder weitergeben. Nehmen wir an, Ihre Strategie sei {{{both}}}. Dann zeigt Codeabschnitt 7-45 die Maskierungskaskade. 
    1010  
    1011 ''Codeabschnitt 7-45 - Escaping funktioniert auch bei Arrays und Objekten'' 
    1012  
    1013 {{{ 
    1014 #!php 
    1015 <?php 
    1016 // Klassendefinition 
    1017 class meineKlasse 
    1018 { 
    1019   public function testeSpezialZeichen($wert = '') 
    1020   { 
    1021     return '<'.$wert.'>'; 
    1022   } 
    1023 } 
    1024   
    1025 // In der Aktion 
    1026 $this->test_array = array('&', '<', '>'); 
    1027 $this->test_array_of_arrays = array(array('&')); 
    1028 $this->test_objekt = new meineKlasse(); 
    1029   
    1030 // Im Template 
    1031 <?php foreach($test_array as $wert): ?> 
    1032   <?php echo $wert ?> 
    1033 <?php endforeach; ?> 
    1034  => &amp; &lt; &gt; 
    1035 <?php echo $test_array_of_arrays[0][0] ?> 
    1036  => &amp; 
    1037 <?php echo $test_objekt->testeSpezialZeichen('&') ?> 
    1038  => &lt;&amp;&gt; 
    1039 }}} 
    1040  
    1041 Die Variablen im Template sind jedoch nicht von dem Typ, den Sie womöglich erwarten. Das Output-Escaping-System "dekoriert" sie und verwandelt sie in spezielle Objekte: 
    1042  
    1043 {{{ 
    1044 <?php echo get_class($test_array) ?> 
    1045  => sfOutputEscaperArrayDecorator 
    1046 <?php echo get_class($test_objekt) ?> 
    1047  => sfOutputEscaperObjectDecorator 
    1048 }}} 
    1049  
    1050 Das erklärt auch, warum einige Standard-PHP-Funktionen (wie {{{array_shift()}}}, {{{print_r()}}} usw.) bei maskierten Arrays nicht mehr funktionieren. Aber Sie können darauf immer noch mit {{{[]}}} zugreifen, sie mit {{{foreach}}} traversieren, und die Anzahl mit {{{count()}}} zurückgeben (wobei letzteres nur mit PHP 5.2 oder neuer funktioniert). Und in Templates sollten die Daten ohnehin schreibgeschützt sein, die meisten Zugriffe werden also auf Arten geschehen, die funktionieren. 
    1051  
    1052 Sie haben immer noch eine Möglichkeit, über das {{{$sf_data}}}-Objekt an die Rohdaten zu gelangen. Zusätzlich werden Methoden von maskierten Objekten so verändert, dass sie einen zusätzlichen Parameter akzeptieren: Eine Maskierungsmethode. Sie können also eine andere Maskierungsmethode wählen jedesmal, wenn Sie eine Variable in einem Template anzeigen, oder Sie können mit dem {{{ESC_RAW}}}-Helfer die Maskierung komplett abschalten. Codeabschnitt 7-46 zeigt ein Beispiel. 
    1053  
    1054 ''Codeabschnitt 7-46 - Methoden von maskierten Objekten akzeptieren einen zusätzlichen Parameter'' 
    1055 {{{ 
    1056 #!php 
    1057 <?php echo $test_object->testeSpezialZeichen('&') ?> 
    1058 => &lt;&amp;&gt; 
    1059 // Die drei folgenden Zeilen geben den gleichen Wert zurück 
    1060 <?php echo $test_object->testeSpezialZeichen('&', ESC_RAW) ?> 
    1061 <?php echo $sf_data->getRaw('test_object')->testeSpezialZeichen('&') ?> 
    1062 <?php echo $sf_data->get('test_object', ESC_RAW)->testeSpezialZeichen('&') ?> 
    1063  => <&> 
    1064 }}} 
    1065  
    1066 Wenn Sie in Ihren Templates mit Objekten arbeiten, werden Sie den Trick mit dem zusätzlichen Parameter häufig verwenden, da er die schnellste Möglichkeit bietet, Rohdaten direkt aus einem Methodenaufruf zu bekommen. 
    1067  
    1068     Die üblichen symfony-Variablen werden ebenfalls maskiert, wenn Sie Output Escaping aktivieren. Achten Sie also darauf: {{{$sf_user}}}, {{{$sf_request}}}, {{{$sf_param}}} und {{{$sf_context}}} funktionieren immer noch, aber ihre Methoden geben maskierte Daten zurück – es sei denn, Sie geben {{{ESC_RAW}}} als letzten Parameter bei den Methodenaufrufen an. 
    1069  
    1070 = Zusammenfassung = 
    1071 Viele verschiedene Tools stehen Ihnen zur Verfügung, um die Präsentationsschicht zu bearbeiten. Template erstellen Sie dank der Helfer innert Sekunden. Layouts, Partials, Komponenten und Komponentenslots bringen sowohl Modularität als auch Wiederverwendbarkeit. Die Viewkonfiguration bedient sich der Geschwindigkeitvorteile von YAML, um die (meisten) Seitenheader zu verwalten. Die Konfigurationskaskade bewahrt Sie davor, jede Einstellung für jede View zu definieren. Für jede Änderung der Präsentation, die von dynamischen Daten abhängt, hat die Aktion Zugriff auf das {{{sfResponse}}}-Objekt. Und die Sicht ist dank dem Output-Escaping-System sicher vor XSS-Angriffen.