Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

560 lines (513 sloc) 38.799 kb
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
Remove this if you use the .htaccess -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title>Symfony 4 absolute beginners</title>
<link rel="stylesheet" type="text/css" href="stylesheets/bootstrap.css">
<link rel="stylesheet" type="text/css" href="stylesheets/bootstrap-responsive.css">
<link rel="stylesheet" type="text/css" href="stylesheets/app.css">
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="script/app.js"></script>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<a class="brand" href="http://symfony.com/what-is-symfony">Sprache</a>
<ul class="nav">
<li><a href="index.html">Deutsch</a></li>
<li><a href="index_en.html">English</a></li>
<li><a href="index_fr.html">Fran&#231;ais</a></li>
</ul>
<ul class="nav pull-right">
<li class="divider-vertical"></li>
<li><a href="https://github.com/peponi/Symfony-for-absolute-beginners">Github</a></li>
</ul>
</div>
</div>
<div class="container">
<div class="row">
</div>
<div class="row">
<!-- Docs nav ================================================= -->
<div class="content">
<div class="span3 bs-docs-sidebar affix">
<a href="http://symfony.com/what-is-symfony"><img src="img/logo_symfony_header.png" alt="Symfony" id="logo_symfony"></a>
<div class="pageination">
<a href="index.html" class="marginleft20px"><- Seite 1</a> |
<span class="muted"> Seite 2 -></span>
</div>
<br>
<ul class="nav nav-list bs-docs-sidenav ">
<li><a id="nex" class="pointer"> 6. Projekt beginnen</a></li>
<li><a id="rou" class="pointer"> 7. Route erstellen</a></li>
<li><a id="for" class="pointer"> 8. Formular generieren</a></li>
<li><a id="per" class="pointer"> 9. Formulardaten speichern</a></li>
</ul>
<br>
</div>
<div class="span9 offset3">
<div class="span5 offset3 marginbottom20">
<img src="img/a_sensiolabs_product.png" alt="a SensioLabs product" id="sensiolab">
<a href="http://symfony.com/download"> <img src="img/download.jpeg"></a>
</div>
<section id="next">
<h1>Projekt beginnen</h1>
<p>Bevor man in Symfony die erste Zeile Code schreibt, sollte bereits ein HTML Prototyp bereit liegen. Wenn dem nicht so ist, sollte man wenigstens vage Vorstellungen von der Funktion, der Arbeitsweise, der GUI und dem Aussehen der Seite, die man erstellen möchte zu Papier gebracht haben.<p>
<p>Um schnell grundlegende Strukturen der Seite anzulegen, eignet sich ein <a href="https://de.wikipedia.org/wiki/Rapid_Application_Development">Rapid Prototype Framework</a> wie
<a href="http://twitter.github.com/bootstrap/scaffolding.html">Twitter Bootstrap</a>,
<a href="http://html5boilerplate.com/html5boilerplate.com/dist/mobile/">HTML5Boilerplate</a>,
<a href="http://foundation.zurb.com/docs/grid.php">Foundation</a>,
<a href="http://www.prowebdesign.ro/yet-another-boilerplate-for-responsive-mobile-web-design-yamb-v-2/">yamb</a> oder
<a href="http://gumbyframework.com/docs/grid">Gumpy</a> .
</p>
<p>Das <a href="http://www.gridsystemgenerator.com/">Gridsystem</a> eines dieser Frameworks reicht fürs Erste aus um Bereiche zu schaffen, in die später z.B. eine Navigationsbar, Formulare oder Videos kommen sollen.</p>
<p><i class="icon-info-sign"></i> Hier findest du eine <a href="http://usablica.github.com/front-end-frameworks/compare.html?v=2.0">&Uuml;bersicht</a></p>
<p>Bleiben wir beim Restaurant Beispiel und bauen mal folgende Seitenstruktur:<p>
<img src="img/wireframe_website.png">
<p>In Bootstrap w&uuml;rde das wie folgt aussehen:</p>
<pre class="highlight">
<<span class="sd">!DOCTYPE html</span>>
<<span class="c1">html</span> lang=<span class="s1">"en"</span>>
<<span class="c1">head</span>>
<<span class="c1">link</span> rel=<span class="s1">"stylesheet"</span> type=<span class="s1">"text/css"</span> href=<span class="s1">"css/bootstrap.css"</span>>
<<span class="c1">link</span> rel=<span class="s1">"stylesheet"</span> type=<span class="s1">"text/css"</span> href=<span class="s1">"css/bootstrap-responsive.css"</span>>
<span class="g">< /</span><span class="c1">head</span>>
<<span class="c1">body</span>>
<<span class="c1">div</span> class=<span class="s1">"container"</span>>
<<span class="c1">div</span> class=<span class="s1">"row-fluid"</span>>
<<span class="c1">div</span> class=<span class="s1">"span3"</span>><span class="g">< /</span><span class="c1">div</span>>
<<span class="c1">div</span> class=<span class="s1">"span9"</span>><span class="g">< /</span><span class="c1">div</span>>
<span class="g">< /</span><span class="c1">div</span>>
<span class="g">< /</span><span class="c1">div</span>>
<span class="g">< /</span><span class="c1">body</span>>
<span class="g">< /</span><span class="c1">html</span>>
</pre>
<p>That's all. Keep it simple!<p>
<p>Das <b>div span3</b> wird eine statische Fl&auml;che in dem die Navigations-Links abgelegt werden, und das <b>div span9</b> wird eine dynamische Fl&auml;che wo der Content reingeladen wird, den wir über die Links anfordern.</p>
<p>Da die CSS Dateien von Symfony <a href="#templates">schon inkludiert wurden</a>, und die header / body Struktur ebenfalls schon in <b>Symfony/app/Resources/view/base.html.twig</b> generiert wird, brauchen wir nur diesen Teil</p>
<pre class="highlight">
<<span class="c1">div</span> class=<span class="s1">"container"</span>>
<<span class="c1">div</span> class=<span class="s1">"row-fluid"</span>>
<<span class="c1">div</span> class=<span class="s1">"span3"</span>><span class="g"> hier kommen die Links rein < /</span><span class="c1">div</span>>
<<span class="c1">div</span> class=<span class="s1">"span9"</span>><span class="g"> hier kommt der Content rein < /</span><span class="c1">div</span>>
<span class="g">< /</span><span class="c1">div</span>>
<span class="g">< /</span><span class="c1">div</span>>
</pre>
<p>in die <b>/Symfony/src/YourCompany/RestaurantBundle/Resources/views/Default/index.html.twig</b> kopieren.</p>
<br>
<p>Was haben wir bis jetzt? </p>
<ul>
<li>Die Datenbank und die PHP Klassen, welche die Tabellen abbilden unter <b>RestaurantBundle/Entity/</b></li>
<li>Eine leere HTML Datei die aber schon den Bereich der Seite aufgliedert<br><b>RestaurantBundle/Resources/views/Default/index.html.twig</b></li>
<li>Eine leere Controller Klasse in <b>RestaurantBundle/Controller/DefaultController.php</b> die bisher nur auf eine Action reagiert, dem Aufruf von <a href="http://127.0.0.1:8080/Symfony/web/app_dev.php/demo/">http://127.0.0.1:8080/Symfony/web/app_dev.php/demo/</a></li>
</ul>
<p>Wir haben also das <b>Model</b> stehen, einen leeren <b>Controller</b> und eine nichts anzeigende <b>View</b>.</p>
</section>
<section id="routen">
<h2>Routen erstellen</h2>
<p>Damit in der View etwas angezeigt werden kann, müssen wir im Controller Sachen aus der Datenbank holen und zur View senden, da wir aber noch nichts in der Datenbank haben, ist es sinnvoll erstmal ein Formular für eine der beiden Tabellen zu bauen, um diese zu bef&uuml;llen.</p>
<p>&Ouml;ffnen wir also mal den <b>DefaultController.php</b> und schauen uns an, was bisher drin steht.</b>
<pre class="highlight">
<span class="k">class</span> DefaultController <span class="k">extends</span> Controller
{
<span class="sd">/**
* @Route("/demo"/{name})
* @Template()
*/</span>
<span class="k">public function</span> indexAction($name)
{
<span class="k">return</span> <span class="k">array</span>(<span class="s1">"name"</span> => $name);
}
}
</pre>
<p>Wenn du bei der <a href="#entity">Generierung</a> der Entities <b>Annotations</b> ausgew&auml;hlt hast, sollte die Route die die indexAction() ausl&ouml;st, direkt &uuml;ber der Function stehen.<br>
Wenn du <b>yml</b> ausgew&auml;hlt hast, sollte &uuml;ber <b>public function indexAction()</b> nichts stehen. Die Route findest du daf&uuml;r in <b>RestaurantBundle/Resources/config/routing.yml</b>.</p>
<pre class="highlight">
YourCompanyRestaurantBundle_homepage:
pattern: /demo/{name}
defaults: { _controller: YourCompanyRestaurantBundle:Default:index }
</pre>
<p>Der <b>Vorteil</b> der Annotations ist, dass du alle Routen direkt &uuml;ber den Funktionen siehst die ausgef&uuml;hrt werden, wenn die Route aufgerufen wird.
<br>Der <b>Vorteil</b> alle Routen in einer yml Datei zu haben, ist der, dass man alle Routen &uuml;bersichtlich in einem Blick hat. Der <b>Nachteil</b> dabei ist, dass man eine weitere Datei st&auml;ndig im Editor offen haben muss um Route und Funktion abzugleichen.</p>
<p>Ich pers&ouml;nlich nutze aus genanntem Grund lieber die Annotations. Aber das ist Geschmackssache.</p>
<br>
<p id="routealias">Da wir zuerst ein Formular erstellen wollen um die Datenbank zu bef&uuml;llen, erstellen wir im DefaultController eine neue Action und eine neue Route die auf diese Action verweist.</p>
<pre class="highlight">
<span class="k">class</span> DefaultController <span class="k">extends</span> Controller
{
...
<span class="sd">/**
* @Route("/insert/restaurant", name="insertrestaurant")
* @Template()
*/</span>
<span class="k">public function</span> insertrestaurantAction()
{
<span class="k">return</span> $this<span class="k">-></span>render(<span class="s1">'YourCompanyRestaurantBundle:Default:index.html.twig'</span>);
}
}
</pre>
<p>Wir sehen die Route &uuml;ber der neuen Funktion, die &uuml;ber <a href="http://127.0.0.1:8080/Symfony/web/app_dev.php/insert/restaurant">http://127.0.0.1:8080/Symfony/web/app_dev.php/insert/restaurant</a> aufgerufen werden kann. Im gleichen Zug haben wir mit <b>name="insertrestaurant"</b> der Route einen <b>Alias</b> gegeben. Das ist z.B. dann wichtig wenn wir die Route im index.html.twig in einem href=" " aufrufen wollen.</p>
<p>F&uuml;r die yml Freunde m&uuml;sste die Route wie folgt aussehen.</p>
<pre class="highlight">
..
YourCompanyRestaurantBundle_insertrestaurant:
pattern: /insert/restaurant
defaults: { _controller: YourCompanyRestaurantBundle:Default:insertrestaurant }
</pre>
<br>
<p>Im Moment rufen wir in der <b>insertrestaurantAction()</b> nur die Controller Funktion render() auf, die uns eine HTML Datei zusammenbastelt, in der nichts drin steht ausser unserem Bootstrap Grid.</p>
</section>
<section id="form">
<h2>Ein Formular generieren</h2>
<p>Ein Formular m&uuml;ssen wir nicht von Hand ins HTML hacken, das kann ein Formulargenerator von Symfony f&uuml;r uns &uuml;bernehmen.</p>
<pre class="highlight " id="createview">
<span class="k">use</span> YourCompany\RestaurantBundle\Entity\Restaurant;
<span class="k">class</span> DefaultController <span class="k">extends</span> Controller
{
...
<span class="k">public function</span> insertrestaurantAction()
{
$form = $this<span class="k">-></span>createFormBuilder(<span class="k">new</span> Restaurant)
<span class="k">-></span>add(<span class="s1">'name'</span>, <span class="s1">'text'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Name"</span>))
<span class="k">-></span>add(<span class="s1">'startuptime'</span>, <span class="s1">'datetime'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Öffnungszeit"</span>))
<span class="k">-></span>add(<span class="s1">'location'</span>, <span class="s1">'text'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Ort"</span>))
<span class="k">-></span>add(<span class="s1">'description'</span>, <span class="s1">'text'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Beschreibung"</span>))
<span class="k">-></span>getForm();
<span class="k">return</span> $this<span class="k">-></span>render(<span class="s1">'YourCompanyRestaurantBundle:Default:index.html.twig'</span>,
<span class="k">array</span>(
<span class="s1">'form'</span> => $form<span class="k">-></span>createView()
));
}
}
</pre>
<p>Was wir hier tun ist die <b>createFormBuilder()</b> Funktion der Controller Klasse aufzurufen und ihr ein leeres Restaurant Objekt mitzugeben, damit sie weiss, wie die Struktur des Formulars ausehen soll.</p>
<p>Die Struktur bildet sich aus den Attributen des Restaurant Objektes <b>$name</b>, <b>$startuptime</b>, <b>$location</b> und <b>$description</b> denen wir jeweils ein <a href="http://www.w3schools.com/tags/att_input_type.asp">Input Type</a> zuweisen. Alle Input Types die man den Feldern im Formbuilder vergeben kann, sind <a href="http://symfony.com/doc/current/book/forms.html#built-in-field-types">hier</a> aufgelistet.<br>Im array() danach vergeben wir noch ein Label, das über dem Input Feld stehen wird.</p>
<p>Der render() Funktion unten &uuml;bergeben wir noch als Array das <b>$form</b> Objekt mit und rufen gleich noch <b>createView()</b> auf, was uns das HTML f&uuml;r die Formularfelder generiert.</p>
<p>Wenn wir jetzt <a href="http://127.0.0.1:8080/Symfony/web/app_dev.php/insert/restaurant">http://127.0.0.1:8080/Symfony/web/app_dev.php/insert/restaurant</a> aufrufen, erzeugen wir zwar HTML Formularfelder und senden sie an <b>index.html.twig</b>, aber leider bringt uns das wenig wenn wir im <b>index.html.twig</b> noch kein Formular haben, in dem wir sie anzeigen könnten.</p>
<p>Also ab in die <b>RestaurantBundle/Resources/views/Default/index.html.twig</b> Datei.</p>
<pre class="highlight">
<<span class="c1">div</span> class=<span class="s1">"container"</span>>
<<span class="c1">div</span> class=<span class="s1">"row-fluid"</span>>
<<span class="c1">div</span> class=<span class="s1">"span3"</span>><span class="g"> hier kommen die Links rein < /</span><span class="c1">div</span>>
<<span class="c1">div</span> class=<span class="s1">"span9"</span>><span class="g">
<<span class="c1">form</span> action=<span class="s1">""</span> method=<span class="s1">"post"</span>>
hier sollen jetzt die Elemente des Formobjektes rein
<<span class="c1">input</span> type=<span class="s1">"submit"</span> class=<span class="s1">"btn btn-info"</span> />
<span class="g">< /</span><span class="c1">form</span>>
< /</span><span class="c1">div</span>>
<span class="g">< /</span><span class="c1">div</span>>
<span class="g">< /</span><span class="c1">div</span>>
</pre>
<p>Wie du siehst haben wir in die zweite Spalte unseres Bootstrap Grids ein <b>form tag</b> hinzugef&uuml;gt und einen <b>submit button</b>, der die Bootstrap CSS Klasse <a href="http://twitter.github.com/bootstrap/base-css.html#buttons">btn-info</a> beinhaltet, damit der Button sch&ouml;n blau wird.</p>
<p>Als n&auml;chstes m&uuml;ssen wir irgendwie die Formular-Input-Felder, die wir im Controller <a href="#createview">schon zu HTML gerendert</a> haben und in der .twig Datei in Gestalt des Parameters <b>'form'</b> schon auf uns warten, in die Mitte des HTML Formulars bringen.</p>
<p>Daf&uuml;r gibt <a href="http://symfony.com/doc/current/book/forms.html#rendering-a-form-in-a-template"> es verschiedene M&ouml;glichkeiten</a> . Um die Input-Felder aus dem Formular-Objekt <b>'form'</b> jetzt auszupacken und der HTML Datei anzuzeigen, nutze ich erst mal <b>form_widget(form)</b>.</p>
<pre class="highlight">
..
<<span class="c1">div</span> class=<span class="s1">"span9"</span>><span class="g">
<<span class="c1">form</span> action=<span class="s1">""</span> method=<span class="s1">"post"</span>>
{{ <span class="k">form_widget</span></7span>(form) }}
<<span class="c1">input</span> type=<span class="s1">"submit"</span> class=<span class="s1">"btn btn-info"</span> />
<span class="g">< /</span><span class="c1">form</span>>
< /</span><span class="c1">div</span>>
..
</pre>
<p>Die Twig Funktion <b>form_widget()</b>, der wir das Formular-Objekt aus dem Parameter &uuml;bergeben, packt alle Inputfelder, die wir im Controller definiert haben, aus und f&uuml;gt sie austomatisch ein.<br>Praktisch, allerdings will man oft die Anordnung der Formularfelder selbst bestimmen.</p>
<p>Zu diesem Zweck gibt es die Twig Funktion <b>form_row()</b>, der wir jedes Feld einzeln übergeben m&uuml;ssen.
<pre class="highlight">
..
<<span class="c1">div</span> class=<span class="s1">"span9"</span>><span class="g">
<<span class="c1">form</span> action=<span class="s1">"</span>{{ <span class="k">path</span>( insertrestaurant ) }}<span class="s1">"</span> method=<span class="s1">"post"</span> {{ <span class="k">form_enctype</span>(form) }}>
{{ <span class="k">form_row</span>(form.name) }}
{{ <span class="k">form_row</span>(form.startuptime) }}
{{ <span class="k">form_row</span>(form.location) }}
{{ <span class="k">form_row</span>(form.description) }}
<<span class="c1">input</span> type=<span class="s1">"submit"</span> class=<span class="s1">"btn btn-info"</span> />
<span class="g">< /</span><span class="c1">form</span>>
< /</span><span class="c1">div</span>>
..
</pre>
<p><i class="icon-info-sign"></i> Ihr erinnert euch, das sind die Felder, die wir oben <a href="#form"> im Controller definiert</a> haben.</p>
<p>Weiterhin rufe ich die Twig Funktion <b>path()</b> oben im <b>action=""</b> Attribute auf und &uuml;bergebe ihr den Alias Namen f&uuml;r unsere <a href="#routealias">Route</a>. <b>path()</b> generiert uns die relative Route zu unser <b>insertrestaurantAction()</b> im Controller.</p>
<dl class="accordion">
<dt class="margintop20 info3 blue">
<p><i class="icon-info-sign"></i>
OK gut und sch&ouml;n, aber was ist jetzt dieses <a href="http://twig.sensiolabs.org/">Twig</a> schon wieder?</p>
</dt>
<dd class="marginleft20px info3">
<p>Twig ist eine Auszeichnungsprache mit deren Hilfe ich die Parameter-Objeket im HTML anzeigen oder ausf&uuml;hren kann.</p>
<code>{{ <span class="k">form_row</span>(form.name) }}</code>
<p>Ist genau dasselbe wie, wenn ich Folgendes schreiben würde</p>
<code><span class="g">< ?</span><span class="sd">php</span> echo $view['form']<span class="k">-></span>row($form['name']) ?></code>
<p>Aber ist doch viel sch&ouml;ner und handlicher oder?</p>
</dd>
</dl>
<p>Soweit so gut.</p>
<p>Wenn wir jetzt <a href="http://127.0.0.1:8080/Symfony/web/app_dev.php/insert/restaurant">http://127.0.0.1:8080/Symfony/web/app_dev.php/insert/restaurant</a> aufrufen, erzeugt uns die Controller Funktion <b>insertrestaurantAction()</b> HTML Formularfelder f&uuml;r jede Spalte der Tabelle Restaurant und übergibt sie dem index.html.twig Template, wo wir sie mit Hilfe von {{ form_row(form.name) }} anzeigen.</p>
<p>Nach dem wir das Formular ausgef&uuml;llt haben und es mit einem Klick auf den Submit-Button abschicken, senden wir es an die Route <b>/insert/restaurant</b> zur Controller Funktion <b>insertrestaurantAction()</b> wo genau ... nichts passiert</b>.</p>
<p>Damit die Daten in die Datenbank gespeichert werden, m&uuml;ssen wir mit insertrestaurantAction() diese F&auml;higkeit hinzuf&uuml;gen.</p>
</section>
<section id="persist">
<h2>Formular Daten in die Datenbank schreiben</h2>
<p>Die Controllerfunktion <b>insertrestaurantAction()</b> sieht im Moment so aus.</p>
<pre class="highlight">
..
<span class="k">public function</span> insertrestaurantAction()
{
$form = $this<span class="k">-></span>createFormBuilder(<span class="k">new</span> Restaurant)
<span class="k">-></span>add(<span class="s1">'name'</span>, <span class="s1">'text'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Name"</span>))
<span class="k">-></span>add(<span class="s1">'startuptime'</span>, <span class="s1">'datetime'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Öffnungszeit"</span>))
<span class="k">-></span>add(<span class="s1">'location'</span>, <span class="s1">'text'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Ort"</span>))
<span class="k">-></span>add(<span class="s1">'description'</span>, <span class="s1">'text'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Beschreibung"</span>))
<span class="k">-></span>getForm();
<span class="k">return</span> $this<span class="k">-></span>render(<span class="s1">'YourCompanyRestaurantBundle:Default:index.html.twig'</span>,
<span class="k">array</span>(
<span class="s1">'form'</span> => $form<span class="k">-></span>createView()
));
}
</pre>
<p>Ein Parameter in dem die Formulardaten stecken wird hier gar nicht erwartet.</p>
<p>Das &auml;ndern wir schnell, in dem wir ein leers Objekt vom Typ Request als Parameter definieren, auf das die Formulardaten, die hier ankommen, gemappt werden können.</p>
<pre class="highlight">
<span class="k">use</span> Symfony\Component\HttpFoundation\Request;
..
<span class="k">public function</span> insertrestaurantAction(Request $request)
{
..
</pre>
<p>Wir fügen noch den Pfad ganz oben im Controller hinzu, wo die Request Klasse zu finden ist</p>
<p>Danach brauchen wir eine Weiche die unterscheidet, ob ein Formular generiert und zum .twig geschickt <b>oder</b> ob schon eines vorhanden ist, das abgespeichert werden soll. Sonst w&uuml;rde das Programm an dieser Stelle immer wieder ein neues Formular erzeugen und wir drehen uns im Kreis</p>
<pre class="highlight">
..
<span class="k">public function</span> insertrestaurantAction(Request $request)
{
$form = $this<span class="k">-></span>createFormBuilder(<span class="k">new</span> Restaurant)
<span class="k">-></span>add(<span class="s1">'name'</span>, <span class="s1">'text'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Name"</span>))
<span class="k">-></span>add(<span class="s1">'startuptime'</span>, <span class="s1">'datetime'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Öffnungszeit"</span>))
<span class="k">-></span>add(<span class="s1">'location'</span>, <span class="s1">'text'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Ort"</span>))
<span class="k">-></span>add(<span class="s1">'description'</span>, <span class="s1">'text'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Beschreibung"</span>))
<span class="k">-></span>getForm();
<span class="k">if</span>( $request<span class="k">-></span>get(<span class="k">"restaurant"</span>) == <span class="k">NULL</span> )
{
<span class="k">return</span> $this<span class="k">-></span>render(<span class="s1">'YourCompanyRestaurantBundle:Default:index.html.twig'</span>,
<span class="k">array</span>(
<span class="k">'form'</span> => $form<span class="k">-></span>createView()
));
}
<span class="k">else</span>
{
<span class="k">if</span> ( $request<span class="k">-></span>getMethod() == <span class="s1">'POST'</span> )
{
$form<span class="k">-></span>bind($request<span class="k">-></span>get(<span class="s1">"restaurant"</span>));
$em = $this<span class="k">-></span>getDoctrine()<span class="k">-></span>getEntityManager();
$em<span class="k">-></span>persist($form<span class="k">-></span>getData());
$em<span class="k">-></span>flush();
<span class="k">return</span> new Response(<span class="s1">'Restaurant daten wurden in die DB geschrieben'</span>);
}
}
}
</pre>
<p>Was wir hier tun, ist es den $request zu durchsuchen ob ein Restaurant Objekt enthalten ist, wenn nicht, dann rendern wir das index.html.twig und senden die Restaurant-Formularfelder zu dieser Datei. Wenn ein Restaurant Objekt im <b>$request</b> ist, schauen wir schnell noch ob die <a href="http://de.wikipedia.org/wiki/Hypertext_Transfer_Protocol#HTTP_GET">HTTP GET Methode</a> auch POST ist und fahren fort. Die Zeile</p>
<code>$form<span class="k">-></span>bind($request<span class="k">-></span>get("restaurant"));</code>
<p>macht folgendes:</p>
<p>Wir rufen die <b>bind()</b> Funktion des leeren Formular-Objektes, das wir oben in der 5. Zeile generiert haben auf und &uuml;bergben ihr das Restaurant Objekt aus dem <b>$request</b> Parameter. Die <b>bind()</b> Funktion saugt jetzt alle Werte, die wir im HTML Formular eingetragen haben, aus dem <b>$request</b> Objekt raus und packt sie in das Formular-Objekt <b>$form</b>.</p>
<p>Danach erzeugen wir einen Doctrine Entity Manager der sich um unser Restaurant k&uuml;mmern soll.</p>
<code>$em = $this<span class="k">-></span>getDoctrine()<span class="k">-></span>getEntityManager();</code>
<p>Diesem Entity Manager sagen wir das er Daten persistieren soll und zwar die Daten unseres $form Objektes, aus dem wir mit getData() alle wichtigen Daten raussaugen.</p>
<code>$em<span class="k">-></span>persist($form<span class="k">-></span>getData());</code>
<p>Dann sp&uuml;len wir alles herunter mit <b>flush()</b> und <b>speichern eine neue Zeile in der Restaurant Tabelle</b>.</p>
<p>Als letztes erzeugen wir noch ein Response Objekt, da <b>jede Symfony-Controller-Funktion als Rückgabewert ein Repsonse Objekt haben muss</b>.</p>
<p>Jetzt k&ouml;nnen wir uns davon &Uuml;berzeugen das die Formulardaten in die MySQL Datenbank geschrieben wurden</p>
<pre class="highlight">
mysql -u root -p
> use symfony;
> select * from Restaurant;
> exit;
</pre>
</section>
<section id="view">
<h2>Daten aus der Datenbank anzeigen</h2>
<p>Um die Daten, die jetzt in der Restaurant Tabelle stecken, in einer HTML Datei anzuzeigen, erzeugen wir erst mal eine neue Controllerfunktion und eine Route, die darauf verweist.</p>
<pre class="highlight">
..
<span class="sd">/**
* @Route("/show/restaurant", name="showrestaurant")
* @Template()
*/</span>
<span class="k">public function</span> showrestaurantAction()
{
$restaurants = $this<span class="k">-></span>getDoctrine()<span class="k">-></span>getRepository(<span class="s1">'YourCompanyRestaurantBundle:Restraurant'</span>)<span class="k">-></span>findAll();
<span class="k">return</span> $this<span class="k">-></span>render(<span class="s1">'YourCompanyRestaurantBundle:Default:index.html.twig'</span>);
}
..
</pre>
<p>Um Daten aus der Datenbank zu holen verwenden wir wieder eine Funktion von Doctrine, <b/>getRepository()</b>.</p>
<pre class="highlight">
..
<span class="sd">/**
* @Route("/show/restaurant", name="showrestaurant")
* @Template()
*/</span>
<span class="k">public function</span> showrestaurantAction()
{
$restaurants = $this<span class="k">-></span>getDoctrine()<span class="k">-></span>getRepository(<span class="s1">'YourCompanyRestaurantBundle:Restraurant'</span>)<span class="k">-></span>findAll();
<span class="k">return</span> $this<span class="k">-></span>render(<span class="s1">'YourCompanyRestaurantBundle:Default:index.html.twig'</span>,
<span class="k">array</span>(
<span class="s1">'restaurant'</span> => $restaurants
));
}
..
</pre>
<p>Wir speichern das SQL-Result in <b>$restaurants</b> und übergeben diese Variable als Parameter der <b>render()</b> Funktion, damit wir in der html.twig Datei darauf zugreifen k&ouml;nnen.</p>
<p>Das erzeugt jetzt einige Fehler, da wir die Daten an die <b>index.html.twig</b> senden, mit der wir im vorangehenden Kapitel in der index.html.twig mit dem Parameter <b>form</b> gearbeitet haben. Das heisst die <b>form_row(form)</b> Funktion erwartet einen Parameter <b>form</b>, der aber gar nicht existiert, weil wir ihn in unsere neue <b>showrestaurantAction()</b> Controller Funktion <b>nicht mit übergeben</b>.</p>
<p>Daf&uuml;r gibt es jetzt 2 M&ouml;glichkeiten:</p>
<ul>
<li>wir erstellen ein neues Twig Template showrestaurants.html.twig und rendern es im Controller </li>
<li>wir erstellen ein showrestaurants.html.twig aber rendern trozdem weiter die index.html.twig</li>
</ul>
<p>Wie funktioniert die 2. L&ouml;sung?</p>
<p>Twig gibt uns ja die M&ouml;glichkeit andere Twigdateien zu implementieren.</p>
<code class="highlight">{% <span class="c1">include</span> showrestaurants.html.twig %}</code>
<p>Damit k&ouml;nnen wir immer genau das Twig Template im rechten Teil der index.html.twig einbinden. Das ben&ouml;tigen wir um die Daten, die wir im Controller zusammenstellen, anzuzeigen.</p>
<p>Erstellen wir zuerst ein Template um die Restaurants anzuzeigen und lagern danach die Formulardaten aus der <b>index.html.twig</b> in eine <b>insertrestaurant.html.twig</b> aus</p>
<p>Die Restaurants k&ouml;nnten z.B. in einer <a href="http://twitter.github.com/bootstrap/base-css.html#tables">Tabelle</a> wie dieser anzeigt werden.</p>
<pre class="highlight">
<span class="sd">// YourCompany/RestaurantBundle/Resources/views/Default/showrestaurants.html.twig</span>
<<span class="c1">table</span> class=<span class="s1">"table table-hover"</span>>
<<span class="c1">thead</span>>
<<span class="c1">tr</span>>
<<span class="c1">th</span>>Name<<span class="c1">/th</span>>
<<span class="c1">th</span>>&Ouml;ffnungszeit<<span class="c1">/th</span>>
<<span class="c1">th</span>>Ort<<span class="c1">/th</span>>
<<span class="c1">th</span>>Beschreibung<<span class="c1">/th</span>>
<<span class="c1">/tr</span>>
<<span class="c1">/thead</span>>
<<span class="c1">tbody</span>>
{% <span class="c1">for</span> restaurant <span class="c1">in</span> restaurants %}
<<span class="c1">tr</span>>
<<span class="c1">td</span>>{{ restaurant.name }}<<span class="c1">/td</span>>
<<span class="c1">td</span>>{{ restaurant.startuptime }}<<span class="c1">/td</span>>
<<span class="c1">td</span>>{{ restaurant.location }}<<span class="c1">/td</span>>
<<span class="c1">td</span>>{{ restaurant.description }}<<span class="c1">/td</span>>
<<span class="c1">/tr</span>>
{% <span class="c1">endfor</span> %}
<<span class="c1">/tbody</span>>
<<span class="c1">/table</span>>
</pre>
<p>Und diesen Teil schneiden wir aus der index.html.twig und kopieren ihn in die insertrestaurant.html.twig</p>
<pre class="highlight">
<<span class="c1">form</span> action=<span class="s1">"</span>{{ <span class="k">path</span>( insertrestaurant ) }}<span class="s1">"</span> method=<span class="s1">"post"</span> {{ <span class="k">form_enctype</span>(form) }}>
{{ <span class="k">form_row</span>(form.name) }}
{{ <span class="k">form_row</span>(form.startuptime) }}
{{ <span class="k">form_row</span>(form.location) }}
{{ <span class="k">form_row</span>(form.description) }}
<<span class="c1">input</span> type=<span class="s1">"submit"</span> class=<span class="s1">"btn btn-info"</span> />
<span class="g">< /</span><span class="c1">form</span>>
</pre>
<p>Nun brauchen wir also nur noch einen Schalter in der <b>index.html.twig</b>, der immer genau die Twig Datei einbindet, an die wir im Controller Daten senden wollen.</p>
<pre class="highlight">
<<span class="c1">div</span> class=<span class="s1">"container"</span>>
<<span class="c1">div</span> class=<span class="s1">"row-fluid"</span>>
<<span class="c1">div</span> class=<span class="s1">"span3"</span>><span class="g"> hier kommen die Links rein < /</span><span class="c1">div</span>>
<<span class="c1">div</span> class=<span class="s1">"span9"</span>><span class="g">
{% <span class="c1">if</span> pathname <span class="c1">is</span> defined %}
{% <span class="c1">if</span> pathname == <span class="s1">"showrestaurant"</span> %}
{% <span class="k">include</span> <span class="s1">'YourCompanyRestaurantBundle:Default:showrestaurant.html.twig'</span> %}
{% <span class="c1">elseif</span> pathname == <span class="s1">"insertrestaurant"</span> %}
{% <span class="k">include</span> <span class="s1">'YourCompanyRestaurantBundle:Default:insertrestaurant.html.twig'</span> %}
{% <span class="c1">endif</span> %}
{% <span class="c1">endif</span> %}
< /</span><span class="c1">div</span>>
<span class="g">< /</span><span class="c1">div</span>>
<span class="g">< /</span><span class="c1">div</span>>
</pre>
<p>Um im <b>index.html.twig</b> zu wissen welche Twig Datei eingebunden werden soll, m&uuml;ssen wir in den Controllerfunktionen einen Wert, eine Adressierung mitgeben, z.B. den <b>pathname</b> der Route.</p>
<pre class="highlight">
..
<span class="sd">/**
* @Route("/show/restaurant", name="showrestaurant")
* @Template()
*/</span>
<span class="k">public function</span> showrestaurantAction()
{
$restaurants = $this<span class="k">-></span>getDoctrine()<span class="k">-></span>getRepository(<span class="s1">'YourCompanyRestaurantBundle:Restraurant'</span>)<span class="k">-></span>findAll();
<span class="k">return</span> $this<span class="k">-></span>render(<span class="s1">'YourCompanyRestaurantBundle:Default:index.html.twig'</span>,
<span class="k">array</span>(
<span class="s1">'restaurant'</span> => $restaurants,
<b><span class="s1">'pathname'</span> => <span class="s1">'showrestaurant'</span></b>
));
}
..
</pre>
<p>Dasselbe machen wir jetzt in der Funktion <b>insertrestaurantAction()</b>.</p>
<pre class="highlight">
..
<span class="k">public function</span> insertrestaurantAction(Request $request)
{
$form = $this<span class="k">-></span>createFormBuilder(<span class="k">new</span> Restaurant)
<span class="k">-></span>add(<span class="s1">'name'</span>, <span class="s1">'text'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Name"</span>))
<span class="k">-></span>add(<span class="s1">'startuptime'</span>, <span class="s1">'datetime'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Öffnungszeit"</span>))
<span class="k">-></span>add(<span class="s1">'location'</span>, <span class="s1">'text'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Ort"</span>))
<span class="k">-></span>add(<span class="s1">'description'</span>, <span class="s1">'text'</span>, <span class="k">array</span>(<span class="s1">"label"</span> => <span class="s1">"Beschreibung"</span>))
<span class="k">-></span>getForm();
<span class="k">if</span>( $request<span class="k">-></span>get("restaurant") == <span class="s1">NULL</span> )
{
<span class="k">return</span> $this<span class="k">-></span>render(<span class="s1">'YourCompanyRestaurantBundle:Default:index.html.twig'</span>,
<span class="k">array</span>(
<span class="k">'form'</span> => $form<span class="k">-></span>createView(),
<b><span class="s1">'pathname'</span> => <span class="s1">'showrestaurant'</span></b>
));
}
...
}
</pre>
<p>Jetzt kann man über folgende Routen im Browser aufrufen</p>
<ul class="liststylenone">
<li><a href="http://127.0.0.1/Symfony/web/app_dev.php/YourCompany/insert/Restaurant/">http://127.0.0.1/Symfony/web/app_dev.php/YourCompany/insert/Restaurant/</a></li>
<li><a href="http://127.0.0.1/Symfony/web/app_dev.php/YourCompany/show/Restaurant/">http://127.0.0.1/Symfony/web/app_dev.php/YourCompany/show/Restaurant/</a></li>
</ul>
<p>Diese Routen brauchen wir jetzt nur noch als Link in die <b>index.html.twig</b> zu schreiben.</p>
<pre class="highlight">
<<span class="c1">div</span> class=<span class="s1">"container"</span>>
<<span class="c1">div</span> class=<span class="s1">"row-fluid"</span>>
<<span class="c1">div</span> class=<span class="s1">"span3"</span>><span class="g">
<b><<span class="c1">ul</span>>
<<span class="c1">li</span>><<span class="c1">a</span> href=<span class="s1">"{{ path( 'insertrestaurant' ) }}"</span>>eingabe<<span class="c1">/a</span>>
<<span class="c1">/li</span>>
<<span class="c1">li</span>><<span class="c1">a</span> href=<span class="s1">"{{ path( 'showrestaurant' ) }}"</span>>ausgabe<<span class="c1">/a</span>>
<<span class="c1">/li</span>>
<<span class="c1">/ul</span>></b>
< /</span><span class="c1">div</span>>
<<span class="c1">div</span> class=<span class="s1">"span9"</span>><span class="g">
{% <span class="c1">if</span> pathname <span class="c1">is</span> defined %}
{% <span class="c1">if</span> pathname == <span class="s1">"showrestaurant"</span> %}
{% <span class="k">include</span> <span class="s1">'YourCompanyRestaurantBundle:Default:showrestaurant.html.twig'</span> %}
{% <span class="c1">elseif</span> pathname == <span class="s1">"insertrestaurant"</span> %}
{% <span class="k">include</span> <span class="s1">'YourCompanyRestaurantBundle:Default:insertrestaurant.html.twig'</span> %}
{% <span class="c1">endif</span> %}
{% <span class="c1">endif</span> %}
< /</span><span class="c1">div</span>>
<span class="g">< /</span><span class="c1">div</span>>
<span class="g">< /</span><span class="c1">div</span>>
</pre>
<p>Und fertig ist der Lack. Jetzt k&ouml;nnen wir Restaurants eingeben und geordnet wieder ausgeben ohne den Browser zu verlassen.</p>
</section>
</div>
</div>
</div>
<div class="row-fluid">
<footer class="footer">
</footer>
</div>
</div>
<div class="phonenav navbar-fixed-bottom">
<div class="breath">
<a class="phonebutton" href="https://github.com/peponi/Symfony-for-absolute-beginners">Github</a>
| <a href="index.html" class="phonebutton"> <- Seite 1 </a>
<span class="phonebutton" id="phonenavigation">Navigation</span>
</div>
</div>
</body>
</html>
Jump to Line
Something went wrong with that request. Please try again.