Symfony
Symfony
2.0
Fabien Potencier
28 September 2011
IFI ymfonyP F F F IFP IFQ F F F F IFR F IFS F PFI PFP PFQ PFR PFS
F F F F F
F F F F F
F F F F F F F F F F
F F F F F F F F F F
F F F F F F F F F F
F F F F F F F F F F
F F F F F F F F F F
F F F F F F F F F F
F F F F F F F F F F
F F F F F F F F F F
F F F F F F F F F F
F F F F F F F F F F
F F F F F F F F F F
F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F
S S T U IP IR IS IS IU IV PH PH PI PI PP PQ PQ PR PS PT PU PU PW QQ i
wigD F F F F F D F F F F
QFI F F F F F F F F F QFP F F F F QFQ F F F QFR QFS euring esoures F F F F F F F F F F F F F QFT ghing esoures F F F F F F F F F F F F F QFU F F F F F F F F F F
F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F
QQ QR QR
35
SFI ymfonyP r SFP ymfonyP versus plt r F F F F F F F SFQ snstlling nd gon(guring ymfony F F F SFR ymfonyP F F F F F SFS gontroller F F F F F F F F F F F F F F F F F SFT outing F F F F F F F F F F F F F F F F F F SFU greting nd using empltes F F F F F F SFV hotrine @A F SFW F F F F F F F F F F F F F F SFIH F F F F F F F F F F F F F F F F SFII F F F F F F F F F F F F F F F F F F SFIP eurity F F F F F F F F F F F F F F F F F F SFIQ r ghe F F F F F F F F F F F F F F F SFIR rnsltions F F F F F F F F F F F F F F F SFIS ervie gontiner F F F F F F F F F F F F F SFIT erformne F F F F F F F F F F F F F F F SFIU snternls F F F F F F F F F F F F F F F F F SFIV es ymfonyP F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F
QW QW RW TQ TV VU IHH IPI IRQ IUH IVS IWW PPT PTH PUV PWQ QIP QIR QQR
337
III
TFI row to grete nd store ymfonyP rojet in git F F F F F F F F F TFP F F F F F F F F F F F F TFQ row to de(ne gontrollers s ervies F F F F F F F F F F F F F F F F F TFR row to fore routes to lwys use r F F F F F F F F F F F F F F TFS row to llow G hrter in route prmeter F F F F F F F F F F TFT row to se esseti for esset wngement F F F F F F F F F F F F F F TFU row to winify tvripts nd tylesheets with s gompressor F TFV row to se esseti por smge yptimiztion with wig puntions F TFW row to epply n esseti pilter to pei( pile ixtension F F F F TFIH row to hndle pile plods with hotrine F F F F F F F F F F F F F F TFII hotrine ixtensionsX imestmpleX luggleD rnsltleD etF TFIP egistering ivent visteners nd usriers F F F F F F F F F F F F F TFIQ row to generte intities from n ixisting htse F F F F F F F F TFIR row to use hotrine9s hfev vyer F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
QQW QQW QRI QRQ QRR QRT QRU QSP QSR QSW QTQ QUH QUI QUQ QUT
ii
TFIS TFIT TFIU TFIV TFIW TFPH TFPI TFPP TFPQ TFPR TFPS TFPT TFPU TFPV TFPW TFQH TFQI TFQP TFQQ TFQR TFQS TFQT TFQU TFQV TFQW TFRH TFRI TFRP TFRQ TFRR TFRS TFRT TFRU TFRV TFRW TFSH TFSI TFSP TFSQ TFSR TFSS TFST TFSU TFSV TFSW
row to work with wultiple intity wngers F F F F F F F F F F F F F F egistering gustom hv puntions F F F F F F F F F F F F F F F F F F row to ustomize porm endering F F F F F F F F F F F F F F F F F F F row to grete gustom porm pield ype F F F F F F F F F F F F F F F row to rete gustom lidtion gonstrint F F F F F F F F F F F F row to wster nd grete new invironments F F F F F F F F F F F F F row to et ixternl rmeters in the ervie gontiner F F F F F F row to se ptory to grete ervies F F F F F F F F F F F F F F F F row to wnge gommon hependenies with rent ervies F F F F row to work with opes F F F F F F F F F F F F F F F F F F F F F F F F row to use doessiontorge to store essions in the htse F F F fundle truture nd fest rties F F F F F F F F F F F F F F F F F F row to use fundle snheritne to yverride prts of fundle F F F F row to expose emnti gon(gurtion for fundle F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F qmil F F F F F F F F F F F F row to ork with imils huring hevelopment F F F F F F F F F F F F row to pool imil F F F F F F F F F F F F F F F F F F F F F F F F F F F row to simulte r euthentition in puntionl est F F F F F row to test the sntertion of severl glients F F F F F F F F F F F F F row to use the ro(ler in puntionl est F F F F F F F F F F F F F F row to test hotrine epositories F F F F F F F F F F F F F F F F F F F row to dd ememer we vogin puntionlity F F F F F F F F F F F row to implement your own oter to lklist s eddresses F F F F F eess gontrol vists @egvsA F F F F F F F F F F F F F F F F F F F F F F edvned egv gonepts F F F F F F F F F F F F F F F F F F F F F F F F row to fore r or r for hi'erent vs F F F F F F F F F F row to ustomize your porm vogin F F F F F F F F F F F F F F F F F F F row to seure ny ervie or wethod in your epplition F F F F F F row to lod eurity sers from the htse @the entity roviderA row to rete ustom ser rovider F F F F F F F F F F F F F F F F F row to rete ustom euthentition rovider F F F F F F F F F F F row to hnge the hefult rget th fehvior F F F F F F F F F F F row to use rnish to speedup my esite F F F F F F F F F F F F F F row to use r insted of wig for empltes F F F F F F F F F F F F row to utolod glsses F F F F F F F F F F F F F F F F F F F F F F F F F row to lote piles F F F F F F F F F F F F F F F F F F F F F F F F F F F F row to rete gonsoleGgommndEvine gommnds F F F F F F F F F F row to optimize your development invironment for deugging F F F wonolog F F F F F F F F F F row to extend glss without using snheritne F F F F F F F F F F F row to ustomize wethod fehvior without using snheritne F F F row to register new equest pormt nd wime ype F F F F F F F row to rete ustom ht golletor F F F F F F F F F F F F F F F F F row to grete ye e ervie in ymfonyP gontroller F F F F
F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F
F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F
QVH QVI QVQ QWW QWW RHI RHV RII RIS RPT RQH RQQ RQV RQW RRW RSI RSQ RSS RSU RSU RSV RSW RTQ RTU RUH RUR RUV RUW RVU RWP RWQ RWQ SHQ SHR SHT SII SIQ SIU SPQ SPR SPW SQI SQP SQR SQU iii
eferene houments UFI prmeworkfundle gon(gurtion @frmeworkA UFP essetifundle gon(gurtion eferene F F F F F UFQ gon(gurtion eferene F F F F F F F F F F F F F UFR eurity gon(gurtion eferene F F F F F F F F UFS wiftmilerfundle gon(gurtion F F F F F F F F UFT wigfundle gon(gurtion eferene F F F F F F UFU gon(gurtion eferene F F F F F F F F F F F F F UFV ero(lerfundle gon(gurtion F F F F F F F F UFW porm ypes eferene F F F F F F F F F F F F F F UFIH wig emplte porm puntion eferene F F F F UFII lidtion gonstrints eferene F F F F F F F F UFIP he hependeny snjetion gs F F F F F F F F F UFIQ ewv F F F F F F F F F F F F F F F F F F F F F F F UFIR equirements for running ymfonyP F F F F F F
Bundles
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
F F F F F F F F F F F F F F
SSU SSU STQ STR SUH SUR SUS SUT SUV SUW TRS TRU UHR UIH UIU
721
V
VI
ymfony i fundles
UPS
727
gontriuting UQI WFI gontriuting gode F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F UQI WFP gontriuting houmenttion F F F F F F F F F F F F F F F F F F F F F F F F F F URP WFQ gommunity F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F URV USQ
iv
ymfonyPD IH c F ymfonyPD F E E E D E ymfonyP F X c ymfony S F
1.1 Symfony2
D r SFQFP we D epheF c ymfonyP tndrd iditionD @distriutionA ymfony D E D ymfonyP @ @vendorsA AF ED ymfonyGD X
Resources/ bin/ src/ Acme/ DemoBundle/ Controller/ Resources/ ... vendor/ symfony/ doctrine/ ... web/ app.php ...
X @without vendorsAD X
1.2
D D ymfonyP ! vX
http://localhost/Symfony/web/cong.php
E F D F D fypss on(gurtion nd go to the elome pge ymfonyPX
http://localhost/Symfony/web/app_dev.php/
ymfonyP 3
IF
1.3
http://localhost/Symfony/web/app_dev.php/demo/hello/Fabien
IFQF
c vX
# app/cong/routing_dev.yml _welcome: pattern: / defaults: { _controller: AcmeDemoBundle:Welcome:index } _demo: resource: "@AcmeDemoBundle/Controller/DemoController.php" type: annotation prex: /demo
V IF
# ...
@ A D E G @FF AF emehemofundleXelomeXindexF X ymfonyP ewv E D ymfonyP wvD r F E F D E F
1.3.2
use Symfony\Component\HttpFoundation\Response; $name = $request->query->get('name'); return new Response('Hello '.$name, 200, array('Content-Type' => 'text/plain'));
X ymfonyP rD eF ymfonyP E r F ymfonyP ontroller X emehemofundleXelomeXindexF E E indexetion emehemofundlegontrollerelomegontrollerX
D D esponseD F rwvED tqE gontentEype imgeGjpgF X gontroller F D r rEF ymfonyPF emehemofundleXelomeXindexFhtmlFtwig E esouresGviewsGelomeGindexFhtmlFtwig emehemofundle @ srGemeGhemofundleAF E F D X
# app/cong/routing_dev.yml _demo:
IH IF
// src/Acme/DemoBundle/Controller/DemoController.php use Sensio\Bundle\FrameworkExtraBundle\Conguration\Route; use Sensio\Bundle\FrameworkExtraBundle\Conguration\Template; class DemoController extends Controller { /** * @Route("/hello/{name}", name="_demo_hello") * @Template() */ public function helloAction($name) { return array('name' => $name); } } // ...
doute@A GhelloG{nme}D E helloetion F D D {nme} pleholderF 6nmeF X rD ymfonyP F D D D F E demplte@A ymfonyP D E F F D D emehemofundleXhemoXhelloFhtmlFtwig @ srGemeGhemofundleGesouresGviewsGhemoGhelloFhtmlFtwigAF X doute@A demplte@A F F IFQF II
1.3.3
srGemeGhemofundleGesouresGviewsGhemoGhelloFhtmlFtwig @ emehemofundleXhemoXhelloFhtmlFtwig AX
{# src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig #} {% extends "AcmeDemoBundle::layout.html.twig" %} {% block title "Hello " ~ name %} {% block content %} <h1>Hello {{ name }}!</h1> {% endblock %}
D ymfonyP wig D E r F ymfonyPF
1.3.4 (bundles)
1.4
IP
IF
Y X F
D D F weG @ppFphpAD X
http://localhost/Symfony/web/app.php/demo/hello/Fabien
ephe modrewriteD v ppFphpX
IFRF
IQ
http://localhost/Symfony/web/demo/hello/Fabien
D D E weGD vX
http://localhost/demo/hello/Fabien
D ymfonyP ppGheGF @ppdevFphpAD D E F @ppFphpAD D F D F F D X
1.5
IR
IF
2.1 Twig,
<head> <title>My Webpage</title> </head> <body> <h1>{{ page_title }}</h1> <ul id="navigation"> {% for item in navigation %} <li><a href="{{ item.href }}">{{ item.caption }}</a></li> {% endfor %} </ul> </body> </html>
X {5 FFF 5}F D ymfony render D X
{# array('name' => 'Fabien') #} {{ name }} {# array('user' => array('name' => 'Fabien')) #} {{ user.name }} {# force array lookup #} {{ user['name'] }} {# array('user' => new User('Fabien')) #} {{ user.name }} {{ user.getName }} {# force method name lookup #} {{ user.name() }} {{ user.getName() }} {# pass arguments to a method #} {{ user.date('Y-m-d') }}
IT PF
X D F D F
2.2
{# src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig #} {% extends "AcmeDemoBundle::layout.html.twig" %} {% block title "Hello " ~ name %} {% block content %} <h1>Hello {{ name }}!</h1> {% endblock %}
emehemofundleXXlyoutFhtmlFtwig D c E F XX D FF esouresGviewsGF lyoutFhtmlFtwigX
PFPF
IU
2.3 ,
wig D Y ymfonyPD we F
2.3.1
E D F emeddedFhtmlFtwigX
{# src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig #} {% extends "AcmeDemoBundle::layout.html.twig" %} {# override the body block from embedded.html.twig #} {% block content %} {% include "AcmeDemoBundle:Demo:embedded.html.twig" %} {% endblock %}
2.3.2
} }
// ...
2.3.3
we D F vE D pth vED F vE D X
// src/Acme/DemoBundle/Controller/DemoController.php use Sensio\Bundle\FrameworkExtraBundle\Conguration\Route; use Sensio\Bundle\FrameworkExtraBundle\Conguration\Template; /** * @Route("/hello/{name}", name="_demo_hello") * @Template() */ public function helloAction($name) { return array('name' => $name); }
X url vEX {{ url@9demohello9D { 9nme9X 9homs9 }A }}F
2.3.4 : , JavaScript-
<link href="{{ asset('css/blog.css') }}" rel="stylesheet" type="text/css" /> <img src="{{ asset('images/logo.png') }}" />
sset F D we F
2.4
2.5
PH
PF
c ymfonyP3 D D F
3.1
// src/Acme/DemoBundle/Controller/DemoController.php use Sensio\Bundle\FrameworkExtraBundle\Conguration\Route; use Sensio\Bundle\FrameworkExtraBundle\Conguration\Template; /** * @Route("/hello/{name}", defaults={"_format"="xml"}, name="_demo_hello") * @Template() */ public function helloAction($name) { return array('name' => $name); }
fy using the request formt @s de(ned y the formt vlueAD ymfonyP utomtilly selets the right templteD here helloFxmlFtwigX
/** * @Route("/hello/{name}.{_format}", defaults={"_format"="html"}, requirements={"_format"="html|xml|js * @Template() */ public function helloAction($name) { return array('name' => $name); }
he ontroller will now GdemoGhelloGpienFjsonF e lled for vs like GdemoGhelloGpienFxml or
he requirements entry de(nes regulr expressions tht pleholders must mthF sn this exmpleD if you try to request the GdemoGhelloGpienFjs resoureD you will get RHR r errorD s it does not mth the formt requirementF
3.2
D rediret@AX
$response = $this->forward('AcmeDemoBundle:Hello:fancy', array('name' => $name, 'color' => 'green')); // do something with the response or return it directly
PP
QF
3.3
D E equestX
$request = $this->getRequest(); $request->isXmlHttpRequest(); // is it an Ajax request? $request->getPreferredLanguage(array('en', 'fr')); $request->query->get('page'); // get a $_GET parameter $request->request->get('page'); // get a $_POST parameter
equest ppFrequestX
{{ app.request.query.get('page') }} {{ app.request.parameter('page') }}
3.4
$session = $this->getRequest()->getSession(); // store an attribute for reuse during a later user request $session->set('foo', 'bar'); // in another controller for another request $foo = $session->get('foo'); // set the user locale $session->setLocale('fr');
D X
QFQF
PQ
// store a message for the very next request (in a controller) $session->setFlash('notice', 'Congratulations, your action succeeded!'); // display the message back in the next request (in a template) {{ app.session.ash('notice') }}
his is useful when you need to set suess messge efore redireting the user to nother pge @whih will then show the messgeAF
he ymfony tndrd idition omes with simple seurity on(gurtion tht (ts most ommon needsX
# app/cong/security.yml security: encoders: Symfony\Component\Security\Core\User\User: plaintext role_hierarchy: ROLE_ADMIN: ROLE_USER ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] providers: in_memory: users: user: { password: userpass, roles: [ 'ROLE_USER' ] } admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] } rewalls: dev: pattern: ^/(_(proler|wdt)|css|images|js)/ security: false login: pattern: ^/demo/secured/login$ security: false secured_area: pattern: ^/demo/secured/ form_login: check_path: /demo/secured/login_check login_path: /demo/secured/login logout: path: /demo/secured/logout
PR QF
target: /demo/
his on(gurtion requires users to log in for ny v strting with GdemoGseuredG nd de(nes two vlid usersX user nd dminF woreoverD the dmin user hs yviehwsx roleD whih inludes the yvii role s well @see the rolehierrhy settingAF X por redilityD psswords re stored in ler text in this simple on(gurtionD ut you n use ny hshing lgorithm y tweking the enoders setionF qoing to the httpXGGlolhostGymfonyGweGppdevFphpGdemoGseuredGhello v will utomtilly rediret you to the login form euse this resoure is proteted y (rewllF ou n lso fore the tion to require given role y using the deure nnottion on the ontrollerX
use Sensio\Bundle\FrameworkExtraBundle\Conguration\Route; use Sensio\Bundle\FrameworkExtraBundle\Conguration\Template; use JMS\SecurityExtraBundle\Annotation\Secure; /** * @Route("/hello/admin/{name}", name="_demo_secured_hello_admin") * @Secure(roles="ROLE_ADMIN") * @Template() */ public function helloAdminAction($name) { return array('name' => $name); }
xowD log in s user @who does not hve the yviehwsx roleA nd from the seured hello pgeD lik on the rello resoure seured linkF ymfonyP should return RHQ r sttus odeD inditing tht the user is foridden from essing tht resoureF X he ymfonyP seurity lyer is very )exile nd omes with mny di'erent user providers @like one for the hotrine ywA nd uthentition providers @like r siD r digestD or SHW erti(tesAF ed the eurity hpter of the ook for more informtion on how to use nd on(gure themF
es soon s your wesite strts to generte more tr0D you will wnt to void generting the sme resoure gin nd ginF ymfonyP uses r he heders to mnge resoures heF por simple hing strtegiesD use the onvenient dghe@A nnottionX QFTF ghing esoures PS
use Sensio\Bundle\FrameworkExtraBundle\Conguration\Route; use Sensio\Bundle\FrameworkExtraBundle\Conguration\Template; use Sensio\Bundle\FrameworkExtraBundle\Conguration\Cache; /** * @Route("/hello/{name}", name="_demo_hello") * @Template() * @Cache(maxage="86400") */ public function helloAction($name) { return array('name' => $name); }
sn this exmpleD the resoure will e hed for dyF fut you n lso use vlidtion insted of expirtion or omintion of oth if tht (ts your needs etterF esoure hing is mnged y the ymfonyP uiltEin reverse proxyF fut euse hing is mnged using regulr r he hedersD you n reple the uiltEin reverse proxy with rnish or quid nd esily sle your pplitionF X fut wht if you nnot he whole pgesc ymfonyP still hs the solution vi idge ide snludes @isAD whih re supported ntivelyF vern more y reding the r ghe hpter of the ookF
3.7
D D E IH F D F E D ymfonyP F F
PT
QF
3 D c F F E ymfonyD E F
4.1
D ut the diretory struture of the tndrd idition distriution re)ets the typil nd reommended struture of ymfonyP pplitionX
eppuernel D ppGF X
registerfundles@A D E Y registergontinergon(gurtion@A @ AY
r utoloding n e on(gured vi ppGutolodFphpX
// app/autoload.php use Symfony\Component\ClassLoader\UniversalClassLoader; $loader = new UniversalClassLoader(); $loader->registerNamespaces(array( 'Symfony' => array(__DIR__.'/../vendor/symfony/src', __DIR__.'/../vendor/bundles'), 'Sensio' => __DIR__.'/../vendor/bundles', 'JMS' => __DIR__.'/../vendor/bundles', 'Doctrine\\Common' => __DIR__.'/../vendor/doctrine-common/lib', 'Doctrine\\DBAL' => __DIR__.'/../vendor/doctrine-dbal/lib', 'Doctrine' => __DIR__.'/../vendor/doctrine/lib', 'Monolog' => __DIR__.'/../vendor/monolog/src', 'Assetic' => __DIR__.'/../vendor/assetic/src', 'Metadata' => __DIR__.'/../vendor/metadata/src', )); $loader->registerPrexes(array( 'Twig_Extensions_' => __DIR__.'/../vendor/twig-extensions/lib', 'Twig_' => __DIR__.'/../vendor/twig/lib', )); // ... $loader->registerNamespaceFallbacks(array(
PV RF
4.2
en pplition is mde up of undles s de(ned in the registerfundles@A method of the eppuernel lssF ih undle is diretory tht ontins single fundle lss tht desries itX
// app/AppKernel.php public function registerBundles() { $bundles = array( new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), new Symfony\Bundle\SecurityBundle\SecurityBundle(), new Symfony\Bundle\TwigBundle\TwigBundle(), new Symfony\Bundle\MonologBundle\MonologBundle(), new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), new Symfony\Bundle\DoctrineBundle\DoctrineBundle(), new Symfony\Bundle\AsseticBundle\AsseticBundle(),
RFPF PW
);
if (in_array($this->getEnvironment(), array('dev', 'test'))) { $bundles[] = new Acme\DemoBundle\AcmeDemoBundle(); $bundles[] = new Symfony\Bundle\WebProlerBundle\WebProlerBundle(); $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); } } return $bundles;
sn ddition to the emehemofundle tht we hve lredy tlked outD notie tht the kernel lso enles other undles suh s the prmeworkfundleD hotrinefundleD wiftmilerfundleD nd essetifundle undleF hey re ll prt of the ore frmeworkF
4.2.2 Conguring a Bundle
D E ewvD wvD rF X
# app/cong/cong.yml imports: - { resource: parameters.ini } - { resource: security.yml } framework: secret: %secret% charset: UTF-8 router: { resource: "%kernel.root_dir%/cong/routing.yml" } form: true csrf_protection: true validation: { enable_annotations: true } templating: { engines: ['twig'] } #assets_version: SomeVersionScheme session: default_locale: %locale% auto_start: true # Twig Conguration twig: debug: %kernel.debug% strict_variables: %kernel.debug% # Assetic Conguration
QH RF
assetic: debug: %kernel.debug% use_controller: false lters: cssrewrite: ~ # closure: # jar: %kernel.root_dir%/java/compiler.jar # yui_css: # jar: %kernel.root_dir%/java/yuicompressor-2.4.2.jar # Doctrine Conguration doctrine: dbal: driver: %database_driver% host: %database_host% dbname: %database_name% user: %database_user% password: %database_password% charset: UTF8 orm: auto_generate_proxy_classes: %kernel.debug% auto_mapping: true # Swiftmailer Conguration swiftmailer: transport: %mailer_transport% host: %mailer_host% username: %mailer_user% password: %mailer_password% jms_security_extra: secure_controllers: true secure_all_services: false
ih entry like frmework de(nes the on(gurtion for spei( undleF por exmpleD frmework on(gures the prmeworkfundle while swiftmiler on(gures the wiftmilerfundleF @environmentA D F por exmpleD the dev environment lods the on(gdevFyml (leD whih lods the min on(gurtion @iFeF on(gFymlA nd then modi(es it to dd some deugging toolsX
framework: router: { resource: "%kernel.root_dir%/cong/routing_dev.yml" } proler: { only_exceptions: false } web_proler: toolbar: true intercept_redirects: false monolog: handlers: main: type: stream path: %kernel.logs_dir%/%kernel.environment%.log level: debug rephp: type: rephp level: info assetic: use_controller: true
sn ddition to eing nie wy to orgnize nd on(gure your odeD undle n extend nother undleF fundle inheritne llows you to override ny existing undle in order to ustomize its ontrollersD templtesD or ny of its (lesF his is where the logil nmes @eFgF demehemofundleGgontrollerGeuredgontrollerFphpA ome in hndyX they strt where the resoure is tully storedF vogil pile xmes hen you wnt to referene (le from undleD use this nottionX dfxhvixewiGpthGtoG(leY ymfonyP will resolve dfxhvixewi to the rel pth to the undleF por instneD the logil pth demehemofundleGgontrollerGhemogontrollerFphp would e onverted to srGemeGhemofundleGgontrollerGhemogontrollerFphpD euse ymfony knows the lotion of the emehemofundleF vogil gontroller xmes por ontrollersD you need to referene method nmes fxhvixewiXgyxyvvixewiXegsyxxewiF QP using por the formt instneD
RF
ymfony houmenttionD PFH emehemofundleXelomeXindex mps to the indexetion emehemofundlegontrollerelomegontroller lssF vogil emplte xmes por templtesD the logil nme emehemofundleXelomeXindexFhtmlFtwig is onverted to the (le pth srGemeGhemofundleGesouresGviewsGelomeGindexFhtmlFtwigF empltes eome even more interesting when you relize they don9t need to e stored on the (lesystemF ou n esily store them in dtse tle for instneF ixtending fundles sf you follow these onventionsD then you n use undle inheritne to override (lesD ontrollers or templtesF por exmpleD you n rete undle E emexewfundle E nd speify tht its prent is emehemofundleF hen ymfony lods the emehemofundleXelomeXindex ontrollerD it will (rst look for the elomegontroller lss in emexewfundle nd then look inside emehemofundleF his mens tht one undle n override lmost ny prt of nother undle3 ho you understnd now why ymfonyP is so )exilec hre your undles etween pplitionsD store them lolly or glollyD your hoieF method from the
4.4
ymfonyP is proly one of the fstest fullEstk frmeworks roundF fut how n it e so fst if it prses nd interprets tens of ewv nd wv (les for eh requestc he speed is prtly due to its he systemF he pplition on(gurtion is only prsed for the very (rst request nd then ompiled down to plin r ode stored in the ppGheG diretoryF sn the development environmentD ymfonyP is smrt enough to )ush the he when you hnge (leF fut in the prodution environmentD it is your responsiility to ler the he when you updte your ode or hnge its on(gurtionF
ymfony houmenttionD PFH hen developing we pplitionD things n go wrong in mny wysF he log (les in the ppGlogsG diretory tell you everything out the requests nd help you (x the prolem quiklyF
4.5
@ppGonsoleAD E F D D F D X
php app/console
EEhelp X
4.6
b b b
QR
RF
II
QS
QU
QV
gongrtultions3 fy lerning out ymfonyPD you9re well on your wy towrds eing more produtiveD wellErounded nd populr we developer @tullyD you9re on your own for the lst prtAF ymfonyP is uilt to get k to sisX to develop tools tht let you develop fster nd uild more roust pplitionsD while stying out of your wyF ymfony is uilt on the est ides from mny tehnologiesX the tools nd onepts you9re out to lern represent the e'orts of thousnds of peopleD over mny yersF sn other wordsD you9re not just lerning ymfonyD you9re lerning the fundmentls of the weD development est prtiesD nd how to use mny mzing new r lirriesD inside or independent of ymfonyPF oD get redyF rue to the ymfonyP philosophyD this hpter egins y explining the fundmentl onept ommon to we developmentX rF egrdless of your kground or preferred progrmming lngugeD this hpter is mustEred for everyoneF
5.1.1 HTTP is Simple
r @rypertext rnsfer rotool to the geeksA is text lnguge tht llows two mhines to ommunite with eh otherF ht9s it3 por exmpleD when heking for the ltest xkd omiD the following @pproximteA onverstion tkes pleX
QW
end while the tul lnguge used is it more formlD it9s still dedEsimpleF r is the term used to desrie this simple textEsed lngugeF end no mtter how you develop on the weD the gol of your server is lwys to understnd simple text requestsD nd return simple text responsesF ymfonyP is uilt from the groundEup round tht relityF hether you relize it or notD r is something you use everydyF ith ymfonyPD you9ll lern how to mster itF IX ivery onverstion on the we strts with requestF he request is text messge reted y lient @eFgF rowserD n ihone ppD etA in speil formt known s rF he lient sends tht request to serverD nd then wits for the responseF ke look t the (rst prt of the intertion @the requestA etween rowser nd the xkd we serverX
RH
SF
D r D D X
SFIF ymfonyP r
RI
rnslted into rD the response sent k to the rowser will look something like thisX
HTTP/1.1 200 OK Date: Sat, 02 Apr 2011 21:05:05 GMT Server: lighttpd/1.4.19 Content-Type: text/html <html> <!-- HTML for the xkcd comic --> </html>
he r response ontins the requested resoure @the rwv ontent in this seAD s well s other informtion out the responseF he (rst line is espeilly importnt nd ontins the r response sttus ode @PHH in this seAF he sttus ode ommunites the overll outome of the request k to the lientF s the request suessfulc s there n errorc hi'erent sttus odes exist tht indite suessD n errorD or tht the lient needs to do something @eFgF rediret to nother pgeAF e full list n e found on ikipedi9s vist of r sttus odes rtileF vike the requestD n r response ontins dditionl piees of informtion known s r hedersF por exmpleD one importnt r response heder is gontentEypeF he ody of the sme resoure ould e returned in multiple di'erent formts inluding rwvD wvD or tyx to nme fewF he gontentEype heder tells the lient whih formt is eing returnedF wny other heders existD some of whih re very powerfulF por exmpleD ertin heders n e used to rete powerful hing systemF equestsD esponses nd e hevelopment his requestEresponse onverstion is the fundmentl proess tht drives ll ommunition on the weF end s importnt nd powerful s this proess isD it9s inesply simpleF RP SF
ymfony houmenttionD PFH he most importnt ft is thisX regrdless of the lnguge you useD the type of pplition you uild @weD moileD tyx esAD or the development philosophy you followD the end gol of n pplition is lwys to understnd eh request nd rete nd return the pproprite responseF ymfony is rhiteted to mth this relityF X o lern more out the r spei(tionD red the originl r IFI pg or the r fisD whih is n tive e'ort to lrify the originl spei(tionF e gret tool to hek oth the request nd response heders while rowsing is the vive r reders extension for pirefoxF
o how do you intert with the request nd rete response when using rc sn relityD r strts you it from the whole proessX
<?php $uri = $_SERVER['REQUEST_URI']; $foo = $_GET['foo']; header('Content-type: text/html'); echo 'The URI requested is: '.$uri; echo 'The value of the "foo" parameter is: '.$foo;
es strnge s it soundsD this smll pplition is in ft tking informtion from the r request nd using it to rete n r responseF snsted of prsing the rw r request messgeD r prepres superglol vriles suh s 6ii nd 6qi tht ontin ll the informtion from the requestF imilrlyD insted of returning the rEformtted text responseD you n use the heder@A funtion to rete response heders nd simply print out the tul ontent tht will e the ontent portion of the response messgeF r will rete true r response nd return it to the lientX
HTTP/1.1 200 OK Date: Sat, 03 Apr 2011 02:14:33 GMT Server: Apache/2.2.17 (Unix) Content-Type: text/html The URI requested is: /testing?foo=symfony The value of the "foo" parameter is: symfony
SFIF ymfonyP r
RQ
ymfony provides n lterntive to the rw r pproh vi two lsses tht llow you to intert with the r request nd response in n esier wyF he ymfonygomponentrttppoundtionequest lss is simple ojetEoriented representtion of the r request messgeF ith itD you hve ll the request informtion t your (ngertipsX
use Symfony\Component\HttpFoundation\Request; $request = Request::createFromGlobals(); // the URI being requested (e.g. /about) minus any query parameters $request->getPathInfo(); // retrieve GET and POST variables respectively $request->query->get('foo'); $request->request->get('bar'); // retrieves an instance of UploadedFile identied by foo $request->les->get('foo'); $request->getMethod(); $request->getLanguages(); // GET, POST, PUT, DELETE, HEAD // an array of languages the client accepts
es onusD the equest lss does lot of work in the kground tht you9ll never need to worry outF por exmpleD the iseure@A method heks the three di'erent vlues in r tht n indite whether or not the user is onneting vi seured onnetion @iFeF httpsAF ymfony lso provides esponse lssX simple r representtion of n r response messgeF his llows your pplition to use n ojetEoriented interfe to onstrut the response tht needs to e returned to the lientX
use Symfony\Component\HttpFoundation\Response; $response = new Response(); $response->setContent('<html><body><h1>Hello world!</h1></body></html>'); $response->setStatusCode(200); $response->headers->set('Content-Type', 'text/html'); // prints the HTTP headers followed by the content $response->send();
sf ymfony o'ered nothing elseD you would lredy hve toolkit for esily essing request informtion nd n ojetEoriented interfe for reting the responseF iven s you lern the mny powerful fetures in ymfonyD keep in mind tht the gol of your pplition is lwys to interpret request nd rete the pproprite response sed on your pplition logiF RR SF
X he equest nd esponse lsses re prt of stndlone omponent inluded with ymfony lled rttppoundtionF his omponent n e used entirely independent of ymfony nd lso provides lsses for hndling sessions nd (le uplodsF
vike r itselfD the equest nd esponse ojets re pretty simpleF he hrd prt of uilding n pplition is writing wht omes in etweenF sn other wordsD the rel work omes in writing the ode tht interprets the request informtion nd retes the responseF our pplition proly does mny thingsD like sending emilsD hndling form sumissionsD sving things to dtseD rendering rwv pges nd proteting ontent with seurityF row n you mnge ll of this nd still keep your ode orgnized nd mintinlec ymfony ws reted to solve these prolems so tht you don9t hve toF he pront gontroller rditionllyD pplitions were uilt so tht eh pge of site ws its own physil (leX
X sing ephe9s modrewrite @or equivlent with other we serversAD the vs n esily e lened up to e just GD Gontt nd GlogF xowD every request is hndled extly the smeF snsted of individul vs exeuting di'erent r (lesD the front ontroller is lwys exeutedD nd the routing of di'erent vs to di'erent prts of your pplition is done internllyF his solves oth prolems with the originl pprohF elmost ll modern we pps do this E inluding pps like ordressF SFIF ymfonyP r RS
ymfony houmenttionD PFH ty yrgnized fut inside your front ontrollerD how do you know whih pge should e rendered nd how n you render eh in sne wyc yne wy or notherD you9ll need to hek the inoming s nd exeute di'erent prts of your ode depending on tht vlueF his n get ugly quiklyX
// index.php $request = Request::createFromGlobals(); $path = $request->getPathInfo(); // the URL being requested if (in_array($path, array('', '/')) { $response = new Response('Welcome to the homepage.'); } elseif ($path == '/contact') { $response = new Response('Contact us'); } else { $response = new Response('Page not found.', 404); } $response->send();
olving this prolem n e di0ultF portuntely it9s extly wht ymfony is designed to doF he ymfony epplition plow hen you let ymfony hndle eh requestD life is muh esierF ymfony follows the sme simple pttern for every requestX
F SFIX snoming requests re interpreted y the routing nd pssed to ontroller funtions tht return esponse ojetsF RT SF
ymfony houmenttionD PFH ih pge of your site is de(ned in routing on(gurtion (le tht mps di'erent vs to di'erent r funtionsF he jo of eh r funtionD lled ontrollerD is to use informtion from the request E long with mny other tools ymfony mkes ville E to rete nd return esponse ojetF sn other wordsD the ontroller is where your ode goesX it9s where you interpret the request nd rete responseF st9s tht esy3 vet9s reviewX
ih request exeutes front ontroller (leY he routing system determines whih r funtion should e exeuted sed on informtion from the request nd routing on(gurtion you9ve retedY he orret r funtion is exeutedD where your ode retes nd returns the pproprite esponse ojetF
e ymfony equest in etion ithout diving into too muh detilD let9s see this proess in tionF uppose you wnt to dd Gontt pge to your ymfony pplitionF pirstD strt y dding n entry for Gontt to your routing on(gurtion (leX
ou now know tht the gol of ny pp is to interpret eh inoming request nd rete n pproprite responseF es n pplition growsD it eomes more di0ult to keep your ode orgnized nd mintinleF snvrilyD the sme omplex tsks keep oming up over nd over ginX persisting things to the dtseD rendering nd reusing templtesD hndling form sumissionsD sending emilsD vlidting user input nd hndling seurityF he good news is tht none of these prolems is uniqueF ymfony provides frmework full of tools tht llow you to uild your pplitionD not your toolsF ith ymfonyPD nothing is imposed on youX you9re free to use the full ymfony frmeworkD or just one piee of ymfony ll y itselfF tndlone oolsX he ymfonyP gomponents o wht is ymfonyPc pirstD ymfonyP is olletion of over twenty independent lirries tht n e used inside ny r projetF hese lirriesD lled the ymfonyP gomponentsD ontin something useful for lmost ny situtionD regrdless of how your projet is developedF o nme fewX
rttppoundtion E gontins the equest nd esponse lssesD s well s other lsses for hndling sessions nd (le uplodsY outing E owerful nd fst routing system tht llows you to mp spei( s @eFgF GonttA to some informtion out how tht request should e hndled @eFgF exeute the onttetion@A methodAY porm E e fullEfetured nd )exile frmework for reting forms nd hnding form sumissionsY lidtor e system for reting rules out dt nd then vlidting whether or not userEsumitted dt follows those rulesY glssvoder en utoloding lirry tht llows r lsses to e used without needing to mnully require the (les ontining those lssesY emplting e toolkit for rendering templtesD hndling templte inheritne @iFeF templte is deorted with lyoutA nd performing other ommon templte tsksY eurity E e powerful lirry for hndling ll types of seurity inside n pplitionY rnsltion e frmework for trnslting strings in your pplitionF
ih nd every one of these omponents is deoupled nd n e used in ny r projetD regrdless of whether or not you use the ymfonyP frmeworkF ivery prt is mde to e used if needed nd repled when neessryF
RV
SF
ymfony houmenttionD PFH he pull olutionX he ymfonyP prmework o thenD wht is the ymfonyP prmeworkc he ymfonyP prmework is r lirry tht omplishes two distint tsksX IF rovides seletion of omponents @iFeF the ymfonyP gomponentsA nd thirdEprty lirries @eFgF wiftmiler for sending emilsAY PF rovides sensile on(gurtion nd glue lirry tht ties ll of these piees togetherF he gol of the frmework is to integrte mny independent tools in order to provide onsistent experiene for the developerF iven the frmework itself is ymfonyP undle @iFeF pluginA tht n e on(gured or repled entirelyF ymfonyP provides powerful set of tools for rpidly developing we pplitions without imposing on your pplitionF xorml users n quikly strt development y using ymfonyP distriutionD whih provides projet skeleton with sensile defultsF por more dvned usersD the sky is the limitF
hy is ymfonyP etter thn just opening up (le nd writing )t rc sf you9ve never used r frmeworkD ren9t fmilir with the wg philosophyD or just wonder wht ll the hype is round ymfonyPD this hpter is for youF snsted of telling you tht ymfonyP llows you to develop fster nd etter softwre thn with )t rD you9ll see for yourselfF sn this hpterD you9ll write simple pplition in )t rD nd then reftor it to e more orgnizedF ou9ll trvel through timeD seeing the deisions ehind why we development hs evolved over the pst severl yers to where it is nowF fy the endD you9ll see how ymfonyP n resue you from mundne tsks nd let you tke k ontrol of your odeF
5.2.1 A simple Blog in at PHP
sn this hpterD you9ll uild the token log pplition using only )t rF o eginD rete single pge tht displys log entries tht hve een persisted to the dtseF riting in )t r is quik nd dirtyX
$result = mysql_query('SELECT id, title FROM post', $link); ?> <html> <head> <title>List of Posts</title> </head> <body> <h1>List of Posts</h1> <ul> <?php while ($row = mysql_fetch_assoc($result)): ?> <li> <a href="/show.php?id=<?php echo $row['id'] ?>"> <?php echo $row['title'] ?> </a> </li> <?php endwhile; ?> </ul> </body> </html> <?php mysql_close($link);
ht9s quik to writeD fst to exeuteD ndD s your pp growsD impossile to mintinF here re severl prolems tht need to e ddressedX
xo errorEhekingX ht if the onnetion to the dtse filsc oor orgniztionX sf the pplition growsD this single (le will eome inresingly unmintinleF here should you put ode to hndle form sumissionc row n you vlidte dtc here should ode go for sending emilsc hi0ult to reuse odeX ine everything is in one (leD there9s no wy to reuse ny prt of the pplition for other pges of the logF
X enother prolem not mentioned here is the ft tht the dtse is tied to wyvF hough not overed hereD ymfonyP fully integrtes hotrineD lirry dedited to dtse strtion nd mppingF vet9s get to work on solving these prolems nd moreF
SH
SF
ymfony houmenttionD PFH ssolting the resenttion he ode n immeditely gin from seprting the pplition logi from the ode tht prepres the rwv presenttionX
<?php // index.php $link = mysql_connect('localhost', 'myuser', 'mypassword'); mysql_select_db('blog_db', $link); $result = mysql_query('SELECT id, title FROM post', $link); $posts = array(); while ($row = mysql_fetch_assoc($result)) { $posts[] = $row; } mysql_close($link); // include the HTML presentation code require 'templates/list.php';
he rwv ode is now stored in seprte (le @templtesGlistFphpAD whih is primrily n rwv (le tht uses templteElike r syntxX
<html> <head> <title>List of Posts</title> </head> <body> <h1>List of Posts</h1> <ul> <?php foreach ($posts as $post): ?> <li> <a href="/read?id=<?php echo $post['id'] ?>"> <?php echo $post['title'] ?> </a> </li> <?php endforeach; ?> </ul> </body> </html>
fy onventionD the (le tht ontins ll of the pplition logi E indexFphp E is known s ontrollerF he term ontroller is word you9ll her lotD regrdless of the lnguge or frmework you useF st refers simply to the re of your ode tht proesses user input nd prepres the responseF SFPF ymfonyP versus plt r SI
ymfony houmenttionD PFH sn this seD our ontroller prepres dt from the dtse nd then inludes templte to present tht dtF ith the ontroller isoltedD you ould esily hnge just the templte (le if you needed to render the log entries in some other formt @eFgF listFjsonFphp for tyx formtAF ssolting the epplition @hominA vogi o fr the pplition ontins only one pgeF fut wht if seond pge needed to use the sme dtse onnetionD or even the sme rry of log postsc eftor the ode so tht the ore ehvior nd dtEess funtions of the pplition re isolted in new (le lled modelFphpX
<?php // model.php function open_database_connection() { $link = mysql_connect('localhost', 'myuser', 'mypassword'); mysql_select_db('blog_db', $link); } return $link;
function close_database_connection($link) { mysql_close($link); } function get_all_posts() { $link = open_database_connection(); $result = mysql_query('SELECT id, title FROM post', $link); $posts = array(); while ($row = mysql_fetch_assoc($result)) { $posts[] = $row; } close_database_connection($link); } return $posts;
X he (lenme modelFphp is used euse the logi nd dt ess of n pplition is trditionlly known s the model lyerF sn wellEorgnized pplitionD the mjority of the ode representing your usiness logi should live in the model @s opposed to living in SP SF
ymfony houmenttionD PFH ontrollerAF end unlike in this exmpleD only portion @or noneA of the model is tully onerned with essing dtseF he ontroller @indexFphpA is now very simpleX
<!-- templates/layout.php --> <html> <head> <title><?php echo $title ?></title> </head> <body> <?php echo $content ?> </body> </html>
he templte @templtesGlistFphpA n now e simpli(ed to extend the lyoutX
<?php $title = 'List of Posts' ?> <?php ob_start() ?> <h1>List of Posts</h1> <ul> <?php foreach ($posts as $post): ?> <li> <a href="/read?id=<?php echo $post['id'] ?>"> <?php echo $post['title'] ?> </a> </li>
SFPF ymfonyP versus plt r SQ
<?php endforeach; ?> </ul> <?php $content = ob_get_clean() ?> <?php include 'layout.php' ?>
ou9ve now introdued methodology tht llows for the reuse of the lyoutF nfortuntelyD to omplish thisD you9re fored to use few ugly r funtions @ostrt@AD ogetlen@AA in the templteF ymfonyP uses emplting omponent tht llows this to e omplished lenly nd esilyF ou9ll see it in tion shortlyF
5.2.2 Adding a Blog show Page
he log list pge hs now een reftored so tht the ode is etterEorgnized nd reusleF o prove itD dd log show pgeD whih displys n individul log post identi(ed y n id query prmeterF o eginD rete new funtion in the modelFphp (le tht retrieves n individul log result sed on given idX
// model.php function get_post_by_id($id) { $link = open_database_connection(); $id = mysql_real_escape_string($id); $query = 'SELECT date, title, body FROM post WHERE id = '.$id; $result = mysql_query($query); $row = mysql_fetch_assoc($result); close_database_connection($link); } return $row;
xextD rete new (le lled showFphp E the ontroller for this new pgeX
<?php $title = $post['title'] ?> <?php ob_start() ?> <h1><?php echo $post['title'] ?></h1> <div class="date"><?php echo $post['date'] ?></div> <div class="body"> <?php echo $post['body'] ?> </div> <?php $content = ob_get_clean() ?> <?php include 'layout.php' ?>
greting the seond pge is now very esy nd no ode is duplitedF tillD this pge introdues even more lingering prolems tht frmework n solve for youF por exmpleD missing or invlid id query prmeter will use the pge to rshF st would e etter if this used RHR pge to e renderedD ut this n9t relly e done esily yetF orseD hd you forgotten to len the id prmeter vi the mysqlrelespestring@A funtionD your entire dtse would e t risk for n v injetion ttkF enother mjor prolem is tht eh individul ontroller (le must inlude the modelFphp (leF ht if eh ontroller (le suddenly needed to inlude n dditionl (le or perform some other glol tsk @eFgF enfore seurityAc es it stnds nowD tht ode would need to e dded to every ontroller (leF sf you forget to inlude something in one (leD hopefully it doesn9t relte to seurityFFF
5.2.3 A Front Controller to the Rescue
he solution is to use front ontrollerX single r (le through whih ll requests re proessedF ith front ontrollerD the ss for the pplition hnge slightlyD ut strt to eome more )exileX
Without a front controller /index.php => Blog post list page (index.php executed) /show.php => Blog post show page (show.php executed) With index.php as the front controller /index.php => Blog post list page (index.php executed) /index.php/show => Blog post show page (index.php executed)
X he indexFphp portion of the s n e removed if using ephe rewrite rules @or equivlentAF sn tht seD the resulting s of the log show pge would e simply GshowF hen using front ontrollerD single r (le @indexFphp in this seA renders every requestF SFPF ymfonyP versus plt r SS
ymfony houmenttionD PFH por the log post show pgeD GindexFphpGshow will tully exeute the indexFphp (leD whih is now responsile for routing requests internlly sed on the full sF es you9ll seeD front ontroller is very powerful toolF greting the pront gontroller ou9re out to tke ig step with the pplitionF ith one (le hndling ll requestsD you n entrlize things suh s seurity hndlingD on(gurtion lodingD nd routingF sn this pplitionD indexFphp must now e smrt enough to render the log post list pge or the log post show pge sed on the requested sX
<?php // index.php // load and initialize any global libraries require_once 'model.php'; require_once 'controllers.php'; // route the request internally $uri = $_SERVER['REQUEST_URI']; if ($uri == '/index.php') { list_action(); } elseif ($uri == '/index.php/show' && isset($_GET['id'])) { show_action($_GET['id']); } else { header('Status: 404 Not Found'); echo '<html><body><h1>Page Not Found</h1></body></html>'; }
por orgniztionD oth ontrollers @formerly indexFphp nd showFphpA re now r funtions nd eh hs een moved into seprte (leD ontrollersFphpX
function list_action() { $posts = get_all_posts(); require 'templates/list.php'; } function show_action($id) { $post = get_post_by_id($id); require 'templates/show.php'; }
es front ontrollerD indexFphp hs tken on n entirely new roleD one tht inludes loding the ore lirries nd routing the pplition so tht one of the two ontrollers ST SF
ymfony houmenttionD PFH @the listtion@A nd showtion@A funtionsA is lledF sn relityD the front ontroller is eginning to look nd t lot like ymfonyP9s mehnism for hndling nd routing requestsF X enother dvntge of front ontroller is )exile vsF xotie tht the v to the log post show pge ould e hnged from Gshow to Gred y hnging ode in only one lotionF feforeD n entire (le needed to e renmedF sn ymfonyPD vs re even more )exileF fy nowD the pplition hs evolved from single r (le into struture tht is orgnized nd llows for ode reuseF ou should e hppierD ut fr from stis(edF por exmpleD the routing system is (kleD nd wouldn9t reognize tht the list pge @GindexFphpA should e essile lso vi G @if ephe rewrite rules were ddedAF elsoD insted of developing the logD lot of time is eing spent working on the rhiteture of the ode @eFgF routingD lling ontrollersD templtesD etFAF wore time will need to e spent to hndle form sumissionsD input vlidtionD logging nd seurityF hy should you hve to reinvent solutions to ll these routine prolemsc edd ouh of ymfonyP ymfonyP to the resueF fefore tully using ymfonyPD you need to mke sure r knows how to (nd the ymfonyP lssesF his is omplished vi n utoloder tht ymfony providesF en utoloder is tool tht mkes it possile to strt using r lsses without expliitly inluding the (le ontining the lssF pirstD downlod symfony nd ple it into vendorGsymfonyG diretoryF xextD rete n ppGootstrpFphp (leF se it to require the two (les in the pplition nd to on(gure the utoloderX
<?php // bootstrap.php require_once 'model.php'; require_once 'controllers.php'; require_once 'vendor/symfony/src/Symfony/Component/ClassLoader/UniversalClassLoader.php'; $loader = new Symfony\Component\ClassLoader\UniversalClassLoader(); $loader->registerNamespaces(array( 'Symfony' => __DIR__.'/vendor/symfony/src', )); $loader->register();
his tells the utoloder where the ymfony lsses reF ith thisD you n strt using ymfony lsses without using the require sttement for the (les tht ontin themF gore to ymfony9s jo is to interpret philosophy is eh request the nd ide tht n pplition9s min return responseF o this endD SU
ymfony houmenttionD PFH ymfonyP provides oth ymfonygomponentrttppoundtionequest nd ymfonygomponentrttppoundtionesponse lssF hese lsses re ojetEoriented representtions of the rw r request eing proessed nd the r response eing returnedF se them to improve the logX
<?php // index.php require_once 'app/bootstrap.php'; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $request = Request::createFromGlobals(); $uri = $request->getPathInfo(); if ($uri == '/') { $response = list_action(); } elseif ($uri == '/show' && $request->query->has('id')) { $response = show_action($request->query->get('id')); } else { $html = '<html><body><h1>Page Not Found</h1></body></html>'; $response = new Response($html, 404); } // echo the headers and send the response $response->send();
he ontrollers re now responsile for returning esponse ojetF o mke this esierD you n dd new rendertemplte@A funtionD whihD inidentllyD ts quite it like the ymfonyP templting engineX
// controllers.php use Symfony\Component\HttpFoundation\Response; function list_action() { $posts = get_all_posts(); $html = render_template('templates/list.php', array('posts' => $posts)); } return new Response($html);
function show_action($id) { $post = get_post_by_id($id); $html = render_template('templates/show.php', array('post' => $post)); return new Response($html);
SV SF
} // helper function to render templates function render_template($path, array $args) { extract($args); ob_start(); require $path; $html = ob_get_clean(); } return $html;
fy ringing in smll prt of ymfonyPD the pplition is more )exile nd relileF he equest provides dependle wy to ess informtion out the r requestF pei(llyD the getthsnfo@A method returns lened s @lwys returning Gshow nd never GindexFphpGshowAF oD even if the user goes to GindexFphpGshowD the pplition is intelligent enough to route the request through showtion@AF he esponse ojet gives )exiility when onstruting the r responseD llowing r heders nd ontent to e dded vi n ojetEoriented interfeF end while the responses in this pplition re simpleD this )exiility will py dividends s your pplition growsF he mple epplition in ymfonyP he log hs ome long wyD ut it still ontins lot of ode for suh simple pplitionF elong the wyD we9ve lso invented simple routing system nd method using ostrt@A nd ogetlen@A to render templtesF sfD for some resonD you needed to ontinue uilding this frmework from srthD you ould t lest use ymfony9s stndlone outing nd emplting omponentsD whih lredy solve these prolemsF snsted of reEsolving ommon prolemsD you n let ymfonyP tke re of them for youF rere9s the sme smple pplitionD now uilt in ymfonyPX
<?php // src/Acme/BlogBundle/Controller/BlogController.php namespace Acme\BlogBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class BlogController extends Controller { public function listAction() { $posts = $this->get('doctrine')->getEntityManager() ->createQuery('SELECT p FROM AcmeBlogBundle:Post p')
SFPF ymfonyP versus plt r SW
public function showAction($id) { $post = $this->get('doctrine') ->getEntityManager() ->getRepository('AcmeBlogBundle:Post') ->nd($id); if (!$post) { // cause the 404 page not found to be displayed throw $this->createNotFoundException(); } } return $this->render('AcmeBlogBundle:Post:show.html.php', array('post' => $post));
he two ontrollers re still lightweightF ih uses the hotrine yw lirry to retrieve ojets from the dtse nd the emplting omponent to render templte nd return esponse ojetF he list templte is now quite it simplerX
<!-- src/Acme/BlogBundle/Resources/views/Blog/list.html.php --> <?php $view->extend('::layout.html.php') ?> <?php $view['slots']->set('title', 'List of Posts') ?> <h1>List of Posts</h1> <ul> <?php foreach ($posts as $post): ?> <li> <a href="<?php echo $view['router']->generate('blog_show', array('id' => $post->getId())) ?>"> <?php echo $post->getTitle() ?> </a> </li> <?php endforeach; ?> </ul>
he lyout is nerly identilX
<!-- app/Resources/views/layout.html.php --> <html> <head> <title><?php echo $view['slots']->output('title', 'Default title') ?></title>
TH SF
# app/cong/routing.yml blog_list: pattern: /blog defaults: { _controller: AcmeBlogBundle:Blog:list } blog_show: pattern: /blog/show/{id} defaults: { _controller: AcmeBlogBundle:Blog:show }
xow tht ymfonyP is hndling ll the mundne tsksD the front ontroller is ded simpleF end sine it does so littleD you9ll never hve to touh it one it9s reted @nd if you use ymfonyP distriutionD you won9t even need to rete it3AX
<?php // web/app.php require_once __DIR__.'/../app/bootstrap.php'; require_once __DIR__.'/../app/AppKernel.php'; use Symfony\Component\HttpFoundation\Request; $kernel = new AppKernel('prod', false); $kernel->handle(Request::createFromGlobals())->send();
he front ontroller9s only jo is to initilize ymfonyP9s engine @uernelA nd pss it equest ojet to hndleF ymfonyP9s ore then uses the routing mp to determine whih ontroller to llF tust like eforeD the ontroller method is responsile for returning the (nl esponse ojetF here9s relly not muh else to itF por visul representtion of how ymfonyP hndles eh requestD see the request )ow digrmF
TI
ymfony houmenttionD PFH here ymfonyP helivers sn the upoming hptersD you9ll lern more out how eh piee of ymfony works nd the reommended orgniztion of projetF por nowD let9s see how migrting the log from )t r to ymfonyP hs improved lifeX
our pplition now hs ler nd onsistently orgnized ode @though ymfony doesn9t fore you into thisAF his promotes reusility nd llows for new developers to e produtive in your projet more quiklyF IHH7 of the ode you write is for your pplitionF ou don9t need to develop or mintin lowElevel utilities suh s utolodingD routingD or rendering ontrollersF ymfonyP gives you ess to open soure tools suh s hotrine nd the empltingD eurityD pormD lidtion nd rnsltion omponents @to nme fewAF he pplition now enjoys fullyE)exile vs thnks to the outing omponentF ymfonyP9s rEentri rhiteture gives you ess to powerful tools suh s r hing powered y ymfonyP9s internl r he or more powerful tools suh s rnishF his is overed in lter hpter ll out hingF
end perhps est of llD y using ymfonyPD you now hve ess to whole set of highE qulity open soure tools developed y the ymfonyP ommunity3 por more informtionD hek out ymfonyPfundlesForg
5.2.4 Better templates
sf you hoose to use itD ymfonyP omes stndrd with templting engine lled wig tht mkes templtes fster to write nd esier to redF st mens tht the smple pplition ould ontin even less ode3 keD for exmpleD the list templte written in wigX
{# src/Acme/BlogBundle/Resources/views/Blog/list.html.twig #} {% extends "::layout.html.twig" %} {% block title %}List of Posts{% endblock %} {% block body %} <h1>List of Posts</h1> <ul> {% for post in posts %} <li> <a href="{{ path('blog_show', { 'id': post.id }) }}"> {{ post.title }} </a> </li> {% endfor %}
TP
SF
</ul> {% endblock %}
he orresponding lyoutFhtmlFtwig templte is lso esier to writeX
{# app/Resources/views/layout.html.twig #} <html> <head> <title>{% block title %}Default title{% endblock %}</title> </head> <body> {% block body %}{% endblock %} </body> </html>
wig is wellEsupported in ymfonyPF end while r templtes will lwys e supported in ymfonyPD we9ll ontinue to disuss the mny dvntges of wigF por more informtionD see the templting hpterF
5.2.5 Learn more from the Cookbook
row to use r insted of wig for empltes row to de(ne gontrollers s ervies
he gol of this hpter is to get you up nd running with working pplition uilt on top of ymfonyF portuntelyD ymfony o'ers distriutionsD whih re funtionl ymfony strter projets tht you n downlod nd egin developing in immeditelyF X sf you9re looking for instrutions on how est to rete new projet nd store it vi soure ontrolD see sing oure gontrolF
X pirstD hek tht you hve instlled nd on(gured e server @suh s epheA with r SFQFP or higherF por more informtion on ymfonyP requirementsD see the requirements refereneF SFQF snstlling nd gon(guring ymfony TQ
ymfonyP pkges distriutionsD whih re fullyEfuntionl pplitions tht inlude the ymfonyP ore lirriesD seletion of useful undlesD sensile diretory struture nd some defult on(gurtionF hen you downlod ymfonyP distriutionD you9re downloding funtionl pplition skeleton tht n e used immeditely to egin developing your pplitionF trt y visiting the ymfonyP downlod pge t httpXGGsymfonyFomGdownlodF yn this pgeD you9ll see the ymfony tndrd iditionD whih is the min ymfonyP distriutionF rereD you9ll need to mke two hoiesX
hownlod either Ftgz or Fzip rhive E oth re equivlentD downlod whtever you9re more omfortle usingY hownlod the distriution with or without vendorsF sf you hve qit instlled on your omputerD you should downlod ymfonyP without vendorsD s it dds it more )exiility when inluding thirdEprtyGvendor lirriesF
hownlod one of the rhives somewhere under your lol we server9s root diretory nd unpk itF prom xs ommnd lineD this n e done with one of the following ommnds @repling 555 with your tul (lenmeAX
# for .tgz le tar zxvf Symfony_Standard_Vendors_2.0.###.tgz # for a .zip le unzip Symfony_Standard_Vendors_2.0.###.zip
hen you9re (nishedD you should hve ymfonyG diretory tht looks something like thisX
www/ <- your web root directory Symfony/ <- the unpacked archive app/ cache/ cong/ logs/ src/ ... vendor/ ... web/ app.php ...
TR
SF
ymfony houmenttionD PFH pdting endors pinllyD if you downloded the rhive without vendorsD instll the vendors y running the following ommnd from the ommnd lineX
http://localhost/Symfony/web/cong.php
sf there re ny issuesD orret them now efore moving onF
TS
ymfony houmenttionD PFH etting up ermissions yne ommon issue is tht the ppGhe nd ppGlogs diretories must e writle oth y the we server nd the ommnd line userF yn xs systemD if your we server user is di'erent from your ommnd line userD you n run the following ommnds just one in your projet to ensure tht permissions will e setup properlyF ghnge wwwEdt to the we server user nd yournme to your ommnd line userX IF sing egv on system tht supports hmod C wny systems llow you to use the hmod C ommndF ry this (rstD nd if you get n error E try the next methodX
rm -rf app/cache/* rm -rf app/logs/* sudo chmod +a "www-data allow delete,write,append,le_inherit,directory_inherit" app/cache app/logs sudo chmod +a "yourname allow delete,write,append,le_inherit,directory_inherit" app/cache app/logs
PF sing el on system tht does not support hmod C ome systems don9t support hmod CD ut do support nother utility lled setflF ou my need to enle egv support on your prtition nd instll setfl efore using it @s is the se with untuAD like soX
sudo setfacl -R -m u:www-data:rwx -m u:yourname:rwx app/cache app/logs sudo setfacl -dR -m u:www-data:rwx -m u:yourname:rwx app/cache app/logs
QF ithout using egv sf you don9t hve ess to hnging the egv of the diretoriesD you will need to hnge the umsk so tht the he nd log diretories will e groupEwritle or worldEwritle @depending if the we server user nd the ommnd line user re in the sme group or notAF o hieve thisD put the following line t the eginning of the ppGonsoleD weGppFphp nd weGppdevFphp (lesX
umask(0002); // This will let the permissions be 0775 // or umask(0000); // This will let the permissions be 0777
xote tht using the egv is reommended when you hve ess to them on your server euse hnging the umsk is not thredEsfeF hen everything is (neD lik on qo to the elome pge to request your (rst rel ymfonyP wepgeX
http://localhost/Symfony/web/app_dev.php/
ymfonyP should welome nd ongrtulte you for your hrd work so fr3
TT
SF
xow tht you hve fullyEfuntionl ymfonyP pplitionD you n egin development3 our distriution my ontin some smple ode E hek the iehwiFrst (le inluded with the distriution @open it s text (leA to lern out wht smple ode ws inluded with your distriution nd how you n remove it lterF sf you9re new to ymfonyD join us in the ymfonyPD where you9ll lern how to rete pgesD hnge on(gurtionD nd do everything else you9ll need in your new pplitionF
5.3.3 Using Source Control
sf you9re using version ontrol system like qit or uversionD you n setup your version ontrol system nd egin ommitting your projet to it s normlF he ymfony tndrd edition is the strting point for your new projetF por spei( instrutions on how est to setup your projet to e stored in gitD see row to grete nd store ymfonyP rojet in gitF
TU
ymfony houmenttionD PFH sgnoring the vendorG hiretory sf you9ve downloded the rhive without vendorsD you n sfely ignore the entire vendorG diretory nd not ommit it to soure ontrolF ith qitD this is done y reting nd dding the following to Fgitignore (leX
vendor/
xowD the vendor diretory won9t e ommitted to soure ontrolF his is (ne @tullyD it9s gret3A euse when someone else lones or heks out the projetD heGshe n simply run the php inGvendors instll sript to downlod ll the neessry vendor lirriesF
5.4 Symfony2
ymfonyP D P X
rello orld3F D E D E vX
http://localhost/app_dev.php/hello/Symfony
ymfony F F X D ymfonyP E F vD D D lolhost TV SF
// app/AppKernel.php public function registerBundles() { $bundles = array( // ... new Acme\HelloBundle\AcmeHelloBundle(), ); // ... } return $bundles;
ewv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <import resource="@AcmeHelloBundle/Resources/cong/routing.xml" prex="/" /> </routes>
r
// app/cong/routing.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->addCollection( $loader->import('@AcmeHelloBundle/Resources/cong/routing.php'), '/', ); return $collection;
X ymfony esouresGon(gGroutingFymlD emerellofundleF D ppGon(gGroutingFyml E F routingFyml D E D X
ewv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="hello" pattern="/hello/{name}"> <default key="_controller">AcmeHelloBundle:Hello:index</default> </route> </routes>
r
// src/Acme/HelloBundle/Resources/cong/routing.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('hello', new Route('/hello/{name}', array( '_controller' => 'AcmeHelloBundle:Hello:index', ))); return $collection;
X ptternD sD defults D E F @pleholderA @{nme}A ! @wildrdAF D s GhelloGynD GhelloGpienD D D F D E {nme} D D F X s F E F
// src/Acme/HelloBundle/Controller/HelloController.php // ... class HelloController { public function indexAction($name) { return new Response('<html><body>Hello '.$name.'!</body></html>'); } }
X esponse D @ rwvED AF 3 D 3 D X
http://localhost/app_dev.php/hello/Ryan
X ou n lso view your pp in the prod environment y visitingX
http://localhost/app.php/hello/Ryan
sf you get n errorD it9s likely euse you need to ler your he y runningX UP SF
QX @rwv A E F D X
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// src/Acme/HelloBundle/Controller/HelloController.php namespace Acme\HelloBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class HelloController extends Controller { public function indexAction($name) { return $this->render('AcmeHelloBundle:Hello:index.html.twig', array('name' => $name)); // render a PHP template instead // return $this->render('AcmeHelloBundle:Hello:index.html.php', array('name' => $name));
SFRF ymfonyP
UQ
ymfony houmenttionD PFH D F ymfonyP ED P X rE D wigF D D F emerellofundleXrelloXindexFhtmlFtwigD E X fundlexmeXgontrollerxmeXempltexme D F GpthGtoGfundlexmeGesouresGviewsGgontrollerxmeGempltexme D emerellofundle ! D rello ! indexFhtmlFtwig X
wig
1 2 3 4 5 6
<!-- src/Acme/HelloBundle/Resources/views/Hello/index.html.php --> <?php $view->extend('::base.html.php') ?> Hello <?php echo $view->escape($name) ?>!
wigX
wig
UR
SF
{# app/Resources/views/base.html.twig #} <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>{% block title %}Welcome!{% endblock %}</title> {% block stylesheets %}{% endblock %} <link rel="shortcut icon" href="{{ asset('favicon.ico') }}" /> </head> <body> {% block body %}{% endblock %} {% block javascripts %}{% endblock %} </body> </html>
r
<!-- app/Resources/views/base.html.php --> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title><?php $view['slots']->output('title', 'Welcome!') ?></title> <?php $view['slots']->output('stylesheets') ?> <link rel="shortcut icon" href="<?php echo $view['assets']->getUrl('favicon.ico') ?>" /> </head> <body> <?php $view['slots']->output('_content') ?> <?php $view['slots']->output('stylesheets') ?> </body> </html>
rwv ody indexFhtmlFtwigF title indexFhtmlFtwigF title D ! elome3F ! rwv D g D D E F ! F D esponseF D E D esponseF
SFRF ymfonyP
US
// web/app.php require_once __DIR__.'/../app/bootstrap.php.cache'; require_once __DIR__.'/../app/AppKernel.php'; use Symfony\Component\HttpFoundation\Request; $kernel = new AppKernel('prod', false); $kernel->loadClassCache(); $kernel->handle(Request::createFromGlobals())->send();
E @ ! ppFphpA E r D E D ymfonyP E uernelED eppuernelD F X E vD D r E F ED v X
http://localhost/app.php/hello/Ryan
E ppFphp v GhelloGyn E F UT SF
http://localhost/hello/Ryan
E D F D F @ppA ED eppuernel ! E F D ppGF D D ymfony F D ! EF
registerfundles@AX D E @F AY registergontinergon(gurtion@AX @F AF
ppG D E ppGon(gG diretory @F AF ppG @ppGheAD @ppGlogsA @ppGesouresAF F
SFRF ymfonyP
UU
ymfony houmenttionD PFH E ppGutolodFphpF srG vendorGF E inlude requireF D ymfonyP E D E D F D ymfonyP sr E eme @ AF D X
UV
SF
// app/AppKernel.php public function registerBundles() { $bundles = array( new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), new Symfony\Bundle\SecurityBundle\SecurityBundle(), new Symfony\Bundle\TwigBundle\TwigBundle(), new Symfony\Bundle\MonologBundle\MonologBundle(), new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), new Symfony\Bundle\DoctrineBundle\DoctrineBundle(), new Symfony\Bundle\AsseticBundle\AsseticBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new JMS\SecurityExtraBundle\JMSSecurityExtraBundle(), ); if (in_array($this->getEnvironment(), array('dev', 'test'))) { $bundles[] = new Acme\DemoBundle\AcmeDemoBundle(); $bundles[] = new Symfony\Bundle\WebProlerBundle\WebProlerBundle(); $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); } } return $bundles;
SFRF ymfonyP
UW
// app/AppKernel.php public function registerBundles() { $bundles = array( // ... // register your bundles new Acme\TestBundle\AcmeTestBundle(),
); // ... }
return $bundles;
D D F ymfony VH SF
F D D ymfonyPF emerellofundleD E X
gontrollerG @ rellogontrollerFphpAY esouresGon(gG D @ routingFymlAY esouresGviewsG D @ relloGindexFhtmlFtwigAY esouresGpuliG @D F F F AD E weG ssetsXinstll estsG F
D ! D F D ! F D D D F F
5.4.4
ewv
# app/cong/cong.yml imports: - { resource: parameters.ini } - { resource: security.yml } framework: secret: %secret% charset: UTF-8 router: { resource: "%kernel.root_dir%/cong/routing.yml" } form: true csrf_protection: true validation: { enable_annotations: true } templating: { engines: ['twig'] } #assets_version: SomeVersionScheme session: default_locale: %locale% auto_start: true # Twig Conguration twig: debug: %kernel.debug% strict_variables: %kernel.debug% # ...
wv
<!-- app/cong/cong.xml --> <imports> <import resource="parameters.ini" /> <import resource="security.yml" /> </imports> <framework:cong charset="UTF-8" secret="%secret%"> <framework:router resource="%kernel.root_dir%/cong/routing.xml" /> <framework:form /> <framework:csrf-protection /> <framework:validation annotations="true" /> <framework:templating assets-version="SomeVersionScheme"> <framework:engine id="twig" /> </framework:templating> <framework:session default-locale="%locale%" auto-start="true" /> </framework:cong> <!-- Twig Conguration --> <twig:cong debug="%kernel.debug%" strict-variables="%kernel.debug%" />
VP
SF
$this->import('parameters.ini'); $this->import('security.yml'); $container->loadFromExtension('framework', array( 'secret' => '%secret%', 'charset' => 'UTF-8', 'router' => array('resource' => '%kernel.root_dir%/cong/routing.php'), 'form' => array(), 'csrf-protection' => array(), 'validation' => array('annotations' => true), 'templating' => array( 'engines' => array('twig'), #'assets_version' => "SomeVersionScheme", ), 'session' => array( 'default_locale' => "%locale%", 'auto_start' => true, ), )); // Twig Conguration $container->loadFromExtension('twig', array( 'debug' => '%kernel.debug%', 'strict_variables' => '%kernel.debug%', )); // ...
X G ! invironmentsF D frmework twigD E F D frmework ymfony prmeworkfundle D E F F F F
SFRF ymfonyP
VQ
ymfony houmenttionD PFH @ewvD wv nd rAF E F X ewvX D Y wvX D ewvF shi @utoompletionAY rX D D E F
5.4.5
F E r @ EAD F D dev E D prod F dev D prod F D F ymfonyP @devD test prodAD F E E F E dev D ppdevFphpX
http://localhost/app_dev.php/hello/Ryan
D D E prodX
http://localhost/app.php/hello/Ryan
prod D D E wig r F D X
VR
SF
X test E F F
eppuernel X
ewv
# app/cong/cong_dev.yml imports: - { resource: cong.yml } framework: router: { resource: "%kernel.root_dir%/cong/routing_dev.yml" } proler: { only_exceptions: false } # ...
wv
<!-- app/cong/cong_dev.xml --> <imports> <import resource="cong.xml" /> </imports> <framework:cong> <framework:router resource="%kernel.root_dir%/cong/routing_dev.xml" /> <framework:proler only-exceptions="false" /> </framework:cong>
SFRF ymfonyP VS
// app/cong/cong_dev.php $loader->import('cong.php'); $container->loadFromExtension('framework', array( 'router' => array('resource' => '%kernel.root_dir%/cong/routing_dev.php'), 'proler' => array('only-exceptions' => false), )); // ...
imports inlude r E @on(gFymlA F E D F ! prod test X F E D E E F
5.4.6
3 ymfonyP D E F D D X
! D D @A F R X weG @we ssets front ontrollersAD ppG @AD srG @ AD vendorG @ AY ymfonyP @ A D D Y ppGon(g ewvD wv rY E @ ppFphp ppdevFphpA F
VT
SF
5.5 Controller
e ontroller is r funtion you rete tht tkes informtion from the r request nd onstruts nd returns n r response @s ymfonyP esponse ojetAF he response ould e n rwv pgeD n wv doumentD serilized tyx rryD n imgeD rediretD RHR error or nything else you n drem upF he ontroller ontins whtever ritrry logi your pplition needs to render the ontent of pgeF o see how simple this isD let9s look t ymfonyP ontroller in tionF he following ontroller would render pge tht simply prints rello world3X
gontroller e prepres esponse ojet representing the ontent for the homepge of the siteF gontroller f reds the slug prmeter from the request to lod log entry from the dtse nd rete esponse ojet displying tht logF sf the slug n9t e found in the dtseD it retes nd returns esponse ojet with RHR sttus odeF gontroller g hndles the form sumission of ontt formF st reds the form informtion from the requestD sves the ontt informtion to the dtse nd emils the ontt informtion to the wemsterF pinllyD it retes esponse ojet tht redirets the lient9s rowser to the ontt form thnk you pgeF
SFSF gontroller
VU
ivery request hndled y ymfonyP projet goes through the sme simple lifeyleF he frmework tkes re of the repetitive tsks nd ultimtely exeutes ontrollerD whih houses your ustom pplition odeX IF ih request is hndled y single front ontroller (le @eFgF ppFphp or ppdevFphpA tht ootstrps the pplitionY PF he outer reds informtion from the request @eFgF the sAD (nds route tht mthes tht informtionD nd reds the ontroller prmeter from the routeY QF he ontroller from the mthed route is exeuted nd the ode inside the ontroller retes nd returns esponse ojetY RF he r heders nd ontent of the esponse ojet re sent k to the lientF greting pge is s esy s reting ontroller @5QA nd mking route tht mps v to tht ontroller @5PAF X hough similrly nmedD front ontroller is di'erent from the ontrollers we9ll tlk out in this hpterF e front ontroller is short r (le tht lives in your we diretory nd through whih ll requests re diretedF e typil pplition will hve prodution front ontroller @eFgF ppFphpA nd development front ontroller @eFgF ppdevFphpAF ou9ll likely never need to editD view or worry out the front ontrollers in your pplitionF
hile ontroller n e ny r llle @ funtionD method on n ojetD or glosureAD in ymfonyPD ontroller is usully single method inside ontroller ojetF gontrollers re lso lled tionsF
1 2 3 4 5 6 7 8 9 10 11 12
// src/Acme/HelloBundle/Controller/HelloController.php namespace Acme\HelloBundle\Controller; use Symfony\Component\HttpFoundation\Response; class HelloController { public function indexAction($name) { return new Response('<html><body>Hello '.$name.'!</body></html>'); } }
VV
SF
X xote tht the ontroller is the indexetion methodD whih lives inside ontroller lss @rellogontrollerAF hon9t e onfused y the nmingX ontroller lss is simply onvenient wy to group severl ontrollersGtions togetherF ypillyD the ontroller lss will house severl ontrollersGtions @eFgF updteetionD deleteetionD etAF his ontroller is pretty strightforwrdD ut let9s wlk through itX
line QX ymfonyP tkes dvntge of r SFQ nmespe funtionlity to nmespe the entire ontroller lssF he use keyword imports the esponse lssD whih our ontroller must returnF line TX he lss nme is the ontention of nme for the ontroller lss @iFeF relloA nd the word gontrollerF his is onvention tht provides onsisteny to ontrollers nd llows them to e referened only y the (rst prt of the nme @iFeF relloA in the routing on(gurtionF line VX ih tion in ontroller lss is su0xed with etion nd is referened in the routing on(gurtion y the tion9s nme @indexAF sn the next setionD you9ll rete route tht mps s to this tionF ou9ll lern how the route9s pleholders @{nme}A eome rguments to the tion method @6nmeAF line IHX he ontroller retes nd returns esponse ojetF
5.5.3 Mapping a URL to a Controller
he new ontroller returns simple rwv pgeF o tully view this pge in your rowserD you need to rete routeD whih mps spei( v pttern to the ontrollerX
ewv
X ou n lern muh more out the routing system in the outing hpterF
oute rmeters s gontroller erguments ou lredy know tht the ontroller prmeter emerellofundleXrelloXindex refers to rellogontrollerXXindexetion@A method tht lives inside the emerellofundle undleF ht9s more interesting is the rguments tht re pssed to tht methodX
<?php // src/Acme/HelloBundle/Controller/HelloController.php namespace Acme\HelloBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class HelloController extends Controller { public function indexAction($name) { // ... } }
he ontroller hs single rgumentD 6nmeD whih orresponds to the {nme} prmeter from the mthed route @ryn in our exmpleAF sn ftD when exeuting your ontrollerD
WH
SF
ymfony houmenttionD PFH ymfonyP mthes eh rgument of the ontroller with prmeter from the mthed routeF ke the following exmpleX
ewv
<!-- app/cong/routing.xml --> <route id="hello" pattern="/hello/{rst_name}/{last_name}"> <default key="_controller">AcmeHelloBundle:Hello:index</default> <default key="color">green</default> </route>
r
// app/cong/routing.php $collection->add('hello', new Route('/hello/{rst_name}/{last_name}', array( '_controller' => 'AcmeHelloBundle:Hello:index', 'color' => 'green', )));
he ontroller for this n tke severl rgumentsX
// ..
he equest s gontroller ergument por onvenieneD you n lso hve ymfony pss you the equest ojet s n rgument to your ontrollerF his is espeilly onvenient when you9re working with formsD for exmpleX
$form->bindRequest($request); // ...
por onvenieneD ymfonyP omes with se gontroller lss tht ssists with some of the most ommon ontroller tsks nd gives your ontroller lss ess to ny resoure it might needF fy extending this gontroller lssD you n tke dvntge of severl helper methodsF edd the use sttement top the gontroller lss nd then modify the rellogontroller to extend itX
// src/Acme/HelloBundle/Controller/HelloController.php namespace Acme\HelloBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Response; class HelloController extends Controller { public function indexAction($name) { return new Response('<html><body>Hello '.$name.'!</body></html>'); } }
his doesn9t tully hnge nything out how your ontroller worksF sn the next setionD you9ll lern out the helper methods tht the se ontroller lss mkes villeF hese methods re just shortuts to using ore ymfonyP funtionlity tht9s ville to you with or without the use of the se gontroller lssF e gret wy to see the ore funtionlity in tion is to look in the ymfonyfundleprmeworkfundlegontrollergontroller lss itselfF X ixtending the se lss is optionl in ymfonyY it ontins useful shortuts ut nothing mndtoryF ou n lso extend ymfonygomponenthependenysnjetiongontinerewreF he servie ontiner ojet will then e essile vi the ontiner propertyF
SFSF gontroller
WQ
hough ontroller n do virtully nythingD most ontrollers will perform the sme si tsks over nd over ginF hese tsksD suh s rediretingD forwrdingD rendering templtes nd essing ore serviesD re very esy to mnge in ymfonyPF edireting sf you wnt to rediret the user to nother pgeD use the rediret@A methodX
porwrding ou n lso esily forwrd to nother ontroller internlly with the forwrd@A methodF snsted of redireting the user9s rowserD it mkes n internl suErequestD nd lls the spei(ed ontrollerF he forwrd@A method returns the esponse ojet tht9s returned from tht ontrollerX
));
xotie tht the forwrd@A method uses the sme string representtion of the ontroller used in the routing on(gurtionF sn this seD the trget ontroller lss will e rellogontroller inside some emerellofundleF he rry pssed to the method eomes the rguments on the resulting ontrollerF his sme interfe is used when emedding ontrollers into templtes @see imedding gontrollersAF he trget ontroller method should look something like the followingX
public function fancyAction($name, $color) { // ... create and return a Response object }
end just like when reting ontroller for routeD the order of the rguments to fnyetion doesn9t mtterF ymfonyP mthes the index key nmes @eFgF nmeA with the method rgument nmes @eFgF 6nmeAF sf you hnge the order of the rgumentsD ymfonyP will still pss the orret vlue to eh vrileF X vike other se gontroller methodsD the forwrd method is just shortut for ore ymfonyP funtionlityF e forwrd n e omplished diretly vi the httpkernel servieF e forwrd returns esponse ojetX
$httpKernel = $this->container->get('http_kernel'); $response = $httpKernel->forward('AcmeHelloBundle:Hello:fancy', array( 'name' => $name, 'color' => 'green', ));
endering empltes hough not requirementD most ontrollers will ultimtely render templte tht9s responsile for generting the rwv @or other formtA for the ontrollerF he renderiew@A method renders templte nd returns its ontentF he ontent from the templte n e used to rete esponse ojetX
SFSF gontroller
WS
he ymfony templting engine is explined in gret detil in the emplting hpterF X he renderiew method is shortut to diret use of the templting servieF he templting servie n lso e used diretlyX
eessing other ervies hen extending the se ontroller lssD you n ess ny ymfonyP servie vi the get@A methodF rere re severl ommon servies you might needX
hen things re not foundD you should ply well with the r protool nd return RHR responseF o do thisD you9ll throw speil type of exeptionF sf you9re extending the se ontroller lssD do the followingX
WT
SF
public function indexAction() { $product = // retrieve the object from database if (!$product) { throw $this->createNotFoundException('The product does not exist'); } } return $this->render(...);
he retexotpoundixeption@A method retes speil xotpoundrttpixeption ojetD whih ultimtely triggers RHR r response inside ymfonyF yf ourseD you9re free to throw ny ixeption lss in your ontroller E ymfonyP will utomtilly return SHH r response odeF
ymfonyP provides nie session ojet tht you n use to store informtion out the user @e it rel person using rowserD otD or we servieA etween requestsF fy defultD ymfonyP stores the ttriutes in ookie y using the ntive r sessionsF toring nd retrieving informtion from the session n e esily hieved from ny ontrollerX
$session = $this->getRequest()->getSession(); // store an attribute for reuse during a later user request $session->set('foo', 'bar'); // in another controller for another request $foo = $session->get('foo'); // set the user locale $session->setLocale('fr');
hese ttriutes will remin on the user for the reminder of tht user9s sessionF
SFSF gontroller
WU
ymfony houmenttionD PFH plsh wessges ou n lso store smll messges tht will e stored on the user9s session for extly one dditionl requestF his is useful when proessing formX you wnt to rediret nd hve speil messge shown on the next requestF hese types of messges re lled )sh messgesF por exmpleD imgine you9re proessing form sumitX
public function updateAction() { $form = $this->createForm(...); $form->bindRequest($this->getRequest()); if ($form->isValid()) { // do some sort of processing $this->get('session')->setFlash('notice', 'Your changes were saved!'); } } return $this->redirect($this->generateUrl(...));
return $this->render(...);
efter proessing the requestD the ontroller sets notie )sh messge nd then rediretsF he nme @notieA isn9t signi(nt E it9s just wht you9re using to identify the type of the messgeF sn the templte of the next tionD the following ode ould e used to render the notie messgeX
wig
<?php if ($view['session']->hasFlash('notice')): ?> <div class="ash-notice"> <?php echo $view['session']->getFlash('notice') ?> </div> <?php endif; ?>
fy designD )sh messges re ment to live for extly one request @they9re gone in )shAF WV SF
ymfony houmenttionD PFH hey9re designed to e used ross redirets extly s you9ve done in this exmpleF
5.5.8 The Response Object
he only requirement for ontroller is to return esponse ojetF he ymfonygomponentrttppoundtionesponse lss is r strtion round the r response E the textEsed messge (lled with r heders nd ontent tht9s sent k to the lientX
// create a simple Response with a 200 status code (the default) $response = new Response('Hello '.$name, 200); // create a JSON-response with a 200 status code $response = new Response(json_encode(array('name' => $name))); $response->headers->set('Content-Type', 'application/json');
X he heders property is ymfonygomponentrttppoundtionrederfg ojet with severl useful methods for reding nd mutting the esponse hedersF he heder nmes re normlized so tht using gontentEype is equivlent to ontentEtype or even ontenttypeF
fesides the vlues of the routing pleholdersD the ontroller lso hs ess to the equest ojet when extending the se gontroller lssX
$request = $this->getRequest(); $request->isXmlHttpRequest(); // is it an Ajax request? $request->getPreferredLanguage(array('en', 'fr')); $request->query->get('page'); // get a $_GET parameter $request->request->get('page'); // get a $_POST parameter
vike the esponse ojetD the request heders re stored in rederfg ojet nd re esily essileF
SFSF gontroller
WW
henever you rete pgeD you9ll ultimtely need to write some ode tht ontins the logi for tht pgeF sn ymfonyD this is lled ontrollerD nd it9s r funtion tht n do nything it needs in order to return the (nl esponse ojet tht will e returned to the userF o mke life esierD you n hoose to extend se gontroller lssD whih ontins shortut methods for mny ommon ontroller tsksF por exmpleD sine you don9t wnt to put rwv ode in your ontrollerD you n use the render@A method to render nd return the ontent from templteF sn other hptersD you9ll see how the ontroller n e used to persist nd feth ojets from dtseD proess form sumissionsD hndle hing nd moreF
5.5.11 Learn more from the Cookbook
5.6 Routing
feutiful vs re n solute must for ny serious we pplitionF his mens leving ehind ugly vs like indexFphpcrtileidaSU in fvor of something like GredGintroEtoE symfonyF rving )exiility is even more importntF ht if you need to hnge the v of pge from Glog to Gnewsc row mny links should you need to hunt down nd updte to mke the hngec sf you9re using ymfony9s routerD the hnge is simpleF he ymfonyP router lets you de(ne retive vs tht you mp to di'erent res of your pplitionF fy the end of this hpterD you9ll e le toX
grete omplex routes tht mp to ontrollers qenerte vs inside templtes nd ontrollers vod routing resoures from undles @or nywhere elseA heug your routes
5.6.1 Routing in Action
e route is mp from v pttern to ontrollerF por exmpleD suppose you wnt to mth ny v like GlogGmyEpost or GlogGllEoutEsymfony nd send it to ontroller IHH SF
ymfony houmenttionD PFH tht n look up nd render tht log entryF he route is simpleX
ewv
<!-- app/cong/routing.xml --> <?xml version="1.0" encoding="UTF-8" ?> <routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="blog_show" pattern="/blog/{slug}"> <default key="_controller">AcmeBlogBundle:Blog:show</default> </route> </routes>
r
// app/cong/routing.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('blog_show', new Route('/blog/{slug}', array( '_controller' => 'AcmeBlogBundle:Blog:show', ))); return $collection;
he pttern de(ned y the logshow route ts like GlogGB where the wildrd is given the nme slugF por the v GlogGmyElogEpostD the slug vrile gets vlue of myElogEpostD whih is ville for you to use in your ontroller @keep redingAF he ontroller prmeter is speil key tht tells ymfony whih ontroller should e exeuted when v mthes this routeF he ontroller string is lled the logil nmeF st follows pttern tht points to spei( r lss nd methodX
public function showAction($slug) { $blog = // use the $slug varible to query the database return $this->render('AcmeBlogBundle:Blog:show.html.twig', array( 'blog' => $blog, ));
gongrtultions3 ou9ve just reted your (rst route nd onneted it to ontrollerF xowD when you visit GlogGmyEpostD the showetion ontroller will e exeuted nd the 6slug vrile will e equl to myEpostF his is the gol of the ymfonyP routerX to mp the v of request to ontrollerF elong the wyD you9ll lern ll sorts of triks tht mke mpping even the most omplex vs esyF
5.6.2 Routing: Under the Hood
hen request is mde to your pplitionD it ontins n ddress to the ext resoure tht the lient is requestingF his ddress is lled the vD @or sAD nd ould e GonttD GlogGredEmeD or nything elseF ke the following r request for exmpleX
GET /blog/my-blog-post
he gol of the ymfonyP routing system is to prse this v nd determine whih ontroller should e exeutedF he whole proess looks like thisX IF he request is hndled y the ymfonyP front ontroller @eFgF ppFphpAY PF he ymfonyP ore @iFeF uernelA sks the router to inspet the requestY QF he router mthes the inoming v to spei( route nd returns informtion out the routeD inluding the ontroller tht should e exeutedY RF he ymfonyP uernel exeutes the ontrollerD whih ultimtely returns esponse ojetF
5.6.3 Creating Routes
ymfony lods ll the routes for your pplition from single routing on(gurtion (leF he (le is usully ppGon(gGroutingFymlD ut n e on(gured to e nything @inluding n wv or r (leA vi the pplition on(gurtion (leX
ewv
IHP SF
F SFPX he routing lyer is tool tht trnsltes the inoming v into spei( ontroller to exeuteF
<!-- app/cong/cong.xml --> <framework:cong ...> <!-- ... --> <framework:router resource="%kernel.root_dir%/cong/routing.xml" /> </framework:cong>
r
// app/cong/cong.php $container->loadFromExtension('framework', array( // ... 'router' => array('resource' => '%kernel.root_dir%/cong/routing.php'), ));
X iven though ll routes re loded from single (leD it9s ommon prtie to inlude dditionl routing resoures from inside the (leF ee the snluding ixternl outing esoures setion for more informtionF
SFTF outing
IHQ
ymfony houmenttionD PFH fsi oute gon(gurtion he(ning route is esyD nd typil pplition will hve lots of routesF e si route onsists of just two prtsX the pttern to mth nd defults rryX
ewv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="_welcome" pattern="/"> <default key="_controller">AcmeDemoBundle:Main:homepage</default> </route> </routes>
r
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('_welcome', new Route('/', array( '_controller' => 'AcmeDemoBundle:Main:homepage', ))); return $collection;
his route mthes the homepge @GA nd mps it to the emehemofundleXwinXhomepge ontrollerF he ontroller string is trnslted y ymfonyP into n tul r funtion nd exeutedF ht proess will e explined shortly in the gontroller xming ttern setionF outing with leholders yf ourse the routing system supports muh more interesting routesF wny routes will ontin one or more nmed wildrd pleholdersX
ewv
IHR
SF
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="blog_show" pattern="/blog/{slug}"> <default key="_controller">AcmeBlogBundle:Blog:show</default> </route> </routes>
r
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('blog_show', new Route('/blog/{slug}', array( '_controller' => 'AcmeBlogBundle:Blog:show', ))); return $collection;
he pttern will mth nything tht looks like GlogGBF iven etterD the vlue mthing the {slug} pleholder will e ville inside your ontrollerF sn other wordsD if the v is GlogGhelloEworldD 6slug vrileD with vlue of helloEworldD will e ville in the ontrollerF his n e usedD for exmpleD to lod the log post mthing tht stringF he pttern will notD howeverD mth simply GlogF ht9s euseD y defultD ll pleholders re requiredF his n e hnged y dding pleholder vlue to the defults rryF equired nd yptionl leholders o mke things more exitingD dd new route tht displys list of ll the ville log posts for this imginry log pplitionX
ewv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="blog" pattern="/blog"> <default key="_controller">AcmeBlogBundle:Blog:index</default> </route> </routes>
r
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('blog', new Route('/blog', array( '_controller' => 'AcmeBlogBundle:Blog:index', ))); return $collection;
o frD this route is s simple s possile E it ontins no pleholders nd will only mth the ext v GlogF fut wht if you need this route to support pgintionD where GlogGP displys the seond pge of log entriesc pdte the route to hve new {pge} pleholderX
ewv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="blog" pattern="/blog/{page}"> <default key="_controller">AcmeBlogBundle:Blog:index</default> </route>
IHT SF
</routes>
r
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('blog', new Route('/blog/{page}', array( '_controller' => 'AcmeBlogBundle:Blog:index', ))); return $collection;
vike the {slug} pleholder eforeD the vlue mthing {pge} will e ville inside your ontrollerF sts vlue n e used to determine whih set of log posts to disply for the given pgeF fut hold on3 ine pleholders re required y defultD this route will no longer mth on simply GlogF snstedD to see pge I of the logD you9d need to use the v GlogGI3 ine tht9s no wy for rih we pp to ehveD modify the route to mke the {pge} prmeter optionlF his is done y inluding it in the defults olletionX
ewv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="blog" pattern="/blog/{page}"> <default key="_controller">AcmeBlogBundle:Blog:index</default> <default key="page">1</default> </route> </routes>
r
$collection->add('blog', new Route('/blog/{page}', array( '_controller' => 'AcmeBlogBundle:Blog:index', 'page' => 1, ))); return $collection;
fy dding pge to the defults keyD the {pge} pleholder is no longer requiredF he v Glog will mth this route nd the vlue of the pge prmeter will e set to IF he v GlogGP will lso mthD giving the pge prmeter vlue of PF erfetF Glog GlogGI GlogGP {pge} a I {pge} a I {pge} a P
edding equirements ke quik look t the routes tht hve een reted so frX
ewv
blog: pattern: /blog/{page} defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 } blog_show: pattern: /blog/{slug} defaults: { _controller: AcmeBlogBundle:Blog:show }
wv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="blog" pattern="/blog/{page}"> <default key="_controller">AcmeBlogBundle:Blog:index</default> <default key="page">1</default> </route> <route id="blog_show" pattern="/blog/{slug}"> <default key="_controller">AcmeBlogBundle:Blog:show</default> </route> </routes>
IHV
SF
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('blog', new Route('/blog/{page}', array( '_controller' => 'AcmeBlogBundle:Blog:index', 'page' => 1, ))); $collection->add('blog_show', new Route('/blog/{show}', array( '_controller' => 'AcmeBlogBundle:Blog:show', ))); return $collection;
gn you spot the prolemc xotie tht oth routes hve ptterns tht mth v9s tht look like GlogGBF he ymfony router will lwys hoose the (rst mthing route it (ndsF sn other wordsD the logshow route will never e mthedF snstedD v like GlogGmyE logEpost will mth the (rst route @logA nd return nonsense vlue of myElogEpost to the {pge} prmeterF v GlogGP GlogGmyElogEpost route log log prmeters {pge} a P {pge} a myElogEpost
he nswer to the prolem is to dd route requirementsF he routes in this exmple would work perfetly if the GlogG{pge} pttern only mthed vs where the {pge} portion is n integerF portuntelyD regulr expression requirements n esily e dded for eh prmeterF por exmpleX
ewv
blog: pattern: /blog/{page} defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 } requirements: page: \d+
wv
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('blog', new Route('/blog/{page}', array( '_controller' => 'AcmeBlogBundle:Blog:index', 'page' => 1, ), array( 'page' => '\d+', ))); return $collection;
he dC requirement is regulr expression tht sys tht the vlue of the {pge} prmeter must e digit @iFeF numerAF he log route will still mth on v like GlogGP @euse P is numerAD ut it will no longer mth v like GlogGmyElogEpost @euse myE logEpost is not numerAF es resultD v like GlogGmyElogEpost will now properly mth the logshow routeF v GlogGP GlogGmyElogEpost route log logshow prmeters {pge} a P {slug} a myElogEpost
irlier outes lwys in ht this ll mens is tht the order of the routes is very importntF sf the logshow route were pled ove the log routeD the v GlogGP would mth logshow insted of log sine the {slug} prmeter of logshow hs no requirementsF fy using proper ordering nd lever requirementsD you n omplish just out nythingF ine the prmeter requirements re regulr expressionsD the omplexity nd )exiility of eh requirement is entirely up to youF uppose the homepge of your pplition is ville in two di'erent lngugesD sed on the vX
ewv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="homepage" pattern="/{culture}"> <default key="_controller">AcmeDemoBundle:Main:homepage</default> <default key="culture">en</default> <requirement key="culture">en|fr</requirement> </route> </routes>
r
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('homepage', new Route('/{culture}', array( '_controller' => 'AcmeDemoBundle:Main:homepage', 'culture' => 'en', ), array( 'culture' => 'en|fr', ))); return $collection;
por inoming requestsD the {ulture} portion of the v is mthed ginst the regulr expression @en|frAF G Gen Gfr Ges {ulture} a en {ulture} a en {ulture} a fr won9t mth this route
edding r wethod equirements sn ddition to the vD you n lso mth on the method of the inoming request @iFeF qiD riehD yD D hiviiAF uppose you hve ontt form with two ontrollers E one for displying the form @on qi requestA nd one for proessing the form when SFTF outing III
ymfony houmenttionD PFH it9s sumitted @on y requestAF his n e omplished with the following route on(gurtionX
ewv
contact: pattern: /contact defaults: { _controller: AcmeDemoBundle:Main:contact } requirements: _method: GET contact_process: pattern: /contact defaults: { _controller: AcmeDemoBundle:Main:contactProcess } requirements: _method: POST
wv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="contact" pattern="/contact"> <default key="_controller">AcmeDemoBundle:Main:contact</default> <requirement key="_method">GET</requirement> </route> <route id="contact_process" pattern="/contact"> <default key="_controller">AcmeDemoBundle:Main:contactProcess</default> <requirement key="_method">POST</requirement> </route> </routes>
r
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('contact', new Route('/contact', array( '_controller' => 'AcmeDemoBundle:Main:contact', ), array( '_method' => 'GET', ))); $collection->add('contact_process', new Route('/contact', array(
IIP SF
'_controller' => 'AcmeDemoBundle:Main:contactProcess', ), array( '_method' => 'POST', ))); return $collection;
hespite the ft tht these two routes hve identil ptterns @GonttAD the (rst route will mth only qi requests nd the seond route will mth only y requestsF his mens tht you n disply the form nd sumit the form vi the sme vD while using distint ontrollers for the two tionsF X sf no method requirement is spei(edD the route will mth on ll methodsF vike the other requirementsD the method requirement is prsed s regulr expressionF o mth qi or y requestsD you n use qi|yF edvned outing ixmple et this pointD you hve everything you need to rete powerful routing struture in ymfonyF he following is n exmple of just how )exile the routing system n eX
ewv
article_show: pattern: /articles/{culture}/{year}/{title}.{_format} defaults: { _controller: AcmeDemoBundle:Article:show, _format: html } requirements: culture: en|fr _format: html|rss year: \d+
wv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="article_show" pattern="/articles/{culture}/{year}/{title}.{_format}"> <default key="_controller">AcmeDemoBundle:Article:show</default> <default key="_format">html</default> <requirement key="culture">en|fr</requirement> <requirement key="_format">html|rss</requirement> <requirement key="year">\d+</requirement>
SFTF outing IIQ
</route> </routes>
r
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('homepage', new Route('/articles/{culture}/{year}/{title}.{_format}', array( '_controller' => 'AcmeDemoBundle:Article:show', '_format' => 'html', ), array( 'culture' => 'en|fr', '_format' => 'html|rss', 'year' => '\d+', ))); return $collection;
es you9ve seenD this route will only mth if the {ulture} portion of the v is either en or fr nd if the {yer} is numerF his route lso shows how you n use period etween pleholders insted of slshF vs mthing this route might look likeX
GrtilesGenGPHIHGmyEpost GrtilesGfrGPHIHGmyEpostFrss
he peil formt outing rmeter his exmple lso highlights the speil formt routing prmeterF hen using this prmeterD the mthed vlue eomes the request formt of the equest ojetF ltimtelyD the request formt is used for suh things suh s setting the gontentE ype of the response @eFgF json request formt trnsltes into gontentEype of pplitionGjsonAF st n lso e used in the ontroller to render di'erent templte for eh vlue of formtF he formt prmeter is very powerful wy to render the sme ontent in di'erent formtsF
peil outing rmeters es you9ve seenD eh routing prmeter or defult vlue is eventully ville s n rgument in the ontroller methodF edditionllyD there re three prmeters tht re speilX eh dds unique piee of funtionlity inside your pplitionX
ontrollerX es you9ve seenD this prmeter is used to determine whih ontroller is exeuted when the route is mthedY
IIR SF
formtX sed to set the request formt @red moreAY loleX sed to set the lole on the session @red moreAY
5.6.4 Controller Naming Pattern
ivery route must hve ontroller prmeterD whih dittes whih ontroller should e exeuted when tht route is mthedF his prmeter uses simple string pttern lled the logil ontroller nmeD whih ymfony mps to spei( r method nd lssF he pttern hs three prtsD eh seprted y olonX undleXontrollerXtion por exmpleD ontroller vlue of emeflogfundleXflogXshow mensX fundle emeflogfundle gontroller glss floggontroller wethod xme showetion
// src/Acme/BlogBundle/Controller/BlogController.php namespace Acme\BlogBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class BlogController extends Controller { public function showAction($slug) { // ... } }
xotie tht ymfony dds the string gontroller to the lss nme @flog ab floggontrollerA nd etion to the method nme @show ab showetionAF ou ould lso refer to this ontroller using its fullyEquli(ed lss nme nd methodX emeflogfundlegontrollerfloggontrollerXXshowetionF fut if you follow some simple onventionsD the logil nme is more onise nd llows more )exiilityF X sn ddition to using the logil nme or the fullyEquli(ed lss nmeD ymfony supports third wy of referring to ontrollerF his method uses just one olon seprtor @eFgF servienmeXindexetionA nd refers to the ontroller s servie @see row to de(ne gontrollers s erviesAF
SFTF outing
IIS
he route prmeters @eFgF {slug}A re espeilly importnt euse eh is mde ville s n rgument to the ontroller methodX
ell routes re loded vi single on(gurtion (le E usully ppGon(gGroutingFyml @see greting outes oveAF gommonlyD howeverD you9ll wnt to lod routes from other plesD like routing (le tht lives inside undleF his n e done y importing tht (leX
ewv
ewv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="acme_hello" pattern="/hello/{name}"> <default key="_controller">AcmeHelloBundle:Hello:index</default> </route> </routes>
SFTF outing IIU
// src/Acme/HelloBundle/Resources/cong/routing.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('acme_hello', new Route('/hello/{name}', array( '_controller' => 'AcmeHelloBundle:Hello:index', ))); return $collection;
he routes from this (le re prsed nd loded in the sme wy s the min routing (leF re(xing smported outes ou n lso hoose to provide pre(x for the imported routesF por exmpleD suppose you wnt the mehello route to hve (nl pttern of GdminGhelloG{nme} insted of simply GhelloG{nme}X
ewv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <import resource="@AcmeHelloBundle/Resources/cong/routing.xml" prex="/admin" /> </routes>
r
hile dding nd ustomizing routesD it9s helpful to e le to visulize nd get detiled informtion out your routesF e gret wy to see every route in your pplition is vi the routerXdeug onsole ommndF ixeute the ommnd y running the following from the root of your projetF
homepage ANY / contact GET /contact contact_process POST /contact article_show ANY /articles/{culture}/{year}/{title}.{_format} blog ANY /blog/{page} blog_show ANY /blog/{slug}
ou n lso get very spei( informtion on single route y inluding the route nme fter the ommndX
he routing system should lso e used to generte vsF sn relityD routing is iE diretionl systemX mpping the v to ontrollerCprmeters nd routeCprmeters k to vF he XmethodXymfonygomponentoutingouterXXmth nd XmethodXymfonygomponentoutingouterXXgenerte methods form this iE diretionl systemF ke the logshow exmple route from erlierX
$params = $router->match('/blog/my-blog-post'); // array('slug' => 'my-blog-post', '_controller' => 'AcmeBlogBundle:Blog:show') $uri = $router->generate('blog_show', array('slug' => 'my-blog-post')); // /blog/my-blog-post
SFTF outing
IIW
ymfony houmenttionD PFH o generte vD you need to speify the nme of the route @eFgF logshowA nd ny wildrds @eFgF slug a myElogEpostA used in the pttern for tht routeF ith this informtionD ny v n esily e genertedX
class MainController extends Controller { public function showAction($slug) { // ... } $url = $this->get('router')->generate('blog_show', array('slug' => 'my-blog-post'));
sn n upoming setionD you9ll lern how to generte vs from inside templtesF qenerting esolute vs fy defultD the router will generte reltive vs @eFgF GlogAF o generte n solute vD simply pss true to the third rgument of the generte@A methodX
$request->headers->set('HOST', 'www.example.com');
qenerting vs with uery trings he generte method tkes n rry of wildrd vlues to generte the sF fut if you pss extr onesD they will e dded to the s s query stringX
wig
<a href="{{ path('blog_show', { 'slug': 'my-blog-post' }) }}"> Read this blog post. </a>
r
<a href="<?php echo $view['router']->generate('blog_show', array('slug' => 'my-blog-post')) ?>"> Read this blog post. </a>
esolute vs n lso e genertedF
wig
<a href="{{ url('blog_show', { 'slug': 'my-blog-post' }) }}"> Read this blog post. </a>
r
<a href="<?php echo $view['router']->generate('blog_show', array('slug' => 'my-blog-post'), true) ?>"> Read this blog post. </a>
5.6.9 Summary
outing is system for mpping the v of inoming requests to the ontroller funtion tht should e lled to proess the requestF st oth llows you to speify eutiful vs nd keeps the funtionlity of your pplition deoupled from those vsF outing is twoEwy mehnismD mening tht it should lso e used to generte vsF
5.6.10 Learn more from the Cookbook
es you knowD the ontroller is responsile for hndling eh request tht omes into ymfonyP pplitionF sn relityD the ontroller delegtes the most of the hevy work to other ples so tht ode n e tested nd reusedF hen ontroller needs to generte rwvD g or ny other ontentD it hnds the work o' to the templting engineF sn this hpterD you9ll lern how to write powerful templtes tht n e used to return ontent SFUF greting nd using empltes IPI
ymfony houmenttionD PFH to the userD populte emil odiesD nd moreF ou9ll lern shortutsD lever wys to extend templtes nd how to reuse templte odeF
5.7.1 Templates
e templte is simply text (le tht n generte ny textEsed formt @rwvD wvD gD ve FFFAF he most fmilir type of templte is r templte E text (le prsed y r tht ontins mix of text nd r odeX
<!DOCTYPE html> <html> <head> <title>Welcome to Symfony!</title> </head> <body> <h1><?php echo $page_title ?></h1> <ul id="navigation"> <?php foreach ($navigation as $item): ?> <li> <a href="<?php echo $item->getHref() ?>"> <?php echo $item->getCaption() ?> </a> </li> <?php endforeach; ?> </ul> </body> </html>
fut ymfonyP pkges n even more powerful templting lnguge lled wigF wig llows you to write oniseD redle templtes tht re more friendly to we designers ndD in severl wysD more powerful thn r templtesX
<!DOCTYPE html> <html> <head> <title>Welcome to Symfony!</title> </head> <body> <h1>{{ page_title }}</h1> <ul id="navigation"> {% for item in navigation %} <li><a href="{{ item.href }}">{{ item.caption }}</a></li> {% endfor %} </ul>
IPP SF
</body> </html>
wig de(nes two types of speil syntxX
{{ FFF }}X ys somethingX prints vrile or the result of n expression to the templteY {7 FFF 7}X hoes somethingX tg tht ontrols the logi of the templteY it is used to exeute sttements suh s forEloops for exmpleF
X here is third syntx used for reting ommentsX {5 this is omment 5}F his syntx n e used ross multiple lines like the rEequivlent GB omment BG syntxF wig lso ontins (ltersD whih modify ontent efore eing renderedF he following mkes the title vrile ll upperse efore rendering itX
{{ title | upper }}
wig omes with long list of tgs nd (lters tht re ville y defultF ou n even dd your own extensions to wig s neededF X egistering wig extension is s esy s reting new servie nd tgging it with twigFextension tgF es you9ll see throughout the doumenttionD wig lso supports funtions nd new funtions n e esily ddedF por exmpleD the following uses stndrd for tg nd the yle funtion to print ten div tgsD with lternting oddD even lssesX
{% for i in 0..10 %} <div class="{{ cycle(['odd', 'even'], i) }}"> <!-- some HTML here --> </div> {% endfor %}
hroughout this hpterD templte exmples will e shown in oth wig nd rF
IPQ
ymfony houmenttionD PFH hy wigc wig templtes re ment to e simple nd won9t proess r tgsF his is y designX the wig templte system is ment to express presenttionD not progrm logiF he more you use wigD the more you9ll ppreite nd ene(t from this distintionF end of ourseD you9ll e loved y we designers everywhereF wig n lso do things tht r n9tD suh s true templte inheritne @wig templtes ompile down to r lsses tht inherit from eh otherAD whitespe ontrolD sndoxingD nd the inlusion of ustom funtions nd (lters tht only 'et templtesF wig ontins little fetures tht mke writing templtes esier nd more oniseF ke the following exmpleD whih omines loop with logil if sttementX
<ul> {% for user in users %} <li>{{ user.username }}</li> {% else %} <li>No users found</li> {% endfor %} </ul>
wig emplte ghing wig is fstF ih wig templte is ompiled down to ntive r lss tht is rendered t runtimeF he ompiled lsses re loted in the ppGheG{environment}Gtwig diretory @where {environment} is the environmentD suh s dev or prodA nd in some ses n e useful while deuggingF ee for more informtion on environmentsF hen deug mode is enled @ommon in the dev environmentAD wig templte will e utomtilly reompiled when hnges re mde to itF his mens tht during development you n hppily mke hnges to wig templte nd instntly see the hnges without needing to worry out lering ny heF hen deug mode is disled @ommon in the prod environmentAD howeverD you must ler the wig he diretory so tht the wig templtes will regenerteF ememer to do this when deploying your pplitionF
5.7.2 Template Inheritance and Layouts
wore often thn notD templtes in projet shre ommon elementsD like the hederD footerD sider or moreF sn ymfonyPD we like to think out this prolem di'erentlyX templte n e deorted y nother oneF his works extly the sme s r lssesX templte inheritne llows you to uild se lyout templte tht ontins ll the ommon elements of your site de(ned s loks @think r lss with se methodsAF e hild
IPR
SF
ymfony houmenttionD PFH templte n extend the se lyout nd override ny of its loks @think r sulss tht overrides ertin methods of its prent lssAF pirstD uild se lyout (leX
wig
{# app/Resources/views/base.html.twig #} <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>{% block title %}Test Application{% endblock %}</title> </head> <body> <div id="sidebar"> {% block sidebar %} <ul> <li><a href="/">Home</a></li> <li><a href="/blog">Blog</a></li> </ul> {% endblock %} </div> <div id="content"> {% block body %}{% endblock %} </div> </body> </html>
r
<!-- app/Resources/views/base.html.php --> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title><?php $view['slots']->output('title', 'Test Application') ?></title> </head> <body> <div id="sidebar"> <?php if ($view['slots']->has('sidebar'): ?> <?php $view['slots']->output('sidebar') ?> <?php else: ?> <ul> <li><a href="/">Home</a></li> <li><a href="/blog">Blog</a></li> </ul> <?php endif; ?>
SFUF greting nd using empltes IPS
wig
{# src/Acme/BlogBundle/Resources/views/Blog/index.html.twig #} {% extends '::base.html.twig' %} {% block title %}My cool blog posts{% endblock %} {% block body %} {% for entry in blog_entries %} <h2>{{ entry.title }}</h2> <p>{{ entry.body }}</p> {% endfor %} {% endblock %}
r
<!-- src/Acme/BlogBundle/Resources/views/Blog/index.html.php --> <?php $view->extend('::base.html.php') ?> <?php $view['slots']->set('title', 'My cool blog posts') ?> <?php $view['slots']->start('body') ?> <?php foreach ($blog_entries as $entry): ?> <h2><?php echo $entry->getTitle() ?></h2> <p><?php echo $entry->getBody() ?></p> <?php endforeach; ?> <?php $view['slots']->stop() ?>
IPT SF
X he prent templte is identi(ed y speil string syntx @XXseFhtmlFtwigA tht indites tht the templte lives in the ppGesouresGviews diretory of the projetF his nming onvention is explined fully in emplte xming nd votionsF he key to templte inheritne is the {7 extends 7} tgF his tells the templting engine to (rst evlute the se templteD whih sets up the lyout nd de(nes severl loksF he hild templte is then renderedD t whih point the title nd ody loks of the prent re repled y those from the hildF hepending on the vlue of logentriesD the output might look like thisX
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>My cool blog posts</title> </head> <body> <div id="sidebar"> <ul> <li><a href="/">Home</a></li> <li><a href="/blog">Blog</a></li> </ul> </div> <div id="content"> <h2>My rst post</h2> <p>The body of the rst post.</p> <h2>Another post</h2> <p>The body of the second post.</p> </div> </body> </html>
xotie tht sine the hild templte didn9t de(ne sider lokD the vlue from the prent templte is used instedF gontent within {7 lok 7} tg in prent templte is lwys used y defultF ou n use s mny levels of inheritne s you wntF sn the next setionD ommon threeE level inheritne model will e explined long with how templtes re orgnized inside ymfonyP projetF hen working with templte inheritneD here re some tips to keep in mindX
sf you use {7 extends 7} in templteD it must e the (rst tg in tht templteF he more {7 lok 7} tgs you hve in your se templtesD the etterF ememerD
SFUF greting nd using empltes IPU
ymfony houmenttionD PFH hild templtes don9t hve to de(ne ll prent loksD so rete s mny loks in your se templtes s you wnt nd give eh sensile defultF he more loks your se templtes hveD the more )exile your lyout will eF
sf you (nd yourself dupliting ontent in numer of templtesD it proly mens you should move tht ontent to {7 lok 7} in prent templteF sn some sesD etter solution my e to move the ontent to new templte nd inlude it @see snluding other empltesAF sf you need to get the ontent of lok from the prent templteD you n use the {{ prent@A }} funtionF his is useful if you wnt to dd to the ontents of prent lok insted of ompletely overriding itX
ppGesouresGviewsGX he pplitions views diretory n ontin pplitionEwide se templtes @iFeF your pplition9s lyoutsA s well s templtes tht override undle templtes @see yverriding fundle empltesAY pthGtoGundleGesouresGviewsGX ih undle houses its templtes in its esouresGviews diretory @nd sudiretoriesAF he mjority of templtes will live inside undleF
ymfonyP uses undleXontrollerXtemplte string syntx for templtesF his llows for severl di'erent types of templtesD eh whih lives in spei( lotionX
emeflogfundleXflogXindexFhtmlFtwigX his syntx is used to speify templte for spei( pgeF he three prts of the stringD eh seprted y olon @XAD men the followingX
! emeflogfundleX @undleA the templte lives inside the emeflogfundle @eFgF srGemeGflogfundleAY ! flogX @ontrollerA indites tht the templte lives inside the flog sudiretory of esouresGviewsY ! indexFhtmlFtwigX @templteA the tul nme of the (le is indexFhtmlFtwigF essuming tht the emeflogfundle lives t srGemeGflogfundleD the (nl pth to the lyout would e srGemeGflogfundleGesouresGviewsGflogGindexFhtmlFtwigF
IPV
SF
emeflogfundleXXlyoutFhtmlFtwigX his syntx refers to se templte tht9s spei( to the emeflogfundleF ine the middleD ontrollerD portion is missing @eFgF flogAD the templte lives t esouresGviewsGlyoutFhtmlFtwig inside emeflogfundleF XXseFhtmlFtwigX his syntx refers to n pplitionEwide se templte or lyoutF xotie tht the string egins with two olons @XXAD mening tht oth the undle nd ontroller portions re missingF his mens tht the templte is not loted in ny undleD ut insted in the root ppGesouresGviewsG diretoryF
sn the yverriding fundle empltes setionD you9ll (nd out how eh templte living inside the emeflogfundleD for exmpleD n e overridden y pling templte of the sme nme in the ppGesouresGemeflogfundleGviewsG diretoryF his gives the power to override templtes from ny vendor undleF X ropefully the templte nming syntx looks fmilir E it9s the sme nming onvention used to refer to gontroller xming tternF
emplte u0x he undleXontrollerXtemplte formt of eh templte spei(es where the templte (le is lotedF ivery templte nme lso hs two extensions tht speify the formt nd engine for tht templteF
emeflogfundleXflogXindexFhtmlFtwig E rwv formtD wig engine emeflogfundleXflogXindexFhtmlFphp E rwv formtD r engine emeflogfundleXflogXindexFssFtwig E g formtD wig engine
fy defultD ny ymfonyP templte n e written in either wig or rD nd the lst prt of the extension @eFgF Ftwig or FphpA spei(es whih of these two engines should e usedF he (rst prt of the extensionD @eFgF FhtmlD FssD etA is the (nl formt tht the templte will generteF nlike the engineD whih determines how ymfonyP prses the templteD this is simply n orgniztionl tti used in se the sme resoure needs to e rendered s rwv @indexFhtmlFtwigAD wv @indexFxmlFtwigAD or ny other formtF por more informtionD red the emplte pormts setionF X he ville engines n e on(gured nd even new engines ddedF ee emplting gon(gurtion for more detilsF
ou lredy understnd the sis of templtesD how they9re nmed nd how to use templte inheritneF he hrdest prts re lredy ehind youF sn this setionD you9ll lern out SFUF greting nd using empltes IPW
ymfony houmenttionD PFH lrge group of tools ville to help perform the most ommon templte tsks suh s inluding other templtesD linking to pges nd inluding imgesF ymfonyP omes undled with severl speilized wig tgs nd funtions tht ese the work of the templte designerF sn rD the templting system provides n extensile helper system tht provides useful fetures in templte ontextF e9ve lredy seen few uiltEin wig tgs @{7 lok 7} 8 {7 extends 7}A s well s n exmple of r helper @6view9slots9AF vet9s lern few moreF snluding other empltes ou9ll often wnt to inlude the sme templte or ode frgment on severl di'erent pgesF por exmpleD in n pplition with news rtilesD the templte ode displying n rtile might e used on the rtile detil pgeD on pge displying the most populr rtilesD or in list of the ltest rtilesF hen you need to reuse hunk of r odeD you typilly move the ode to new r lss or funtionF he sme is true for templtesF fy moving the reused templte ode into its own templteD it n e inluded from ny other templteF pirstD rete the templte tht you9ll need to reuseF
wig
{# src/Acme/ArticleBundle/Resources/views/Article/articleDetails.html.twig #} <h1>{{ article.title }}</h1> <h3 class="byline">by {{ article.authorName }}</h3> <p> {{ article.body }} </p>
r
<!-- src/Acme/ArticleBundle/Resources/views/Article/articleDetails.html.php --> <h2><?php echo $article->getTitle() ?></h2> <h3 class="byline">by <?php echo $article->getAuthorName() ?></h3> <p> <?php echo $article->getBody() ?> </p>
snluding this templte from ny other templte is simpleX
wig
{% block body %} <h1>Recent Articles<h1> {% for article in articles %} {% include 'AcmeArticleBundle:Article:articleDetails.html.twig' with {'article': article} %} {% endfor %} {% endblock %}
r
<!-- src/Acme/ArticleBundle/Resources/Article/list.html.php --> <?php $view->extend('AcmeArticleBundle::layout.html.php') ?> <?php $view['slots']->start('body') ?> <h1>Recent Articles</h1>
<?php foreach ($articles as $article): ?> <?php echo $view->render('AcmeArticleBundle:Article:articleDetails.html.php', array('article' => $a <?php endforeach; ?> <?php $view['slots']->stop() ?>
he templte is inluded using the {7 inlude 7} tgF xotie tht the templte nme follows the sme typil onventionF he rtilehetilsFhtmlFtwig templte uses n rtile vrileF his is pssed in y the listFhtmlFtwig templte using the with ommndF X he {9rtile9X rtile} syntx is the stndrd wig syntx for hsh mps @iFeF n rry with nmed keysAF sf we needed to pss in multiple elementsD it would look like thisX {9foo9X fooD 9r9X r}F
imedding gontrollers sn some sesD you need to do more thn inlude simple templteF uppose you hve sider in your lyout tht ontins the three most reent rtilesF etrieving the three rtiles my inlude querying the dtse or performing other hevy logi tht n9t e done from within templteF he solution is to simply emed the result of n entire ontroller from your templteF pirstD rete ontroller tht renders ertin numer of reent rtilesX
// make a database call or other logic to get the "$max" most recent articles $articles = ...; } return $this->render('AcmeArticleBundle:Article:recentList.html.twig', array('articles' => $articles));
wig
{# src/Acme/ArticleBundle/Resources/views/Article/recentList.html.twig #} {% for article in articles %} <a href="/article/{{ article.slug }}"> {{ article.title }} </a> {% endfor %}
r
<!-- src/Acme/ArticleBundle/Resources/views/Article/recentList.html.php --> <?php foreach ($articles in $article): ?> <a href="/article/<?php echo $article->getSlug() ?>"> <?php echo $article->getTitle() ?> </a> <?php endforeach; ?>
X xotie tht we9ve heted nd hrdoded the rtile v in this exmple @eFgF GrtileGBslugBAF his is d prtieF sn the next setionD you9ll lern how to do this orretlyF o inlude the ontrollerD you9ll need to refer to it using the stndrd string syntx for ontrollers @iFeF undleXontrollerXtionAX
wig
<div id="sidebar"> <?php echo $view['actions']->render('AcmeArticleBundle:Article:recentArticles', array('max' => 3)) ?> </div>
henever you (nd tht you need vrile or piee of informtion tht you don9t hve ess to in templteD onsider rendering ontrollerF gontrollers re fst to exeute nd promote good ode orgniztion nd reuseF vinking to ges greting links to other pges in your pplition is one of the most ommon jos for templteF snsted of hrdoding vs in templtesD use the pth wig funtion @or the router helper in rA to generte vs sed on the routing on(gurtionF vterD if you wnt to modify the v of prtiulr pgeD ll you9ll need to do is hnge the routing on(gurtionY the templtes will utomtilly generte the new vF pirstD link to the welome pgeD whih is essile vi the following routing on(gurtionX
ewv
$collection = new RouteCollection(); $collection->add('_welcome', new Route('/', array( '_controller' => 'AcmeDemoBundle:Welcome:index', ))); return $collection;
o link to the pgeD just use the pth wig funtion nd refer to the routeX
wig
IQQ
ewv
$collection = new RouteCollection(); $collection->add('article_show', new Route('/article/{slug}', array( '_controller' => 'AcmeArticleBundle:Article:show', ))); return $collection;
sn this seD you need to speify oth the route nme @rtileshowA nd vlue for the {slug} prmeterF sing this routeD let9s revisit the reentvist templte from the previous setion nd link to the rtiles orretlyX
wig
{# src/Acme/ArticleBundle/Resources/views/Article/recentList.html.twig #} {% for article in articles %} <a href="{{ path('article_show', { 'slug': article.slug }) }}"> {{ article.title }} </a> {% endfor %}
r
<!-- src/Acme/ArticleBundle/Resources/views/Article/recentList.html.php --> <?php foreach ($articles in $article): ?> <a href="<?php echo $view['router']->generate('article_show', array('slug' => $article->getSlug()) ?> <?php echo $article->getTitle() ?> </a> <?php endforeach; ?>
IQR
SF
ymfony houmenttionD PFH X ou n lso generte n solute v y using the url wig funtionX
vinking to essets empltes lso ommonly refer to imgesD tvsriptD stylesheets nd other ssetsF yf ourse you ould hrdEode the pth to these ssets @eFgF GimgesGlogoFpngAD ut ymfonyP provides more dynmi option vi the ssets wig funtionX
wig
<img src="{{ asset('images/logo.png') }}" alt="Symfony!" /> <link href="{{ asset('css/blog.css') }}" rel="stylesheet" type="text/css" />
r
<img src="<?php echo $view['assets']->getUrl('images/logo.png') ?>" alt="Symfony!" /> <link href="<?php echo $view['assets']->getUrl('css/blog.css') ?>" rel="stylesheet" type="text/css" />
he sset funtion9s min purpose is to mke your pplition more portleF sf your pplition lives t the root of your host @eFgF httpXGGexmpleFomAD then the rendered pths should e GimgesGlogoFpngF fut if your pplition lives in sudiretory @eFgF httpXGGexmpleFomGmyppAD eh sset pth should render with the sudiretory @eFgF GmyppGimgesGlogoFpngAF he sset funtion tkes re of this y determining how your pplition is eing used nd generting the orret pths ordinglyF edditionllyD if you use the sset funtionD ymfony n utomtilly ppend query string to your ssetD in order to gurntee tht updted stti ssets won9t e hed when deployedF por exmpleD GimgesGlogoFpng might look like GimgesGlogoFpngcvPF por more informtionD see the ssetsversion on(gurtion optionF
5.7.5 Including Stylesheets and Javascripts in Twig
xo site would e omplete without inluding tvsript (les nd stylesheetsF sn ymfonyD the inlusion of these ssets is hndled elegntly y tking dvntge of ymfony9s templte inheritneF
IQS
ymfony houmenttionD PFH X his setion will teh you the philosophy ehind inluding stylesheet nd tvsript ssets in ymfonyF ymfony lso pkges nother lirryD lled essetiD whih follows this philosophy ut llows you to do muh more interesting things with those ssetsF por more informtion on using esseti see row to se esseti for esset wngementF trt y dding two loks to your se templte tht will hold your ssetsX one lled stylesheets inside the hed tg nd nother lled jvsripts just ove the losing ody tgF hese loks will ontin ll of the stylesheets nd tvsripts tht you9ll need throughout your siteX
{# 'app/Resources/views/base.html.twig' #} <html> <head> {# ... #} {% block stylesheets %} <link href="{{ asset('/css/main.css') }}" type="text/css" rel="stylesheet" /> {% endblock %} </head> <body> {# ... #} {% block javascripts %} <script src="{{ asset('/js/main.js') }}" type="text/javascript"></script> {% endblock %} </body> </html>
ht9s esy enough3 fut wht if you need to inlude n extr stylesheet or tvsript from hild templtec por exmpleD suppose you hve ontt pge nd you need to inlude onttFss stylesheet just on tht pgeF prom inside tht ontt pge9s templteD do the followingX
{# src/Acme/DemoBundle/Resources/views/Contact/contact.html.twig #} {# extends '::base.html.twig' #} {% block stylesheets %} {{ parent() }} <link href="{{ asset('/css/contact.css') }}" type="text/css" rel="stylesheet" /> {% endblock %} {# ... #}
sn the hild templteD you simply override the stylesheets lok nd put your new stylesheet tg inside of tht lokF yf ourseD sine you wnt to dd to the prent lok9s ontent @nd not tully reple itAD you should use the prent@A wig funtion to inlude everything IQT SF
ymfony houmenttionD PFH from the stylesheets lok of the se templteF he end result is pge tht inludes oth the minFss nd onttFss stylesheetsF
5.7.6 Conguring and using the templating Service
he hert of the templte system in ymfonyP is the templting ingineF his speil ojet is responsile for rendering templtes nd returning their ontentF hen you render templte in ontrollerD for exmpleD you9re tully using the templting engine servieF por exmpleX
return $this->render('AcmeArticleBundle:Article:index.html.twig');
is equivlent to
ewv
// app/cong/cong.php $container->loadFromExtension('framework', array( // ... 'templating' => array( 'engines' => array('twig'), ), ));
everl on(gurtion options re ville nd re overed in the gon(gurtion eppendixF
IQU
ymfony houmenttionD PFH X he twig engine is mndtory to use the wepro(ler @s well s mny thirdE prty undlesAF
he ymfonyP ommunity prides itself on reting nd mintining high qulity undles @see ymfonyPfundlesForgA for lrge numer of di'erent feturesF yne you use thirdEprty undleD you9ll likely need to override nd ustomize one or more of its templtesF uppose you9ve inluded the imginry openEsoure emeflogfundle in your projet @eFgF in the srGemeGflogfundle diretoryAF end while you9re relly hppy with everythingD you wnt to override the log list pge to ustomize the mrkup spei(lly for your pplitionF fy digging into the flog ontroller of the emeflogfundleD you (nd the followingX
public function indexAction() { $blogs = // some logic to retrieve the blogs } $this->render('AcmeBlogBundle:Blog:index.html.twig', array('blogs' => $blogs));
hen the emeflogfundleXflogXindexFhtmlFtwig is renderedD ymfonyP tully looks in two di'erent lotions for the templteX IF ppGesouresGemeflogfundleGviewsGflogGindexFhtmlFtwig PF srGemeGflogfundleGesouresGviewsGflogGindexFhtmlFtwig o override the undle templteD just opy the indexFhtmlFtwig templte from the undle to ppGesouresGemeflogfundleGviewsGflogGindexFhtmlFtwig @the ppGesouresGemeflogfundle diretory won9t existD so you9ll need to rete itAF ou9re now free to ustomize the templteF his logi lso pplies to se undle templtesF uppose lso tht eh templte in emeflogfundle inherits from se templte lled emeflogfundleXXlyoutFhtmlFtwigF tust s eforeD ymfonyP will look in the following two ples for the templteX IF ppGesouresGemeflogfundleGviewsGlyoutFhtmlFtwig PF srGemeGflogfundleGesouresGviewsGlyoutFhtmlFtwig yne ginD to override the templteD just opy it from the undle to ppGesouresGemeflogfundleGviewsGlyoutFhtmlFtwigF ou9re now free to ustomize this opy s you see (tF sf you tke step kD you9ll see tht ymfonyP lwys strts y looking in the ppGesouresG{fxhvixewi}GviewsG diretory for templteF sf the templte doesn9t exist thereD it ontinues y heking inside the esouresGviews diretory of the undle itselfF IQV SF
ymfony houmenttionD PFH his mens tht ll undle templtes n e overridden y pling them in the orret ppGesoures sudiretoryF yverriding gore empltes ine the ymfonyP frmework itself is just undleD ore templtes n e overridden in the sme wyF por exmpleD the ore wigfundle ontins numer of di'erent exeption nd error templtes tht n e overridden y opying eh from the esouresGviewsGixeption diretory of the wigfundle toD you guessed itD the ppGesouresGwigfundleGviewsGixeption diretoryF
5.7.8 Three-level Inheritance
yne ommon wy to use inheritne is to use threeElevel pprohF his method works perfetly with the three di'erent types of templtes we9ve just overedX
grete ppGesouresGviewsGseFhtmlFtwig (le tht ontins the min lyout for your pplition @like in the previous exmpleAF snternllyD this templte is lled XXseFhtmlFtwigY grete templte for eh setion of your siteF por exmpleD n emeflogfundleD would hve templte lled emeflogfundleXXlyoutFhtmlFtwig tht ontins only log setionEspei( elementsY
{# src/Acme/BlogBundle/Resources/views/layout.html.twig #} {% extends '::base.html.twig' %} {% block body %} <h1>Blog Application</h1> {% block content %}{% endblock %} {% endblock %}
grete individul templtes for eh pge nd mke eh extend the pproprite setion templteF por exmpleD the index pge would e lled something lose to emeflogfundleXflogXindexFhtmlFtwig nd list the tul log postsF
{# src/Acme/BlogBundle/Resources/views/Blog/index.html.twig #} {% extends 'AcmeBlogBundle::layout.html.twig' %} {% block content %} {% for entry in blog_entries %} <h2>{{ entry.title }}</h2> <p>{{ entry.body }}</p> {% endfor %} {% endblock %}
SFUF greting nd using empltes IQW
ymfony houmenttionD PFH xotie tht this templte extends the setion templte E@emeflogfundleXXlyoutFhtmlFtwigA whih inEturn extends the se pplition lyout @XXseFhtmlFtwigAF his is the ommon threeElevel inheritne modelF hen uilding your pplitionD you my hoose to follow this method or simply mke eh pge templte extend the se pplition templte diretly @eFgF {7 extends 9XXseFhtmlFtwig9 7}AF he threeEtemplte model is estEprtie method used y vendor undles so tht the se templte for undle n e esily overridden to properly extend your pplition9s se lyoutF
5.7.9 Output Escaping
hen generting rwv from templteD there is lwys risk tht templte vrile my output unintended rwv or dngerous lientEside odeF he result is tht dynmi ontent ould rek the rwv of the resulting pge or llow mliious user to perform gross ite ripting @A ttkF gonsider this lssi exmpleX
wig
Hello {{ name }}
r
<script>alert('hello!')</script>
ithout ny output espingD the resulting templte will use tvript lert ox to pop upX
Hello <script>alert('hello!')</script>
end while this seems hrmlessD if user n get this frD tht sme user should lso e le to write tvript tht performs mliious tions inside the seure re of n unknowingD legitimte userF he nswer to the prolem is output espingF ith output esping onD the sme templte will render hrmlesslyD nd literlly print the sript tg to the sreenX
Hello <script>alert('helloe')</script>
he wig nd r templting systems pproh the prolem in di'erent wysF sf you9re using wigD output esping is on y defult nd you9re protetedF sn rD output esping is not utomtiD mening you9ll need to mnully espe where neessryF
IRH
SF
ymfony houmenttionD PFH yutput isping in wig sf you9re using wig templtesD then output esping is on y defultF his mens tht you9re proteted outEofEtheEox from the unintentionl onsequenes of userEsumitted odeF fy defultD the output esping ssumes tht ontent is eing esped for rwv outputF sn some sesD you9ll need to disle output esping when you9re rendering vrile tht is trusted nd ontins mrkup tht should not e espedF uppose tht dministrtive users re le to write rtiles tht ontin rwv odeF fy defultD wig will espe the rtile odyF o render it normllyD dd the rw (lterX {{ rtileFody | rw }}F ou n lso disle output esping inside {7 lok 7} re or for n entire templteF por more informtionD see yutput isping in the wig doumenttionF yutput isping in r yutput esping is not utomti when using r templtesF his mens tht unless you expliitly hoose to espe vrileD you9re not protetedF o use output espingD use the speil espe@A view methodX
empltes re generi wy to render ontent in ny formtF end while in most ses you9ll use templtes to render rwv ontentD templte n just s esily generte tvriptD gD wv or ny other formt you n drem ofF por exmpleD the sme resoure is often rendered in severl di'erent formtsF o render n rtile index pge in wvD simply inlude the formt in the templte nmeX
he getequestpormt on the equest ojet defults to htmlD ut n return ny other formt sed on the formt requested y the userF he request formt is most often mnged y the routingD where route n e on(gured so tht Gontt sets the request formt to html while GonttFxml sets the formt to xmlF por more informtionD see the edvned ixmple in the outing hpterF o rete links tht inlude the formt prmeterD inlude formt key in the prmeter hshX
wig
<a href="{{ path('article_show', {'id': 123, '_format': 'pdf'}) }}"> PDF Version </a>
r
<a href="<?php echo $view['router']->generate('article_show', array('id' => 123, '_format' => 'pdf')) ?> PDF Version </a>
he templting engine in ymfony is powerful tool tht n e used eh time you need to generte presenttionl ontent in rwvD wv or ny other formtF end though templtes re ommon wy to generte ontent in ontrollerD their use is not mndtoryF he esponse ojet returned y ontroller n e reted with our without the use of templteX
// creates a Response object whose content is the rendered template $response = $this->render('AcmeArticleBundle:Article:index.html.twig'); // creates a Response object whose content is simple text $response = new Response('response content');
ymfony9s templting engine is very )exile nd two di'erent templte renderers re ville y defultX the trditionl r templtes nd the sleek nd powerful wig templtesF foth support templte hierrhy nd ome pkged with rih set of helper funtions ple of performing the most ommon tsksF IRP SF
ymfony houmenttionD PFH yverllD the topi of templting should e thought of s powerful tool tht9s t your disposlF sn some sesD you my not need to render templteD nd in ymfonyPD tht9s solutely (neF
5.7.12 Learn more from the Cookbook
D E F D ymfony hotrineD D E D F hotrine F X hotrine F hotrine ywD @ wyvD ostgrev wirosoft vAF D row to use hotrine9s hfev vyer F wongohf hotrine yhwF GundlesGhotrinewongohffundleGindexF
5.8.1 :
IRQ
;app/cong/parameters.ini [parameters] database_driver = pdo_mysql database_host = localhost database_name = test_project database_user = root database_password = password
X prmetersFini F E D D hotrineX
doctrine: dbal: driver: %database_driver% host: %database_host% dbname: %database_name% user: %database_user% password: %database_password%
D E F @ A D E D epheF row to et ixternl rmeters in the ervie gontinerF hotrine D X
IRR
SF
hotrine D F D hotrine F rE X
hotrineD D hotrine rodut F D ewvD wv rodut X X e undle n ept only one metdt de(nition formtF por exmpleD it9s not possile to mix ewv metdt de(nitions with nnotted r entity lss de(nitionsF SFVF hotrine @A IRS
ennottions
// src/Acme/StoreBundle/Entity/Product.php namespace Acme\StoreBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="product") */ class Product { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\Column(type="string", length=100) */ protected $name; /** * @ORM\Column(type="decimal", scale=2) */ protected $price; /** * @ORM\Column(type="text") */ protected $description;
ewv
# src/Acme/StoreBundle/Resources/cong/doctrine/Product.orm.yml Acme\StoreBundle\Entity\Product: type: entity table: product id: id: type: integer generator: { strategy: AUTO }
IRT SF
elds: name: type: string length: 100 price: type: decimal scale: 2 description: type: text
wv
<!-- src/Acme/StoreBundle/Resources/cong/doctrine/Product.orm.xml --> <doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> <entity name="Acme\StoreBundle\Entity\Product" table="product"> <id name="id" type="integer" column="id"> <generator strategy="AUTO" /> </id> <eld name="name" column="name" type="string" length="100" /> <eld name="price" column="price" type="decimal" scale="2" /> <eld name="description" column="description" type="text" /> </entity> </doctrine-mapping>
X tle D FF hotrine llows you to hoose from wide vriety of di'erent (eld typesD eh with their own optionsF por informtion on the ville (eld typesD see the hotrine pield ypes eferene setionF FX ou n lso hek out hotrine9s fsi wpping houmenttion for ll detils out mpping informtionF sf you use nnottionsD you9ll need to prepend ll nnottions with yw @eFgF ywgolumn@FFAAD whih is not shown in hotrine9s doumenttionF ou9ll lso need to inlude the use hotrineywwpping s ywY sttementD whih imports the yw nnottions pre(xF
IRU
ymfony houmenttionD PFH X fe reful tht your lss nme nd properties ren9t mpped to proteted v keyword @suh s group or userAF por exmpleD if your entity lss nme is qroupD thenD y defultD your tle nme will e groupD whih will use n v error in some enginesF ee hotrine9s eserved v keywords doumenttion on how to properly espe these nmesF X hen using nother lirry or progrm @ieF hoxygenA tht uses nnottionsD you should ple the dsgnoreennottion nnottion on the lss to indite whih nnottions ymfony should ignoreF por exmpleD to prevent the dfn nnottion from throwing n exeptionD dd the followingX
qenerting qetters nd etters iven though hotrine now knows how to persist rodut ojet to the dtseD the lss itself isn9t relly useful yetF ine rodut is just regulr r lssD you need to rete getter nd setter methods @eFgF getxme@AD setxme@AA in order to ess its properties @sine the properties re protetedAF portuntelyD hotrine n do this for you y runningX
greting the htse lesGhem ou now hve usle rodut lss with mpping informtion so tht hotrine knows extly how to persist itF yf ourseD you don9t yet hve the orresponding produt tle in your dtseF portuntelyD hotrine n utomtilly rete ll the dtse tles needed for every known entity in your pplitionF o do thisD runX
// src/Acme/StoreBundle/Controller/DefaultController.php use Acme\StoreBundle\Entity\Product; use Symfony\Component\HttpFoundation\Response; // ... public function createAction() { $product = new Product(); $product->setName('A Foo Bar'); $product->setPrice('19.99'); $product->setDescription('Lorem ipsum dolor');
IRW
13 14 15 16 17 18
X sf you9re following long with this exmpleD you9ll need to rete route tht points to this tion to see it in workF vet9s wlk through this exmpleX
lines VEII sn this setionD you instntite nd work with the 6produt ojet like ny otherD norml r ojetY line IQ his line fethes hotrine9s entity mnger ojetD whih is responsile for hndling the proess of persisting nd fething ojets to nd from the dtseY line IR he persist@A method tells hotrine to mnge the 6produt ojetF his does not tully use query to e mde to the dtse @yetAF line IS hen the )ush@A method is lledD hotrine looks through ll of the ojets tht it9s mnging to see if they need to e persisted to the dtseF sn this exmpleD the 6produt ojet hs not een persisted yetD so the entity mnger exeutes n sxi query nd row is reted in the produt tleF
X sn ftD sine hotrine is wre of ll your mnged entitiesD when you ll the )ush@A methodD it lultes n overll hngeset nd exeutes the most e0ient queryGqueries possileF por exmpleD if you persist totl of IHH rodut ojets nd then susequently ll )ush@AD hotrine will rete single prepred sttement nd reEuse it for eh insertF his pttern is lled nit of orkD nd it9s used euse it9s fst nd e0ientF hen reting or updting ojetsD the work)ow is lwys the smeF sn the next setionD you9ll see how hotrine is smrt enough to utomtilly issue n hei query if the reord lredy exists in the dtseF X hotrine provides lirry tht llows you to progrmmtilly lod testing dt into your projet @iFeF (xture dtAF por informtionD see GundlesGhotrinepixturesfundleGindexF
ISH
SF
public function showAction($id) { $product = $this->getDoctrine() ->getRepository('AcmeStoreBundle:Product') ->nd($id); if (!$product) { throw $this->createNotFoundException('No product found for id '.$id); } } // do something, like pass the $product object into a template
hen you query for prtiulr type of ojetD you lwys use wht9s known s its repositoryF ou n think of repository s r lss whose only jo is to help you feth entities of ertin lssF ou n ess the repository ojet for n entity lss viX
// query by the primary key (usually "id") $product = $repository->nd($id); // dynamic method names to nd based on a column value $product = $repository->ndOneById($id); $product = $repository->ndOneByName('foo'); // nd *all* products $products = $repository->ndAll(); // nd a group of products based on an arbitrary column value $products = $repository->ndByPrice(19.99);
X yf ourseD you n lso issue omplex queriesD whih you9ll lern more out in the uerying for yjets setionF SFVF hotrine @A ISI
ou n lso tke dvntge of the useful (ndfy nd (ndynefy methods to esily feth ojets sed on multiple onditionsX
// query for one product matching be name and price $product = $repository->ndOneBy(array('name' => 'foo', 'price' => 19.99)); // query for all products matching the name, ordered by price $product = $repository->ndBy( array('name' => 'foo'), array('price' => 'ASC') );
X hen you render ny pgeD you n see how mny queries were mde in the ottom right orner of the we deug toolrF
sf you lik the ionD the pro(ler will openD showing you the ext queries tht were mdeF
pdting n yjet yne you9ve fethed n ojet from hotrineD updting it is esyF uppose you hve route tht mps produt id to n updte tion in ontrollerX
public function updateAction($id) { $em = $this->getDoctrine()->getEntityManager(); $product = $em->getRepository('AcmeStoreBundle:Product')->nd($id); if (!$product) { throw $this->createNotFoundException('No product found for id '.$id); } $product->setName('New product name!'); $em->ush();
ISP SF
return $this->redirect($this->generateUrl('homepage'));
pdting n ojet involves just three stepsX IF fething the ojet from hotrineY PF modifying the ojetY QF lling )ush@A on the entity mnger xotie tht lling 6emEbpersist@6produtA isn9t neessryF ell tht this method simply tells hotrine to mnge or wth the 6produt ojetF sn this seD sine you fethed the 6produt ojet from hotrineD it9s lredy mngedF heleting n yjet heleting n ojet is very similrD ut requires ll to the remove@A method of the entity mngerX
$em->remove($product); $em->ush();
es you might expetD the remove@A method noti(es hotrine tht you9d like to remove the given entity from the dtseF he tul hivii queryD howeverD isn9t tully exeuted until the )ush@A method is lledF
5.8.2 Querying for Objects
ou9ve lredy seen how the repository ojet llows you to run si queries without ny workX
$repository->nd($id); $repository->ndOneByName('Foo');
yf ourseD hotrine lso llows you to write more omplex queries using the hotrine uery vnguge @hvAF hv is similr to v exept tht you should imgine tht you9re querying for one or more ojets of n entity lss @eFgF rodutA insted of querying for rows on tle @eFgF produtAF hen querying in hotrineD you hve two optionsX writing pure hotrine queries or using hotrine9s uery fuilderF
ISQ
ymfony houmenttionD PFH uerying for yjets with hv smging tht you wnt to query for produtsD ut only return produts tht ost more thn IWFWWD ordered from hepest to most expensiveF prom inside ontrollerD do the followingX
$em = $this->getDoctrine()->getEntityManager(); $query = $em->createQuery( 'SELECT p FROM AcmeStoreBundle:Product p WHERE p.price > :price ORDER BY p.price ASC' )->setParameter('price', '19.99'); $products = $query->getResult();
sf you9re omfortle with vD then hv should feel very nturlF he iggest di'erene is tht you need to think in terms of ojets insted of rows in dtseF por this resonD you selet from emetorefundleXrodut nd then lis it s pF he getesult@A method returns n rry of resultsF sf you9re querying for just one ojetD you n use the getingleesult@A method instedX
$product = $query->getSingleResult();
X he getingleesult@A method throws hotrineywxoesultixeption exeption if no results re returned nd hotrineywxonniqueesultixeption if more thn one result is returnedF sf you use this methodD you my need to wrp it in tryE th lok nd ensure tht only one result is returned @if you9re querying on something tht ould fesily return more thn one resultAX
$query = $em->createQuery('SELECT ....') ->setMaxResults(1); try { $product = $query->getSingleResult(); } catch (\Doctrine\Orm\NoResultException $e) { $product = null; } // ...
he hv syntx is inredily powerfulD llowing you to esily join etween entities @the topi of reltions will e overed lterAD groupD etF por more informtionD see the o0il hotrine hotrine uery vnguge doumenttionF
ISR
SF
ymfony houmenttionD PFH etting rmeters ke note of the setrmeter@A methodF hen working with hotrineD it9s lwys good ide to set ny externl vlues s pleholdersD whih ws done in the ove queryX
->setParameter('price', '19.99')
sing prmeters insted of pling vlues diretly in the query string is done to prevent v injetion ttks nd should lwys e doneF sf you9re using multiple prmetersD you n set their vlues t one using the setrmeters@A methodX
sing hotrine9s uery fuilder snsted of writing the queries diretlyD you n lterntively use hotrine9s ueryfuilder to do the sme jo using nieD ojetEoriented interfeF sf you use n shiD you n lso tke dvntge of utoEompletion s you type the method nmesF prom inside ontrollerX
$repository = $this->getDoctrine() ->getRepository('AcmeStoreBundle:Product'); $query = $repository->createQueryBuilder('p') ->where('p.price > :price') ->setParameter('price', '19.99') ->orderBy('p.price', 'ASC') ->getQuery(); $products = $query->getResult();
he ueryfuilder ojet ontins every method neessry to uild your queryF fy lling the getuery@A methodD the query uilder returns norml uery ojetD whih is the sme ojet you uilt diretly in the previous setionF por more informtion on hotrine9s uery fuilderD onsult hotrine9s uery fuilder doumenttionF
ISS
ymfony houmenttionD PFH gustom epository glsses sn the previous setionsD you egn onstruting nd using more omplex queries from inside ontrollerF sn order to isolteD test nd reuse these queriesD it9s good ide to rete ustom repository lss for your entity nd dd methods with your query logi thereF o do thisD dd the nme of the repository lss to your mpping de(nitionF
ennottions
// src/Acme/StoreBundle/Entity/Product.php namespace Acme\StoreBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass="Acme\StoreBundle\Repository\ProductRepository") */ class Product { //... }
ewv
<!-- src/Acme/StoreBundle/Resources/cong/doctrine/Product.orm.xml --> <!-- ... --> <doctrine-mapping> <entity name="Acme\StoreBundle\Entity\Product" repository-class="Acme\StoreBundle\Repository\ProductRepository"> <!-- ... --> </entity> </doctrine-mapping>
hotrine n generte the repository lss for you y running the sme ommnd used erlier to generte the missing getter nd setter methodsX
ymfony houmenttionD PFH lssF his method will query for ll of the rodut entitiesD ordered lphetillyF
// src/Acme/StoreBundle/Repository/ProductRepository.php namespace Acme\StoreBundle\Repository; use Doctrine\ORM\EntityRepository; class ProductRepository extends EntityRepository { public function ndAllOrderedByName() { return $this->getEntityManager() ->createQuery('SELECT p FROM AcmeStoreBundle:Product p ORDER BY p.name ASC') ->getResult(); } }
X he entity mnger n e essed vi 6thisEbgetintitywnger@A from inside the repositoryF ou n use this new method just like the defult (nder methods of the repositoryX
uppose tht the produts in your pplition ll elong to extly one tegoryF sn this seD you9ll need gtegory ojet nd wy to relte rodut ojet to gtegory ojetF trt y reting the gtegory entityF ine you know tht you9ll eventully need to persist the lss through hotrineD you n let hotrine rete the lss for youF
ISU
ymfony houmenttionD PFH eltionship wpping wetdt o relte the gtegory nd rodut entitiesD strt y reting produts property on the gtegory lssX
// src/Acme/StoreBundle/Entity/Category.php // ... use Doctrine\Common\Collections\ArrayCollection; class Category { // ... /** * @ORM\OneToMany(targetEntity="Product", mappedBy="category") */ protected $products; public function __construct() { $this->products = new ArrayCollection(); }
pirstD sine gtegory ojet will relte to mny rodut ojetsD produts rry property is dded to hold those rodut ojetsF eginD this isn9t done euse hotrine needs itD ut insted euse it mkes sense in the pplition for eh gtegory to hold n rry of rodut ojetsF X he ode in the onstrut@A method is importnt euse hotrine requires the 6produts property to e n errygolletion ojetF his ojet looks nd ts lmost extly like n rryD ut hs some dded )exiilityF sf this mkes you unomfortleD don9t worryF tust imgine tht it9s n rry nd you9ll e in good shpeF xextD sine eh rodut lss n relte to extly one gtegory ojetD you9ll wnt to dd 6tegory property to the rodut lssX
pinllyD now tht you9ve dded new property to oth the gtegory nd rodut lssesD tell hotrine to generte the missing getter nd setter methods for youX
ISW
he metdt ove the 6produts property of the gtegory ojet is less importntD nd simply tells hotrine to look t the rodutFtegory property to (gure out how the reltionship is mppedF fefore you ontinueD e sure to tell hotrine to dd the new tegory tleD nd produtFtegoryid olumnD nd new foreign keyX
ITH
SF
ymfony houmenttionD PFH ving elted intities xowD let9s see the ode in tionF smgine you9re inside ontrollerX
// ... use Acme\StoreBundle\Entity\Category; use Acme\StoreBundle\Entity\Product; use Symfony\Component\HttpFoundation\Response; // ... class DefaultController extends Controller { public function createProductAction() { $category = new Category(); $category->setName('Main Products'); $product = new Product(); $product->setName('Foo'); $product->setPrice(19.99); // relate this product to the category $product->setCategory($category); $em = $this->getDoctrine()->getEntityManager(); $em->persist($category); $em->persist($product); $em->ush(); return new Response( 'Created product id: '.$product->getId().' and category id: '.$category->getId() );
xowD single row is dded to oth the tegory nd produt tlesF he produtFtegoryid olumn for the new produt is set to whtever the id is of the new tegoryF hotrine mnges the persistene of this reltionship for youF pething elted yjets hen you need to feth ssoited ojetsD your work)ow looks just like it did eforeF pirstD feth 6produt ojet nd then ess its relted gtegoryX
sn this exmpleD you (rst query for rodut ojet sed on the produt9s idF his issues query for just the produt dt nd hydrtes the 6produt ojet with tht dtF vterD when you ll 6produtEbgetgtegory@AEbgetxme@AD hotrine silently mkes seond query to (nd the gtegory tht9s relted to this rodutF st prepres the 6tegory ojet nd returns it to youF
ht9s importnt is the ft tht you hve esy ess to the produt9s relted tegoryD ut the tegory dt isn9t tully retrieved until you sk for the tegory @iFeF it9s lzily lodedAF ou n lso query in the other diretionX
ITP
SF
sn this seD the sme things oursX you (rst query out for single gtegory ojetD nd then hotrine mkes seond query to retrieve the relted rodut ojetsD ut only oneGif you sk for them @iFeF when you ll Ebgetroduts@AAF he 6produts vrile is n rry of ll rodut ojets tht relte to the given gtegory ojet vi their tegoryid vlueF eltionships nd roxy glsses his lzy loding is possile euseD when neessryD hotrine returns proxy ojet in ple of the true ojetF vook gin t the ove exmpleX
$product = $this->getDoctrine() ->getRepository('AcmeStoreBundle:Product') ->nd($id); $category = $product->getCategory(); // prints "Proxies\AcmeStoreBundleEntityCategoryProxy" echo get_class($category);
his proxy ojet extends the true gtegory ojetD nd looks nd ts extly like itF he di'erene is thtD y using proxy ojetD hotrine n dely querying for the rel gtegory dt until you tully need tht dt @eFgF until you ll 6tegoryE bgetxme@AAF he proxy lsses re generted y hotrine nd stored in the he diretoryF end though you9ll proly never even notie tht your 6tegory ojet is tully proxy ojetD it9s importnt to keep in mindF sn the next setionD when you retrieve the produt nd tegory dt ll t one @vi joinAD hotrine will return the true gtegory ojetD sine nothing needs to e lzily lodedF
toining to elted eords sn the ove exmplesD two queries were mde E one for the originl ojet @eFgF gtegoryA nd one for the relted ojet@sA @eFgF the rodut ojetsAF X ememer tht you n see ll of the queries mde during request vi the we deug toolrF yf ourseD if you know up front tht you9ll need to ess oth ojetsD you n void SFVF hotrine @A ITQ
ymfony houmenttionD PFH the seond query y issuing join in the originl queryF edd the following method to the rodutepository lssX
// src/Acme/StoreBundle/Repository/ProductRepository.php public function ndOneByIdJoinedToCategory($id) { $query = $this->getEntityManager() ->createQuery(' SELECT p, c FROM AcmeStoreBundle:Product p JOIN p.category c WHERE p.id = :id' )->setParameter('id', $id); try { return $query->getSingleResult(); } catch (\Doctrine\ORM\NoResultException $e) { return null; }
xowD you n use this method in your ontroller to query for rodut ojet nd its relted gtegory with just one queryX
public function showAction($id) { $product = $this->getDoctrine() ->getRepository('AcmeStoreBundle:Product') ->ndOneByIdJoinedToCategory($id); $category = $product->getCategory(); } // ...
wore snformtion on essoitions his setion hs een n introdution to one ommon type of entity reltionshipD the oneEtoEmny reltionshipF por more dvned detils nd exmples of how to use other types of reltions @eFgF oneEtoEoneD mnyEtoEmnyAD see hotrine9s essoition wpping houmenttionF X sf you9re using nnottionsD you9ll need to prepend ll nnottions with yw @eFgF ywyneownyAD whih is not re)eted in hotrine9s doumenttionF ou9ll lso need to inlude the use hotrineywwpping s ywY sttementD whih imports the yw nnottions pre(xF ITR SF
5.8.4 Conguration
hotrine is highly on(gurleD though you proly won9t ever need to worry out most of its optionsF o (nd out more out on(guring hotrineD see the hotrine setion of the referene mnulF
5.8.5 Lifecycle Callbacks
ometimesD you need to perform n tion right efore or fter n entity is insertedD updtedD or deletedF hese types of tions re known s lifeyle llksD s they9re llk methods tht you need to exeute during di'erent stges of the lifeyle of n entity @eFgF the entity is insertedD updtedD deletedD etAF sf you9re using nnottions for your metdtD strt y enling the lifeyle llksF his is not neessry if you9re using ewv or wv for your mppingX
ennottions
<!-- src/Acme/StoreBundle/Resources/cong/doctrine/Product.orm.xml --> <!-- ... --> <doctrine-mapping> <entity name="Acme\StoreBundle\Entity\Product"> <!-- ... --> <lifecycle-callbacks> <lifecycle-callback type="prePersist" method="setCreatedValue" /> </lifecycle-callbacks> </entity> </doctrine-mapping>
X he ove exmple ssumes tht you9ve reted nd mpped reted property @not shown hereAF xowD right efore the entity is (rst persistedD hotrine will utomtilly ll this method nd the reted (eld will e set to the urrent dteF his n e repeted for ny of the other lifeyle eventsD whih inludeX
ITT
SF
ymfony houmenttionD PFH vifeyle gllks nd ivent visteners xotie tht the setgretedlue@A method reeives no rgumentsF his is lwys the se for lifeyle llks nd is intentionlX lifeyle llks should e simple methods tht re onerned with internlly trnsforming dt in the entity @eFgF setting retedGupdted (eldD generting slug vlueAF sf you need to do some hevier lifting E like perform logging or send n emil E you should register n externl lss s n event listener or susrier nd give it ess to whtever resoures you needF por more informtionD see egistering ivent visteners nd usriersF
hotrine is quite )exileD nd numer of thirdEprty extensions re ville tht llow you to esily perform repeted nd ommon tsks on your entitiesF hese inlude thing suh s luggleD imestmpleD voggleD rnsltleD nd reeF por more informtion on how to (nd nd use these extensionsD see the ookook rtile out using ommon hotrine extensionsF
5.8.7 Doctrine Field Types Reference
hotrine omes with lrge numer of (eld types villeF ih of these mps r dt type to spei( olumn type in whtever dtse you9re usingF he following types re supported in hotrineX
trings
! string @used for shorter stringsA ! text @used for lrger stringsA
xumers
! integer ! smllint ! igint ! deiml ! )ot
yther ypes
! oolen ! ojet @serilized nd stored in gvyf (eldA ! rry @serilized nd stored in gvyf (eldA por more informtionD see hotrine9s wpping ypes doumenttionF pield yptions ih (eld n hve set of options pplied to itF he ville options inlude type @defults to stringAD nmeD lengthD unique nd nullleF ke few nnottions exmplesX
/** * A string eld with length 255 that cannot be null * (reecting the default values for the "type", "length" and *nullable* options) * * @ORM\Column() */ protected $name; /** * A string eld of length 150 that persists to an "email_address" column * and has a unique index. * * @ORM\Column(name="email_address", unique="true", length="150") */ protected $email;
X here re few more options not listed hereF por more detilsD see hotrine9s roperty wpping doumenttion
he hotrineP yw integrtion o'ers severl onsole ommnds under the dotrine nmespeF o view the ommnd list you n run the onsole without ny rgumentsX
php app/console
e list of ville ommnd will print outD mny of whih strt with the dotrineX pre(xF ou n (nd out more informtion out ny of these ommnds @or ny ymfony ommndA y
ITV
SF
ymfony houmenttionD PFH running the help ommndF por exmpleD to get detils out the dotrineXdtseXrete tskD runX
dotrineXensureEprodutionEsettings E heks to see if the urrent environment is on(gured e0iently for produtionF his should lwys e run in the prod environmentX
5.8.9 Summary
ith hotrineD you n fous on your ojets nd how they9re useful in your pplition nd worry out dtse persistene seondF his is euse hotrine llows you to use ny r ojet to hold your dt nd relies on mpping metdt informtion to mp n ojet9s dt to prtiulr dtse tleF end even though hotrine revolves round simple oneptD it9s inredily powerfulD llowing you to rete omplex queries nd susrie to events tht llow you to tke di'erent tions s ojets go through their persistene lifeyleF por more informtion out hotrineD see the hotrine setion of the ookookD whih inludes the following rtilesX
ITW
5.9
D F ymfonyPF
5.9.1
<!-- app/phpunit.xml.dist --> <phpunit bootstrap="../src/autoload.php"> <testsuites> <testsuite name="Project Test Suite"> <directory>../src/*/*Bundle/Tests</directory> </testsuite> </testsuites> ... </phpunit>
X
IUH
SF
# Controller $ phpunit -c app src/Acme/HelloBundle/Tests/Controller/ # Model $ phpunit -c app src/Acme/HelloBundle/Tests/Model/ # Article $ phpunit -c app src/Acme/HelloBundle/Tests/Model/ArticleTest.php # Bundle $ phpunit -c app src/Acme/HelloBundle/
5.9.3
@ AF D E rnit D X
Y Y Y Y F
D D E F D ymfonyP eestgseF hemogontrollerD X
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class DemoControllerTest extends WebTestCase { public function testIndex() { $client = static::createClient(); $crawler = $client->request('GET', '/demo/hello/Fabien'); } $this->assertTrue($crawler->lter('html:contains("Hello Fabien")')->count() > 0);
reteglient@A D X
request($method, $uri, array $parameters = array(), array $les = array(), array $server = array(), $content = null, $changeHistory = true )
D grwlerD E th g D glientX
$crawler = $client->submit($form, array( 'name' => 'Lucas', 'country' => 'France', 'like_symfony' => true, 'photo' => '/path/to/lucas.jpg', ));
D D F grwler hywX
SFWF
IUQ
// CSS . $this->assertTrue($crawler->lter($selector)->count() > 0); // CSS n . $this->assertEquals($count, $crawler->lter($selector)->count()); // . $this->assertTrue($client->getResponse()->headers->contains($key, $value)); // regexp. $this->assertRegExp($regexp, $client->getResponse()->getContent()); // . $this->assertTrue($client->getResponse()->isSuccessful()); $this->assertTrue($client->getResponse()->isNotFound()); $this->assertEquals(200, $client->getResponse()->getStatusCode()); // . $this->assertTrue($client->getResponse()->isRedirect('google.com'));
5.9.4
r D F X frowseruit grwlerF
ymfonyPX
IUR
SF
$link = $crawler->selectLink('Go elsewhere...')->link(); $crawler = $client->click($link); $form = $crawler->selectButton('validate')->form(); $crawler = $client->submit($form, array('name' => 'Fabien'));
lik@A sumit@A grwlerF F D sumitD r vD es F F X vink porm grwlerF request@AX
// $client->request('POST', '/submit', array('name' => 'Fabien')); // use Symfony\Component\HttpFoundation\File\UploadedFile; $photo = new UploadedFile('/path/to/photo.jpg', 'photo.jpg', 'image/jpeg', 123); // $photo = array('tmp_name' => '/path/to/photo.jpg', 'name' => 'photo.jpg', 'type' => 'image/jpeg', 'size' => $client->request('POST', '/submit', array('name' => 'Fabien'), array('photo' => $photo));
$client->followRedirects(false);
D E followediret@AX
$crawler = $client->followRedirect();
D D E SFWF IUS
$client->insulate();
D X
$container = $client->getContainer();
IUT
SF
D D E X
$prole = $client->getProle();
r D E esponse F E D followediret@AX
// -, (, ) // $crawler = $client->followRedirect();
D followedirets@AX
5.9.5 Crawler
grwler F rwv D D F
SFWF
IUU
IUV
SF
ymfony houmenttionD PFH (lter@9hI9A (lterpth@9hI9A eq@IA (rst@A lst@A silings@A nextell@A previousell@A prents@A hildren@A redue@6lmdA D g D th D flse
D F F grwler X
grwler X
// $crawler->attr('class'); // $crawler->text(); // (_text ) $crawler->extract(array('_text', 'href')); // lambda $data = $crawler->each(function ($node, $i) {
SFWF IUW
});
return $node->getAttribute('href');
D seletvink@A X
$crawler->selectLink('Click here');
D D D D ltF lik@A vinkD link@AX
D seletfutton@AX
$crawler->selectButton('submit');
D D F F Y es D F seletfutton@A utton input sumitY X
$form = $crawler->form();
IVH
SF
$client->submit($form);
sumit@AX
// $form['name'] = 'Fabien';
es X
SFWF
IVI
<!-- hello/phpunit.xml.dist --> <testsuites> <testsuite name="Project Test Suite"> <directory>../src/*/*Bundle/Tests</directory> <directory>../src/Acme/Bundle/*Bundle/Tests</directory> </testsuite> </testsuites>
D `(lterbX
<lter> <whitelist> <directory>../src</directory> <exclude> <directory>../src/*/*Bundle/Resources</directory> <directory>../src/*/*Bundle/Tests</directory> <directory>../src/Acme/Bundle/*Bundle/Resources</directory> <directory>../src/Acme/Bundle/*Bundle/Tests</directory> </exclude> </whitelist> </lter>
D D uernelD testD F F D X IVP SF
ewv
# app/cong/cong_test.yml imports: - { resource: cong_dev.yml } framework: error_handler: false test: ~ web_proler: toolbar: false intercept_redirects: false monolog: handlers: main: type: stream path: %kernel.logs_dir%/%kernel.environment%.log level: debug
wv
<!-- app/cong/cong_test.xml --> <container> <imports> <import resource="cong_dev.xml" /> </imports> <webproler:cong toolbar="false" intercept-redirects="false" /> <framework:cong error_handler="false"> <framework:test /> </framework:cong> <monolog:cong> <monolog:main type="stream" path="%kernel.logs_dir%/%kernel.environment%.log" level="debug" /> </monolog:cong> </container>
r
SFWF IVQ
// app/cong/cong_test.php $loader->import('cong_dev.php'); $container->loadFromExtension('framework', array( 'error_handler' => false, 'test' => true, )); $container->loadFromExtension('web_proler', array( 'toolbar' => false, 'intercept-redirects' => false, )); $container->loadFromExtension('monolog', array( 'handlers' => array( 'main' => array('type' => 'stream', 'path' => '%kernel.logs_dir%/%kernel.environment%.log' 'level' => 'debug') )));
@testA @trueAD D reteglient@A X
$client = static::createClient(array(), array( 'HTTP_HOST' => 'en.example.com', 'HTTP_USER_AGENT' => 'MySuperBrowser/1.0', ));
r X
$client->request('GET', '/', array(), array( 'HTTP_HOST' => 'en.example.com', 'HTTP_USER_AGENT' => 'MySuperBrowser/1.0', ));
X D testFlientFlss testFlientF
IVR
SF
row to simulte r euthentition in puntionl est row to test the sntertion of severl glients row to use the ro(ler in puntionl est
5.10
E F E D E r D E X
ewv
SFIHF
IVS
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\NotBlank() */ public $name; }
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <?xml version="1.0" encoding="UTF-8" ?> <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/ <class name="Acme\BlogBundle\Entity\Author"> <property name="name"> <constraint name="NotBlank" /> </property> </class> </constraint-mapping>
r
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\NotBlank; class Author { public $name; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('name', new NotBlank());
IVT SF
X roteted privte D @F AF
use Symfony\Component\HttpFoundation\Response; use Acme\BlogBundle\Entity\Author; // ... public function indexAction() { $author = new Author(); // ... do something to the $author object $validator = $this->get('validator'); $errors = $validator->validate($author); if (count($errors) > 0) { return new Response(print_r($errors, true)); } else { return new Response('The author is valid! Yes!'); }
6nme D X
SFIHF
IVU
ymfony houmenttionD PFH ou ould lso pss the olletion of errors into templteF
if (count($errors) > 0) { return $this->render('AcmeBlogBundle:Author:validate.html.twig', array( 'errors' => $errors, )); } else { // ... }
D X
wig
{# src/Acme/BlogBundle/Resources/views/Author/validate.html.twig #} <h3>The author has the following errors</h3> <ul> {% for error in errors %} <li>{{ error.message }}</li> {% endfor %} </ul>
r
<!-- src/Acme/BlogBundle/Resources/views/Author/validate.html.php --> <h3>The author has the following errors</h3> <ul> <?php foreach ($errors as $error): ?> <li><?php echo $error->getMessage() ?></li> <?php endforeach; ?> </ul>
X @onstrint violtionAAD ymfonygomponentlidtorgonstrintioltionF @ E
ymfony houmenttionD PFH F he typil form sumission work)ow looks like the following from inside ontrollerX
use Acme\BlogBundle\Entity\Author; use Acme\BlogBundle\Form\AuthorType; use Symfony\Component\HttpFoundation\Request; // ... public function updateAction(Request $request) { $author = new Acme\BlogBundle\Entity\Author(); $form = $this->createForm(new AuthorType(), $author); if ($request->getMethod() == 'POST') { $form->bindRequest($request); if ($form->isValid()) { // the validation passed, do something with the $author object } $this->redirect($this->generateUrl('...'));
X his exmple uses n euthorype form lssD whih is not shown hereF D pormsF
5.10.2
he ymfonyP vlidtor is enled y defultD ut you must expliitly enle nnottions if you9re using the nnottion method to speify your onstrintsX
ewv
SFIHF
IVW
5.10.3
vlidtor @FF E AF D D vlidtorF r D E F D X F ymfonyP X E D F D D F ymfonyP F F ome onstrintsD like xotflnkD re simple wheres othersD like the ghoie onstrintD hve severl on(gurtion options villeF uppose tht the euthor lss hs nother propertyD gender tht n e set to either mle or femleX
ewv
# src/Acme/BlogBundle/Resources/cong/validation.yml Acme\BlogBundle\Entity\Author: properties: gender: - Choice: { choices: [male, female], message: Choose a valid gender. }
IWH
SF
ennottions
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Choice( * choices = { "male", "female" }, * message = "Choose a valid gender." *) */ public $gender; }
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <?xml version="1.0" encoding="UTF-8" ?> <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/ <class name="Acme\BlogBundle\Entity\Author"> <property name="gender"> <constraint name="Choice"> <option name="choices"> <value>male</value> <value>female</value> </option> <option name="message">Choose a valid gender.</option> </constraint> </property> </class> </constraint-mapping>
r
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\NotBlank; class Author { public $gender; public static function loadValidatorMetadata(ClassMetadata $metadata)
SFIHF IWI
$metadata->addPropertyConstraint('gender', new Choice(array( 'choices' => array('male', 'female'), 'message' => 'Choose a valid gender.', )));
he options of onstrint n lwys e pssed in s n rryF ome onstrintsD howeverD lso llow you to pss the vlue of oneD defultD option in ple of the rryF sn the se of the ghoie onstrintD the hoies options n e spei(ed in this wyF
ewv
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Choice({"male", "female"}) */ protected $gender; }
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <?xml version="1.0" encoding="UTF-8" ?> <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/ <class name="Acme\BlogBundle\Entity\Author"> <property name="gender"> <constraint name="Choice"> <value>male</value> <value>female</value> </constraint> </property>
IWP SF
</class> </constraint-mapping>
r
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\Choice; class Author { protected $gender; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('gender', new Choice(array('male', 'female'))); }
his is purely ment to mke the on(gurtion of the most ommon option of onstrint shorter nd quikerF sf you9re ever unsure of how to speify n optionD either hek the es doumenttion for the onstrint or ply it sfe y lwys pssing in n rry of options @the (rst method shown oveAF
5.10.4
@ nmeA E E @ getpullxmeAF he (rst is the most ommon nd esy to useD ut the seond llows you to speify more omplex vlidtion rulesF F ymfonyP E privteD proteted puli F E D 6(rstxme euthor E Q F
ewv
- NotBlank: ~ - MinLength: 3
ennottions
// Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\NotBlank() * @Assert\MinLength(3) */ private $rstName; }
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <class name="Acme\BlogBundle\Entity\Author"> <property name="rstName"> <constraint name="NotBlank" /> <constraint name="MinLength">3</constraint> </property> </class>
r
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\MinLength; class Author { private $rstName; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('rstName', new NotBlank()); $metadata->addPropertyConstraint('rstName', new MinLength(3)); }
IWR
SF
ymfony houmenttionD PFH F ymfonyP E puli D get isF D F D E F por exmpleD suppose you wnt to mke sure tht pssword (eld doesn9t mth the (rst nme of the user @for seurity resonsAF ou n do this y reting n issswordvegl methodD nd then sserting tht this method must return trueX
ewv
# src/Acme/BlogBundle/Resources/cong/validation.yml Acme\BlogBundle\Entity\Author: getters: passwordLegal: - "True": { message: "The password cannot match your rst name" }
ennottions
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\True(message = "The password cannot match your rst name") */ public function isPasswordLegal() { // return true or false } }
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <class name="Acme\BlogBundle\Entity\Author"> <getter property="passwordLegal"> <constraint name="True"> <option name="message">The password cannot match your rst name</option> </constraint> </getter> </class>
r
SFIHF
IWS
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\True; class Author { public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addGetterConstraint('passwordLegal', new True(array( 'message' => 'The password cannot match your rst name', ))); } }
xowD rete the issswordvegl@A methodD nd inlude the logi you needX
glsses ome onstrints pply to the entire lss eing vlidtedF por exmpleD the gllk onstrint is generi onstrint tht9s pplied to the lss itselfF hen tht lss is vlidtedD methods spei(ed y tht onstrint re simply exeuted so tht eh n provide more ustom vlidtionF
5.10.5 Validation Groups
o frD you9ve een le to dd onstrints to lss nd sk whether or not tht lss psses ll of the de(ned onstrintsF sn some sesD howeverD you9ll need to vlidte n ojet ginst only some of the onstrints on tht lssF o do thisD you n orgnize eh onstrint into one or more vlidtion groupsD nd then pply vlidtion ginst just one group of onstrintsF por exmpleD suppose you hve ser lssD whih is used oth when user registers nd when user updtes hisGher ontt informtion lterX
IWT
SF
ewv
# src/Acme/BlogBundle/Resources/cong/validation.yml Acme\BlogBundle\Entity\User: properties: email: - Email: { groups: [registration] } password: - NotBlank: { groups: [registration] } - MinLength: { limit: 7, groups: [registration] } city: - MinLength: 2
ennottions
// src/Acme/BlogBundle/Entity/User.php namespace Acme\BlogBundle\Entity; use Symfony\Component\Security\Core\User\UserInterface use Symfony\Component\Validator\Constraints as Assert; class User implements UserInterface { /** * @Assert\Email(groups={"registration"}) */ private $email; /** * @Assert\NotBlank(groups={"registration"}) * @Assert\MinLength(limit=7, groups={"registration"}) */ private $password; /** * @Assert\MinLength(2) */ private $city;
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <class name="Acme\BlogBundle\Entity\User"> <property name="email"> <constraint name="Email"> <option name="groups"> <value>registration</value>
SFIHF IWU
</option> </constraint> </property> <property name="password"> <constraint name="NotBlank"> <option name="groups"> <value>registration</value> </option> </constraint> <constraint name="MinLength"> <option name="limit">7</option> <option name="groups"> <value>registration</value> </option> </constraint> </property> <property name="city"> <constraint name="MinLength">7</constraint> </property> </class>
r
// src/Acme/BlogBundle/Entity/User.php namespace Acme\BlogBundle\Entity; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\Email; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\MinLength; class User { public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('email', new Email(array( 'groups' => array('registration') ))); $metadata->addPropertyConstraint('password', new NotBlank(array( 'groups' => array('registration') ))); $metadata->addPropertyConstraint('password', new MinLength(array( 'limit' => 7, 'groups' => array('registration') )));
IWV
SF
hefult E ontins the onstrints not ssigned to ny other groupY registrtion E ontins the onstrints on the emil nd pssword (elds onlyF
o tell the vlidtor to use spei( groupD pss one or more group nmes s the seond rgument to the vlidte@A methodX
5.11
SFIIF
IWW
D D F D F D D D skD X
// src/Acme/TaskBundle/Entity/Task.php namespace Acme\TaskBundle\Entity; class Task { protected $task; protected $dueDate; public function getTask() { return $this->task; } public function setTask($task) { $this->task = $task; } public function getDueDate() { return $this->dueDate; } public function setDueDate(\DateTime $dueDate = null) { $this->dueDate = $dueDate; }
X D D D E D emeskfundle @ E AX
// src/Acme/TaskBundle/Controller/DefaultController.php namespace Acme\TaskBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Acme\TaskBundle\Entity\Task; use Symfony\Component\HttpFoundation\Request; class DefaultController extends Controller { public function newAction(Request $request) { // create a task and give it some dummy data for this example $task = new Task(); $task->setTask('Write a blog post'); $task->setDueDate(new \DateTime('tomorrow')); $form = $this->createFormBuilder($task) ->add('task', 'text') ->add('dueDate', 'date') ->getForm(); return $this->render('AcmeTaskBundle:Default:new.html.twig', array( 'form' => $form->createView(), ));
ymfony houmenttionD PFH F X tsk duehteD E tsk duehte skF @E D textD dteAD D D rwv @EA F ymfonyP D @E AF F E @ 6formE breteiew@A AD X
wig
{# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #} <form action="{{ path('task_new') }}" method="post" {{ form_enctype(form) }}> {{ form_widget(form) }} <input type="submit" /> </form>
r
<form action="<?php echo $view['router']->generate('task_new') ?>" method="post" <?php echo $view[ <?php echo $view['form']->widget($form) ?> <input type="submit" /> </form>
X D tsknew PHP SF
ymfony houmenttionD PFH emeskfundleXhefultXnewF 3 formwidget@formAD E @ AF D F D D F F D D D tsk E tsk 6tsk @FF AF X D rwv F X D E tskD getsk@A setsk@A skF D D D form G F foolen isset @D isulished@AA @D getulished@AAF
E F D E F X
// ... public function newAction(Request $request) { // just setup a fresh $task object (remove the dummy data) $task = new Task(); $form = $this->createFormBuilder($task) ->add('task', 'text') ->add('dueDate', 'date') ->getForm(); if ($request->getMethod() == 'POST') { $form->bindRequest($request); if ($form->isValid()) { // perform some action, such as saving the task to the database
SFIIF
PHQ
} }
return $this->redirect($this->generateUrl('task_success'));
// ...
D D E tsk duehte 6tskF indequest@AF X indequest@A F F E X IF qiF Y PF @FF yAD @ AD Y QF D D 6tsk @D AD D @D thnk you suessAF X E F
ewv
// Acme/TaskBundle/Entity/Task.php use Symfony\Component\Validator\Constraints as Assert; class Task { /** * @Assert\NotBlank() */ public $task; /** * @Assert\NotBlank() * @Assert\Type("\DateTime") */ protected $dueDate;
wv
<!-- Acme/TaskBundle/Resources/cong/validation.xml --> <class name="Acme\TaskBundle\Entity\Task"> <property name="task"> <constraint name="NotBlank" /> </property> <property name="dueDate"> <constraint name="NotBlank" /> <constraint name="Type"> <value>\DateTime</value> </constraint> </property> </class>
r
SFIIF PHS
// Acme/TaskBundle/Entity/Task.php use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\Type; class Task { // ... public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('task', new NotBlank()); $metadata->addPropertyConstraint('dueDate', new NotBlank()); $metadata->addPropertyConstraint('dueDate', new Type('\DateTime'));
PHT
SF
text textre emil integer money numer pssword perent serh url
SFIIF
PHU
olletion repeted
ridden pields
hidden srf
PHV
SF
(eld form
F his topi is overed in the row to grete gustom porm pield ype rtile of the ookookF D F D duehte F D dte (eld D @ AX
D D F @ AF required requiredD E F D required trueF D D rwvS E D F D flse required D rwvS F D true required F D @D E EAD D xotflnk xotxull ymfonyF D required D E F
SFIIF
PHW
public function newAction() { $task = new Task(); $form = $this->createFormBuilder($task) ->add('task') ->add('dueDate', null, array('widget' => 'single_text')) ->getForm();
5.11.5
D D D D F D E X FF on(gurtionElokX
.. code-block:: html+jinja {# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #} <form action="{{ path('task_new') }}" method="post" {{ form_enctype(form) }}> {{ form_errors(form) }} {{ form_row(form.task) }} {{ form_row(form.dueDate) }} {{ form_rest(form) }} <input type="submit" /> </form> .. code-block:: html+php <!-- // src/Acme/TaskBundle/Resources/views/Default/newAction.html.php -->
<form action="<?php echo $view['router']->generate('task_new') ?>" method="post" <?php echo $view['for <?php echo $view['form']->errors($form) ?> <?php echo $view['form']->row($form['task']) ?> <?php echo $view['form']->row($form['dueDate']) ?>
SFIIF PII
wig
<?php echo $view['form']->errors($form) ?> <div> <?php echo $view['form']->label($form['task']) ?> <?php echo $view['form']->errors($form['task']) ?> <?php echo $view['form']->widget($form['task']) ?> </div> <div> <?php echo $view['form']->label($form['dueDate']) ?> <?php echo $view['form']->errors($form['dueDate']) ?> <?php echo $view['form']->widget($form['dueDate']) ?> </div> <?php echo $view['form']->rest($form) ?>
D X
wig
wig
SFIIF
PIQ
<?php echo $view['form']->widget($form['task'], array( 'attr' => array('class' => 'task_eld'), )) ?>
wig emplte puntion eferene sf you9re using wigD full referene of the form rendering funtions is ville in the referene mnulF ed this to know everything out the helpers ville nd the options tht n e used with ehF
5.11.6 Creating Form Classes
es you9ve seenD form n e reted nd used diretly in ontrollerF roweverD etter prtie is to uild the form in seprteD stndlone r lssD whih n then e reused nywhere in your pplitionF grete new lss tht will house the logi for uilding the tsk formX
// src/Acme/TaskBundle/Form/Type/TaskType.php namespace Acme\TaskBundle\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilder; class TaskType extends AbstractType { public function buildForm(FormBuilder $builder, array $options) { $builder->add('task'); $builder->add('dueDate', null, array('widget' => 'single_text')); } public function getName() { return 'task'; }
his new lss ontins ll the diretions needed to rete the tsk form @note tht the getxme@A method should return unique identi(er for this form typeAF st n e used to quikly uild form ojet in the ontrollerX
// src/Acme/TaskBundle/Controller/DefaultController.php
PIR
SF
// add this new use statement at the top of the class use Acme\TaskBundle\Form\Type\TaskType; public function newAction() { $task = // ... $form = $this->createForm(new TaskType(), $task); } // ...
ling the form logi into its own lss mens tht the form n e esily reused elsewhere in your projetF his is the est wy to rete formsD ut the hoie is ultimtely up to youF etting the dtlss ivery form needs to know the nme of the lss tht holds the underlying dt @eFgF emeskfundleintityskAF sullyD this is just guessed sed o' of the ojet pssed to the seond rgument to reteporm @iFeF 6tskAF vterD when you egin emedding formsD this will no longer e su0ientF oD while not lwys neessryD it9s generlly good ide to expliitly speify the dtlss option y dd the following to your form type lssX
he gol of form is to trnslte dt from n ojet @eFgF skA to n rwv form nd then trnslte userEsumitted dt k to the originl ojetF es suhD the topi of persisting the sk ojet to the dtse is entirely unrelted to the topi of formsF futD if you9ve on(gured the sk lss to e persisted vi hotrine @iFeF you9ve dded mpping metdt for itAD then persisting it fter form sumission n e done when the form is vlidX
}
sfD for some resonD you don9t hve ess to your originl 6tsk ojetD you n feth it from the formX
$task = $form->getData();
por more informtionD see the hotrine yw hpterF he key thing to understnd is tht when the form is oundD the sumitted dt is trnsferred to the underlying ojet immeditelyF sf you wnt to persist tht dtD you simply need to persist the ojet itself @whih lredy ontins the sumitted dtAF
5.11.8 Embedded Forms
yftenD you9ll wnt to uild form tht will inlude (elds from mny di'erent ojetsF por exmpleD registrtion form my ontin dt elonging to ser ojet s well s mny eddress ojetsF portuntelyD this is esy nd nturl with the form omponentF imedding ingle yjet uppose tht eh sk elongs to simple gtegory ojetF trtD of ourseD y reting the gtegory ojetX
// src/Acme/TaskBundle/Entity/Category.php namespace Acme\TaskBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class Category { /** * @Assert\NotBlank() */ public $name; }
xextD dd new tegory property to the sk lssX
PIT
SF
/** * @Assert\Type(type="Acme\TaskBundle\Entity\Category") */ protected $category; // ... public function getCategory() { return $this->category; } public function setCategory(Category $category = null) { $this->category = $category; }
xow tht your pplition hs een updted to re)et the new requirementsD rete form lss so tht gtegory ojet n e modi(ed y the userX
// src/Acme/TaskBundle/Form/Type/CategoryType.php namespace Acme\TaskBundle\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilder; class CategoryType extends AbstractType { public function buildForm(FormBuilder $builder, array $options) { $builder->add('name'); } public function getDefaultOptions(array $options) { return array( 'data_class' => 'Acme\TaskBundle\Entity\Category', ); } public function getName() { return 'category'; }
SFIIF
PIU
ymfony houmenttionD PFH he end gol is to llow the gtegory of sk to e modi(ed right inside the tsk form itselfF o omplish thisD dd tegory (eld to the skype ojet whose type is n instne of the new gtegoryype lssX
public function buildForm(FormBuilder $builder, array $options) { // ... } $builder->add('category', new CategoryType());
he (elds from gtegoryype n now e rendered longside those from the skype lssF ender the gtegory (elds in the sme wy s the originl sk (eldsX
wig
<!-- ... --> <h3>Category</h3> <div class="category"> <?php echo $view['form']->row($form['category']['name']) ?> </div> <?php echo $view['form']->rest($form) ?> <!-- ... -->
hen the user sumits the formD the sumitted dt for the gtegory (elds re used to onstrut n instne of gtegoryD whih is then set on the tegory (eld of the sk instneF he gtegory instne is essile nturlly vi 6tskEbgetgtegory@A nd n e persisted to the dtse or used however you needF imedding golletion of porms ou n lso emed olletion of forms into one formF his is done y using the olletion (eld typeF por more informtionD see the olletion (eld type refereneF PIV SF
ivery prt of how form is rendered n e ustomizedF ou9re free to hnge how eh form row rendersD hnge the mrkup used to render errorsD or even ustomize how textre tg should e renderedF xothing is o'ElimitsD nd di'erent ustomiztions n e used in di'erent plesF ymfony uses templtes to render eh nd every prt of formD suh s lel tgsD input tgsD error messges nd everything elseF sn wigD eh form frgment is represented y wig lokF o ustomize ny prt of how form rendersD you just need to override the pproprite lokF sn rD eh form frgment is rendered vi n individul templte (leF o ustomize ny prt of how form rendersD you just need to override the existing templte y reting new oneF o understnd how this worksD let9s ustomize the formrow frgment nd dd lss ttriute to the div element tht surrounds eh rowF o do thisD rete new templte (le tht will store the new mrkupX
wig
{# src/Acme/TaskBundle/Resources/views/Form/elds.html.twig #} {% block eld_row %} {% spaceless %} <div class="form_row"> {{ form_label(form) }} {{ form_errors(form) }} {{ form_widget(form) }} </div> {% endspaceless %} {% endblock eld_row %}
r
<!-- src/Acme/TaskBundle/Resources/views/Form/eld_row.html.php --> <div class="form_row"> <?php echo $view['form']->label($form, $label) ?> <?php echo $view['form']->errors($form) ?> <?php echo $view['form']->widget($form, $parameters) ?> </div>
he (eldrow form frgment is used when rendering most (elds vi the formrow funtionF o tell the form omponent to use your new (eldrow frgment de(ned oveD dd the following to the top of the templte tht renders the formX
wig
SFIIF PIW
(eldrow E used y formrow to render most (eldsY textrewidget E used y formwidget to render textre (eld typeY (elderrors E used y formerrors to render errors for (eldY
ih frgment follows the sme si ptternX typeprtF he type portion orresponds to the (eld type eing rendered @eFgF textreD hekoxD dteD etA wheres the prt portion
PPH
SF
ymfony houmenttionD PFH orresponds to wht is eing rendered @eFgF lelD widgetD errorsD etAF fy defultD there re R possile prts of form tht n e renderedX lel widget errors row @eFgF @eFgF @eFgF @eFgF (eldlelA (eldwidgetA (elderrorsA (eldrowA renders renders renders renders the the the the (eld9s (eld9s (eld9s (eld9s lel rwv representtion errors entire row @lelD widget 8 errorsA
X here re tully Q other prts E rowsD restD nd entype E ut you should rrely if ever need to worry out overriding themF fy knowing the (eld type @eFgF textreA nd whih prt you wnt to ustomize @eFgF widgetAD you n onstrut the frgment nme tht needs to e overridden @eFgF textrewidgetAF emplte prgment snheritne sn some sesD the frgment you wnt to ustomize will pper to e missingF por exmpleD there is no textreerrors frgment in the defult themes provided with ymfonyF o how re the errors for textre (eld renderedc he nswer isX vi the (elderrors frgmentF hen ymfony renders the errors for textre typeD it looks (rst for textreerrors frgment efore flling k to the (elderrors frgmentF ih (eld type hs prent type @the prent type of textre is (eldAD nd ymfony uses the frgment for the prent type if the se frgment doesn9t existF oD to override the errors for only textre (eldsD opy the (elderrors frgmentD renme it to textreerrors nd ustomize itF o override the defult error rendering for ll (eldsD opy nd ustomize the (elderrors frgment diretlyF X he prent type of eh (eld type is ville in the form type referene for eh (eld typeF
qlol porm heming sn the ove exmpleD you used the formtheme helper @in wigA to import the ustom form frgments into just tht formF ou n lso tell ymfony to import form ustomiztions ross your entire projetF
Twig
o utomtilly inlude the ustomized loks from the (eldsFhtmlFtwig templte reted erlier in ll templtesD modify your pplition on(gurtion (leX
SFIIF
PPI
ewv
<!-- app/cong/cong.xml --> <twig:cong ...> <twig:form> <resource>AcmeTaskBundle:Form:elds.html.twig</resource> </twig:form> <!-- ... --> </twig:cong>
r
// app/cong/cong.php $container->loadFromExtension('twig', array( 'form' => array('resources' => array( 'AcmeTaskBundle:Form:elds.html.twig', )) // ... ));
eny loks inside the (eldsFhtmlFtwig templte re now used glolly to de(ne form outputF
PPP
SF
ymfony houmenttionD PFH gustomizing porm yutput ll in ingle pile with wig sn wigD you n lso ustomize form lok right inside the templte where tht ustomiztion is neededX
{% extends '::base.html.twig' %} {# import "_self" as the form theme #} {% form_theme form _self %} {# make the form fragment customization #} {% block eld_row %} {# custom eld row output #} {% endblock eld_row %} {% block content %} {# ... #} {{ form_row(form.task) }} {% endblock %}
he {7 formtheme form self 7} tg llows form loks to e ustomized diretly inside the templte tht will use those ustomiztionsF se this method to quikly mke form output ustomiztions tht will only ever e needed in single templteF
PHP
o utomtilly inlude the ustomized templtes from the emeGskfundleGesouresGviewsGporm diretory reted erlier in ll templtesD modify your pplition on(gurtion (leX
ewv
// app/cong/cong.php $container->loadFromExtension('framework', array( 'templating' => array('form' => array('resources' => array( 'AcmeTaskBundle:Form', ))) // ... ));
eny frgments inside the emeGskfundleGesouresGviewsGporm diretory re now used glolly to de(ne form outputF
5.11.10 CSRF Protection
gp E or grossEsite request forgery E is method y whih mliious user ttempts to mke your legitimte users unknowingly sumit dt tht they don9t intend to sumitF portuntelyD gp ttks n e prevented y using gp token inside your formsF he good news is thtD y defultD ymfony emeds nd vlidtes gp tokens utomtilly for youF his mens tht you n tke dvntge of the gp protetion without doing nythingF sn ftD every form in this hpter hs tken dvntge of the gp protetion3 gp protetion works y dding hidden (eld to your form E lled token y defult E tht ontins vlue tht only you nd your user knowsF his ensures tht the user E not some other entity E is sumitting the given dtF ymfony utomtilly vlidtes the presene nd ury of this tokenF he token (eld is hidden (eld nd will e utomtilly rendered if you inlude the formrest@A funtion in your templteD whih ensures tht ll unErendered (elds re outputF he gp token n e ustomized on formEyEform sisF por exmpleX
PPR
SF
public function getDefaultOptions(array $options) { return array( 'data_class' => 'Acme\TaskBundle\Entity\Task', 'csrf_protection' => true, 'csrf_eld_name' => '_token', // a unique key to help generate the secret token 'intention' => 'task_item', ); } } // ...
o disle gp protetionD set the srfprotetion option to flseF gustomiztions n lso e mde glolly in your projetF por more informtionD see the form on(gurtion referene setionF X he intention option is optionl ut gretly enhnes the seurity of the generted token y mking it di'erent for eh formF
ou now know ll of the uilding loks neessry to uild omplex nd funtionl forms for your pplitionF hen uilding formsD keep in mind tht the (rst gol of form is to trnslte dt from n ojet @skA to n rwv form so tht the user n modify tht dtF he seond gol of form is to tke the dt sumitted y the user nd to reEpply it to the ojetF here9s still muh more to lern out the powerful world of formsD suh s how to hndle (le uplods with hotrine or how to rete form where dynmi numer of suEforms n e dded @eFgF todo list where you n keep dding more (elds vi tvsript efore sumittingAF ee the ookook for these topisF elsoD e sure to len on the (eld type referene doumenttionD whih inludes exmples of how to use eh (eld type nd its optionsF
5.11.12 Learn more from the Cookbook
row to hndle pile plods with hotrine pile pield eferene greting gustom pield ypes row to ustomize porm endering
SFIIF PPS
5.12 Security
eurity is twoEstep proess whose gol is to prevent user from essing resoure tht heGshe should not hve ess toF sn the (rst step of the proessD the seurity system identi(es who the user is y requiring the user to sumit some sort of identi(tionF his is lled uthentitionD nd it mens tht the system is trying to (nd out who you reF yne the system knows who you reD the next step is to determine if you should hve ess to given resoureF his prt of the proess is lled uthoriztionD nd it mens tht the system is heking to see if you hve privileges to perform ertin tionF
ine the est wy to lern is to see n exmpleD let9s dive right inF X ymfony9s seurity omponent is ville s stndlone r lirry for use inside ny r projetF
he seurity omponent n e on(gured vi your pplition on(gurtionF sn ftD most stndrd seurity setups re just mtter of using the right on(gurtionF he following on(gurtion tells ymfony to seure ny v mthing GdminGB nd to sk the user for redentils using si r uthentition @iFeF the oldEshool usernmeGpssword oxAX PPT SF
ewv
# app/cong/security.yml security: rewalls: secured_area: pattern: ^/ anonymous: ~ http_basic: realm: "Secured Demo Area" access_control: - { path: ^/admin, roles: ROLE_ADMIN } providers: in_memory: users: ryan: { password: ryanpass, roles: 'ROLE_USER' } admin: { password: kitten, roles: 'ROLE_ADMIN' } encoders: Symfony\Component\Security\Core\User\User: plaintext
wv
<!-- app/cong/security.xml --> <srv:container xmlns="http://symfony.com/schema/dic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:srv="http://symfony.com/schema/dic/services" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services <cong> <rewall name="secured_area" pattern="^/"> <anonymous /> <http-basic realm="Secured Demo Area" /> </rewall> <access-control> <rule path="^/admin" role="ROLE_ADMIN" /> </access-control> <provider name="in_memory"> <user name="ryan" password="ryanpass" roles="ROLE_USER" /> <user name="admin" password="kitten" roles="ROLE_ADMIN" /> </provider> <encoder class="Symfony\Component\Security\Core\User\User" algorithm="plaintext" /> </cong>
SFIPF eurity PPU
</srv:container>
r
// app/cong/security.php $container->loadFromExtension('security', array( 'rewalls' => array( 'secured_area' => array( 'pattern' => '^/', 'anonymous' => array(), 'http_basic' => array( 'realm' => 'Secured Demo Area', ), ), ), 'access_control' => array( array('path' => '^/admin', 'role' => 'ROLE_ADMIN'), ), 'providers' => array( 'in_memory' => array( 'users' => array( 'ryan' => array('password' => 'ryanpass', 'roles' => 'ROLE_USER'), 'admin' => array('password' => 'kitten', 'roles' => 'ROLE_ADMIN'), ), ), ), 'encoders' => array( 'Symfony\Component\Security\Core\User\User' => 'plaintext', ), ));
X e stndrd ymfony distriution seprtes the seurity on(gurtion into seprte (le @eFgF ppGon(gGseurityFymlAF sf you don9t hve seprte seurity (leD you n put the on(gurtion diretly into your min on(g (le @eFgF ppGon(gGon(gFymlAF he end result of this on(gurtion is fullyEfuntionl seurity system tht looks like the followingX
here re two users in the system @ryn nd dminAY sers uthentite themselves vi the si r uthentition promptY eny v mthing GdminGB is seuredD nd only the dmin user n ess itY ell vs not mthing GdminGB re essile y ll users @nd the user is never prompted to loginAF
PPV
SF
ymfony houmenttionD PFH vet9s look rie)y t how seurity works nd how eh prt of the on(gurtion omes into plyF
5.12.2 How Security Works: Authentication and Authorization
ymfony9s seurity system works y determining who user is @iFeF uthentitionA nd then heking to see if tht user should hve ess to spei( resoure or vF pirewlls @euthentitionA hen user mkes request to v tht9s proteted y (rewllD the seurity system is tivtedF he jo of the (rewll is to determine whether or not the user needs to e uthentitedD nd if he doesD to send response k to the user inititing the uthentition proessF e (rewll is tivted when the v of n inoming request mthes the on(gured (rewll9s regulr expression pttern on(g vlueF sn this exmpleD the pttern @GA will mth every inoming requestF he ft tht the (rewll is tivted does not menD howeverD tht the r uthentition usernme nd pssword ox is displyed for every vF por exmpleD ny user n ess Gfoo without eing prompted to uthentiteF
SFIPF eurity
PPW
ymfony houmenttionD PFH his works (rst euse the (rewll llows nonymous users vi the nonymous on(gurtion prmeterF sn other wordsD the (rewll doesn9t require the user to fully uthentite immeditelyF end euse no speil role is needed to ess Gfoo @under the essontrol setionAD the request n e ful(lled without ever sking the user to uthentiteF sf you remove the nonymous keyD the (rewll will lwys mke user fully uthentite immeditelyF eess gontrols @euthoriztionA sf user requests GdminGfooD howeverD the proess ehves di'erentlyF his is euse of the essontrol on(gurtion setion tht sys tht ny v mthing the regulr expression pttern Gdmin @iFeF Gdmin or nything mthing GdminGBA requires the yviehwsx roleF oles re the sis for most uthoriztionX user n ess GdminGfoo only if it hs the yviehwsx roleF
vike eforeD when the user originlly mkes the requestD the (rewll doesn9t sk for ny identi(tionF roweverD s soon s the ess ontrol lyer denies the user ess PQH SF
ymfony houmenttionD PFH @euse the nonymous user doesn9t hve the yviehwsx roleAD the (rewll jumps into tion nd initites the uthentition proessF he uthentition proess depends on the uthentition mehnism you9re usingF por exmpleD if you9re using the form login uthentition methodD the user will e redireted to the login pgeF sf you9re using r uthentitionD the user will e sent n r RHI response so tht the user sees the usernme nd pssword oxF he user now hs the opportunity to sumit its redentils k to the pplitionF sf the redentils re vlidD the originl request n e reEtriedF
sn this exmpleD the user ryn suessfully uthentites with the (rewllF fut sine ryn doesn9t hve the yviehwsx roleD he9s still denied ess to GdminGfooF ltimtelyD this mens tht the user will see some sort of messge inditing tht ess hs een deniedF X hen ymfony denies the user essD the user sees n error sreen nd reeives RHQ r sttus ode @poriddenAF ou n ustomize the ess denied error sreen y following the diretions in the irror ges ookook entry to ustomize the RHQ error pgeF
SFIPF eurity
PQI
ymfony houmenttionD PFH pinllyD if the dmin user requests GdminGfooD similr proess tkes pleD exept nowD fter eing uthentitedD the ess ontrol lyer will let the request pss throughX
he request )ow when user requests proteted resoure is strightforwrdD ut inredily )exileF es you9ll see lterD uthentition n e hndled in ny numer of wysD inluding vi form loginD FSHW erti(teD or y uthentiting the user vi witterF egrdless of the uthentition methodD the request )ow is lwys the smeX IF e user esses proteted resoureY PF he pplition redirets the user to the login formY QF he user sumits its redentils @eFgF usernmeGpsswordAY RF he (rewll uthentites the userY SF he uthentited user reEtries the originl requestF X he ext proess tully depends little it on whih uthentition mehnism you9re usingF por exmpleD when using form loginD the user sumits its redentils to one v tht proesses the form @eFgF GloginhekA nd then is redireted k to the originlly requested v @eFgF GdminGfooAF fut with r uthentitionD the user sumits its redentils diretly to the originl v @eFgF GdminGfooA nd then the pge is PQP SF
ymfony houmenttionD PFH returned to the user in tht sme request @iFeF no rediretAF hese types of idiosynrsies shouldn9t use you ny prolemsD ut they9re good to keep in mindF
X ou9ll lso lern lter how nything n e seured in ymfonyPD inluding spei( ontrollersD ojetsD or even r methodsF
o frD you9ve seen how to lnket your pplition eneth (rewll nd then protet ess to ertin res with rolesF fy using r euthentitionD you n e'ortlessly tp into the ntive usernmeGpssword ox o'ered y ll rowsersF roweverD ymfony supports mny uthentition mehnisms out of the oxF por detils on ll of themD see the eurity gon(gurtion efereneF sn this setionD you9ll enhne this proess y llowing the user to uthentite vi trditionl rwv login formF pirstD enle form login under your (rewllX
ewv
# app/cong/cong.yml security: rewalls: secured_area: pattern: ^/ anonymous: ~ form_login: login_path: /login check_path: /login_check
wv
<!-- app/cong/cong.xml --> <srv:container xmlns="http://symfony.com/schema/dic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:srv="http://symfony.com/schema/dic/services" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services <cong> <rewall name="secured_area" pattern="^/"> <anonymous /> <form-login login_path="/login" check_path="/login_check" />
SFIPF eurity PQQ
// app/cong/cong.php $container->loadFromExtension('security', array( 'rewalls' => array( 'secured_area' => array( 'pattern' => '^/', 'anonymous' => array(), 'form_login' => array( 'login_path' => '/login', 'check_path' => '/login_check', ), ), ), ));
X sf you don9t need to ustomize your loginpth or hekpth vlues @the vlues used here re the defult vluesAD you n shorten your on(gurtionX
ewv
form_login: ~
wv
<form-login />
r
ewv
PQR
SF
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="login" pattern="/login"> <default key="_controller">AcmeSecurityBundle:Security:login</default> </route> <route id="login_check" pattern="/login_check" /> </routes>
r
// app/cong/routing.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('login', new Route('/login', array( '_controller' => 'AcmeDemoBundle:Security:login', ))); $collection->add('login_check', new Route('/login_check', array())); return $collection;
X ou will not need to implement ontroller for the Gloginhek v s the (rewll will utomtilly th nd proess ny form sumitted to this vF st9s optionlD ut helpfulD to rete route so tht you n use it to generte the form sumission v in the login templte elowF xotie tht the nme of the login route isn9t importntF ht9s importnt is tht the v of the route @GloginA mthes the loginpth on(g vlueD s tht9s where the seurity system will rediret users tht need to loginF xextD rete the ontroller tht will disply the login formX
use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\Security\Core\SecurityContext; class SecurityController extends Controller { public function loginAction() { $request = $this->getRequest(); $session = $request->getSession(); // get the login error if there is one if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) { $error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR); } else { $error = $session->get(SecurityContext::AUTHENTICATION_ERROR); } return $this->render('AcmeSecurityBundle:Security:login.html.twig', array( // last username entered by the user 'last_username' => $session->get(SecurityContext::LAST_USERNAME), 'error' => $error, ));
hon9t let this ontroller onfuse youF es you9ll see in momentD when the user sumits the formD the seurity system utomtilly hndles the form sumission for youF sf the user hd sumitted n invlid usernme or psswordD this ontroller reds the form sumission error from the seurity system so tht it n e displyed k to the userF sn other wordsD your jo is to disply the login form nd ny login errors tht my hve ourredD ut the seurity system itself tkes re of heking the sumitted usernme nd pssword nd uthentiting the userF pinllyD rete the orresponding templteX
wig
{# src/Acme/SecurityBundle/Resources/views/Security/login.html.twig #} {% if error %} <div>{{ error.message }}</div> {% endif %} <form action="{{ path('login_check') }}" method="post"> <label for="username">Username:</label> <input type="text" id="username" name="_username" value="{{ last_username }}" /> <label for="password">Password:</label>
PQT SF
<input type="password" id="password" name="_password" /> {# #} If you want to control the URL the user is redirected to on success (more details below) <input type="hidden" name="_target_path" value="/account" />
<?php // src/Acme/SecurityBundle/Resources/views/Security/login.html.php ?> <?php if ($error): ?> <div><?php echo $error->getMessage() ?></div> <?php endif; ?> <form action="<?php echo $view['router']->generate('login_check') ?>" method="post"> <label for="username">Username:</label> <input type="text" id="username" name="_username" value="<?php echo $last_username ?>" /> <label for="password">Password:</label> <input type="password" id="password" name="_password" /> <!-If you want to control the URL the user is redirected to on success (more details below) <input type="hidden" name="_target_path" value="/account" /> --> <input type="submit" name="login" /> </form>
X he error vrile pssed into the templte is n instne of ymfonygomponenteuritygoreixeptioneuthentitionixeptionF st my ontin more informtion E or even sensitive informtion E out the uthentition filureD so use it wisely3 he form hs very few requirementsF pirstD y sumitting the form to Gloginhek @vi the loginhek routeAD the seurity system will interept the form sumission nd proess the form for you utomtillyF eondD the seurity system expets the sumitted (elds to e lled usernme nd pssword @these (eld nmes n e on(guredAF end tht9s it3 hen you sumit the formD the seurity system will utomtilly hek the user9s redentils nd either uthentite the user or send the user k to the login form where the error n e displyedF
SFIPF eurity
PQU
ymfony houmenttionD PFH vet9s review the whole proessX IF he user tries to ess resoure tht is protetedY PF he (rewll initites the uthentition proess y redireting the user to the login form @GloginAY QF he Glogin pge renders login form vi the route nd ontroller reted in this exmpleY RF he user sumits the login form to GloginhekY SF he seurity system interepts the requestD heks the user9s sumitted redentilsD uthentites the user if they re orretD nd sends the user k to the login form if they re notF fy defultD if the sumitted redentils re orretD the user will e redireted to the originl pge tht ws requested @eFgF GdminGfooAF sf the user originlly went stright to the login pgeD he9ll e redireted to the homepgeF his n e highly ustomizedD llowing you toD for exmpleD rediret the user to spei( vF por more detils on this nd how to ustomize the form login proess in generlD see row to ustomize your porm voginF
PQV
SF
ymfony houmenttionD PFH evoid gommon itflls hen setting up your login formD wth out for few ommon pitfllsF IF grete the orret routes pirstD e sure tht you9ve de(ned the Glogin nd Gloginhek routes orretly nd tht they orrespond to the loginpth nd hekpth on(g vluesF e mison(gurtion here n men tht you9re redireted to RHR pge insted of the login pgeD or tht sumitting the login form does nothing @you just see the login form over nd over ginAF PF fe sure the login pge isn9t seure elsoD e sure tht the login pge does not require ny roles to e viewedF por exmpleD the following on(gurtion E whih requires the yviehwsx role for ll vs @inluding the Glogin vAD will use rediret loopX ewv
<access-control> <rule path="^/login" role="IS_AUTHENTICATED_ANONYMOUSLY" /> <rule path="^/" role="ROLE_ADMIN" /> </access-control>
r
'access_control' => array( array('path' => '^/login', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'), array('path' => '^/', 'role' => 'ROLE_ADMIN'), ),
elsoD if your (rewll does not llow for nonymous usersD you9ll need to rete speil (rewll tht llows nonymous users for the login pgeX ewv SFIPF eurity rewalls:
PQW
he (rst step in seurity is lwys uthentitionX the proess of verifying who the user isF ith ymfonyD uthentition n e done in ny wy E vi form loginD si r euthentitionD or even vi peookF yne the user hs een uthentitedD uthoriztion eginsF euthoriztion provides stndrd nd powerful wy to deide if user n ess ny resoure @ vD model ojetD method llD FFFAF his works y ssigning spei( roles to eh userD nd then requiring di'erent roles for di'erent resouresF he proess of uthoriztion hs two di'erent sidesX IF he user hs spei( set of rolesY PF e resoure requires spei( role in order to e essedF sn this setionD you9ll fous on how to seure di'erent resoures @eFgF vsD method llsD etA with di'erent rolesF vterD you9ll lern more out how roles re reted nd ssigned to usersF euring pei( v tterns he most si wy to seure prt of your pplition is to seure n entire v ptternF ou9ve seen this lredy in the (rst exmple of this hpterD where nything mthing the regulr expression pttern Gdmin requires the yviehwsx roleF ou n de(ne s mny v ptterns s you need E eh is regulr expressionF
ewv
# app/cong/cong.yml security: # ... access_control: - { path: ^/admin/users, roles: ROLE_SUPER_ADMIN } - { path: ^/admin, roles: ROLE_ADMIN }
wv
<!-- app/cong/cong.xml --> <cong> <!-- ... --> <rule path="^/admin/users" role="ROLE_SUPER_ADMIN" /> <rule path="^/admin" role="ROLE_ADMIN" /> </cong>
r
PRH
SF
// app/cong/cong.php $container->loadFromExtension('security', array( // ... 'access_control' => array( array('path' => '^/admin/users', 'role' => 'ROLE_SUPER_ADMIN'), array('path' => '^/admin', 'role' => 'ROLE_ADMIN'), ), ));
X repending the pth with ensures tht only vs eginning with the pttern re mthedF por exmpleD pth of simply Gdmin @without the A would orretly mth GdminGfoo ut would lso mth vs like GfooGdminF por eh inoming requestD ymfonyP tries to (nd mthing ess ontrol rule @the (rst one winsAF sf the user isn9t uthentited yetD the uthentition proess is initited @iFeF the user is given hne to loginAF roweverD if the user is uthentited ut doesn9t hve the required roleD n ymfonygomponenteuritygoreixeptioneessheniedixeption exeption is thrownD whih you n hndle nd turn into nie ess denied error pge for the userF ee for more informtionF ine ymfony uses the (rst ess ontrol rule it mthesD v like GdminGusersGnew will mth the (rst rule nd require only the yviiehwsx roleF eny v like GdminGlog will mth the seond rule nd require yviehwsxF euring y s gertin situtions my rise when you my need to restrit ess to given route sed on sF his is prtiulrly relevnt in the se of idge ide snludes @isAD for exmpleD whih utilize route nmed internlF hen is is usedD the internl route is required y the gtewy he to enle di'erent hing options for susetions within given pgeF his route omes with the Ginternl pre(x y defult in the stndrd edition @ssuming you9ve unommented those lines from the routing (leAF rere is n exmple of how you might seure this route from outside essX
ewv
# app/cong/security.yml security: # ... access_control: - { path: ^/_internal, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
wv
SFIPF eurity
PRI
'access_control' => array( array('path' => '^/_internal', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', 'ip' => '127.0.0 ),
euring y ghnnel wuh like seuring sed on sD requiring the use of v is s simple s dding new essontrol entryX
ewv
# app/cong/security.yml security: # ... access_control: - { path: ^/cart/checkout, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: http
wv
'access_control' => array( array('path' => '^/cart/checkout', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', 'requires_ch ),
euring gontroller roteting your pplition sed on v ptterns is esyD ut my not e (neEgrined enough in ertin sesF hen neessryD you n esily fore uthoriztion from inside ontrollerX
ou n lso hoose to instll nd use the optionl tweurityixtrfundleD whih n seure your ontroller using nnottionsX
ymfony houmenttionD PFH por more informtionD see the ookook rtileX eess gontrol vists @egvsAF
5.12.5 Users
sn the previous setionsD you lerned how you n protet di'erent resoures y requiring set of roles for resoureF sn this setion we9ll explore the other side of uthoriztionX usersF here do sers ome fromc @ser rovidersA huring uthentitionD the user sumits set of redentils @usully usernme nd psswordAF he jo of the uthentition system is to mth those redentils ginst some pool of usersF o where does this list of users ome fromc sn ymfonyPD users n ome from nywhere E on(gurtion (leD dtse tleD we servieD or nything else you n drem upF enything tht provides one or more users to the uthentition system is known s user providerF ymfonyP omes stndrd with the two most ommon user providersX one tht lods users from on(gurtion (le nd one tht lods users from dtse tleF
ewv
# app/cong/cong.yml security: # ... providers: default_provider: users: ryan: { password: ryanpass, roles: 'ROLE_USER' } admin: { password: kitten, roles: 'ROLE_ADMIN' }
wv
<!-- app/cong/cong.xml --> <cong> <!-- ... --> <provider name="default_provider"> <user name="ryan" password="ryanpass" roles="ROLE_USER" /> <user name="admin" password="kitten" roles="ROLE_ADMIN" /> </provider> </cong>
PRR SF
// app/cong/cong.php $container->loadFromExtension('security', array( // ... 'providers' => array( 'default_provider' => array( 'users' => array( 'ryan' => array('password' => 'ryanpass', 'roles' => 'ROLE_USER'), 'admin' => array('password' => 'kitten', 'roles' => 'ROLE_ADMIN'), ), ), ), ));
his user provider is lled the inEmemory user providerD sine the users ren9t stored nywhere in dtseF he tul user ojet is provided y ymfony @ymfonygomponenteuritygoreserserAF X eny user provider n lod users diretly from on(gurtion y speifying the users on(gurtion prmeter nd listing the users eneth itF X sf your usernme is ompletely numeri @eFgF UUA or ontins dsh @eFgF userEnmeAD you should use tht lterntive syntx when speifying users in ewvX
users: - { name: 77, password: pass, roles: 'ROLE_USER' } - { name: user-name, password: pass, roles: 'ROLE_USER' }
por smller sitesD this method is quik nd esy to setupF por more omplex systemsD you9ll wnt to lod your users from the dtseF
/** * @ORM\Entity */ class User implements UserInterface { /** * @ORM\Column(type="string", length="255") */ protected $username; } // ...
es fr s the seurity system is onernedD the only requirement for your ustom user lss is tht it implements the ymfonygomponenteuritygoresersersnterfe interfeF his mens tht your onept of user n e nythingD s long s it implements this interfeF X he user ojet will e serilized nd sved in the session during requestsD therefore it is reommended tht you implement the erilizle interfe in your user ojetF his is espeilly importnt if your ser lss hs prent lss with privte propertiesF xextD on(gure n entity user providerD nd point it to your ser lssX
ewv
<!-- app/cong/security.xml --> <cong> <provider name="main"> <entity class="Acme\UserBundle\Entity\User" property="username" /> </provider> </cong>
r
));
),
'main' => array( 'entity' => array('class' => 'Acme\UserBundle\Entity\User', 'property' => 'username'), ),
ith the introdution of this new providerD the uthentition system will ttempt to lod ser ojet from the dtse y using the usernme (eld of tht lssF X his exmple is just ment to show you the si ide ehind the entity providerF por full working exmpleD see row to lod eurity sers from the htse @the entity roviderAF por more informtion on reting your own ustom provider @eFgF if you needed to lod users vi we servieAD see row to rete ustom ser roviderF inoding the ser9s ssword o frD for simpliityD ll the exmples hve stored the users9 psswords in plin text @whether those users re stored in on(gurtion (le or in dtse somewhereAF yf ourseD in rel pplitionD you9ll wnt to enode your users9 psswords for seurity resonsF his is esily omplished y mpping your ser lss to one of severl uiltEin enodersF por exmpleD to store your users in memoryD ut osure their psswords vi shID do the followingX
ewv
# app/cong/cong.yml security: # ... providers: in_memory: users: ryan: { password: bb87a29949f3a1ee0559f8a57357487151281386, roles: 'ROLE_USER' } admin: { password: 74913f5cd5f61ec0bcfdb775414c2fb3d161b620, roles: 'ROLE_ADMIN' } encoders: Symfony\Component\Security\Core\User\User: algorithm: sha1 iterations: 1 encode_as_base64: false
wv
<!-- ... --> <provider name="in_memory"> <user name="ryan" password="bb87a29949f3a1ee0559f8a57357487151281386" roles="ROLE_USER <user name="admin" password="74913f5cd5f61ec0bcfdb775414c2fb3d161b620" roles="ROLE_ADM </provider>
// app/cong/cong.php $container->loadFromExtension('security', array( // ... 'providers' => array( 'in_memory' => array( 'users' => array( 'ryan' => array('password' => 'bb87a29949f3a1ee0559f8a57357487151281386', 'roles' => 'ROL 'admin' => array('password' => '74913f5cd5f61ec0bcfdb775414c2fb3d161b620', 'roles' => 'RO ), ), ), 'encoders' => array( 'Symfony\Component\Security\Core\User\User' => array( 'algorithm' => 'sha1', 'iterations' => 1, 'encode_as_base64' => false, ), ), ));
fy setting the itertions to I nd the enodesseTR to flseD the pssword is simply run through the shI lgorithm one time nd without ny extr enodingF ou n now lulte the hshed pssword either progrmmtilly @eFgF hsh@9shI9D 9rynpss9AA or vi some online tool like funtionsEonlineFom sf you9re reting your users dynmilly @nd storing them in dtseAD you n use even tougher hshing lgorithms nd then rely on n tul pssword enoder ojet to help you enode psswordsF por exmpleD suppose your ser ojet is emeserfundleintityser @like in the ove exmpleAF pirstD on(gure the enoder for tht userX
ewv
Acme\UserBundle\Entity\User: sha512
wv
<!-- app/cong/cong.xml --> <cong> <!-- ... --> <encoder class="Acme\UserBundle\Entity\User" algorithm="sha512" /> </cong>
r
// app/cong/cong.php $container->loadFromExtension('security', array( // ... 'encoders' => array( 'Acme\UserBundle\Entity\User' => 'sha512', ),
));
sn this seD you9re using the stronger shSIP lgorithmF elsoD sine you9ve simply spei(ed the lgorithm @shSIPA s stringD the system will defult to hshing your pssword SHHH times in row nd then enoding it s seTRF sn other wordsD the pssword hs een gretly ofusted so tht the hshed pssword n9t e deoded @iFeF you n9t determine the pssword from the hshed psswordAF sf you hve some sort of registrtion form for usersD you9ll need to e le to determine the hshed pssword so tht you n set it on your userF xo mtter wht lgorithm you on(gure for your user ojetD the hshed pssword n lwys e determined in the following wy from ontrollerX
$factory = $this->get('security.encoder_factory'); $user = new Acme\UserBundle\Entity\User(); $encoder = $factory->getEncoder($user); $password = $encoder->encodePassword('ryanpass', $user->getSalt()); $user->setPassword($password);
etrieving the ser yjet efter uthentitionD the ser ojet of the urrent user n e essed vi the seurityFontext servieF prom inside ontrollerD this will look likeX
SFIPF eurity
PRW
sing wultiple ser roviders ih uthentition mehnism @eFgF r euthentitionD form loginD etA uses extly one user providerD nd will use the (rst delred user provider y defultF fut wht if you wnt to speify few users vi on(gurtion nd the rest of your users in the dtsec his is possile y reting new provider tht hins the two togetherX
ewv
# app/cong/security.yml security: providers: chain_provider: providers: [in_memory, user_db] in_memory: users: foo: { password: test } user_db: entity: { class: Acme\UserBundle\Entity\User, property: username }
wv
<!-- app/cong/cong.xml --> <cong> <provider name="chain_provider"> <provider>in_memory</provider> <provider>user_db</provider> </provider> <provider name="in_memory"> <user name="foo" password="test" /> </provider> <provider name="user_db"> <entity class="Acme\UserBundle\Entity\User" property="username" /> </provider> </cong>
PSH
SF
// app/cong/cong.php $container->loadFromExtension('security', array( 'providers' => array( 'chain_provider' => array( 'providers' => array('in_memory', 'user_db'), ), 'in_memory' => array( 'users' => array( 'foo' => array('password' => 'test'), ), ), 'user_db' => array( 'entity' => array('class' => 'Acme\UserBundle\Entity\User', 'property' => 'username'), ), ), ));
xowD ll uthentition mehnisms will use the hinproviderD sine it9s the (rst spei(edF he hinprovider willD in turnD try to lod the user from oth the inmemory nd userd providersF X sf you hve no resons to seprte your inmemory users from your userd usersD you n omplish this even more esily y omining the two soures into single providerX
ewv
# app/cong/security.yml security: providers: main_provider: users: foo: { password: test } entity: { class: Acme\UserBundle\Entity\User, property: username }
wv
<!-- app/cong/cong.xml --> <cong> <provider name=="main_provider"> <user name="foo" password="test" /> <entity class="Acme\UserBundle\Entity\User" property="username" /> </provider> </cong>
r
SFIPF eurity
PSI
// app/cong/cong.php $container->loadFromExtension('security', array( 'providers' => array( 'main_provider' => array( 'users' => array( 'foo' => array('password' => 'test'), ), 'entity' => array('class' => 'Acme\UserBundle\Entity\User', 'property' => 'username'), ), ), ));
ou n lso on(gure the (rewll or individul uthentition mehnisms to use spei( providerF eginD unless provider is spei(ed expliitlyD the (rst provider is lwys usedX
ewv
# app/cong/cong.yml security: rewalls: secured_area: # ... provider: user_db http_basic: realm: "Secured Demo Area" provider: in_memory form_login: ~
wv
<!-- app/cong/cong.xml --> <cong> <rewall name="secured_area" pattern="^/" provider="user_db"> <!-- ... --> <http-basic realm="Secured Demo Area" provider="in_memory" /> <form-login /> </rewall> </cong>
r
// app/cong/cong.php $container->loadFromExtension('security', array( 'rewalls' => array( 'secured_area' => array( // ... 'provider' => 'user_db',
PSP SF
));
),
),
'http_basic' => array( // ... 'provider' => 'in_memory', ), 'form_login' => array(),
sn this exmpleD if user tries to login vi r uthentitionD the uthentition system will use the inmemory user providerF fut if the user tries to login vi the form loginD the userd provider will e used @sine it9s the defult for the (rewll s wholeAF por more informtion out user provider nd (rewll on(gurtionD see the eurity gon(gurtion efereneF
5.12.6 Roles
he ide of role is key to the uthoriztion proessF ih user is ssigned set of roles nd then eh resoure requires one or more rolesF sf the user hs the required rolesD ess is grntedF ytherwise ess is deniedF oles re pretty simpleD nd re silly strings tht you n invent nd use s needed @though roles re ojets internllyAF por exmpleD if you need to strt limiting ess to the log dmin setion of your wesiteD you ould protet tht setion using yvifvyqehwsx roleF his role doesn9t need to e de(ned nywhere E you n just strt using itF X ell roles must egin with the yvi pre(x to e mnged y ymfonyPF sf you de(ne your own roles with dedited ole lss @more dvnedAD don9t use the yvi pre(xF
rierrhil oles snsted of ssoiting mny roles to usersD you n de(ne role inheritne rules y reting role hierrhyX
ewv
wv
<!-- app/cong/security.xml --> <cong> <role id="ROLE_ADMIN">ROLE_USER</role> <role id="ROLE_SUPER_ADMIN">ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH</role> </cong>
r
// app/cong/security.php $container->loadFromExtension('security', array( 'role_hierarchy' => array( 'ROLE_ADMIN' => 'ROLE_USER', 'ROLE_SUPER_ADMIN' => array('ROLE_ADMIN', 'ROLE_ALLOWED_TO_SWITCH'), ), ));
sn the ove on(gurtionD users with yviehwsx role will lso hve the yvii roleF he yviiehwsx role hs yviehwsxD yvievvyihysgr nd yvii @inherited from yviehwsxAF
5.12.7 Logging Out
sullyD you9ll lso wnt your users to e le to log outF portuntelyD the (rewll n hndle this utomtilly for you when you tivte the logout on(g prmeterX
ewv
# app/cong/cong.yml security: rewalls: secured_area: # ... logout: path: /logout target: / # ...
wv
<!-- app/cong/cong.xml --> <cong> <rewall name="secured_area" pattern="^/"> <!-- ... --> <logout path="/logout" target="/" /> </rewall>
PSR SF
// app/cong/cong.php $container->loadFromExtension('security', array( 'rewalls' => array( 'secured_area' => array( // ... 'logout' => array('path' => 'logout', 'target' => '/'), ), ), // ... ));
yne this is on(gured under your (rewllD sending user to Glogout @or whtever you on(gure the pth to eAD will unEuthentite the urrent userF he user will then e sent to the homepge @the vlue de(ned y the trget prmeterAF foth the pth nd trget on(g prmeters defult to wht9s spei(ed hereF sn other wordsD unless you need to ustomize themD you n omit them entirely nd shorten your on(gurtionX
ewv
logout: ~
wv
<logout />
r
ewv
SFIPF eurity
PSS
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="logout" pattern="/logout" /> </routes>
r
// app/cong/routing.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('logout', new Route('/logout', array())); return $collection;
yne the user hs een logged outD he will e redireted to whtever pth is de(ned y the trget prmeter ove @eFgF the homepgeAF por more informtion on on(guring the logoutD see the eurity gon(gurtion efereneF
5.12.8 Access Control in Templates
sf you wnt to hek if the urrent user hs role inside templteD use the uiltEin helper funtionX
wig
PST
SF
sf you wnt to hek if the urrent user hs role in your ontrollerD use the isqrnted method of the seurity ontextX
public function indexAction() { // show dierent content to admin users if($this->get('security.context')->isGranted('ADMIN')) { // Load admin content here } // load other regular content here }
X e (rewll must e tive or n exeption will e thrown when the isqrnted method is lledF ee the note ove out templtes for more detilsF
ometimesD it9s useful to e le to swith from one user to nother without hving to logout nd login gin @for instne when you re deugging or trying to understnd ug user sees tht you n9t reprodueAF his n e esily done y tivting the swithuser (rewll listenerX
ewv
<!-- app/cong/security.xml --> <cong> <rewall> <!-- ... --> <switch-user /> </rewall> </cong>
r
SFIPF eurity
PSU
// app/cong/security.php $container->loadFromExtension('security', array( 'rewalls' => array( 'main'=> array( // ... 'switch_user' => true ), ), ));
o swith to nother userD just dd query string with the swithuser prmeter nd the usernme s the vlue to the urrent vX httpXGGexmpleFomGsomewherecswithuserathoms o swith k to the originl userD use the speil exit usernmeX httpXGGexmpleFomGsomewherecswithuseraexit yf ourseD this feture needs to e mde ville to smll group of usersF fy defultD ess is restrited to users hving the yvievvyihysgr roleF he nme of this role n e modi(ed vi the role settingF por extr seurityD you n lso hnge the query prmeter nme vi the prmeter settingX
ewv
# app/cong/security.yml security: rewalls: main: // ... switch_user: { role: ROLE_ADMIN, parameter: _want_to_be_this_user }
wv
<!-- app/cong/security.xml --> <cong> <rewall> <!-- ... --> <switch-user role="ROLE_ADMIN" parameter="_want_to_be_this_user" /> </rewall> </cong>
r
));
),
),
fy defultD ymfonyP relies on ookie @the essionA to persist the seurity ontext of the userF fut if you use erti(tes or r uthentition for instneD persistene is not needed s redentils re ville for eh requestF sn tht seD nd if you don9t need to store nything else etween requestsD you n tivte the stteless uthentition @whih mens tht no ookie will e ever reted y ymfonyPAX
ewv
<!-- app/cong/security.xml --> <cong> <rewall stateless="true"> <http-basic /> </rewall> </cong>
r
// app/cong/security.php $container->loadFromExtension('security', array( 'rewalls' => array( 'main' => array('http_basic' => array(), 'stateless' => true), ), ));
X sf you use form loginD ymfonyP will rete ookie even if you set stteless to trueF
SFIPF eurity
PSW
eurity n e deep nd omplex issue to solve orretly in your pplitionF portuntelyD ymfony9s seurity omponent follows wellEproven seurity model sed round uthentition nd uthoriztionF euthentitionD whih lwys hppens (rstD is hndled y (rewll whose jo is to determine the identity of the user through severl di'erent methods @eFgF r uthentitionD login formD etAF sn the ookookD you9ll (nd exmples of other methods for hndling uthentitionD inluding how to implement rememer me ookie funtionlityF yne user is uthentitedD the uthoriztion lyer n determine whether or not the user should hve ess to spei( resoureF wost ommonlyD roles re pplied to vsD lsses or methods nd if the urrent user doesn9t hve tht roleD ess is deniedF he uthoriztion lyerD howeverD is muh deeperD nd follows system of voting so tht multiple prties n determine if the urrent user should hve ess to given resoureF pind out more out this nd other topis in the ookookF
5.12.13 Learn more from the Cookbook
poring rGr flklist users y s ddress with ustom voter eess gontrol vists @egvsA row to dd ememer we vogin puntionlity
he nture of rih we pplitions mens tht they9re dynmiF xo mtter how e0ient your pplitionD eh request will lwys ontin more overhed thn serving stti (leF end for most e pplitionsD tht9s (neF ymfonyP is lightning fstD nd unless you9re doing some serious hevyEliftingD eh request will ome k quikly without putting too muh stress on your serverF fut s your site growsD tht overhed n eome prolemF he proessing tht9s normlly performed on every request should e done only oneF his is extly wht hing ims to omplishF
5.13.1 Caching on the Shoulders of Giants
he most e'etive wy to improve performne of n pplition is to he the full output of pge nd then ypss the pplition entirely on eh susequent requestF yf ourseD PTH SF
ymfony houmenttionD PFH this isn9t lwys possile for highly dynmi wesitesD or is itc sn this hpterD we9ll show you how the ymfonyP he system works nd why we think this is the est possile pprohF he ymfonyP he system is di'erent euse it relies on the simpliity nd power of the r he s de(ned in the r spei(tionF snsted of reinventing hing methodologyD ymfonyP emres the stndrd tht de(nes si ommunition on the eF yne you understnd the fundmentl r vlidtion nd expirtion hing modelsD you9ll e redy to mster the ymfonyP he systemF por the purposes of lerning how to he with ymfonyPD we9ll over the sujet in four stepsX
tep IX e gtewy heD or reverse proxyD is n independent lyer tht sits in front of your pplitionF he reverse proxy hes responses s they9re returned from your pplition nd nswers requests with hed responses efore they hit your pplitionF ymfonyP provides its own reverse proxyD ut ny reverse proxy n e usedF tep PX r he heders re used to ommunite with the gtewy he nd ny other hes etween your pplition nd the lientF ymfonyP provides sensile defults nd powerful interfe for interting with the he hedersF tep QX r expirtion nd vlidtion re the two models used for determining whether hed ontent is fresh @n e reused from the heA or stle @should e regenerted y the pplitionAF tep RX idge ide snludes @isA llow r he to e used to he pge frgments @even nested frgmentsA independentlyF ith isD you n even he n entire pge for TH minutesD ut n emedded sider for only S minutesF
ine hing with r isn9t unique to ymfonyD mny rtiles lredy exist on the topiF sf you9re new to r hingD we highly reommend yn omyko9s rtile hings ghes hoF enother inEdepth resoure is wrk xottinghm9s ghe utorilF
5.13.2 Caching with a Gateway Cache
hen hing with rD the he is seprted from your pplition entirely nd sits etween your pplition nd the lient mking the requestF he jo of the he is to ept requests from the lient nd pss them k to your pplitionF he he will lso reeive responses k from your pplition nd forwrd them on to the lientF he he is the middleEmn of the requestEresponse ommunition etween the lient nd your pplitionF elong the wyD the he will store eh response tht is deemed hele @ee sntrodution to r ghingAF sf the sme resoure is requested ginD the he sends the hed response to the lientD ignoring your pplition entirelyF
SFIQF r ghe
PTI
ymfony houmenttionD PFH his type of he is known s r gtewy he nd mny exist suh s rnishD quid in reverse proxy modeD nd the ymfonyP reverse proxyF ypes of ghes fut gtewy he isn9t the only type of heF sn ftD the r he heders sent y your pplition re onsumed nd interpreted y up to three di'erent types of hesX
frowser hesX ivery rowser omes with its own lol he tht is minly useful for when you hit k or for imges nd other ssetsF he rowser he is privte he s hed resoures ren9t shred with nyone elseF roxy hesX e proxy is shred he s mny people n e ehind single oneF st9s usully instlled y lrge orportions nd ss to redue lteny nd network tr0F qtewy hesX vike proxyD it9s lso shred he ut on the server sideF snstlled y network dministrtorsD it mkes wesites more slleD relile nd performntF
X qtewy hes re sometimes referred to s reverse proxy hesD surrogte hesD or even r elertorsF
X he signi(ne of privte versus shred hes will eome more ovious s we tlk out hing responses ontining ontent tht is spei( to extly one user @eFgF ount informtionAF ih response from your pplition will likely go through one or oth of the (rst two he typesF hese hes re outside of your ontrol ut follow the r he diretions set in the responseF ymfonyP everse roxy ymfonyP omes with reverse proxy @lso lled gtewy heA written in rF inle it nd hele responses from your pplition will strt to e hed right wyF snstlling it is just s esyF ih new ymfonyP pplition omes with preEon(gured hing kernel @eppgheA tht wrps the defult one @eppuernelAF he hing uernel is the reverse proxyF o enle hingD modify the ode of front ontroller to use the hing kernelX
require_once __DIR__.'/../app/AppCache.php'; use Symfony\Component\HttpFoundation\Request; $kernel = new AppKernel('prod', false); $kernel->loadClassCache(); // wrap the default AppKernel with the AppCache one $kernel = new AppCache($kernel); $kernel->handle(Request::createFromGlobals())->send();
he hing kernel will immeditely t s reverse proxy E hing responses from your pplition nd returning them to the lientF X he he kernel hs speil getvog@A method tht returns string representtion of wht hppened in the he lyerF sn the development environmentD use it to deug nd vlidte your he strtegyX
error_log($kernel->getLog());
he eppghe ojet hs sensile defult on(gurtionD ut it n e (nely tuned vi set of options you n set y overriding the getyptions@A methodX
// app/AppCache.php class AppCache extends Cache { protected function getOptions() { return array( 'debug' => false, 'default_ttl' => 0, 'private_headers' => array('Authorization', 'Cookie'), 'allow_reload' => false, 'allow_revalidate' => false, 'stale_while_revalidate' => 2, 'stale_if_error' => 60, ); } }
X nless overridden in getyptions@AD the deug option will e set to utomtilly e the deug vlue of the wrpped eppuernelF rere is list of the min optionsX
ymfony houmenttionD PFH no expliit freshness informtion is provided in responseF ixpliit gheEgontrol or ixpires heders override this vlue @defultX HAY
privtehedersX et of request heders tht trigger privte gheEgontrol ehvior on responses tht don9t expliitly stte whether the response is puli or privte vi gheEgontrol diretiveF @defultX euthoriztion nd gookieAY llowrelodX pei(es whether the lient n fore he relod y inluding gheEgontrol noEhe diretive in the requestF et it to true for ompline with pg PTIT @defultX flseAY llowrevlidteX pei(es whether the lient n fore he revlidte y inluding gheEgontrol mxEgeaH diretive in the requestF et it to true for ompline with pg PTIT @defultX flseAY stlewhilerevlidteX pei(es the defult numer of seonds @the grnulrity is the seond s the esponse v preision is seondA during whih the he n immeditely return stle response while it revlidtes it in the kground @defultX PAY this setting is overridden y the stleEwhileErevlidte r gheE gontrol extension @see pg SVTIAY stleiferrorX pei(es the defult numer of seonds @the grnulrity is the seondA during whih the he n serve stle response when n error is enountered @defultX THAF his setting is overridden y the stleEifEerror r gheEgontrol extension @see pg SVTIAF
sf deug is trueD ymfonyP utomtilly dds EymfonyEghe heder to the response ontining useful informtion out he hits nd missesF ghnging from one everse roxy to enother he ymfonyP reverse proxy is gret tool to use when developing your wesite or when you deploy your wesite to shred host where you nnot instll nything eyond r odeF fut eing written in rD it nnot e s fst s proxy written in gF ht9s why we highly reommend you to use rnish or quid on your prodution servers if possileF he good news is tht the swith from one proxy server to nother is esy nd trnsprent s no ode modi(tion is needed in your pplitionF trt esy with the ymfonyP reverse proxy nd upgrde lter to rnish when your tr0 inresesF por more informtion on using rnish with ymfonyPD see the row to use rnish ookook hpterF
X he performne of the ymfonyP reverse proxy is independent of the omplexity of the pplitionF ht9s euse the pplition kernel is only ooted when the request needs to e forwrded to itF
PTR
SF
o tke dvntge of the ville he lyersD your pplition must e le to ommunite whih responses re hele nd the rules tht govern whenGhow tht he should eome stleF his is done y setting r he heders on the responseF X ueep in mind tht r is nothing more thn the lnguge @ simple text lngugeA tht we lients @eFgF rowsersA nd we servers use to ommunite with eh otherF hen we tlk out r hingD we9re tlking out the prt of tht lnguge tht llows lients nd servers to exhnge informtion relted to hingF r spei(es four response he heders tht we9re onerned withX
he gheEgontrol reder he gheEgontrol heder is unique in tht it ontins not oneD ut vrious piees of informtion out the heility of responseF ih piee of informtion is seprted y ommX gheEgontrolX privteD mxEgeaHD mustErevlidte gheEgontrolX mxEgeaQTHHD mustErevlidte ymfony provides n strtion round the gheEgontrol heder to mke its retion more mngeleX
$response = new Response(); // mark the response as either public or private $response->setPublic(); $response->setPrivate(); // set the private or shared max age
SFIQF r ghe PTS
puliX sndites tht the response my e hed y oth privte nd shred hesY privteX sndites tht ll or prt of the response messge is intended for single user nd must not e hed y shred heF
ymfony onservtively defults eh response to e privteF o tke dvntge of shred hes @like the ymfonyP reverse proxyAD the response will need to e expliitly set s puliF fe wethods r hing only works for sfe r methods @like qi nd riehAF feing sfe mens tht you never hnge the pplition9s stte on the server when serving the request @you n of ourse log informtionD he dtD etAF his hs two very resonle onsequenesX
ou should never hnge the stte of your pplition when responding to qi or rieh requestF iven if you don9t use gtewy heD the presene of proxy hes men tht ny qi or rieh request my or my not tully hit your serverF hon9t expet D y or hivii methods to heF hese methods re ment to e used when mutting the stte of your pplition @eFgF deleting log postAF ghing them would prevent ertin requests from hitting nd mutting your pplitionF
ghing ules nd hefults r IFI llows hing nything y defult unless there is n expliit gheEgontrol hederF sn prtieD most hes do nothing when requests hve ookieD n uthoriztion hederD use nonEsfe method @iFeF D yD hiviiAD or when responses hve rediret sttus odeF
PTT
SF
ymfony houmenttionD PFH ymfonyP utomtilly sets sensile nd onservtive gheEgontrol heder when none is set y the developer y following these rulesX
sf no he heder is de(ned @gheEgontrolD ixpiresD ig or vstEwodi(edAD gheE gontrol is set to noEheD mening tht the response will not e hedY sf gheEgontrol is empty @ut one of the other he heders is presentAD its vlue is set to privteD mustErevlidteY fut if t lest one gheEgontrol diretive is setD nd no puli9 or privte diretives hve een expliitly ddedD ymfonyP dds the privte diretive utomtilly @exept when sEmxge is setAF
5.13.4 HTTP Expiration and Validation
ith the expirtion modelD you simply speify how long response should e onsidered fresh y inluding gheEgontrol ndGor n ixpires hederF ghes tht understnd expirtion will not mke the sme request until the hed version rehes its expirtion time nd eomes stleF hen pges re relly dynmi @iFeF their representtion hnges oftenAD the vlidtion model model is often neessryF ith this modelD the he stores the responseD ut sks the server on eh request whether or not the hed response is still vlidF he pplition uses unique response identi(er @the itg hederA ndGor timestmp @the vstEwodi(ed hederA to hek if the pge hs hnged sine eing hedF
he gol of oth models is to never generte the sme response twie y relying on he to store nd return fresh responsesF eding the r pei(tion he r spei(tion de(nes simple ut powerful lnguge in whih lients nd servers n ommuniteF es we developerD the requestEresponse model of the spei(tion domintes our workF nfortuntelyD the tul spei(tion doument E pg PTIT E n e di0ult to redF here is n onEgoing e'ort @r fisA to rewrite the pg PTITF st does not desrie new version of rD ut mostly lri(es the originl r spei(tionF he orgniztion is lso improved s the spei(tion is split into seven prtsY everything relted to r hing n e found in two dedited prts @R E gonditionl equests nd T E ghingX frowser nd intermediry hesAF es we developerD we strongly urge you to red the spei(tionF sts lrity nd power E even more thn ten yers fter its retion E is invluleF hon9t e putEo' y the pperne of the spe E its ontents re muh more eutiful thn its overF
SFIQF r ghe
PTU
ymfony houmenttionD PFH ixpirtion he expirtion model is the more e0ient nd strightforwrd of the two hing models nd should e used whenever possileF hen response is hed with n expirtionD the he will store the response nd return it diretly without hitting the pplition until it expiresF he expirtion model n e omplished using one of twoD nerly identilD r hedersX ixpires or gheEgontrolF ixpirtion with the ixpires reder eording to the r spei(tionD the ixpires heder (eld gives the dteGtime fter whih the response is onsidered stleF he ixpires heder n e set with the setixpires@A esponse methodF st tkes hteime instne s n rgumentX
// Sets the number of seconds after which the response // should no longer be considered fresh $response->setMaxAge(600);
PTV
SF
SFIQF r ghe
PTW
he esponseXXisxotwodi(ed@A method ompres the ig sent with the equest with the one set on the esponseF sf the two mthD the method utomtilly sets the esponse sttus ode to QHRF his lgorithm is simple enough nd very generiD ut you need to rete the whole esponse efore eing le to ompute the igD whih is suEoptimlF sn other wordsD it sves on ndwidthD ut not g ylesF sn the yptimizing your gode with lidtion setionD we9ll show how vlidtion n e used more intelligently to determine the vlidity of he without doing so muh workF X ymfonyP lso supports wek igs y pssing true s the seond rgument to the XmethodXymfonygomponentrttppoundtionesponseXXsetig methodF
lidtion with the vstEwodi(ed reder he vstEwodi(ed heder is the seond form of vlidtionF eording to the r spei(tionD he vstEwodi(ed heder (eld indites the dte nd time t whih the origin server elieves the representtion ws lst modi(edF sn other wordsD the pplition deides whether or not the hed ontent hs een updted sed on whether or not it9s een updted sine the response ws hedF por instneD you n use the ltest updte dte for ll the ojets needed to ompute the resoure representtion s the vlue for the vstEwodi(ed heder vlueX
public function showAction($articleSlug) { // ... $articleDate = new \DateTime($article->getUpdatedAt()); $authorDate = new \DateTime($author->getUpdatedAt()); $date = $authorDate > $articleDate ? $authorDate : $articleDate; $response->setLastModied($date); $response->isNotModied($this->getRequest());
PUH SF
return $response;
he esponseXXisxotwodi(ed@A method ompres the sfEwodi(edEine heder sent y the request with the vstEwodi(ed heder set on the responseF sf they re equivlentD the esponse will e set to QHR sttus odeF X he sfEwodi(edEine request heder equls the vstEwodi(ed heder of the lst response sent to the lient for the prtiulr resoureF his is how the lient nd server ommunite with eh other nd deide whether or not the resoure hs een updted sine it ws hedF
yptimizing your gode with lidtion he min gol of ny hing strtegy is to lighten the lod on the pplitionF ut nother wyD the less you do in your pplition to return QHR responseD the etterF he esponseXXisxotwodi(ed@A method does extly tht y exposing simple nd e0ient ptternX
public function showAction($articleSlug) { // Get the minimum information to compute // the ETag or the Last-Modied value // (based on the Request, data is retrieved from // a database or a key-value store for instance) $article = // ... // create a Response with a ETag and/or a Last-Modied header $response = new Response(); $response->setETag($article->computeETag()); $response->setLastModied($article->getPublishedAt()); // Check that the Response is not modied for the given Request if ($response->isNotModied($this->getRequest())) { // return the 304 Response immediately return $response; } else { // do more work here - like retrieving more data $comments = // ... // or render a template with the $response you've already started return $this->render( 'MyBundle:MyController:article.html.twig', array('article' => $article, 'comments' => $comments),
SFIQF r ghe PUI
);
$response
hen the esponse is not modi(edD the isxotwodi(ed@A utomtilly sets the response sttus ode to QHRD removes the ontentD nd removes some heders tht must not e present for QHR responses @see XmethodXymfonygomponentrttppoundtionesponseXXsetxotwodi(edAF rying the esponse o frD we9ve ssumed tht eh s hs extly one representtion of the trget resoureF fy defultD r hing is done y using the s of the resoure s the he keyF sf two people request the sme s of hele resoureD the seond person will reeive the hed versionF ometimes this isn9t enough nd di'erent versions of the sme s need to e hed sed on one or more request heder vluesF por instneD if you ompress pges when the lient supports itD ny given s hs two representtionsX one when the lient supports ompressionD nd one when it does notF his determintion is done y the vlue of the eeptEinoding request hederF sn this seD we need the he to store oth ompressed nd unompressed version of the response for the prtiulr s nd return them sed on the request9s eeptEinoding vlueF his is done y using the ry response hederD whih is ommEseprted list of di'erent heders whose vlues trigger di'erent representtion of the requested resoureX
// set one vary header $response->setVary('Accept-Encoding'); // set multiple vary headers $response->setVary(array('Accept-Encoding', 'User-Agent'));
he setry@A method tkes heder nme or n rry of heder nmes for whih the response vriesF
PUP
SF
ymfony houmenttionD PFH ixpirtion nd lidtion ou n of ourse use oth vlidtion nd expirtion within the sme esponseF es expirtion wins over vlidtionD you n esily ene(t from the est of oth worldsF sn other wordsD y using oth expirtion nd vlidtionD you n instrut the he to serve the hed ontentD while heking k t some intervl @the expirtionA to verify tht the ontent is still vlidF wore esponse wethods he esponse lss provides mny more methods relted to the heF rere re the most useful onesX
// Marks the Response stale $response->expire(); // Force the response to return a proper 304 response with no content $response->setNotModied();
edditionllyD most heErelted r heders n e set vi the single setghe@A methodX
// Set cache settings in one call $response->setCache(array( 'etag' => $etag, 'last_modied' => $date, 'max_age' => 10, 's_maxage' => 10, 'public' => true, // 'private' => true, ));
qtewy hes re gret wy to mke your wesite perform etterF fut they hve one limittionX they n only he whole pgesF sf you n9t he whole pges or if prts of pge hs more dynmi prtsD you re out of lukF portuntelyD ymfonyP provides solution for these sesD sed on tehnology lled isD or idge ide snludesF ekm % wrote this spei(tion lmost IH yers goD nd it llows spei( prts of pge to hve di'erent hing strtegy thn the min pgeF he is spei(tion desries tgs you n emed in your pges to ommunite with the gtewy heF ynly one tg is implemented in ymfonyPD inludeD s this is the only useful one outside of ekm ontextX %
<html> <body>
SFIQF r ghe PUQ
Some content <!-- Embed the content of another page here --> <esi:include src="http://..." /> More content </body> </html>
X xotie from the exmple tht eh is tg hs fullyEquli(ed vF en is tg represents pge frgment tht n e fethed vi the given vF hen request is hndledD the gtewy he fethes the entire pge from its he or requests it from the kend pplitionF sf the response ontins one or more is tgsD these re proessed in the sme wyF sn other wordsD the gtewy he either retrieves the inluded pge frgment from its he or requests the pge frgment from the kend pplition ginF hen ll the is tgs hve een resolvedD the gtewy he merges eh into the min pge nd sends the (nl ontent to the lientF ell of this hppens trnsprently t the gtewy he level @iFeF outside of your pplitionAF es you9ll seeD if you hoose to tke dvntge of is tgsD ymfonyP mkes the proess of inluding them lmost e'ortlessF sing is in ymfonyP pirstD to use isD e sure to enle it in your pplition on(gurtionX
ewv
<!-- app/cong/cong.xml --> <framework:cong ...> <!-- ... --> <framework:esi enabled="true" /> </framework:cong>
r
PUR
SF
// app/cong/cong.php $container->loadFromExtension('framework', array( // ... 'esi' => array('enabled' => true), ));
xowD suppose we hve pge tht is reltively sttiD exept for news tiker t the ottom of the ontentF ith isD we n he the news tiker independent of the rest of the pgeF
sn this exmpleD we9ve given the fullEpge he lifetime of ten minutesF xextD let9s inlude the news tiker in the templte y emedding n tionF his is done vi the render helper @ee templtingEemeddingEontroller for more detilsAF es the emedded ontent omes from nother pge @or ontroller for tht mtterAD ymfonyP uses the stndrd render helper to on(gure is tgsX
wig
SFIQF r ghe
PUS
ymfony houmenttionD PFH he emedded tion n now speify its own hing rulesD entirely independent of the mster pgeF
ith isD the full pge he will e vlid for THH seondsD ut the news omponent he will only lst for TH seondsF e requirement of isD howeverD is tht the emedded tion e essile vi v so the gtewy he n feth it independently of the rest of the pgeF yf ourseD n tion n9t e essed vi v unless it hs route tht points to itF ymfonyP tkes re of this vi generi route nd ontrollerF por the is inlude tg to work properlyD you must de(ne the internl routeX
ewv
PUT
SF
ymfony houmenttionD PFH X ine this route llows ll tions to e essed vi vD you might wnt to protet it y using the ymfonyP (rewll feture @y llowing ess to your reverse proxy9s s rngeAF ee the euring y s setion of the eurity ghpter for more informtion on how to do thisF yne gret dvntge of this hing strtegy is tht you n mke your pplition s dynmi s needed nd t the sme timeD hit the pplition s little s possileF X yne you strt using isD rememer to lwys use the sEmxge diretive insted of mxEgeF es the rowser only ever reeives the ggregted resoureD it is not wre of the suEomponentsD nd so it will oey the mxEge diretive nd he the entire pgeF end you don9t wnt thtF he render helper supports two other useful optionsX
ltX used s the lt ttriute on the is tgD whih llows you to speify n lterntive v to e used if the sr nnot e foundY ignoreerrorsX if set to trueD n onerror ttriute will e dded to the is with vlue of ontinue inditing thtD in the event of filureD the gtewy he will simply remove the is tg silentlyF
5.13.6 Cache Invalidation
here re only two hrd things in gomputer ieneX he invlidtion nd nming thingsF !hil urlton ou should never need to invlidte hed dt euse invlidtion is lredy tken into ount ntively in the r he modelsF sf you use vlidtionD you never need to invlidte nything y de(nitionY nd if you use expirtion nd need to invlidte resoureD it mens tht you set the expires dte too fr wy in the futureF X st9s lso euse there is no invlidtion mehnism tht you n use ny reverse proxy without hnging nything in your pplition odeF etullyD ll reverse proxies provide wys to purge hed dtD ut you should void them s muh s possileF he most stndrd wy is to purge the he for given v y requesting it with the speil qi r methodF rere is how you n on(gure the ymfonyP reverse proxy to support the qi r methodX
protected function invalidate(Request $request) { if ('PURGE' !== $request->getMethod()) { return parent::invalidate($request); } $response = new Response(); if (!$this->store->purge($request->getUri())) { $response->setStatusCode(404, 'Not purged'); } else { $response->setStatusCode(200, 'Purged'); } } return $response;
X ou must protet the qi r method somehow to void rndom people purging your hed dtF
5.13.7 Summary
ymfonyP ws designed to follow the proven rules of the rodX rF ghing is no exeptionF wstering the ymfonyP he system mens eoming fmilir with the r he models nd using them e'etivelyF his mens thtD insted of relying only on ymfonyP doumenttion nd ode exmplesD you hve ess to world of knowledge relted to r hing nd gtewy hes suh s rnishF
5.13.8 Learn more from the Cookbook
5.14 Translations
he term interntionliztion refers to the proess of strting strings nd other loleE spei( piees out of your pplition nd into lyer where they n e trnslted nd onverted sed on the user9s lole @iFeF lnguge nd ountryAF por textD this mens wrpping eh with funtion ple of trnslting the text @or messgeA into the lnguge of the userX
PUV
SF
// text will *always* print out in English echo 'Hello World'; // text can be translated into the end-user's language or default to English echo $translator->trans('Hello World');
X he term lole refers roughly to the user9s lnguge nd ountryF st n e ny string tht your pplition then uses to mnge trnsltions nd other formt di'erenes @eFgF urreny formtAF e reommended the syTQWEI lnguge odeD n undersore @AD then the syQITT ountry ode @eFgF frp for prenhGprneAF sn this hpterD we9ll lern how to prepre n pplition to support multiple loles nd then how to rete trnsltions for multiple lolesF yverllD the proess hs severl ommon stepsX IF inle nd on(gure ymfony9s rnsltion omponentY PF estrt strings @iFeF messgesA y wrpping them in lls to the rnsltorY QF grete trnsltion resoures for eh supported lole tht trnslte eh messge in the pplitionY RF hetermineD set nd mnge the user9s lole in the sessionF
5.14.1 Conguration
rnsltions re hndled y rnsltor servie tht uses the user9s lole to lookup nd return trnslted messgesF fefore using itD enle the rnsltor in your on(gurtionX
ewv
));
he fllk option de(nes the fllk lole when trnsltion does not exist in the user9s loleF X hen trnsltion does not exist for loleD the trnsltor (rst tries to (nd the trnsltion for the lnguge @fr if the lole is frp for instneAF sf this lso filsD it looks for trnsltion using the fllk loleF he lole used in trnsltions is the one stored in the user sessionF
5.14.2 Basic Translation
rnsltion of text is done through the trnsltor servie @ymfonygomponentrnsltionrnsltorAF o trnslte lok of text @lled messgeAD use the XmethodXymfonygomponentrnsltionrnsltorXXtrns methodF upposeD for exmpleD tht we9re trnslting simple messge from inside ontrollerX
hen this ode is exeutedD ymfonyP will ttempt to trnslte the messge ymfonyP is gret sed on the lole of the userF por this to workD we need to tell ymfonyP how to trnslte the messge vi trnsltion resoureD whih is olletion of messge trnsltions for given loleF his ditionry of trnsltions n e reted in severl di'erent formtsD vspp eing the reommended formtX
wv
<!-- messages.fr.xli --> <?xml version="1.0"?> <xli version="1.2" xmlns="urn:oasis:names:tc:xli:document:1.2"> <le source-language="en" datatype="plaintext" original="le.ext"> <body> <trans-unit id="1"> <source>Symfony2 is great</source> <target>J'aime Symfony2</target> </trans-unit> </body>
PVH SF
</le> </xli>
r
he lole of the urrent userD whih is stored in the sessionD is determinedY e tlog of trnslted messges is loded from trnsltion resoures de(ned for the lole @eFgF frpAF wessges from the fllk lole re lso loded nd dded to the tlog if they don9t lredy existF he end result is lrge ditionry of trnsltionsF ee wessge gtlogues for more detilsY sf the messge is loted in the tlogD the trnsltion is returnedF sf notD the trnsltor returns the originl messgeF
hen using the trns@A methodD ymfonyP looks for the ext string inside the pproprite messge tlog nd returns it @if it existsAF wessge leholders ometimesD messge ontining vrile needs to e trnsltedX
SFIRF rnsltions
PVI
ymfony houmenttionD PFH roweverD reting trnsltion for this string is impossile sine the trnsltor will try to look up the ext messgeD inluding the vrile portions @eFgF rello yn or rello pienAF snsted of writing trnsltion for every possile itertion of the 6nme vrileD we n reple the vrile with pleholderX
public function indexAction($name) { $t = $this->get('translator')->trans('Hello %name%', array('%name%' => $name)); } new Response($t);
ymfonyP will now look for trnsltion of the rw messge @rello 7nme7A nd then reple the pleholders with their vluesF greting trnsltion is done just s eforeX
wv
<!-- messages.fr.xli --> <?xml version="1.0"?> <xli version="1.2" xmlns="urn:oasis:names:tc:xli:document:1.2"> <le source-language="en" datatype="plaintext" original="le.ext"> <body> <trans-unit id="1"> <source>Hello %name%</source> <target>Bonjour %name%</target> </trans-unit> </body> </le> </xli>
r
ymfony houmenttionD PFH IF estrt the messge tht needs to e trnslted y proessing it through the rnsltorF PF grete trnsltion for the messge in eh lole tht you hoose to supportF he seond step is done y reting messge tlogues tht de(ne the trnsltions for ny numer of di'erent lolesF
5.14.3 Message Catalogues
hen messge is trnsltedD ymfonyP ompiles messge tlogue for the user9s lole nd looks in it for trnsltion of the messgeF e messge tlogue is like ditionry of trnsltions for spei( loleF por exmpleD the tlogue for the frp lole might ontin the following trnsltionX ymfonyP is qret ab t9ime ymfonyP st9s the responsiility of the developer @or trnsltorA of n interntionlized pplition to rete these trnsltionsF rnsltions re stored on the (lesystem nd disovered y ymfonyD thnks to some onventionsF X ih time you rete new trnsltion resoure @or instll undle tht inludes trnsltion resoureAD e sure to ler your he so tht ymfony n disover the new trnsltion resoureX
rnsltion votions nd xming gonventions ymfonyP looks for messge (les @iFeF trnsltionsA in two lotionsX
por messges found in undleD the orresponding messge (les should live in the esouresGtrnsltionsG diretory of the undleY o override ny undle trnsltionsD ppGesouresGtrnsltions diretoryF
ple messge (les in the
he (lenme of the trnsltions is lso importnt s ymfonyP uses onvention to determine detils out the trnsltionsF ih messge (le must e nmed ording to the following ptternX dominFloleFloderX
dominX en optionl wy to orgnize messges into groups @eFgF dminD nvigtion or the defult messgesA E see sing wessge hominsY loleX he lole tht the trnsltions re for @eFgF enqfD enD etAY loderX row ymfonyP should lod nd prse the (le @eFgF xli'D php or ymlAF
SFIRF rnsltions PVQ
ymfony houmenttionD PFH he loder n e the nme of ny registered loderF fy defultD ymfony provides the following lodersX
greting rnsltions ih (le onsists of series of idEtrnsltion pirs for the given domin nd loleF he id is the identi(er for the individul trnsltionD nd n e the messge in the min lole @eFgF ymfony is gretA of your pplition or unique identi(er @eFgF symfonyPFgret E see the sider elowAX
wv
<!-- src/Acme/DemoBundle/Resources/translations/messages.fr.xli --> <?xml version="1.0"?> <xli version="1.2" xmlns="urn:oasis:names:tc:xli:document:1.2"> <le source-language="en" datatype="plaintext" original="le.ext"> <body> <trans-unit id="1"> <source>Symfony2 is great</source> <target>J'aime Symfony2</target> </trans-unit> <trans-unit id="2"> <source>symfony2.great</source> <target>J'aime Symfony2</target> </trans-unit> </body> </le> </xli>
r
PVR
SF
);
'symfony2.great'
ewv
SFIRF rnsltions
PVS
ymfony houmenttionD PFH sing el or ueyword wessges his exmple illustrtes the two di'erent philosophies when reting messges to e trnsltedX
symfony2: is: great: Symfony2 is great amazing: Symfony2 is amazing has: bundles: Symfony2 has bundles user: login: Login
r
return array( 'symfony2' => array( 'is' => array( 'great' => 'Symfony2 is great', 'amazing' => 'Symfony2 is amazing', ), 'has' => array( 'bundles' => 'Symfony2 has bundles', ), ), 'user' => array( 'login' => 'Login', ), );
he multiple levels re )ttened into single idGtrnsltion pirs y dding dot @FA PVT SF etween every levelD therefore the ove exmples re equivlent to the followingX ewv
es we9ve seenD messge (les re orgnized into the di'erent loles tht they trnslteF he messge (les n lso e orgnized further into dominsF hen reting messge (lesD the domin is the (rst portion of the (lenmeF he defult domin is messgesF por exmpleD suppose thtD for orgniztionD trnsltions were split into three di'erent dominsX messgesD dmin nd nvigtionF he prenh trnsltion would hve the following messge (lesX
he lole of the urrent user is stored in the session nd is essile vi the session servieX
ewv
ewv
contact: pattern: /{_locale}/contact defaults: { _controller: AcmeDemoBundle:Contact:index, _locale: en } requirements: _locale: en|fr|de
wv
<route id="contact" pattern="/{_locale}/contact"> <default key="_controller">AcmeDemoBundle:Contact:index</default> <default key="_locale">en</default> <requirement key="_locale">en|fr|de</requirement> </route>
r
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('contact', new Route('/{_locale}/contact', array( '_controller' => 'AcmeDemoBundle:Contact:index', '_locale' => 'en',
PVV SF
=> 'en|fr|de'
return $collection;
hen using the speil lole prmeter in routeD the mthed lole will utomtilly e set on the user9s sessionF sn other wordsD if user visits the s GfrGonttD the lole fr will utomtilly e set s the lole for the user9s sessionF ou n now use the user9s lole to rete routes to other trnslted pges in your pplitionF
5.14.6 Pluralization
wessge plurliztion is tough topi s the rules n e quite omplexF por instneD here is the mthemti representtion of the ussin plurliztion rulesX
(($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) &&
es you n seeD in ussinD you n hve three di'erent plurl formsD eh given n index of HD I or PF por eh formD the plurl is di'erentD nd so the trnsltion is lso di'erentF hen trnsltion hs di'erent forms due to plurliztionD you n provide ll the forms s string seprted y pipe @|AX
$t = $this->get('translator')->transChoice( 'There is one apple|There are %count% apples', 10, array('%count%' => 10) );
he seond rgument @IH in this exmpleAD is the numer of ojets eing desried nd is used to determine whih trnsltion to use nd lso to populte the 7ount7 pleholderF fsed on the given numerD the trnsltor hooses the right plurl formF sn inglishD most words hve singulr form when there is extly one ojet nd plurl form for ll other numers @HD PD QFFFAF oD if ount is ID the trnsltor will use the (rst string @here is one ppleA s the trnsltionF ytherwise it will use here re 7ount7 pplesF rere is the prenh trnsltionX
SFIRF rnsltions
PVW
'one: There is one apple|some: There are %count% apples' 'none_or_one: Il y a %count% pomme|some: Il y a %count% pommes'
he tgs re relly only hints for trnsltors nd don9t 'et the logi used to determine whih plurl form to useF he tgs n e ny desriptive string tht ends with olon @XAF he tgs lso do not need to e the sme in the originl messge s in the trnslted oneF ixpliit sntervl lurliztion he esiest wy to plurlize messge is to let ymfonyP use internl logi to hoose whih string to use sed on given numerF ometimesD you9ll need more ontrol or wnt di'erent trnsltion for spei( ses @for HD or when the ount is negtiveD for exmpleAF por suh sesD you n use expliit mth intervlsX
'{0} There is no apples|{1} There is one apple|]1,19] There are %count% apples|[20,Inf] There are many apples'
he intervls follow the sy QIEII nottionF he ove string spei(es four di'erent intervlsX extly HD extly ID PEIWD nd PH nd higherF ou n lso mix expliit mth rules nd stndrd rulesF sn this seD if the ount is not mthed y spei( intervlD the stndrd rules tke e'et fter removing the expliit rulesX
'{0} There is no apples|[20,Inf] There are many apples|There is one apple|a_few: There are %count% apples'
por exmpleD for I ppleD the stndrd rule here is one pple will e usedF por PEIW pplesD the seond stndrd rule here re 7ount7 pples will e seletedF en ymfonygomponentrnsltionsntervl n represent (nite set of numersX
{1,2,3,4}
yr numers etween two other numersX
ymfony houmenttionD PFH he left delimiter n e @inlusiveA or @exlusiveAF he right delimiter n e @exlusiveA or @inlusiveAF feside numersD you n use Esnf nd Csnf for the in(niteF
5.14.7 Translations in Templates
wost of the timeD trnsltion ours in templtesF ymfonyP provides ntive support for oth wig nd r templtesF wig empltes ymfonyP provides speilized wig tgs @trns nd trnshoieA to help with messge trnsltion of stti loks of textX
{% trans %}Hello %name%{% endtrans %} {% transchoice count %} {0} There is no apples|{1} There is one apple|]1,Inf] There are %count% apples {% endtranschoice %}
he trnshoie tg utomtilly gets the 7ount7 vrile from the urrent ontext nd psses it to the trnsltorF his mehnism only works when you use pleholder following the 7vr7 ptternF X sf you need to use the perent hrter @7A in stringD espe it y douling itX {7 trns 7}erentX 7perent777{7 endtrns 7} ou n lso speify the messge domin nd pss some dditionl vrilesX
{% trans with {'%name%': 'Fabien'} from "app" %}Hello %name%{% endtrans %} {% transchoice count with {'%name%': 'Fabien'} from "app" %} {0} There is no apples|{1} There is one apple|]1,Inf] There are %count% apples {% endtranschoice %}
he trns nd trnshoie (lters n e used to trnslte vrile texts nd omplex expressionsX
{{ message | trans }} {{ message | transchoice(5) }} {{ message | trans({'%name%': 'Fabien'}, "app") }} {{ message | transchoice(5, {'%name%': 'Fabien'}, 'app') }}
SFIRF rnsltions PWI
X sing the trnsltion tgs or (lters hve the sme e'etD ut with one sutle di'ereneX utomti output esping is only pplied to vriles trnslted using (lterF sn other wordsD if you need to e sure tht your trnslted vrile is not output espedD you must pply the rw (lter fter the trnsltion (lterX
{# text translated between tags is never escaped #} {% trans %} <h3>foo</h3> {% endtrans %} {% set message = '<h3>foo</h3>' %} {# a variable translated via a lter is escaped by default #} {{ message | trans | raw }} {# but static strings are never escaped #} {{ '<h3>foo</h3>' | trans }}
<?php echo $view['translator']->trans('Symfony2 is great') ?> <?php echo $view['translator']->transChoice( '{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples', 10, array('%count%' => 10) ) ?>
hen trnslting messgeD ymfonyP uses the lole from the user9s session or the fllk lole if neessryF ou n lso mnully speify the lole to use for trnsltionX
);
'{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples', 10, array('%count%' => 10), 'messages', 'fr_FR',
he trnsltion of dtse ontent should e hndled y hotrine through the rnsltle ixtensionF por more informtionD see the doumenttion for tht lirryF
5.14.10 Summary
ith the ymfonyP rnsltion omponentD reting n interntionlized pplition no longer needs to e pinful proess nd oils down to just few si stepsX
estrt messges in your pplition y wrpping eh in either the XmethodXymfonygomponentrnsltionrnsltorXXtrns or XmethodXymfonygomponentrnsltionrnsltorXXtrnsghoie methodsY rnslte eh messge into multiple loles y reting trnsltion messge (lesF ymfonyP disovers nd proesses eh (le euse its nme follows spei( onventionY wnge the user9s loleD whih is stored in the sessionF
e modern r pplition is full of ojetsF yne ojet my filitte the delivery of emil messges while nother my llow you to persist informtion into dtseF sn your pplitionD you my rete n ojet tht mnges your produt inventoryD or nother ojet tht proesses dt from thirdEprty esF he point is tht modern pplition does mny things nd is orgnized into mny ojets tht hndle eh tskF sn this hpterD we9ll tlk out speil r ojet in ymfonyP tht helps you instntiteD orgnize nd retrieve the mny ojets of your pplitionF his ojetD lled servie ontinerD will llow you to stndrdize nd entrlize the wy ojets re onstruted in your pplitionF he ontiner mkes your life esierD is super fstD nd emphsizes n rhiteture tht promotes reusle nd deoupled odeF end sine ll ore ymfonyP lsses use the ontinerD you9ll lern how to extendD on(gure nd use ny ojet in ymfonyPF sn lrge prtD the servie ontiner is the iggest ontriutor to the speed nd extensiility of ymfonyPF SFISF ervie gontiner PWQ
ymfony houmenttionD PFH pinllyD on(guring nd using the servie ontiner is esyF fy the end of this hpterD you9ll e omfortle reting your own ojets vi the ontiner nd ustomizing ojets from ny thirdEprty undleF ou9ll egin writing ode tht is more reusleD testle nd deoupledD simply euse the servie ontiner mkes writing good ode so esyF
5.15.1 What is a Service?
ut simplyD ervie is ny r ojet tht performs some sort of glol tskF st9s purposefullyEgeneri nme used in omputer siene to desrie n ojet tht9s reted for spei( purpose @eFgF delivering emilsAF ih servie is used throughout your pplition whenever you need the spei( funtionlity it providesF ou don9t hve to do nything speil to mke servieX simply write r lss with some ode tht omplishes spei( tskF gongrtultionsD you9ve just reted servie3 X es ruleD r ojet is servie if it is used glolly in your pplitionF e single wiler servie is used glolly to send emil messges wheres the mny wessge ojets tht it delivers re not serviesF imilrlyD rodut ojet is not servieD ut n ojet tht persists rodut ojets to dtse is servieF o wht9s the ig del thenc he dvntge of thinking out servies is tht you egin to think out seprting eh piee of funtionlity in your pplition into series of serviesF ine eh servie does just one joD you n esily ess eh servie nd use its funtionlity wherever you need itF ih servie n lso e more esily tested nd on(gured sine it9s seprted from the other funtionlity in your pplitionF his ide is lled servieEoriented rhiteture nd is not unique to ymfonyP or even rF truturing your pplition round set of independent servie lsses is wellEknown nd trusted ojetEoriented estEprtieF hese skills re key to eing good developer in lmost ny lngugeF
5.15.2 What is a Service Container?
e ervie gontiner @or dependeny injetion ontinerA is simply r ojet tht mnges the instntition of servies @iFeF ojetsAF por exmpleD suppose we hve simple r lss tht delivers emil messgesF ithout servie ontinerD we must mnully rete the ojet whenever we need itX
ymfony houmenttionD PFH miler servie somewhere elsec e ertinly don9t wnt to repet the miler on(gurtion every time we need to use the wiler ojetF ht if we needed to hnge the trnsport from sendmil to smtp everywhere in the pplitionc e9d need to hunt down every ple we rete wiler servie nd hnge itF
5.15.3 Creating/Conguring Services in the Container
e etter nswer is to let the servie ontiner rete the wiler ojet for youF sn order for this to workD we must teh the ontiner how to rete the wiler servieF his is done vi on(gurtionD whih n e spei(ed in ewvD wv or rX
ewv
<!-- app/cong/cong.xml --> <services> <service id="my_mailer" class="Acme\HelloBundle\Mailer"> <argument>sendmail</argument> </service> </services>
r
ymfony houmenttionD PFH ess the servies of the ontiner vi the get@A shortut methodX
class HelloController extends Controller { // ... public function sendEmailAction() { // ... $mailer = $this->get('my_mailer'); $mailer->send('ryan@foobar.net', ... ); }
hen we sk for the mymiler servie from the ontinerD the ontiner onstruts the ojet nd returns itF his is nother mjor dvntge of using the servie ontinerF xmelyD servie is never onstruted until it9s neededF sf you de(ne servie nd never use it on requestD the servie is never retedF his sves memory nd inreses the speed of your pplitionF his lso mens tht there9s very little or no performne hit for de(ning lots of serviesF ervies tht re never used re never onstrutedF es n dded onusD the wiler servie is only reted one nd the sme instne is returned eh time you sk for the servieF his is lmost lwys the ehvior you9ll need @it9s more )exile nd powerfulAD ut we9ll lern lter how you n on(gure servie tht hs multiple instnesF
5.15.4 Service Parameters
he retion of new servies @iFeF ojetsA vi the ontiner is pretty strightforwrdF rmeters mke de(ning servies more orgnized nd )exileX
ewv
# app/cong/cong.yml parameters: my_mailer.class: Acme\HelloBundle\Mailer my_mailer.transport: sendmail services: my_mailer: class: %my_mailer.class% arguments: [%my_mailer.transport%]
wv
<parameter key="my_mailer.class">Acme\HelloBundle\Mailer</parameter> <parameter key="my_mailer.transport">sendmail</parameter> </parameters> <services> <service id="my_mailer" class="%my_mailer.class%"> <argument>%my_mailer.transport%</argument> </service> </services>
r
// app/cong/cong.php use Symfony\Component\DependencyInjection\Denition; $container->setParameter('my_mailer.class', 'Acme\HelloBundle\Mailer'); $container->setParameter('my_mailer.transport', 'sendmail'); $container->setDenition('my_mailer', new Denition( '%my_mailer.class%', array('%my_mailer.transport%') ));
he end result is extly the sme s efore E the di'erene is only in how we de(ned the servieF fy surrounding the mymilerFlss nd mymilerFtrnsport strings in perent @7A signsD the ontiner knows to look for prmeters with those nmesF hen the ontiner is uiltD it looks up the vlue of eh prmeter nd uses it in the servie de(nitionF he purpose of prmeters is to feed informtion into serviesF yf ourse there ws nothing wrong with de(ning the servie without using ny prmetersF rmetersD howeverD hve severl dvntgesX
seprtion nd orgniztion of ll servie options under single prmeters keyY prmeter vlues n e used in multiple servie de(nitionsY when reting servie in undle @we9ll show this shortlyAD using prmeters llows the servie to e esily ustomized in your pplitionF
he hoie of using or not using prmeters is up to youF righEqulity thirdEprty undles will lwys use prmeters s they mke the servie stored in the ontiner more on(gurleF por the servies in your pplitionD howeverD you my not need the )exiility of prmetersF
5.15.5 Importing other Container Conguration Resources
X sn this setionD we9ll refer to servie on(gurtion (les s resouresF his is to highlight tht ft thtD while most on(gurtion resoures will e (les @eFgF ewvD wvD SFISF ervie gontiner PWU
ymfony houmenttionD PFH rAD ymfonyP is so )exile tht on(gurtion ould e loded from nywhere @eFgF dtse or even vi n externl we servieAF he servie ontiner is uilt using single on(gurtion resoure @ppGon(gGon(gFyml y defultAF ell other servie on(gurtion @inluding the ore ymfonyP nd thirdEprty undle on(gurtionA must e imported from inside this (le in one wy or notherF his gives you solute )exiility over the servies in your pplitionF ixternl servie on(gurtion n e imported in two di'erent wysF pirstD we9ll tlk out the method tht you9ll use most ommonly in your pplitionX the imports diretiveF sn the following setionD we9ll introdue the seond methodD whih is the )exile nd preferred method for importing servie on(gurtion from thirdEprty undlesF smporting gon(gurtion with imports o frD we9ve pled our mymiler servie ontiner de(nition diretly in the pplition on(gurtion (le @eFgF ppGon(gGon(gFymlAF yf ourseD sine the wiler lss itself lives inside the emerellofundleD it mkes more sense to put the mymiler ontiner de(nition inside the undle s wellF pirstD move the mymiler ontiner de(nition into new ontiner resoure (le inside emerellofundleF sf the esoures or esouresGon(g diretories don9t existD rete themF
ewv
# src/Acme/HelloBundle/Resources/cong/services.yml parameters: my_mailer.class: Acme\HelloBundle\Mailer my_mailer.transport: sendmail services: my_mailer: class: %my_mailer.class% arguments: [%my_mailer.transport%]
wv
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <parameters> <parameter key="my_mailer.class">Acme\HelloBundle\Mailer</parameter> <parameter key="my_mailer.transport">sendmail</parameter> </parameters> <services> <service id="my_mailer" class="%my_mailer.class%"> <argument>%my_mailer.transport%</argument>
PWV
SF
</service> </services>
r
// src/Acme/HelloBundle/Resources/cong/services.php use Symfony\Component\DependencyInjection\Denition; $container->setParameter('my_mailer.class', 'Acme\HelloBundle\Mailer'); $container->setParameter('my_mailer.transport', 'sendmail'); $container->setDenition('my_mailer', new Denition( '%my_mailer.class%', array('%my_mailer.transport%') ));
he de(nition itself hsn9t hngedD only its lotionF yf ourse the servie ontiner doesn9t know out the new resoure (leF portuntelyD we n esily import the resoure (le using the imports key in the pplition on(gurtionF
ewv
// app/cong/cong.php $this->import('@AcmeHelloBundle/Resources/cong/services.php');
he imports diretive llows your pplition to inlude servie ontiner on(gurtion resoures from ny other lotion @most ommonly from undlesAF he resoure lotionD for (lesD is the solute pth to the resoure (leF he speil demerello syntx resolves the diretory pth of the emerellofundle undleF his helps you speify the pth to the resoure without worrying lter if you move the emerellofundle to di'erent diretoryF
PWW
ymfony houmenttionD PFH smporting gon(gurtion vi gontiner ixtensions hen developing in ymfonyPD you9ll most ommonly use the imports diretive to import ontiner on(gurtion from the undles you9ve reted spei(lly for your pplitionF hirdEprty undle ontiner on(gurtionD inluding ymfonyP ore serviesD re usully loded using nother method tht9s more )exile nd esy to on(gure in your pplitionF rere9s how it worksF snternllyD eh undle de(nes its servies very muh like we9ve seen so frF xmelyD undle uses one or more on(gurtion resoure (les @usully wvA to speify the prmeters nd servies for tht undleF roweverD insted of importing eh of these resoures diretly from your pplition on(gurtion using the imports diretiveD you n simply invoke servie ontiner extension inside the undle tht does the work for youF e servie ontiner extension is r lss reted y the undle uthor to omplish two thingsX
import ll servie ontiner resoures needed to on(gure the servies for the undleY provide semntiD strightforwrd on(gurtion so tht the undle n e on(gured without interting with the )t prmeters of the undle9s servie ontiner on(gurtionF
sn other wordsD servie ontiner extension on(gures the servies for undle on your ehlfF end s we9ll see in momentD the extension provides sensileD highElevel interfe for on(guring the undleF ke the prmeworkfundle E the ore ymfonyP frmework undle E s n exmpleF he presene of the following ode in your pplition on(gurtion invokes the servie ontiner extension inside the prmeworkfundleX
ewv
# app/cong/cong.yml framework: secret: xxxxxxxxxx charset: UTF-8 form: true csrf_protection: true router: { resource: "%kernel.root_dir%/cong/routing.yml" } # ...
wv
<!-- app/cong/cong.xml --> <framework:cong charset="UTF-8" secret="xxxxxxxxxx"> <framework:form /> <framework:csrf-protection /> <framework:router resource="%kernel.root_dir%/cong/routing.xml" /> <!-- ... --> </framework>
QHH SF
// app/cong/cong.php $container->loadFromExtension('framework', array( 'secret' => 'xxxxxxxxxx', 'charset' => 'UTF-8', 'form' => array(), 'csrf-protection' => array(), 'router' => array('resource' => '%kernel.root_dir%/cong/routing.php'), // ... ));
hen the on(gurtion is prsedD the ontiner looks for n extension tht n hndle the frmework on(gurtion diretiveF he extension in questionD whih lives in the prmeworkfundleD is invoked nd the servie on(gurtion for the prmeworkfundle is lodedF sf you remove the frmework key from your pplition on(gurtion (le entirelyD the ore ymfonyP servies won9t e lodedF he point is tht you9re in ontrolX the ymfonyP frmework doesn9t ontin ny mgi or perform ny tions tht you don9t hve ontrol overF yf ourse you n do muh more thn simply tivte the servie ontiner extension of the prmeworkfundleF ih extension llows you to esily ustomize the undleD without worrying out how the internl servies re de(nedF sn this seD the extension llows you to ustomize the hrsetD errorhndlerD srfprotetionD router on(gurtion nd muh moreF snternllyD the prmeworkfundle uses the options spei(ed here to de(ne nd on(gure the servies spei( to itF he undle tkes re of reting ll the neessry prmeters nd servies for the servie ontinerD while still llowing muh of the on(gurtion to e esily ustomizedF es n dded onusD most servie ontiner extensions re lso smrt enough to perform vlidtion E notifying you of options tht re missing or the wrong dt typeF hen instlling or on(guring undleD see the undle9s doumenttion for how the servies for the undle should e instlled nd on(guredF he options ville for the ore undles n e found inside the eferene quideF X xtivelyD the servie ontiner only reognizes the prmetersD serviesD nd imports diretivesF eny other diretives re hndled y servie ontiner extensionF
o frD our originl mymiler servie is simpleX it tkes just one rgument in its onstrutorD whih is esily on(gurleF es you9ll seeD the rel power of the ontiner is relized when you need to rete servie tht depends on one or more other servies in the ontinerF
QHI
ymfony houmenttionD PFH vet9s strt with n exmpleF uppose we hve new servieD xewsletterwngerD tht helps to mnge the preprtion nd delivery of n emil messge to olletion of ddressesF yf ourse the mymiler servie is lredy relly good t delivering emil messgesD so we9ll use it inside xewsletterwnger to hndle the tul delivery of the messgesF his pretend lss might look something like thisX
namespace Acme\HelloBundle\Newsletter; use Acme\HelloBundle\Mailer; class NewsletterManager { protected $mailer; public function __construct(Mailer $mailer) { $this->mailer = $mailer; } } // ...
ithout using the servie ontinerD we n rete new xewsletterwnger firly esily from inside ontrollerX
ewv
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <parameters> <!-- ... --> <parameter key="newsletter_manager.class">Acme\HelloBundle\Newsletter\NewsletterManager</par </parameters> <services> <service id="my_mailer" ... > <!-- ... --> </service> <service id="newsletter_manager" class="%newsletter_manager.class%"> <argument type="service" id="my_mailer"/> </service> </services>
r
// ... $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager' $container->setDenition('my_mailer', ... ); $container->setDenition('newsletter_manager', new Denition( '%newsletter_manager.class%', array(new Reference('my_mailer')) ));
sn ewvD the speil dmymiler syntx tells the ontiner to look for servie nmed mymiler nd to pss tht ojet into the onstrutor of xewsletterwngerF sn this seD howeverD the spei(ed servie mymiler must existF sf it does notD n exeption will e thrownF ou n mrk your dependenies s optionl E this will e disussed in the next setionF sing referenes is very powerful tool tht llows you to rete independent servie lsses with wellEde(ned dependeniesF sn this exmpleD the newslettermnger servie needs the mymiler servie in order to funtionF hen you de(ne this dependeny in the servie ontinerD the ontiner tkes re of ll the work of instntiting the ojetsF
QHQ
ymfony houmenttionD PFH yptionl hependeniesX etter snjetion snjeting dependenies into the onstrutor in this mnner is n exellent wy of ensuring tht the dependeny is ville to useF sf you hve optionl dependenies for lssD then setter injetion my e etter optionF his mens injeting the dependeny using method ll rther thn through the onstrutorF he lss would look like thisX
namespace Acme\HelloBundle\Newsletter; use Acme\HelloBundle\Mailer; class NewsletterManager { protected $mailer; public function setMailer(Mailer $mailer) { $this->mailer = $mailer; } } // ...
snjeting the dependeny y the setter method just needs hnge of syntxX
ewv
# src/Acme/HelloBundle/Resources/cong/services.yml parameters: # ... newsletter_manager.class: Acme\HelloBundle\Newsletter\NewsletterManager services: my_mailer: # ... newsletter_manager: class: %newsletter_manager.class% calls: - [ setMailer, [ @my_mailer ] ]
wv
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <parameters> <!-- ... --> <parameter key="newsletter_manager.class">Acme\HelloBundle\Newsletter\NewsletterManager</par </parameters>
QHR
SF
<services> <service id="my_mailer" ... > <!-- ... --> </service> <service id="newsletter_manager" class="%newsletter_manager.class%"> <call method="setMailer"> <argument type="service" id="my_mailer" /> </call> </service> </services>
r
// ... $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager' $container->setDenition('my_mailer', ... ); $container->setDenition('newsletter_manager', new Denition( '%newsletter_manager.class%' ))->addMethodCall('setMailer', array( new Reference('my_mailer') ));
X he pprohes presented in this setion re lled onstrutor injetion nd setter injetionF he ymfonyP servie ontiner lso supports property injetionF
ometimesD one of your servies my hve n optionl dependenyD mening tht the dependeny is not required for your servie to work properlyF sn the exmple oveD the mymiler servie must existD otherwise n exeption will e thrownF fy modifying the newslettermnger servie de(nitionD you n mke this referene optionlF he ontiner will then injet it if it exists nd do nothing if it doesn9tX
ewv
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <services> <service id="my_mailer" ... > <!-- ... --> </service> <service id="newsletter_manager" class="%newsletter_manager.class%"> <argument type="service" id="my_mailer" on-invalid="ignore" /> </service> </services>
r
// ... $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager' $container->setDenition('my_mailer', ... ); $container->setDenition('newsletter_manager', new Denition( '%newsletter_manager.class%', array(new Reference('my_mailer', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)) ));
sn ewvD the speil dc syntx tells the servie ontiner tht the dependeny is optionlF yf ourseD the xewsletterwnger must lso e written to llow for n optionl dependenyX
ine ymfonyP nd ll thirdEprty undles on(gure nd retrieve their servies vi the ontinerD you n esily ess them or even use them in your own serviesF o keep things simpleD ymfonyP y defult does not require tht ontrollers e de(ned s serviesF QHT SF
ymfony houmenttionD PFH purthermore ymfonyP injets the entire servie ontiner into your ontrollerF por exmpleD to hndle the storge of informtion on user9s sessionD ymfonyP provides session servieD whih you n ess inside stndrd ontroller s followsX
sn ymfonyPD you9ll onstntly use servies provided y the ymfony ore or other thirdE prty undles to perform tsks suh s rendering templtes @templtingAD sending emils @milerAD or essing informtion on the request @requestAF e n tke this step further y using these servies inside servies tht you9ve reted for your pplitionF vet9s modify the xewsletterwnger to use the rel ymfonyP miler servie @insted of the pretend mymilerAF vet9s lso pss the templting engine servie to the xewsletterwnger so tht it n generte the emil ontent vi templteX
namespace Acme\HelloBundle\Newsletter; use Symfony\Component\Templating\EngineInterface; class NewsletterManager { protected $mailer; protected $templating; public function __construct(\Swift_Mailer $mailer, EngineInterface $templating) { $this->mailer = $mailer; $this->templating = $templating; } } // ...
ewv
wv
<service id="newsletter_manager" class="%newsletter_manager.class%"> <argument type="service" id="mailer"/> <argument type="service" id="templating"/> </service>
r
$container->setDenition('newsletter_manager', new Denition( '%newsletter_manager.class%', array( new Reference('mailer'), new Reference('templating') ) ));
he newslettermnger servie now hs ess to the ore miler nd templting serviesF his is ommon wy to rete servies spei( to your pplition tht leverge the power of di'erent servies within the frmeworkF X fe sure tht swiftmiler entry ppers in your pplition on(gurtionF es we mentioned in smporting gon(gurtion vi gontiner ixtensionsD the swiftmiler key invokes the servie extension from the wiftmilerfundleD whih registers the miler servieF
es we9ve seenD de(ning servies inside the ontiner is esyD generlly involving servie on(gurtion key nd few prmetersF roweverD the ontiner hs severl other tools ville tht help to tg servies for speil funtionlityD rete more omplex serviesD nd perform opertions fter the ontiner is uiltF wrking ervies s puli G privte hen de(ning serviesD you9ll usully wnt to e le to ess these de(nitions within your pplition odeF hese servies re lled puliF por exmpleD the dotrine servie registered with the ontiner when using the hotrinefundle is puli servie s you n ess it viX
$doctrine = $container->get('doctrine');
roweverD there re useEses when you don9t wnt servie to e puliF his is ommon when servie is only de(ned euse it ould e used s n rgument for nother servieF
QHV
SF
ymfony houmenttionD PFH X sf you use privte servie s n rgument to more thn one other servieD this will result in two di'erent instnes eing used s the instntition of the privte servie is done inline @eFgF new rivtepoofr@AAF imply sidX e servie will e privte when you do not wnt to ess it diretly from your odeF rere is n exmpleX
ewv
$container->get('foo');
roweverD if servie hs een mrked s privteD you n still lis it @see elowA to ess this servie @vi the lisAF X ervies re y defult puliF
elising hen using ore or third prty undles within your pplitionD you my wnt to use shortuts to ess some serviesF ou n do so y lising them ndD furthermoreD you n even lis nonEpuli serviesF
ewv
QHW
ewv
QIH
SF
ymfony houmenttionD PFH gs @tgsA sn the sme wy tht log post on the e might e tgged with things suh s ymfony or rD servies on(gured in your ontiner n lso e tggedF sn the servie ontinerD tg implies tht the servie is ment to e used for spei( purposeF ke the following exmpleX
ewv
row to se ptory to grete ervies row to wnge gommon hependenies with rent ervies row to de(ne gontrollers s ervies
5.16 Performance
ymfonyP is fstD right out of the oxF yf ourseD if you relly need speedD there re mny wys tht you n mke ymfony even fsterF sn this hpterD you9ll explore mny of the most ommon nd powerful wys to mke your ymfony pplition even fsterF
5.16.1 Use a Byte Code Cache (e.g. APC)
yne the est @nd esiestA things tht you should do to improve your performne is to use yte ode heF he ide of yte ode he is to remove the need to onstntly reompile the r soure odeF here re numer of yte ode hes villeD some of whih re open soureF he most widely used yte ode he is proly eg sing yte ode he relly hs no downsideD nd ymfonyP hs een rhiteted to perform relly well in this type of environmentF purther yptimiztions fyte ode hes usully monitor the soure (les for hngesF his ensures tht if the soure of (le hngesD the yte ode is reompiled utomtillyF his is relly onvenientD ut oviously dds overhedF
QIP
SF
ymfony houmenttionD PFH por this resonD some yte ode hes o'er n option to disle these heksF yviouslyD when disling these heksD it will e up to the server dmin to ensure tht the he is lered whenever ny soure (les hngeF ytherwiseD the updtes you9ve mde won9t e seenF por exmpleD to disle these heks in egD simply dd pFsttaH to your phpFini on(gurtionF
5.16.2 Use an Autoloader that caches (e.g. ApcUniversalClassLoader)
fy defultD the ymfonyP stndrd edition uses the niverslglssvoder in the utoloderFphp (leF his utoloder is esy to useD s it will utomtilly (nd ny new lsses tht you9ve pled in the registered diretoriesF nfortuntelyD this omes t ostD s the loder itertes over ll on(gured nmespes to (nd prtiulr (leD mking (leexists lls until it (nlly (nds the (le it9s looking forF he simplest solution is to he the lotion of eh lss fter it9s loted the (rst timeF ymfony omes with lss E epniverslglssvoder E loder tht extends the niverslglssvoder nd stores the lss lotions in egF o use this lss loderD simply dpt your utoloderFphp s followsX
// app/autoload.php require __DIR__.'/../vendor/symfony/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php'; use Symfony\Component\ClassLoader\ApcUniversalClassLoader; $loader = new ApcUniversalClassLoader('some caching unique prex'); // ...
X hen using the eg utoloderD if you dd new lssesD they will e found utomtilly nd everything will work the sme s efore @iFeF no reson to ler the heAF roweverD if you hnge the lotion of prtiulr nmespe or pre(xD you9ll need to )ush your eg heF ytherwiseD the utoloder will still e looking t the old lotion for ll lsses inside tht nmespeF
o ensure optiml )exiility nd ode reuseD ymfonyP pplitions leverge vriety of lsses nd Qrd prty omponentsF fut loding ll of these lsses from seprte (les on eh request n result in some overhedF o redue this overhedD the ymfonyP tndrd idition provides sript to generte soElled ootstrp (leD onsisting of multiple lsses de(nitions in single (leF fy inluding this (le @whih ontins opy of mny of the ore
SFITF erformne
QIQ
ymfony houmenttionD PFH lssesAD ymfony no longer needs to inlude ny of the soure (les ontining those lssesF his will redue dis sy quite itF sf you9re using the ymfonyP tndrd iditionD then you9re proly lredy using the ootstrp (leF o e sureD open your front ontroller @usully ppFphpA nd hek to mke sure tht the following line existsX
require_once __DIR__.'/../app/bootstrap.php.cache';
xote tht there re two disdvntges when using ootstrp (leX
the (le needs to e regenerted whenever ny of the originl soures hnge @iFeF when you updte the ymfonyP soure or vendor lirriesAY when deuggingD one will need to ple rek points inside the ootstrp (leF
sf you9re using ymfonyP tndrd iditionD the ootstrp (le is utomtilly reuilt fter updting the vendor lirries vi the php inGvendors instll ommndF footstrp piles nd fyte gode ghes iven when using yte ode heD performne will improve when using ootstrp (le sine there will e less (les to monitor for hngesF yf ourse if this feture is disled in the yte ode he @eFgF pFsttaH in egAD there is no longer reson to use ootstrp (leF
5.17 Internals
vooks like you wnt to understnd how ymfonyP works nd how to extend itF ht mkes me very hppy3 his setion is n inEdepth explntion of the ymfonyP internlsF X ou need to red this setion only if you wnt to understnd how ymfonyP works ehind the seneD or if you wnt to extend ymfonyPF
5.17.1 Overview
he ymfonyP ode is mde of severl independent lyersF ih lyer is uilt on top of the previous oneF X eutoloding is not mnged y the frmework diretlyY it9s done independently with the help of the ymfonygomponentglssvoderniverslglssvoder lss nd the srGutolodFphp (leF ed the dedited hpter for more informtionF QIR SF
ymfony houmenttionD PFH rttppoundtion gomponent he deepest level is the XnmespeXymfonygomponentrttppoundtion omponentF rttppoundtion provides the min ojets needed to del with rF st is n yjetE yriented strtion of some ntive r funtions nd vrilesX
he ymfonygomponentrttppoundtionequest lss strts the min r glol vriles like 6qiD 6yD 6gyyusiD 6psviD nd 6iiY he ymfonygomponentrttppoundtionesponse lss strts some r funtions like heder@AD setookie@AD nd ehoY he ymfonygomponentrttppoundtionession lss ymfonygomponentrttppoundtionessiontorgeessiontorgesnterfe interfe strt session mngement sessionB@A funtionsF
rttpuernel gomponent yn top of rttppoundtion is the XnmespeXymfonygomponentrttpuernel omponentF rttpuernel hndles the dynmi prt of rY it is thin wrpper on top of the equest nd esponse lsses to stndrdize the wy requests re hndledF st lso provides extension points nd tools tht mkes it the idel strting point to rete e frmework without too muh overhedF st lso optionlly dds on(gurility nd extensiilityD thnks to the hependeny snjetion omponent nd powerful plugin system @undlesAF FX ed more out the rttpuernel omponentF ed more out hependeny snjetion nd fundlesF prmeworkfundle fundle he XnmespeXymfonyfundleprmeworkfundle undle is the undle tht ties the min omponents nd lirries together to mke lightweight nd fst wg frmeworkF st omes with sensile defult on(gurtion nd onventions to ese the lerning urveF
5.17.2 Kernel
nd
he ymfonygomponentrttpuernelrttpuernel lss is the entrl lss of ymfonyP nd is responsile for hndling lient requestsF sts min gol is to onvert ymfonygomponentrttppoundtionequest ojet to ymfonygomponentrttppoundtionesponse ojetF ivery ymfonyP uernel implements ymfonygomponentrttpuernelrttpuernelsnterfeX SFIUF snternls QIS
he XmethodXymfonygomponentrttpuernelgontrollergontrolleresolversnterfeXXgetgontroller method returns the gontroller @ r llleA ssoited with the given equestF he defult implementtion @ymfonygomponentrttpuernelgontrollergontrolleresolverA looks for ontroller request ttriute tht represents the ontroller nme @ lssXXmethod stringD like fundleflogfundleostgontrollerXindexetionAF
X he defult implementtion uses the ymfonyfundleprmeworkfundleiventvisteneroutervis to de(ne the ontroller equest ttriute @see kernelFrequest iventAF
he XmethodXymfonygomponentrttpuernelgontrollergontrolleresolversnterfeXXgetergument method returns n rry of rguments to pss to the gontroller llleF he defult implementtion utomtilly resolves the method rgumentsD sed on the equest ttriutesF wthing gontroller method rguments from equest ttriutes por eh method rgumentD ymfonyP tries to get the vlue of equest ttriute with the sme nmeF sf it is not de(nedD the rgument defult vlue is used if de(nedX
// Symfony2 will look for an 'id' attribute (mandatory) // and an 'admin' one (optional) public function showAction($id, $admin = true) { // ... }
QIT
SF
ymfony houmenttionD PFH rndling equests he hndle@A method tkes equest nd lwys returns esponseF o onvert the equestD hndle@A relies on the esolver nd n ordered hin of ivent noti(tions @see the next setion for more informtion out eh iventAX IF fefore doing nything elseD the kernelFrequest event is noti(ed ! if one of the listeners returns esponseD it jumps to step V diretlyY PF he esolver is lled to determine the gontroller to exeuteY QF visteners of the kernelFontroller event n now mnipulte the gontroller llle the wy they wnt @hnge itD wrp itD FFFAY RF he uernel heks tht the gontroller is tully vlid r llleY SF he esolver is lled to determine the rguments to pss to the gontrollerY TF he uernel lls the gontrollerY UF sf the gontroller does not return esponseD listeners of the kernelFview event n onvert the gontroller return vlue to esponseY VF visteners of the kernelFresponse event n mnipulte the esponse @ontent nd hedersAY WF he esponse is returnedF sf n ixeption is thrown during proessingD the kernelFexeption is noti(ed nd listeners re given hne to onvert the ixeption to esponseF sf tht worksD the kernelFresponse event is noti(edY if notD the ixeption is reEthrownF sf you don9t wnt ixeptions to e ught @for emedded requests for instneAD disle the kernelFexeption event y pssing flse s the third rgument to the hndle@A methodF snternl equests et ny time during the hndling of request @the mster9 oneAD suErequest n e hndledF ou n pss the request type to the hndle@A method @its seond rgumentAX
rttpuernelsnterfeXXweiiiY rttpuernelsnterfeXXfiiF
he type is pssed to ll events nd listeners n t ordingly @some proessing must only our on the mster requestAF
SFIUF snternls
QIU
ymfony houmenttionD PFH ivents ih event thrown y the uernel is ymfonygomponentrttpuerneliventuerneliventF his mens hs ess to the sme si informtionX sulss of tht eh event
getequestype@A E returns the type of the request @rttpuernelsnterfeXXweiii or rttpuernelsnterfeXXfiiAY getuernel@A E returns the uernel hndling the requestY getequest@A E returns the urrent equest eing hndledF
getRequestType()
he getequestype@A method llows listeners to know the type of the requestF por instneD if listener must only e tive for mster requestsD dd the following ode t the eginning of your listener methodX
kernel.request Event
ivent glssX ymfonygomponentrttpuerneliventqetesponseivent he gol of this event is to either return esponse ojet immeditely or setup vriles so tht gontroller n e lled fter the eventF eny listener n return esponse ojet vi the setesponse@A method on the eventF sn this seD ll other listeners won9t e lledF his event is used y prmeworkfundle to populte the ontroller equest ttriuteD vi the ymfonyfundleprmeworkfundleiventvisteneroutervistenerF equestvistener uses ymfonygomponentoutingoutersnterfe ojet to mth the equest nd determine the gontroller nme @stored in the ontroller equest ttriuteAF
QIV
SF
kernel.controller Event
ivent glssX ymfonygomponentrttpuerneliventpiltergontrollerivent his event is not used y prmeworkfundleD ut n e n entry point used to modify the ontroller tht should e exeutedX
use Symfony\Component\HttpKernel\Event\FilterControllerEvent; public function onKernelController(FilterControllerEvent $event) { $controller = $event->getController(); // ... // the controller can be changed to any PHP callable $event->setController($controller);
kernel.view Event
ivent glssX ymfonygomponentrttpuerneliventqetesponseporgontrolleresultivent his event is not used y prmeworkfundleD ut it n e used to implement view suE systemF his event is lled only if the gontroller does not return esponse ojetF he purpose of the event is to llow some other return vlue to e onverted into esponseF he vlue returned y the gontroller is essile vi the getgontrolleresult methodX
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; use Symfony\Component\HttpFoundation\Response; public function onKernelView(GetResponseForControllerResultEvent $event) { $val = $event->getReturnValue(); $response = new Response(); // some how customize the Response from the return value } $event->setResponse($response);
kernel.response Event
ivent glssX ymfonygomponentrttpuerneliventpilteresponseivent he purpose of this event is to llow other systems to modify or reple the esponse ojet fter its retionX SFIUF snternls QIW
public function onKernelResponse(FilterResponseEvent $event) { $response = $event->getResponse(); // .. modify the response object }
he prmeworkfundle registers severl listenersX
ymfonygomponentrttpuerneliventvistenerro(lervistenerX ollets dt for the urrent requestY ymfonyfundleero(lerfundleiventvistenereheugoolrvistenerX injets the e heug oolrY ymfonygomponentrttpuerneliventvisteneresponsevistenerX esponse gontentEype sed on the request formtY
(xes the
ymfonygomponentrttpuerneliventvistenerisivistenerX dds urrogteE gontrol r heder when the esponse needs to e prsed for is tgsF
kernel.exception Event
ivent glssX ymfonygomponentrttpuerneliventqetesponseporixeptionivent prmeworkfundle registers n ymfonygomponentrttpuerneliventvistenerixeptionvistener tht forwrds the equest to given gontroller @the vlue of the exeptionlistenerFontroller prmeter ! must e in the lssXXmethod nottionAF e listener on this event n rete nd set esponse ojetD rete nd set new ixeption ojetD or do nothingX
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpFoundation\Response; public function onKernelException(GetResponseForExceptionEvent $event) { $exception = $event->getException(); $response = new Response(); // setup the Response object based on the caught exception $event->setResponse($response); // you can alternatively set a new Exception // $exception = new \Exception('Some special exception'); // $event->setException($exception);
QPH
SF
yjeted yriented ode hs gone long wy to ensuring ode extensiilityF fy reting lsses tht hve well de(ned responsiilitiesD your ode eomes more )exile nd developer n extend them with sulsses to modify their ehviorsF fut if he wnts to shre his hnges with other developers who hve lso mde their own sulssesD ode inheritne is mootF gonsider the relEworld exmple where you wnt to provide plugin system for your projetF e plugin should e le to dd methodsD or do something efore or fter method is exeutedD without interfering with other pluginsF his is not n esy prolem to solve with single inheritneD nd multiple inheritne @were it possile with rA hs its own drwksF he ymfonyP ivent hispther implements the yserver pttern in simple nd e'etive wy to mke ll these things possile nd to mke your projets truly extensileF ke simple exmple from the ymfonyP rttpuernel omponentF yne esponse ojet hs een retedD it my e useful to llow other elements in the system to modify it @eFgF dd some he hedersA efore it9s tully usedF o mke this possileD the ymfonyP kernel throws n event E kernelFresponseF rere9s how it workX
e listener @r ojetA tells entrl dispther ojet tht it wnts to listen to the kernelFresponse eventY et some pointD the ymfonyP kernel tells the dispther ojet to dispth the kernelFresponse eventD pssing with it n ivent ojet tht hs ess to the esponse ojetY he dispther noti(es @iFeF lls method onA ll listeners of the kernelFresponse eventD llowing eh of them to mke modi(tions to the esponse ojetF
ivents hen n event is dispthedD it9s identi(ed y unique nme @eFgF kernelFresponseAD whih ny numer of listeners might e listening toF en ymfonygomponentiventhisptherivent instne is lso reted nd pssed to ll of the listenersF es you9ll see lterD the ivent ojet itself often ontins dt out the event eing dispthedF
Naming Conventions
he unique event nme n e ny stringD ut optionlly follows few simple nming onventionsX
use only lowerse lettersD numersD dots @FAD nd undersores @AY pre(x nmes with nmespe followed y dot @eFgF kernelFAY
SFIUF snternls
QPI
end nmes with ver tht indites wht tion is eing tken @eFgF requestAF
rere re some exmples of good event nmesX
kernelFresponse formFpresetdt
he event nme @stringA tht this listener wnts to listen toY e r llle tht will e noti(ed when n event is thrown tht it listens toY en optionl priority integer @higher equls more importntA tht determines when listener is triggered versus other listeners @defults to HAF sf two listeners hve the sme priorityD they re exeuted in the order tht they were dded to the disptherF
X e r llle is r vrile tht n e used y the lluserfun@A funtion nd returns true when pssed to the isllle@A funtionF st n e glosure instneD string representing funtionD or n rry representing n ojet method or lss methodF o frD you9ve seen how r ojets n e registered s listenersF ou n lso register r glosures s event listenersX
use Symfony\Component\EventDispatcher\Event; $dispatcher->addListener('foo.action', function (Event $event) { // will be executed when the foo.action event is dispatched });
yne listener is registered with the disptherD it wits until the event is noti(edF sn the ove exmpleD when the fooFtion event is dispthedD the dispther lls the emevistenerXXonpooetion method nd psses the ivent ojet s the single rgumentX
use Symfony\Component\EventDispatcher\Event; class AcmeListener { // ... public function onFooAction(Event $event) { // do something }
X sf you use the ymfonyP wg frmeworkD listeners n e registered vi your on(gurtionF es n dded onusD the listener ojets re instntited only when neededF sn mny sesD speil ivent sulss tht9s spei( to the given event is pssed to the listenerF his gives the listener ess to speil informtion out the eventF ghek the doumenttion or implementtion of eh event to determine the ext ymfonygomponentiventhisptherivent instne
SFIUF snternls
QPQ
ymfony houmenttionD PFH tht9s eing pssedF por exmpleD the kernelFevent event psses n instne of ymfonygomponentrttpuerneliventpilteresponseiventX
use Symfony\Component\HttpKernel\Event\FilterResponseEvent public function onKernelResponse(FilterResponseEvent $event) { $response = $event->getResponse(); $request = $event->getRequest(); } // ...
greting nd hispthing n ivent sn ddition to registering listeners with existing eventsD you n rete nd throw your own eventsF his is useful when reting thirdEprty lirries nd lso when you wnt to keep di'erent omponents of your own system )exile nd deoupledF
namespace Acme\StoreBundle; nal class StoreEvents { /** * The store.order event is thrown each time an order is created * in the system. * * The event listener receives an Acme\StoreBundle\Event\FilterOrderEvent * instance. * * @var string */ const onStoreOrder = 'store.order'; }
xotie tht this lss doesn9t tully do nythingF he purpose of the toreivents lss is just to e lotion where informtion out ommon events n e entrlizedF xotie lso tht speil pilteryrderivent lss will e pssed to eh listener of this eventF
QPR
SF
namespace Acme\StoreBundle\Event; use Symfony\Component\EventDispatcher\Event; use Acme\StoreBundle\Order; class FilterOrderEvent extends Event { protected $order; public function __construct(Order $order) { $this->order = $order; } public function getOrder() { return $this->order; }
use Acme\StoreBundle\StoreEvents; use Acme\StoreBundle\Order; use Acme\StoreBundle\Event\FilterOrderEvent; // the order is somehow created or retrieved $order = new Order();
SFIUF snternls QPS
// ... // create the FilterOrderEvent and dispatch it $event = new FilterOrderEvent($order); $dispatcher->dispatch(StoreEvents::onStoreOrder, $event);
xotie tht the speil pilteryrderivent ojet is reted nd pssed to the dispth methodF xowD ny listener to the storeForder event will reeive the pilteryrderivent nd hve ess to the yrder ojet vi the getyrder methodX
// some listener class that's been registered for onStoreOrder use Acme\StoreBundle\Event\FilterOrderEvent; public function onStoreOrder(FilterOrderEvent $event) { $order = $event->getOrder(); // do something to or with the order }
ssing long the ivent hispther yjet sf you hve look t the iventhispther lssD you will notie tht the lss does not t s ingleton @there is no getsnstne@A stti methodAF ht is intentionlD s you might wnt to hve severl onurrent event dispthers in single r requestF fut it lso mens tht you need wy to pss the dispther to the ojets tht need to onnet or notify eventsF he est prtie is to injet the event dispther ojet into your ojetsD k dependeny injetionF ou n use onstrutor injetionX
class Foo { protected $dispatcher = null; public function __construct(EventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; }
yr setter injetionX
QPT
SF
ghoosing etween the two is relly mtter of tsteF wny tend to prefer the onstrutor injetion s the ojets re fully initilized t onstrution timeF fut when you hve long list of dependeniesD using setter injetion n e the wy to goD espeilly for optionl dependeniesF X sf you use dependeny injetion like we did in the two exmples oveD you n then use the ymfonyP hependeny snjetion omponent to elegntly mnge these ojetsF
sing ivent usriers he most ommon wy to listen to n event is to register n event listener with the disptherF his listener n listen to one or more events nd is noti(ed eh time those events re dispthedF enother wy to listen to events is vi n event susrierF en event susrier is r lss tht9s le to tell the dispther extly whih events it should susrie toF st implements the ymfonygomponentiventhisptheriventusriersnterfe interfeD whih requires single stti method lled getusriediventsF ke the following exmple of susrier tht susries to the kernelFresponse nd storeForder eventsX
namespace Acme\StoreBundle\Event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; class StoreSubscriber implements EventSubscriberInterface { static public function getSubscribedEvents() { return array( 'kernel.response' => 'onKernelResponse', 'store.order' => 'onStoreOrder', ); } public function onKernelResponse(FilterResponseEvent $event) { // ... }
SFIUF snternls QPU
his is very similr to listener lssD exept tht the lss itself n tell the dispther whih events it should listen toF o register susrier with the disptherD use the XmethodXymfonygomponentiventhisptheriventhisptherXXddusrier methodX
xowD ny listeners to storeForder tht hve not yet een lled will not e lledF
5.17.4 Proler
hen enledD the ymfonyP pro(ler ollets useful informtion out eh request mde to your pplition nd store them for lter nlysisF se the pro(ler in the development QPV SF
ymfony houmenttionD PFH environment to help you to deug your ode nd enhne performneY use it in the prodution environment to explore prolems fter the ftF ou rrely hve to del with the pro(ler diretly s ymfonyP provides visulizer tools like the e heug oolr nd the e ro(lerF sf you use the ymfonyP tndrd iditionD the pro(lerD the we deug toolrD nd the we pro(ler re ll lredy on(gured with sensile settingsF X he pro(ler ollets informtion for ll requests @simple requestsD rediretsD exeptionsD ejx requestsD is requestsY nd for ll r methods nd ll formtsAF st mens tht for single vD you n hve severl ssoited pro(ling dt @one per externl requestGresponse pirAF
isulizing ro(ling ht
SFIUF snternls
QPW
// get the latest 10 tokens $tokens = $container->get('proler')->nd('', '', 10); // get the latest 10 tokens for all URL containing /admin/ $tokens = $container->get('proler')->nd('', '/admin/', 10); // get the latest 10 tokens for local requests $tokens = $container->get('proler')->nd('127.0.0.1', '', 10);
sf you wnt to mnipulte pro(ling dt on di'erent mhine thn the one where the informtion were genertedD use the export@A nd import@A methodsX
// on the production machine $prole = $container->get('proler')->loadProle($token); $data = $proler->export($prole); // on the development machine $proler->import($data); Conguration
he defult ymfonyP on(gurtion omes with sensile settings for the pro(lerD the we deug toolrD nd the we pro(lerF rere is for instne the on(gurtion for the development environmentX
ewv
# load the proler framework: proler: { only_exceptions: false } # enable the web proler web_proler: toolbar: true
QQH
SF
<!-- xmlns:webproler="http://symfony.com/schema/dic/webproler" --> <!-- xsi:schemaLocation="http://symfony.com/schema/dic/webproler http://symfony.com/schema/dic/we <!-- load the proler --> <framework:cong> <framework:proler only-exceptions="false" /> </framework:cong> <!-- enable the web proler --> <webproler:cong toolbar="true" intercept-redirects="true" verbose="true" />
r
// load the proler $container->loadFromExtension('framework', array( 'proler' => array('only-exceptions' => false), )); // enable the web proler $container->loadFromExtension('web_proler', array( 'toolbar' => true, 'intercept-redirects' => true, 'verbose' => true, ));
hen onlyEexeptions is set to trueD the pro(ler only ollets dt when n exeption is thrown y the pplitionF hen intereptEredirets is set to trueD the we pro(ler interepts the redirets nd gives you the opportunity to look t the olleted dt efore following the rediretF hen verose is set to trueD the e heug oolr displys lot of informtionF etting verose to flse hides some seondry informtion to mke the toolr shorterF sf you enle the we pro(lerD you lso need to mount the pro(ler routesX
ewv
prex: /_proler
wv
$collection->addCollection($loader->import("@WebProlerBundle/Resources/cong/routing/proler.xml")
es the pro(ler dds some overhedD you might wnt to enle it only under ertin irumstnes in the prodution environmentF he onlyEexeptions settings limits pro(ling to SHH pgesD ut wht if you wnt to get informtion when the lient s omes from spei( ddressD or for limited portion of the wesitec ou n use request mtherX
ewv
# enables the proler only for request coming for the 192.168.0.0 network framework: proler: matcher: { ip: 192.168.0.0/24 } # enables the proler only for the /admin URLs framework: proler: matcher: { path: "^/admin/" } # combine rules framework: proler: matcher: { ip: 192.168.0.0/24, path: "^/admin/" } # use a custom matcher instance dened in the "custom_matcher" service framework: proler: matcher: { service: custom_matcher }
wv
<!-- enables the proler only for request coming for the 192.168.0.0 network --> <framework:cong> <framework:proler> <framework:matcher ip="192.168.0.0/24" /> </framework:proler> </framework:cong> <!-- enables the proler only for the /admin URLs --> <framework:cong>
QQP SF
<framework:proler> <framework:matcher path="^/admin/" /> </framework:proler> </framework:cong> <!-- combine rules --> <framework:cong> <framework:proler> <framework:matcher ip="192.168.0.0/24" path="^/admin/" /> </framework:proler> </framework:cong> <!-- use a custom matcher instance dened in the "custom_matcher" service --> <framework:cong> <framework:proler> <framework:matcher service="custom_matcher" /> </framework:proler> </framework:cong>
r
// enables the proler only for request coming for the 192.168.0.0 network $container->loadFromExtension('framework', array( 'proler' => array( 'matcher' => array('ip' => '192.168.0.0/24'), ), )); // enables the proler only for the /admin URLs $container->loadFromExtension('framework', array( 'proler' => array( 'matcher' => array('path' => '^/admin/'), ), )); // combine rules $container->loadFromExtension('framework', array( 'proler' => array( 'matcher' => array('ip' => '192.168.0.0/24', 'path' => '^/admin/'), ), )); # use a custom matcher instance dened in the "custom_matcher" service $container->loadFromExtension('framework', array( 'proler' => array( 'matcher' => array('service' => 'custom_matcher'), ),
SFIUF snternls QQQ
));
row to use the ro(ler in puntionl est row to rete ustom ht golletor row to extend glss without using snheritne row to ustomize wethod fehvior without using snheritne
es puli ymfonyP @ AD X
Y Y @ A Y D F
F es F he stle es is sed on whitelistD tgged with dpiF hereforeD everything not tgged expliitly is not prt of the stle esF X esF es of ymfony PFHD the following omponents hve puli tgged esX
pinder rttppoundtion rttpuernel vole roess outing emplting rnsltion lidtor ml ymfonyP r ymfonyP versus plt r snstlling nd gon(guring ymfony ymfonyP gontroller outing greting nd using empltes hotrine @A eurity r ghe rnsltions ervie gontiner erformne snternls es ymfonyP ymfonyP r ymfonyP versus plt r
SFIVF es ymfonyP QQS
snstlling nd gon(guring ymfony ymfonyP gontroller outing greting nd using empltes hotrine @A eurity r ghe rnsltions ervie gontiner erformne snternls es ymfonyP
QQT
SF
III
QQU
X hough this entry is spei(lly out gitD the sme generi priniples will pply if you9re storing your projet in uversionF yne you9ve red through ymfonyP nd eome fmilir with using ymfonyD you9ll noEdout e redy to strt your own projetF sn this ookook rtileD you9ll lern the est wy to strt new ymfonyP projet tht9s stored using the git soure ontrol mngement systemF
6.1.1 Initial Project Setup
o get strtedD you9ll need to downlod ymfony nd initilize your lol git repositoryX IF hownlod the ymfonyP tndrd idition without vendorsF PF nzipGuntr the distriutionF st will rete folder lled ymfony with your new projet strutureD on(g (lesD etF enme it to whtever you likeF QF grete new (le lled Fgitignore t the root of your new projet @eFgF next to the deps (leA nd pste the following into itF piles mthing these ptterns will e ignored y gitX
RF gopy ppGon(gGprmetersFini to ppGon(gGprmetersFiniFdistF he prmetersFini (le is ignored y git @see oveA so tht mhineEspei( settings like dtse psswords ren9t ommittedF fy reting the prmetersFiniFdist (leD new developers n quikly lone the projetD opy this (le to prmetersFiniD ustomize itD nd strt developingF SF snitilize your git repositoryX
$ git init
TF edd ll of the initil (les to gitX
$ git add .
UF grete n initil ommit with your strted projetX
ivery ymfony projet uses lrge group of thirdEprty vendor lirriesF fy defultD these lirries re downloded y running the php inGvendors instll sriptF his sript reds from the deps (leD nd downlods the given lirries into the vendorG diretoryF st lso reds depsFlok (leD pinning eh lirry listed there to the ext git ommit hshF sn this setupD the vendors lirries ren9t prt of your git repositoryD not even s sumodulesF snstedD we rely on the deps nd depsFlok (les nd the inGvendors sript to mnge everythingF hose (les re prt of your repositoryD so the neessry versions of eh thirdE prty lirry re versionEontrolled in gitD nd you n use the vendors sript to ring your projet up to dteF
QRH
TF
ymfony houmenttionD PFH henever developer lones projetD heGshe should run the php inGvendors instll sript to ensure tht ll of the needed vendor lirries re downlodedF pgrding ymfony ine ymfony is just group of thirdEprty lirries nd thirdEprty lirries re entirely ontrolled through deps nd depsFlokD upgrding ymfony mens simply upgrding eh of these (les to mth their stte in the ltest ymfony tndrd iditionF yf ourseD if you9ve dded new entries to deps or depsFlokD e sure to reple only the originl prts @iFeF e sure not to lso delete ny of your ustom entriesAF X here is lso php inGvendors updte ommndD ut this hs nothing to do with upgrding your projet nd you will normlly not need to use itF his ommnd is used to freeze the versions of ll of your vendor lirries y reding their urrent stte nd reording it into the depsFlok (leF
endors nd umodules snsted of using the depsD inGvendors system for mnging your vendor lirriesD you my insted hoose to use ntive git sumodulesF here is nothing wrong with this pprohD though the deps system is the o0il wy to solve this prolem nd git sumodules n e di0ult to work with t timesF
6.1.3 Storing your Project on a Remote Server
ou now hve fullyEfuntionl ymfonyP projet stored in gitF roweverD in most sesD you9ll lso wnt to store your projet on remote server oth for kup purposesD nd so tht other developers n ollorte on the projetF he esiest wy to store your projet on remote server is vi qitruF uli repositories re freeD however you will need to py monthly fee to host privte repositoriesF elterntivelyD you n store your git repository on ny server y reting reones repository nd then pushing to itF yne lirry tht helps mnge this is qitoliteF
6.2
TFPF
QRI
ymfony houmenttionD PFH wigfundleD D F D E X IF @ AY PF wigfundleXXixeptionXshow D @F exeptionontroller in the wig refereneAY X D F kernelFexeptionD F F kernelFexeption iventF wigfundleF E D D F F overidingE undleEtempltesF D ED E D X ppGesouresGwigfundleGviewsGixeptionGerrorFhtmlFtwigX
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>An Error Occurred: {{ status_text }}</title> </head> <body> <h1>Oops! An Error Occurred</h1> <h2>The server returned a "{{ status_code }} {{ status_text }}".</h2> </body> </html>
X wig9D F wig E D D ymfonyPF por more informtion out wig see greting nd using empltesF rwv D ymfony D tyx @errorFjsonFtwigAD wvD @errorFxmlFtwigAD tvsript @errorFjsFtwigAF F D E QRP TF
sn the ookD you9ve lerned how esily ontroller n e used when it extends the se ymfonyfundleprmeworkfundlegontrollergontroller lssF hile this works (neD ontrollers n lso e spei(ed s serviesF
QRQ
ymfony houmenttionD PFH o refer to ontroller tht9s de(ned s servieD use the single olon @XA nottionF por exmpleD suppose we9ve de(ned servie lled myontroller nd we wnt to forwrd to method lled indexetion@A inside the servieX
ometimesD you wnt to seure some routes nd e sure tht they re lwys essed vi the r protoolF he outing omponent llows you to enfore the r sheme vi the sheme requirementX
ewv
QRR
TF
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="secure" pattern="/secure"> <default key="_controller">AcmeDemoBundle:Main:secure</default> <requirement key="_scheme">https</requirement> </route> </routes>
r
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('secure', new Route('/secure', array( '_controller' => 'AcmeDemoBundle:Main:secure', ), array( '_scheme' => 'https', ))); return $collection;
he ove on(gurtion fores the seure route to lwys use rF hen generting the seure vD nd if the urrent sheme is rD ymfony will utomtilly generte n solute v with r s the shemeX
# If the current scheme is HTTPS {{ path('secure') }} # generates /secure # If the current scheme is HTTP {{ path('secure') }} # generates https://example.com/secure
he requirement is lso enfored for inoming requestsF sf you try to ess the Gseure pth with rD you will utomtilly e redireted to the sme vD ut with the r shemeF he ove exmple uses https for the shemeD ut you n lso fore v to lwys use httpF X he eurity omponent provides nother wy to enfore the r sheme vi the requireshnnel settingF his lterntive method is etter suited to seure n re of your wesite @ll vs under GdminA or when you wnt to seure vs de(ned in third prty undleF TFRF row to fore routes to lwys use r QRS
ometimesD you need to ompose vs with prmeters tht n ontin slsh GF por exmpleD tke the lssi GhelloG{nme} routeF fy defultD GhelloGpien will mth this route ut not GhelloGpienGurisF his is euse ymfony uses this hrter s seprtor etween route prtsF his guide overs how you n modify route so tht GhelloGpienGuris mthes the GhelloG{nme} routeD where {nme} equls pienGurisF
6.5.1 Congure the Route
fy defultD the symfony routing omponents requires tht the prmeters mth the following regex ptternX GCF his mens tht ll hrters re llowed exept GF ou must expliitly llow G to e prt of your prmeter y speifying more permissive regex ptternF
ewv
<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing <route id="_hello" pattern="/hello/{name}"> <default key="_controller">AcmeDemoBundle:Demo:hello</default> <requirement key="name">.+</requirement> </route> </routes>
r
$collection = new RouteCollection(); $collection->add('_hello', new Route('/hello/{name}', array( '_controller' => 'AcmeDemoBundle:Demo:hello', ), array( 'name' => '.+', ))); return $collection;
ennottions
use Sensio\Bundle\FrameworkExtraBundle\Conguration\Route; class DemoController { /** * @Route("/hello/{name}", name="_hello", requirements={"name" = ".+"}) */ public function helloAction($name) { // ... } }
ht9s it3 xowD the {nme} prmeter n ontin the G hrterF
esseti is powerful sset mngement lirry whih is pkged with the ymfonyP tndrd idition nd n e esily used in ymfonyP diretly from wig or r templtesF esseti omines two mjor idesX ssets nd (ltersF he ssets re (les suh s gD tvript nd imges (lesF he (lters re things tht n e pplied to these (les efore they re served to the rowserF his llows seprtion etween the sset (les stored in the pplition nd the (les tully presented to the userF ithout essetiD you just serve the (les tht re stored in the pplition diretlyX
wig
ymfony houmenttionD PFH fut with essetiD you n mnipulte these ssets however you wnt @or lod them from nywhereA efore serving themF hese mens you nX
winify nd omine ll of your g nd t (les un ll @or just someA of your g or t (les through some sort of ompilerD suh s viD e or go'eeript un imge optimiztions on your imges
6.6.1 Assets
sing esseti provides mny dvntges over diretly serving the (lesF he (les do not need to e stored where they re served from nd n e drwn from vrious soures suh s from within undleX
wig
<?php foreach ($view['assetic']->javascripts( array('@AcmeFooBundle/Resources/public/js/*')) as $url): ?> <script type="text/javascript" src="<?php echo $view->escape($url) ?>"></script> <?php endforeach; ?>
sn this exmpleD ll of the (les in the esouresGpuliGjsG diretory of the emepoofundle will e loded nd served from di'erent lotionF he tul rendered tg might simply look likeX `sript sraGjsGdIPQFjsb`Gsriptb ou n lso omine severl (les into oneF his helps to redue the numer of r requests whih is good for front end performneD s most rowsers will only proess limited numer t time slowing down pge lod timesF st lso llows you to mintin the (les more esily y splitting them into mngele prtsF his n lso help with reEusility s you n esily split projet spei( (les from those whih n e used in other pplitions ut still serve them s single (leX
wig
<?php foreach ($view['assetic']->javascripts( array('@AcmeFooBundle/Resources/public/js/*', '@AcmeBarBundle/Resources/public/js/form.js', '@AcmeBarBundle/Resources/public/js/calendar.js')) as $url): ?> <script src="<?php echo $view->escape($url) ?>"></script> <?php endforeach; ?>
his does not only pply to your own (les you n lso use esseti to omine third prty ssetsD suh s juery with your own into single (leX
wig
<?php foreach ($view['assetic']->javascripts( array('@AcmeFooBundle/Resources/public/js/thirdparty/jquery.js', '@AcmeFooBundle/Resources/public/js/*')) as $url): ?> <script src="<?php echo $view->escape($url) ?>"></script> <?php endforeach; ?>
6.6.2 Filters
edditionlly to this esseti n pply (lters to the ssets efore they re servedF his inludes tsks suh s ompressing the output for smller (le sizes whih is nother vlule front end optimistionF yther (lters inlude ompiling tvript (le from go'eeript (les nd e to gF wny of the (lters do not do the work diretly ut use other lirries to do itD this so you will often hve to instll tht softwre s wellF he gret dvntge of using esseti to invoke these lirries is tht insted of hving to run them mnully when you hve worked on the (lesD esseti will tke re of this for you nd remove this step ltogether from your development nd deployment proessesF o use (lter you must speify it in the esseti on(gurtion s they re not enled y defultF por exmple to use the tvript s gompressor the following on(g needs to e ddedX TFTF row to se esseti for esset wngement QRW
ewv
// app/cong/cong.php $container->loadFromExtension('assetic', array( 'lters' => array( 'yui_js' => array( 'jar' => '%kernel.root_dir%/Resources/java/yuicompressor.jar', ), ), ));
ou n then speify using the (lter in the templteX
wig
<?php foreach ($view['assetic']->javascripts( array('@AcmeFooBundle/Resources/public/js/*'), array('yui_js')) as $url): ?> <script src="<?php echo $view->escape($url) ?>"></script> <?php endforeach; ?>
e more detil guide to on(guring nd using esseti (lters s well s detils of esseti9s deug mode n e found in row to winify tvripts nd tylesheets with s gompressorF
QSH
TF
sf you wish to you n ontrol the vs whih esseti produesF his is done from the templte nd is reltive to the puli doument rootX
wig
<?php foreach ($view['assetic']->javascripts( array('@AcmeFooBundle/Resources/public/js/*'), array(), array('output' => 'js/combined.js') ) as $url): ?> <script src="<?php echo $view->escape($url) ?>"></script> <?php endforeach; ?>
X ymfony lso ontins method for he ustingD where the (nl v generted y esseti in the prod environment ontins query prmeter tht n e inremented vi on(gurtion on eh deploymentF por more informtionD see the ssetsversion on(gurtion optionF
he proess of reting the (les served up n e quite slow espeilly when using some of the (lters whih invoke third prty softwre to the tul workF iven when working in the development environment the slow down in the pge lods if this ws to e done eh time would quikly get frustrtingF portuntely in the dev environment esseti hes the output so this will not hppenD rther thn hving to ler the he mnully thoughD it monitors for hnges to the ssets nd regenertes the (les s neededF his mens you n work on the sset (les nd see the results on pge lod ut without hving to su'er ontinul slow pge lodsF por produtionD where you will not e mking hnges to the sset (lesD performne n e inresed y voiding the step of heking for hngesF esseti llows you to go further thn this nd void touhing ymfonyP nd even r t ll when serving the (lesF his is done y dumping ll of the output (les using onsole ommndF hese n then e served diretly y the we server s stti (lesD inresing performne nd llowing the we server to del with hing hedersF he onsole ommnd to dump the (les isX TFTF row to se esseti for esset wngement QSI
6.7 How
to
Minify
JavaScripts
and
Stylesheets
with
YUI
Compressor
hoo3 provides n exellent utility for minifying tvripts nd stylesheets so they trvel over the wire fsterD the s gompressorF hnks to essetiD you n tke dvntge of this tool very esilyF
6.7.1 Download the YUI Compressor JAR
he s gompressor is written in tv nd distriuted s teF hownlod the te from the hoo3 site nd sve it to ppGesouresGjvGyuiompressorFjrF
6.7.2 Congure the YUI Filters
xow you need to on(gure two esseti (lters in your pplitionD one for minifying tvripts with the s gompressor nd one for minifying stylesheetsX
ewv
// app/cong/cong.php $container->loadFromExtension('assetic', array( 'lters' => array( 'yui_css' => array( 'jar' => '%kernel.root_dir%/Resources/java/yuicompressor.jar', ), 'yui_js' => array( 'jar' => '%kernel.root_dir%/Resources/java/yuicompressor.jar', ), ), ));
ou now hve ess to two new esseti (lters in your pplitionX yuiss nd yuijsF hese will use the s gompressor to minify stylesheets nd tvriptsD respetivelyF
6.7.3 Minify your Assets
ou hve s gompressor on(gured nowD ut nothing is going to hppen until you pply one of these (lters to n ssetF ine your ssets re prt of the view lyerD this work is done in your templtesX
wig
<?php foreach ($view['assetic']->javascripts( array('@AcmeFooBundle/Resources/public/js/*'), array('yui_js')) as $url): ?> <script src="<?php echo $view->escape($url) ?>"></script> <?php endforeach; ?>
X he ove exmple ssumes tht you hve undle lled emepoofundle nd your tvript (les re in the esouresGpuliGjs diretory under your undleF his isn9t importnt however E you n inlude your tvsript (les no mtter where they reF
QSQ
ymfony houmenttionD PFH ith the ddition of the yuijs (lter to the sset tgs oveD you should now see mini(ed tvripts oming over the wire muh fsterF he sme proess n e repeted to minify your stylesheetsF
wig
{% stylesheets '@AcmeFooBundle/Resources/public/css/*' lter='yui_css' %} <link rel="stylesheet" type="text/css" media="screen" href="{{ asset_url }}" /> {% endstylesheets %}
r
<?php foreach ($view['assetic']->stylesheets( array('@AcmeFooBundle/Resources/public/css/*'), array('yui_css')) as $url): ?> <link rel="stylesheet" type="text/css" media="screen" href="<?php echo $view->escape($url) ?>" /> <?php endforeach; ?>
wini(ed tvripts nd tylesheets re very di0ult to redD let lone deugF feuse of thisD esseti lets you disle ertin (lter when your pplition is in deug modeF ou n do this e pre(xing the (lter nme in your templte with question mrkX cF his tells esseti to only pply this (lter when deug mode is o'F
wig
<?php foreach ($view['assetic']->javascripts( array('@AcmeFooBundle/Resources/public/js/*'), array('?yui_js')) as $url): ?> <script src="<?php echo $view->escape($url) ?>"></script> <?php endforeach; ?>
6.8 How
to
Use
Assetic
For
Image
Optimization
with
Twig
Functions
emongst its mny (ltersD esseti hs four (lters whih n e used for onEtheE)y imge optimiztionF his llows you to get the ene(ts of smller (le sizes without hving to QSR TF
ymfony houmenttionD PFH use n imge editor to proess eh imgeF he results re hed nd n e dumped for prodution so there is no performne hit for your end usersF
6.8.1 Using Jpegoptim
tpegoptim is utility for optimizing tiq (lesF o use it with essetiD dd the following to the esseti on(gX
ewv
// app/cong/cong.php $container->loadFromExtension('assetic', array( 'lters' => array( 'jpegoptim' => array( 'bin' => 'path/to/jpegoptim', ), ), ));
X xotie tht to use jpegoptimD you must hve it lredy instlled on your systemF he in option points to the lotion of the ompiled inryF st n now e used from templteX
wig
<?php foreach ($view['assetic']->images( array('@AcmeFooBundle/Resources/public/images/example.jpg'), array('jpegoptim')) as $url): ?> <img src="<?php echo $view->escape($url) ?>" alt="Example"/> <?php endforeach; ?>
emoving ll isp ht fy defultD running this (lter only removes some of the met informtion stored in the (leF eny isp dt nd omments re not removedD ut you n remove these y using the stripll optionX
ewv
<!-- app/cong/cong.xml --> <assetic:cong> <assetic:lter name="jpegoptim" bin="path/to/jpegoptim" strip_all="true" /> </assetic:cong>
r
// app/cong/cong.php $container->loadFromExtension('assetic', array( 'lters' => array( 'jpegoptim' => array( 'bin' => 'path/to/jpegoptim', 'strip_all' => 'true', ), ), ));
QST TF
ymfony houmenttionD PFH vowering wximum ulity he qulity level of the tiq is not 'eted y defultF ou n gin further (le size redutions y setting the mx qulity setting lower thn the urrent level of the imgesF his will of ourse e t the expense of imge qulityX
ewv
<!-- app/cong/cong.xml --> <assetic:cong> <assetic:lter name="jpegoptim" bin="path/to/jpegoptim" max="70" /> </assetic:cong>
r
// app/cong/cong.php $container->loadFromExtension('assetic', array( 'lters' => array( 'jpegoptim' => array( 'bin' => 'path/to/jpegoptim', 'max' => '70', ), ), ));
sf you9re using wigD it9s possile to hieve ll of this with shorter syntx y enling nd using speil wig funtionF trt y dding the following on(gX
ewv
<!-- app/cong/cong.xml --> <assetic:cong> <assetic:lter name="jpegoptim" bin="path/to/jpegoptim" /> <assetic:twig> <assetic:twig_function name="jpegoptim" /> </assetic:twig> </assetic:cong>
r
// app/cong/cong.php $container->loadFromExtension('assetic', array( 'lters' => array( 'jpegoptim' => array( 'bin' => 'path/to/jpegoptim', ), ), 'twig' => array( 'functions' => array('jpegoptim'), ), ), ));
he wig templte n now e hnged to the followingX
ewv
<!-- app/cong/cong.xml --> <assetic:cong> <assetic:lter name="jpegoptim" bin="path/to/jpegoptim" /> <assetic:twig> <assetic:twig_function name="jpegoptim" output="images/*.jpg" /> </assetic:twig> </assetic:cong>
r
// app/cong/cong.php $container->loadFromExtension('assetic', array( 'lters' => array( 'jpegoptim' => array( 'bin' => 'path/to/jpegoptim', ), ), 'twig' => array( 'functions' => array( 'jpegoptim' => array( output => 'images/*.jpg' ), ), ), ));
esseti (lters n e pplied to individul (lesD groups of (les or evenD s you9ll see hereD (les tht hve spei( extensionF o show you how to hndle eh optionD let9s suppose tht you wnt to use esseti9s go'eeript (lterD whih ompiles go'eeript (les into tvsriptF he min on(gurtion is just the pths to o'ee nd nodeF hese defult respetively to GusrGinGo'ee nd GusrGinGnodeX
ewv
TFWF row to epply n esseti pilter to pei( pile ixtension QSW
<!-- app/cong/cong.xml --> <assetic:cong> <assetic:lter name="coee" bin="/usr/bin/coee" node="/usr/bin/node" /> </assetic:cong>
r
// app/cong/cong.php $container->loadFromExtension('assetic', array( 'lters' => array( 'coee' => array( 'bin' => '/usr/bin/coee', 'node' => '/usr/bin/node', ), ), ));
ou n now serve up single go'eeript (le s tvript from within your templtesX
wig
wig
<?php foreach ($view['assetic']->javascripts( array('@AcmeFooBundle/Resources/public/js/example.coee', '@AcmeFooBundle/Resources/public/js/another.coee'), array('coee')) as $url): ?> <script src="<?php echo $view->escape($url) ?>" type="text/javascript"></script> <?php endforeach; ?>
foth the (les will now e served up s single (le ompiled into regulr tvriptF
6.9.3 Filtering based on a File Extension
yne of the gret dvntges of using esseti is reduing the numer of sset (les to lower r requestsF sn order to mke full use of thisD it would e good to omine ll your tvript nd go'eeript (les together sine they will ultimtely ll e served s tvriptF nfortuntely just dding the tvript (les to the (les to e omined s ove will not work s the regulr tvript (les will not survive the go'eeript ompiltionF his prolem n e voided y using the pplyto option in the on(gD whih llows you to speify tht (lter should lwys e pplied to prtiulr (le extensionsF sn this se you n speify tht the go'ee (lter is pplied to ll Fo'ee (lesX
ewv
# app/cong/cong.yml assetic:
TFWF row to epply n esseti pilter to pei( pile ixtension QTI
<!-- app/cong/cong.xml --> <assetic:cong> <assetic:lter name="coee" bin="/usr/bin/coee" node="/usr/bin/node" apply_to="\.coee$" /> </assetic:cong>
r
// app/cong/cong.php $container->loadFromExtension('assetic', array( 'lters' => array( 'coee' => array( 'bin' => '/usr/bin/coee', 'node' => '/usr/bin/node', 'apply_to' => '\.coee$', ), ), ));
ith thisD you no longer need to speify the o'ee (lter in the templteF ou n lso list regulr tvript (lesD ll of whih will e omined nd rendered s single tvript (le @with only the Fo'ee (les eing run through the go'eeript (lterAX
wig
'@AcmeFooBundle/Resources/public/js/regular.js'), as $url): ?> <script src="<?php echo $view->escape($url) ?>" type="text/javascript"></script> <?php endforeach; ?>
rndling (le uplods with hotrine entities is no di'erent thn hndling ny other (le uplodF sn other wordsD you9re free to move the (le in your ontroller fter hndling form sumissionF por exmples of how to do thisD see the (le type referene pgeF sf you hoose toD you n lso integrte the (le uplod into your entity lifeyle @iFeF retionD updte nd removlAF sn this seD s your entity is retedD updtedD nd removed from hotrineD the (le uploding nd removl proessing will tke ple utomtilly @without needing to do nything in your ontrollerAY o mke this workD you9ll need to tke re of numer of detilsD whih will e overed in this ookook entryF
6.10.1 Basic Setup
// src/Acme/DemoBundle/Entity/Document.php namespace Acme\DemoBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\Entity */ class Document { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ public $id; /** * @ORM\Column(type="string", length=255) * @Assert\NotBlank
TFIHF row to hndle pile plods with hotrine QTQ
*/ public $name; /** * @ORM\Column(type="string", length=255, nullable=true) */ public $path; public function getAbsolutePath() { return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path; } public function getWebPath() { return null === $this->path ? null : $this->getUploadDir().'/'.$this->path; } protected function getUploadRootDir() { // the absolute directory path where uploaded documents should be saved return __DIR__.'/../../../../web/'.$this->getUploadDir(); } protected function getUploadDir() { // get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view. return 'uploads/documents'; }
he houment entity hs nme nd it is ssoited with (leF he pth property stores the reltive pth to the (le nd is persisted to the dtseF he getesoluteth@A is onveniene method tht returns the solute pth to the (le while the geteth@A is onveniene method tht returns the we pthD whih n e used in templte to link to the uploded (leF X sf you hve not done so lredyD you should proly red the (le type doumenttion (rst to understnd how the si uplod proess worksF
X sf you9re using nnottions to speify your nnottion rules @s shown in this exmpleAD e sure tht you9ve enled vlidtion y nnottion @see vlidtion on(gurtionAF o hndle the tul (le uplod in the formD use virtul (le (eldF por exmpleD if you9re QTR TF
ymfony houmenttionD PFH uilding your form diretly in ontrollerD it might look like thisX
public function uploadAction() { // ... $form = $this->createFormBuilder($document) ->add('name') ->add('le') ->getForm() ; } // ...
xextD rete this property on your houment lss nd dd some vlidtion rulesX
X es you re using the pile onstrintD ymfonyP will utomtilly guess tht the form (eld is (le uplod inputF ht9s why you did not hve to set it expliitly when reting the form ove @Ebdd@9(le9AAF he following ontroller shows you how to hndle the entire proessX
use Acme\DemoBundle\Entity\Document; use Sensio\Bundle\FrameworkExtraBundle\Conguration\Template; // ... /** * @Template() */ public function uploadAction() { $document = new Document(); $form = $this->createFormBuilder($document)
TFIHF row to hndle pile plods with hotrine QTS
if ($this->getRequest()->getMethod() === 'POST') { $form->bindRequest($this->getRequest()); if ($form->isValid()) { $em = $this->getDoctrine()->getEntityManager(); $em->persist($document); $em->ush(); } $this->redirect($this->generateUrl('...'));
} }
X hen writing the templteD don9t forget to set the entype ttriuteX
<h1>Upload File</h1> <form action="#" method="post" {{ form_enctype(form) }}> {{ form_widget(form) }} <input type="submit" value="Upload Document" /> </form>
he previous ontroller will utomtilly persist the houment entity with the sumitted nmeD ut it will do nothing out the (le nd the pth property will e lnkF en esy wy to hndle the (le uplod is to move it just efore the entity is persisted nd then set the pth property ordinglyF trt y lling new uplod@A method on the houment lssD whih you9ll rete in moment to hndle the (le uplodX
}
he uplod@A method will tke dvntge of the ymfonygomponentrttppoundtionpileplodedpile ojetD whih is wht9s returned fter (le (eld is sumittedX
public function upload() { // the le property can be empty if the eld is not required if (null === $this->le) { return; } // we use the original le name here but you should // sanitize it at least to avoid any security issues // move takes the target directory and then the target lename to move to $this->le->move($this->getUploadRootDir(), $this->le->getClientOriginalName()); // set the path property to the lename where you'ved saved the le $this->setPath($this->le->getClientOriginalName()); // clean up the le property as you won't need it anymore $this->le = null;
iven if this implementtion worksD it su'ers from mjor )wX ht if there is prolem when the entity is persistedc he (le would hve lredy moved to its (nl lotion even though the entity9s pth property didn9t persist orretlyF o void these issuesD you should hnge the implementtion so tht the dtse opertion nd the moving of the (le eome tomiX if there is prolem persisting the entity or if the (le nnot e movedD then nothing should hppenF o do thisD you need to move the (le right s hotrine persists the entity to the dtseF his n e omplished y hooking into n entity lifeyle llkX
QTU
ymfony houmenttionD PFH xextD reftor the houment lss to tke dvntge of these llksX
use Symfony\Component\HttpFoundation\File\UploadedFile; /** * @ORM\Entity * @ORM\HasLifecycleCallbacks */ class Document { /** * @ORM\PrePersist() * @ORM\PreUpdate() */ public function preUpload() { if (null !== $this->le) { // do whatever you want to generate a unique name $this->setPath(uniqid().'.'.$this->le->guessExtension()); } } /** * @ORM\PostPersist() * @ORM\PostUpdate() */ public function upload() { if (null === $this->le) { return; } // you must throw an exception here if the le cannot be moved // so that the entity is not persisted to the database // which the UploadedFile move() method does automatically $this->le->move($this->getUploadRootDir(), $this->path); } unset($this->le);
he lss now does everything you needX it genertes unique (lenme efore persistingD moves the (le fter persistingD nd removes the (le if the entity is ever deletedF X he dywreersist@A nd dywostersist@A event llks re triggered efore nd fter the entity is persisted to the dtseF yn the other hndD the dywrepdte@A nd dywostpdte@A event llks re lled when the entity is updtedF X he repdte nd ostpdte llks re only triggered if there is hnge in one of the entity9s (eld tht re persistedF his mens thtD y defultD if you modify only the 6(le propertyD these events will not e triggeredD s the property itself is not diretly persisted vi hotrineF yne solution would e to use n updted (eld tht9s persisted to hotrineD nd to modify it mnully when hnging the (leF
sf you wnt to use the id s the nme of the (leD the implementtion is slightly di'erent s you need to sve the extension under the pth propertyD insted of the tul (lenmeX
use Symfony\Component\HttpFoundation\File\UploadedFile; /** * @ORM\Entity * @ORM\HasLifecycleCallbacks */ class Document { /** * @ORM\PrePersist() * @ORM\PreUpdate() */ public function preUpload() { if (null !== $this->le) { $this->setPath($this->le->guessExtension()); } } /** * @ORM\PostPersist()
TFIHF row to hndle pile plods with hotrine QTW
* @ORM\PostUpdate() */ public function upload() { if (null === $this->le) { return; } // you must throw an exception here if the le cannot be moved // so that the entity is not persisted to the database // which the UploadedFile move() method does $this->le->move($this->getUploadRootDir(), $this->id.'.'.$this->le->guessExtension()); } unset($this->le);
/** * @ORM\PostRemove() */ public function removeUpload() { if ($le = $this->getAbsolutePath()) { unlink($le); } } public function getAbsolutePath() { return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->id.'.'.$this->path; }
6.11 Doctrine
Extensions:
Timestampable:
Sluggable,
Translatable, etc.
hotrineP is very )exileD nd the ommunity hs lredy reted series of useful hotrine extensions to help you with tsks ommon entityErelted tsksF yne undle in prtiulr E the hotrineixtensionsfundle E provides integrtion with n extensions lirry tht o'ers luggleD rnsltleD imestmpleD voggleD nd ree ehviorsF ee the undle for more detilsF
QUH
TF
hotrine pkges rih event system tht (res events when lmost nything hppens inside the systemF por youD this mens tht you n rete ritrry servies nd tell hotrine to notify those ojets whenever ertin tion @eFgF preveA hppens within hotrineF his ould e usefulD for exmpleD to rete n independent serh index whenever n ojet in your dtse is svedF hotrine de(nes two types of ojets tht n listen to hotrine eventsX listeners nd susriersF foth re very similrD ut listeners re it more strightforwrdF por moreD see he ivent ystem on hotrine9s wesiteF
6.12.1 Conguring the Listener/Subscriber
o register servie to t s n event listener or susrier you just hve to tg it with the pproprite nmeF hepending on your useEseD you n hook listener into every hfev onnetion nd yw entity mnger or just into one spei( hfev onnetion nd ll the entity mngers tht use this onnetionF
ewv
doctrine: dbal: default_connection: default connections: default: driver: pdo_sqlite memory: true services: my.listener: class: Acme\SearchBundle\Listener\SearchIndexer tags: - { name: doctrine.event_listener, event: postSave } my.listener2: class: Acme\SearchBundle\Listener\SearchIndexer2 tags: - { name: doctrine.event_listener, event: postSave, connection: default } my.subscriber: class: Acme\SearchBundle\Listener\SearchIndexerSubsriber tags: - { name: doctrine.event_subscriber, connection: default }
wv
QUI
<?xml version="1.0" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:doctrine="http://symfony.com/schema/dic/doctrine"> <doctrine:cong> <doctrine:dbal default-connection="default"> <doctrine:connection driver="pdo_sqlite" memory="true" /> </doctrine:dbal> </doctrine:cong> <services> <service id="my.listener" class="Acme\SearchBundle\Listener\SearchIndexer"> <tag name="doctrine.event_listener" event="postSave" /> </service> <service id="my.listener2" class="Acme\SearchBundle\Listener\SearchIndexer2"> <tag name="doctrine.event_listener" event="postSave" connection="default" /> </service> <service id="my.subscriber" class="Acme\SearchBundle\Listener\SearchIndexerSubsriber"> <tag name="doctrine.event_subscriber" connection="default" /> </service> </services> </container>
sn the previous exmpleD servie myFlistener ws on(gured s hotrine listener on the event postveF ht lss ehind tht servie must hve postve methodD whih will e lled when the event is thrownX
// src/Acme/SearchBundle/Listener/SearchIndexer.php namespace Acme\SearchBundle\Listener; use Doctrine\ORM\Event\LifecycleEventArgs; use Acme\StoreBundle\Entity\Product; class SearchIndexer { public function postSave(LifecycleEventArgs $args) { $entity = $args->getEntity(); $entityManager = $args->getEntityManager(); // perhaps you only want to act on some "Product" entity if ($entity instanceof Product) { // do something with the Product
QUP TF
sn eh eventD you hve ess to vifeyleiventergs ojetD whih gives you ess to oth the entity ojet of the event nd the entity mnger itselfF yne importnt thing to notie is tht listener will e listening for ll entities in your pplitionF oD if you9re interested in only hndling spei( type of entity @eFgF rodut entity ut not flogost entityAD you should hek for the lss nme of the entity in your method @s shown oveAF
hen strting work on rnd new projet tht uses dtseD two di'erent situtions omes nturllyF sn most sesD the dtse model is designed nd uilt from srthF ometimesD howeverD you9ll strt with n existing nd proly unhngele dtse modelF portuntelyD hotrine omes with unh of tools to help generte model lsses from your existing dtseF X es the hotrine tools doumenttion sysD reverse engineering is oneEtime proess to get strted on projetF hotrine is le to onvert pproximtely UHEVH7 of the neessry mpping informtion sed on (eldsD indexes nd foreign key onstrintsF hotrine n9t disover inverse ssoitionsD inheritne typesD entities with foreign keys s primry keys or semntil opertions on ssoitions suh s sde or lifeyle eventsF ome dditionl work on the generted entities will e neessry fterwrds to design eh to (t your domin model spei(itiesF his tutoril ssumes you9re using simple log pplition with the following two tlesX logpost nd logommentF e omment reord is linked to post reord thnks to foreign key onstrintF
CREATE TABLE `blog_post` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `title` varchar(100) COLLATE utf8_unicode_ci NOT NULL, `content` longtext COLLATE utf8_unicode_ci NOT NULL, `created_at` datetime NOT NULL, PRIMARY KEY (`id`), ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE `blog_comment` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `post_id` bigint(20) NOT NULL,
TFIQF row to generte intities from n ixisting htse QUQ
`author` varchar(20) COLLATE utf8_unicode_ci NOT NULL, `content` longtext COLLATE utf8_unicode_ci NOT NULL, `created_at` datetime NOT NULL, PRIMARY KEY (`id`), KEY `blog_comment_post_id_idx` (`post_id`), CONSTRAINT `blog_post_id` FOREIGN KEY (`post_id`) REFERENCES `blog_post` (`id`) ON DELETE CA ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
fefore diving into the reipeD e sure your dtse onnetion prmeters re orretly setup in the ppGon(gGprmetersFini (le @or wherever your dtse on(gurtion is keptA nd tht you hve initilized undle tht will host your future entity lssF sn this tutorilD we will ssume tht n emeflogfundle exists nd is loted under the srGemeGflogfundle folderF he (rst step towrds uilding entity lsses from n existing dtse is to sk hotrine to introspet the dtse nd generte the orresponding metdt (lesF wetdt (les desrie the entity lss to generte sed on tles (eldsF
<?xml version="1.0" encoding="utf-8"?> <doctrine-mapping> <entity name="BlogPost" table="blog_post"> <change-tracking-policy>DEFERRED_IMPLICIT</change-tracking-policy> <id name="id" type="bigint" column="id"> <generator strategy="IDENTITY"/> </id> <eld name="title" type="string" column="title" length="100"/> <eld name="content" type="text" column="content"/> <eld name="isPublished" type="boolean" column="is_published"/> <eld name="createdAt" type="datetime" column="created_at"/> <eld name="updatedAt" type="datetime" column="updated_at"/> <eld name="slug" type="string" column="slug" length="255"/> <lifecycle-callbacks/> </entity> </doctrine-mapping>
yne the metdt (les re genertedD you n sk hotrine to import the shem nd uild QUR TF
ymfony houmenttionD PFH relted entity lsses y exeuting the following two ommndsF
<?php // src/Acme/BlogBundle/Entity/BlogComment.php namespace Acme\BlogBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * Acme\BlogBundle\Entity\BlogComment * * @ORM\Table(name="blog_comment") * @ORM\Entity */ class BlogComment { /** * @var bigint $id * * @ORM\Column(name="id", type="bigint", nullable=false) * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") */ private $id; /** * @var string $author * * @ORM\Column(name="author", type="string", length=100, nullable=false) */ private $author; /** * @var text $content * * @ORM\Column(name="content", type="text", nullable=false) */ private $content; /**
TFIQF row to generte intities from n ixisting htse QUS
* @var datetime $createdAt * * @ORM\Column(name="created_at", type="datetime", nullable=false) */ private $createdAt; /** * @var BlogPost * * @ORM\ManyToOne(targetEntity="BlogPost") * @ORM\JoinColumn(name="post_id", referencedColumnName="id") */ private $post;
es you n seeD hotrine onverts ll tle (elds to pure privte nd nnotted lss propertiesF he most impressive thing is tht it lso disovered the reltionship with the flogost entity lss sed on the foreign key onstrintF gonsequentlyD you n (nd privte 6post property mpped with flogost entity in the floggomment entity lssF he lst ommnd generted ll getters nd setters for your two flogost nd floggomment entity lss propertiesF he generted entities re now redy to e usedF rve fun3
X his rtile is out hotrine hfev9s lyerF ypillyD you9ll work with the higher level hotrine yw lyerD whih simply uses the hfev ehind the senes to tully ommunite with the dtseF o red more out the hotrine ywD see hotrine @AF he hotrine htse estrtion vyer @hfevA is n strtion lyer tht sits on top of hy nd o'ers n intuitive nd )exile es for ommuniting with the most populr reltionl dtsesF sn other wordsD the hfev lirry mkes it esy to exeute queries nd perform other dtse tionsF X ed the o0il hotrine hfev houmenttion to lern ll the detils nd pilities of hotrine9s hfev lirryF o get strtedD on(gure the dtse onnetion prmetersX
ewv
QUT
TF
# app/cong/cong.yml doctrine: dbal: driver: pdo_mysql dbname: Symfony2 user: root password: null charset: UTF8
wv
// app/cong/cong.xml <doctrine:cong> <doctrine:dbal name="default" dbname="Symfony2" user="root" password="null" driver="pdo_mysql" /> </doctrine:cong>
r
// app/cong/cong.php $container->loadFromExtension('doctrine', array( 'dbal' => array( 'driver' => 'pdo_mysql', 'dbname' => 'Symfony2', 'user' => 'root', 'password' => null, ), ));
por full hfev on(gurtion optionsD see hotrine hfev gon(gurtionF ou n then ess the hotrine hfev onnetion y essing the dtseonnetion servieX
class UserController extends Controller { public function indexAction() { $conn = $this->get('database_connection'); $users = $conn->fetchAll('SELECT * FROM users'); } // ...
QUU
ou n register ustom mpping types through ymfony9s on(gurtionF hey will e dded to ll on(gured onnetionsF por more informtion on ustom mpping typesD red hotrine9s gustom wpping ypes setion of their doumenttionF
ewv
<!-- app/cong/cong.xml --> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:doctrine="http://symfony.com/schema/dic/doctrine" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctrine/doct <doctrine:cong> <doctrine:dbal> <doctrine:dbal default-connection="default"> <doctrine:connection> <doctrine:mapping-type name="enum">string</doctrine:mapping-type> </doctrine:connection> </doctrine:dbal> </doctrine:cong> </container>
r
// app/cong/cong.php $container->loadFromExtension('doctrine', array( 'dbal' => array( 'connections' => array( 'default' => array( 'mapping_types' => array( 'enum' => 'string', ),
QUV TF
));
),
),
),
he hemool is used to inspet the dtse to ompre the shemF o hieve this tskD it needs to know whih mpping type needs to e used for eh dtse typesF egistering new ones n e done through the on(gurtionF vet9s mp the ixw type @not suppoorted y hfev y defultA to the string mpping typeX
ewv
# app/cong/cong.yml doctrine: dbal: connection: default: // Other connections parameters mapping_types: enum: string
wv
<!-- app/cong/cong.xml --> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:doctrine="http://symfony.com/schema/dic/doctrine" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctrine/doct <doctrine:cong> <doctrine:dbal> <doctrine:type name="custom_rst" class="Acme\HelloBundle\Type\CustomFirst" /> <doctrine:type name="custom_second" class="Acme\HelloBundle\Type\CustomSecond" /> </doctrine:dbal> </doctrine:cong> </container>
r
));
),
ou n use multiple entity mngers in ymfonyP pplitionF his is neessry if you re using di'erent dtses or even vendors with entirely di'erent sets of entitiesF sn other wordsD one entity mnger tht onnets to one dtse will hndle some entities while nother entity mnger tht onnets to nother dtse might hndle the restF X sing multiple entity mngers is pretty esyD ut more dvned nd not usully requiredF fe sure you tully need multiple entity mngers efore dding in this lyer of omplexityF he following on(gurtion ode shows how you n on(gure two entity mngersX
ewv
doctrine: orm: default_entity_manager: default entity_managers: default: connection: default mappings: AcmeDemoBundle: ~ AcmeStoreBundle: ~ customer: connection: customer mappings: AcmeCustomerBundle: ~
sn this seD you9ve de(ned two entity mngers nd lled them defult nd ustomerF he defult entity mnger mnges entities in the emehemofundle nd emetorefundleD while the ustomer entity mnger mnges entities in the emegustomerfundleF hen working with multiple entity mngersD you should e expliit out whih entity mnger you wntF sf you do omit the entity mnger9s nme when sking for itD the defult entity mnger @iFeF defultA is returnedX
QVH
TF
class UserController extends Controller { public function indexAction() { // both return the "default" em $em = $this->get('doctrine')->getEntityManager(); $em = $this->get('doctrine')->getEntityManager('default'); } $customerEm = $this->get('doctrine')->getEntityManager('customer');
ou n now use hotrine just s you did efore E using the defult entity mnger to persist nd feth entities tht it mnges nd the ustomer entity mnger to persist nd feth its entitiesF
hotrine llows you to speify ustom hv funtionsF por more informtion on this topiD red hotrine9s ookook rtile hv ser he(ned puntionsF sn ymfonyD you n register your ustom hv funtions s followsX
ewv
# app/cong/cong.yml doctrine: orm: # ... entity_managers: default: # ... dql: string_functions: test_string: Acme\HelloBundle\DQL\StringFunction second_string: Acme\HelloBundle\DQL\SecondStringFunction numeric_functions: test_numeric: Acme\HelloBundle\DQL\NumericFunction datetime_functions: test_datetime: Acme\HelloBundle\DQL\DatetimeFunction
wv
<doctrine:cong> <doctrine:orm> <!-- ... --> <doctrine:entity-manager name="default"> <!-- ... --> <doctrine:dql> <doctrine:string-function name="test_string>Acme\HelloBundle\DQL\StringFunction</d <doctrine:string-function name="second_string>Acme\HelloBundle\DQL\SecondStringFun <doctrine:numeric-function name="test_numeric>Acme\HelloBundle\DQL\NumericFuncti <doctrine:datetime-function name="test_datetime>Acme\HelloBundle\DQL\DatetimeFun </doctrine:dql> </doctrine:entity-manager> </doctrine:orm> </doctrine:cong> </container>
r
// app/cong/cong.php $container->loadFromExtension('doctrine', array( 'orm' => array( // ... 'entity_managers' => array( 'default' => array( // ... 'dql' => array( 'string_functions' => array( 'test_string' => 'Acme\HelloBundle\DQL\StringFunction', 'second_string' => 'Acme\HelloBundle\DQL\SecondStringFunction', ), 'numeric_functions' => array( 'test_numeric' => 'Acme\HelloBundle\DQL\NumericFunction', ), 'datetime_functions' => array( 'test_datetime' => 'Acme\HelloBundle\DQL\DatetimeFunction', ), ), ), ), ), ));
QVP
TF
ymfony gives you wide vriety of wys to ustomize how form is renderedF sn this guideD you9ll lern how to ustomize every possile prt of your form with s little e'ort s possile whether you use wig or r s your templting engineF
6.17.1 Form Rendering Basics
ell tht the lelD error nd rwv widget of form (eld n esily e rendered y using the formrow wig funtion or the row r helper methodX
wig
{{ form_row(form.age) }}
r
wig
<div> <?php echo $view['form']->label($form['age']) }} ?> <?php echo $view['form']->errors($form['age']) }} ?> <?php echo $view['form']->widget($form['age']) }} ?> </div>
sn oth sesD the form lelD errors nd rwv widget re rendered y using set of mrkup tht ships stndrd with ymfonyF por exmpleD oth of the ove templtes would renderX
<div> <label for="form_age">Age</label> <ul> <li>This eld is required</li> </ul> <input type="number" id="form_age" name="form[age]" /> </div>
TFIUF row to ustomize porm endering QVQ
ymfony houmenttionD PFH o quikly prototype nd test formD you n render the entire form with just one lineX
wig
{{ form_widget(form) }}
r
ymfony uses form frgments E smll piee of templte tht renders just one prt of form E to render every prt of form E E (eld lelsD errorsD input text (eldsD selet tgsD et he frgments re de(ned s loks in wig nd s templte (les in rF e theme is nothing more thn set of frgments tht you wnt to use when rendering formF sn other wordsD if you wnt to ustomize one portion of how form is renderedD you9ll import theme whih ontins ustomiztion of the pproprite form frgmentsF ymfony omes with defult theme @formdivlyoutFhtmlFtwig in wig nd prmeworkfundleXporm in rA tht de(nes eh nd every frgment needed to render every prt of formF sn the next setion you will lern how to ustomize theme y overriding some or ll of its frgmentsF por exmpleD when the widget of integer type (eld is renderedD n input numer (eld is generted
wig
{{ form_widget(form.age) }}
r
QVR
TF
ymfony houmenttionD PFH sn wig tht would defult to the lok integerwidget from the formdivlyoutFhtmlFtwig templteF sn r it would rther e the integerwidgetFhtmlFphp prmeworkfundleGesouresGviewsGporm folderF (le loted in
wig
wig
{% block eld_widget %} {% set type = type|default('text') %} <input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" /> {% endblock eld_widget %}
r
<!-- FrameworkBundle/Resources/views/Form/eld_widget.html.php --> <input type="<?php echo isset($type) ? $view->escape($type) : "text" ?>" value="<?php echo $view->escape($value) ?>" <?php echo $view['form']->renderBlock('attributes') ?> />
he point isD the frgments ditte the rwv output of eh prt of formF o ustomize the form outputD you just need to identify nd override the orret frgmentF e set of these form frgment ustomiztions is known s form themeF hen rendering formD you n hoose whih form theme@sA you wnt to pplyF sn wig theme is single templte (le nd the frgments re the loks de(ned in this (leF sn r theme is folder nd the the frgments re individul templte (les in this folderF
QVS
unowing whih lok to ustomize sn this exmpleD the ustomized frgment nme is integerwidget euse you wnt to override the rwv widget for ll integer (eld typesF sf you need to ustomize textre (eldsD you would ustomize textrewidgetF es you n seeD the frgment nme is omintion of the (eld type nd whih prt of the (eld is eing rendered @eFgF widgetD lelD errorsD rowAF es suhD to ustomize how errors re rendered for just input text (eldsD you should ustomize the texterrors frgmentF wore ommonlyD howeverD you9ll wnt to ustomize how errors re displyed ross ll (eldsF ou n do this y ustomizing the (elderrors frgmentF his tkes dvntge of (eld type inheritneF pei(llyD sine the text type extends from the (eld typeD the form omponent will (rst look for the typeEspei( frgment @eFgF texterrorsA efore flling k to its prent frgment nme if it doesn9t exist @eFgF (elderrorsAF por more informtion on this topiD see porm prgment xmingF
o see the power of form themingD suppose you wnt to wrp every input numer (eld with div tgF he key to doing this is to ustomize the integerwidget frgmentF
6.17.4 Form Theming in Twig
hen ustomizing the form (eld lok in wigD you hve two options on where the ustomized form lok n liveX wethod snside the sme templte s the form snside seprte templte ros uik nd esy gn e reused y mny templtes gons gn9t e reused in other templtes equires n extr templte to e reted
foth methods hve the sme e'et ut re etter in di'erent situtionsF wethod IX snside the sme emplte s the porm he esiest wy to ustomize the integerwidget lok is to ustomize it diretly in the templte tht9s tully rendering the formF
{% block integer_widget %} <div class="integer_widget"> {% set type = type|default('number') %} {{ block('eld_widget') }} </div> {% endblock %} {% block content %} {# render the form #} {{ form_row(form.age) }} {% endblock %}
fy using the speil {7 formtheme form self 7} tgD wig looks inside the sme templte for ny overridden form loksF essuming the formFge (eld is n integer type (eldD when its widget is renderedD the ustomized integerwidget lok will e usedF he disdvntge of this method is tht the ustomized form lok n9t e reused when rendering other forms in other templtesF sn other wordsD this method is most useful when mking form ustomiztions tht re spei( to single form in your pplitionF sf you wnt to reuse form ustomiztion ross severl @or llA forms in your pplitionD red on to the next setionF wethod PX snside eprte emplte ou n lso hoose to put the ustomized integerwidget form lok in seprte templte entirelyF he ode nd endEresult re the smeD ut you n now reEuse the form ustomiztion ross mny templtesX
{# src/Acme/DemoBundle/Resources/views/Form/elds.html.twig #} {% block integer_widget %} <div class="integer_widget"> {% set type = type|default('number') %} {{ block('eld_widget') }} </div> {% endblock %}
xow tht you9ve reted the ustomized form lokD you need to tell ymfony to use itF snside the templte where you9re tully rendering your formD tell ymfony to use the templte vi the formtheme tgX
QVU
ymfony houmenttionD PFH hen the formFge widget is renderedD ymfony will use the integerwidget lok from the new templte nd the input tg will e wrpped in the div element spei(ed in the ustomized lokF
6.17.5 Form Theming in PHP
hen using r s templting engineD the only method to ustomize frgment is to rete new templte (le E this is similr to the seond method used y wigF he templte (le must e nmed fter the frgmentF ou must rete integerwidgetFhtmlFphp (le in order to ustomize the integerwidget frgmentF
<!-- src/Acme/DemoBundle/Resources/views/Form/integer_widget.html.php --> <div class="integer_widget"> <?php echo $view['form']->renderBlock('eld_widget', array('type' => isset($type) ? $type : "number")) ?> </div>
xow tht you9ve reted the ustomized form templteD you need to tell ymfony to use itF snside the templte where you9re tully rendering your formD tell ymfony to use the theme vi the setheme helper methodX
o frD to override prtiulr form lokD the est method is to opy the defult lok from formdivlyoutFhtmlFtwigD pste it into di'erent templteD nd the ustomize itF sn mny sesD you n void doing this y referening the se lok when ustomizing itF his is esy to doD ut vries slightly depending on if your form lok ustomiztions re in the sme templte s the form or seprte templteF eferening floks from inside the sme emplte s the porm smport the loks y dding use tg in the templte where you9re rendering the formX
QVV
TF
ymfony houmenttionD PFH xowD when the loks from formdivlyoutFhtmlFtwig re importedD the integerwidget lok is lled seintegerwidgetF his mens tht when you rede(ne the integerwidget lokD you n referene the defult mrkup vi seintegerwidgetX
{# src/Acme/DemoBundle/Resources/views/Form/elds.html.twig #} {% extends 'form_div_layout.html.twig' %} {% block integer_widget %} <div class="integer_widget"> {{ parent() }} </div> {% endblock %}
X st is not possile to referene the se lok when using r s the templting engineF ou hve to mnully opy the ontent from the se lok to your new templte (leF
sf you9d like ertin form ustomiztion to e glol to your pplitionD you n omplish this y mking the form ustomiztions in n externl templte nd then importing it inside your pplition on(gurtionX wig fy using the following on(gurtionD ny ustomized form loks inside the emehemofundleXpormX(eldsFhtmlFtwig templte will e used glolly when form is renderedF
ewv
TFIUF row to ustomize porm endering QVW
<!-- app/cong/cong.xml --> <twig:cong ...> <twig:form> <resource>AcmeDemoBundle:Form:elds.html.twig</resource> </twig:form> <!-- ... --> </twig:cong>
r
// app/cong/cong.php $container->loadFromExtension('twig', array( 'form' => array('resources' => array( 'AcmeDemoBundle:Form:elds.html.twig', )) // ... ));
fy defultD wig uses div lyout when rendering formsF ome peopleD howeverD my prefer to render forms in tle lyoutF se the formtlelyoutFhtmlFtwig resoure to use suh lyoutX
ewv
// app/cong/cong.php $container->loadFromExtension('twig', array( 'form' => array('resources' => array( 'form_table_layout.html.twig', )) // ... ));
sf you only wnt to mke the hnge in one templteD dd the following line to your templte (le rther thn dding the templte s resoureX
ewv
// app/cong/cong.php // PHP $container->loadFromExtension('framework', array( 'templating' => array('form' => array('resources' => array( 'AcmeDemoBundle:Form', ))) // ... ));
fy defultD the r engine uses div lyout when rendering formsF ome peopleD howeverD my prefer to render forms in tle lyoutF se the prmeworkfundleXpormle resoure to use suh lyoutX
ewv
<!-- app/cong/cong.xml --> <framework:cong ...> <framework:templating> <framework:form> <resource>FrameworkBundle:FormTable</resource> </framework:form> </framework:templating> <!-- ... --> </framework:cong>
QWP
TF
// app/cong/cong.php $container->loadFromExtension('framework', array( 'templating' => array('form' => array('resources' => array( 'FrameworkBundle:FormTable', ))) // ... ));
sf you only wnt to mke the hnge in one templteD dd the following line to your templte (le rther thn dding the templte s resoureX
o frD you9ve seen the di'erent wys you n ustomize the widget output of ll text (eld typesF ou n lso ustomize individul (eldsF por exmpleD suppose you hve two text (elds E (rstnme nd lstnme E ut you only wnt to ustomize one of the (eldsF his n e omplished y ustomizing frgment whose nme is omintion of the (eld id ttriute nd whih prt of the (eld is eing ustomizedF por exmpleX
wig
{% form_theme form _self %} {% block _product_name_widget %} <div class="text_widget"> {{ block('eld_widget') }} </div> {% endblock %} {{ form_widget(form.name) }}
r
<!-- Main template --> <?php echo $view['form']->setTheme($form, array('AcmeDemoBundle:Form')); ?> <?php echo $view['form']->widget($form['name']); ?>
TFIUF row to ustomize porm endering QWQ
wig
{% form_theme form _self %} {% block _product_name_row %} <div class="name_row"> {{ form_label(form) }} {{ form_errors(form) }} {{ form_widget(form) }} </div> {% endblock %}
r
<!-- _product_name_row.html.php --> <div class="name_row"> <?php echo $view['form']->label($form) ?> <?php echo $view['form']->errors($form) ?> <?php echo $view['form']->widget($form) ?> </div>
o frD this reipe hs shown you severl di'erent wys to ustomize single piee of how form is renderedF he key is to ustomize spei( frgment tht orresponds to the portion of the form you wnt to ontrol @see nming form loksAF
QWR
TF
ymfony houmenttionD PFH sn the next setionsD you9ll see how you n mke severl ommon form ustomiztionsF o pply these ustomiztionsD use one of the methods desried in the porm heming setionF gustomizing irror yutput X he form omponent only hndles how the vlidtion errors re renderedD nd not the tul vlidtion error messgesF he error messges themselves re determined y the vlidtion onstrints you pply to your ojetsF por more informtionD see the hpter on vlidtionF here re mny di'erent wys to ustomize how errors re rendered when form is sumitted with errorsF he error messges for (eld re rendered when you use the formerrors helperX
wig
{{ form_errors(form.age) }}
r
wig
{% block eld_errors %} {% spaceless %} {% if errors|length > 0 %} <ul class="error_list"> {% for error in errors %} <li>{{ error.messageTemplate|trans(error.messageParameters, 'validators') }}</li> {% endfor %} </ul> {% endif %} {% endspaceless %} {% endblock eld_errors %}
r
QWS
<!-- elds_errors.html.php --> <?php if ($errors): ?> <ul class="error_list"> <?php foreach ($errors as $error): ?> <li><?php echo $view['translator']->trans( $error->getMessageTemplate(), $error->getMessageParameters(), 'validators' ) ?></li> <?php endforeach; ?> </ul> <?php endif ?>
X ee porm heming for how to pply this ustomiztionF ou n lso ustomize the error output for just one spei( (eld typeF por exmpleD ertin errors tht re more glol to your form @iFeF not spei( to just one (eldA re rendered seprtelyD usully t the top of your formX
wig
{{ form_errors(form) }}
r
wig
<!-- eld_row.html.php --> <div class="form_row"> <?php echo $view['form']->label($form) ?> <?php echo $view['form']->errors($form) ?> <?php echo $view['form']->widget($form) ?> </div>
X ee porm heming for how to pply this ustomiztionF
edding equired esterisk to pield vels sf you wnt to denote ll of your required (elds with required sterisk @BAD you n do this y ustomizing the (eldlel frgmentF sn wigD if you9re mking the form ustomiztion inside the sme templte s your formD modify the use tg nd dd the followingX
{% use 'form_div_layout.html.twig' with eld_label as base_eld_label %} {% block eld_label %} {{ block('base_eld_label') }} {% if required %} <span class="required" title="This eld is required">*</span> {% endif %} {% endblock %}
sn wigD if you9re mking the form ustomiztion inside seprte templteD use the followingX
{% extends 'form_div_layout.html.twig' %} {% block eld_label %} {{ parent() }} {% if required %} <span class="required" title="This eld is required">*</span>
QWU
{% endif %} {% endblock %}
hen using r s templting engine you hve to opy the ontent from the originl templteX
<!-- original content --> <label for="<?php echo $view->escape($id) ?>" <?php foreach($attr as $k => $v) { printf('%s="%s" ', $view-> <!-- customization --> <?php if ($required) : ?> <span class="required" title="This eld is required">*</span> <?php endif ?>
X ee porm heming for how to pply this ustomiztionF
edding help messges ou n lso ustomize your form widgets to hve n optionl help messgeF sn wigD sf you9re mking the form ustomiztion inside the sme templte s your formD modify the use tg nd dd the followingX
{% use 'form_div_layout.html.twig' with eld_widget as base_eld_widget %} {% block eld_widget %} {{ block('base_eld_widget') }} {% if help is dened %} <span class="help">{{ help }}</span> {% endif %} {% endblock %}
sn twigD sf you9re mking the form ustomiztion inside seprte templteD use the followingX
{% extends 'form_div_layout.html.twig' %} {% block eld_widget %} {{ parent() }} {% if help is dened %} <span class="help">{{ help }}</span>
QWV
TF
{% endif %} {% endblock %}
hen using r s templting engine you hve to opy the ontent from the originl templteX
<!-- eld_widget.html.php --> <!-- Original content --> <input type="<?php echo isset($type) ? $view->escape($type) : "text" ?>" value="<?php echo $view->escape($value) ?>" <?php echo $view['form']->renderBlock('attributes') ?> /> <!-- Customization --> <?php if (isset($help)) : ?> <span class="help"><?php echo $view->escape($help) ?></span> <?php endif ?>
o render help messge elow (eldD pss in help vrileX
wig
his rtile hs not een written yetD ut will soonF sf you9re interested in writing this entryD see gontriuting to the houmenttionF
ou n rete ustom onstrint y extending the se onstrint lssD ymfonygomponentlidtorgonstrintF yptions for your onstrint re represented s
QWW
ymfony houmenttionD PFH puli properties on the onstrint lssF por exmpleD the rl onstrint inludes the messge nd protools propertiesX
namespace Symfony\Component\Validator\Constraints; use Symfony\Component\Validator\Constraint; /** * @Annotation */ class Url extends Constraint { public $message = 'This value is not a valid URL'; public $protocols = array('http', 'https', 'ftp', 'ftps'); }
X he dennottion nnottion is neessry for this new onstrint in order to mke it ville for use in lsses vi nnottionsF es you n seeD onstrint lss is firly minimlF he tul vlidtion is performed y nother onstrint vlidtor lssF he onstrint vlidtor lss is spei(ed y the onstrint9s vlidtedfy@A methodD whih inludes some simple defult logiX
class NotBlankValidator extends ConstraintValidator { public function isValid($value, Constraint $constraint) { if (null === $value || '' === $value) { $this->setMessage($constraint->message); } return false;
return true;
RHH TF
sf your onstrint vlidtor hs dependeniesD suh s dtse onnetionD it will need to e on(gured s servie in the dependeny injetion ontinerF his servie must inlude the vlidtorFonstrintvlidtor tg nd n lis ttriuteX
ewv
<service id="validator.unique.your_validator_name" class="Fully\Qualied\Validator\Class\Name"> <argument type="service" id="doctrine.orm.default_entity_manager" /> <tag name="validator.constraint_validator" alias="alias_name" /> </service>
r
ivery pplition is the omintion of ode nd set of on(gurtion tht dittes how tht ode should funtionF he on(gurtion my de(ne the dtse eing usedD whether or not something should e hedD or how verose logging should eF sn ymfonyPD the ide of environments is the ide tht the sme odese n e run using multiple di'erent TFPHF row to wster nd grete new invironments RHI
ymfony houmenttionD PFH on(gurtionsF por exmpleD the dev environment should use on(gurtion tht mkes development esy nd friendlyD while the prod environment should use set of on(gurtion optimized for speedF
6.20.1 Dierent Environments, Dierent Conguration Files
e typil ymfonyP pplition egins with three environmentsX devD prodD nd testF es disussedD eh environment simply represents wy to exeute the sme odese with di'erent on(gurtionF st should e no surprise then tht eh environment lods its own individul on(gurtion (leF sf you9re using the ewv on(gurtion formtD the following (les re usedX
for the dev environmentX ppGon(gGon(gdevFyml for the prod environmentX ppGon(gGon(gprodFyml for the test environmentX ppGon(gGon(gtestFyml
his works vi simple stndrd tht9s used y defult inside the eppuernel lssX
// app/AppKernel.php // ... class AppKernel extends Kernel { // ... public function registerContainerConguration(LoaderInterface $loader) { $loader->load(__DIR__.'/cong/cong_'.$this->getEnvironment().'.yml'); }
es you n seeD when ymfonyP is lodedD it uses the given environment to determine whih on(gurtion (le to lodF his omplishes the gol of multiple environments in n elegntD powerful nd trnsprent wyF yf ourseD in relityD eh environment di'ers only somewht from othersF qenerllyD ll environments will shre lrge se of ommon on(gurtionF ypening the dev on(gurtion (leD you n see how this is omplished esily nd trnsprentlyX
ewv
$loader->import('cong.php'); // ...
o shre ommon on(gurtionD eh environment9s on(gurtion (le simply (rst imports from entrl on(gurtion (le @on(gFymlAF he reminder of the (le n then devite from the defult on(gurtion y overriding individul prmetersF por exmpleD y defultD the wepro(ler toolr is disledF roweverD in the dev environmentD the toolr is tivted y modifying the defult vlue in the dev on(gurtion (leX
ewv
<!-- app/cong/cong_dev.xml --> <imports> <import resource="cong.xml" /> </imports> <webproler:cong toolbar="true" # ... />
r
));
o exeute the pplition in eh environmentD lod up the pplition using either the ppFphp @for the prod environmentA or the ppdevFphp @for the dev environmentA front ontrollerX
<?php require_once __DIR__.'/../app/bootstrap_cache.php'; require_once __DIR__.'/../app/AppCache.php'; use Symfony\Component\HttpFoundation\Request; $kernel = new AppCache(new AppKernel('prod', false)); $kernel->handle(Request::createFromGlobals())->send();
es you n seeD the prod key spei(es tht this environment will run in the prod environmentF e ymfonyP pplition n e exeuted in ny environment y using this ode nd hnging the environment stringF X he test environment is used when writing funtionl tests nd is not essile in the rowser diretly vi front ontrollerF sn other wordsD unlike the other environmentsD there is no pptestFphp front ontroller (leF
RHR
TF
ymfony houmenttionD PFH heug wode smportntD ut unrelted to the topi of environments is the flse key on line V of the front ontroller oveF his spei(es whether or not the pplition should run in deug modeF egrdless of the environmentD ymfonyP pplition n e run with deug mode set to true or flseF his 'ets mny things in the pplitionD suh s whether or not errors should e displyed or if he (les re dynmilly reuilt on eh requestF hough not requirementD deug mode is generlly set to true for the dev nd test environments nd flse for the prod environmentF snternllyD the vlue of the deug mode eomes the kernelFdeug prmeter used inside the servie ontinerF sf you look inside the pplition on(gurtion (leD you9ll see the prmeter usedD for exmpleD to turn logging on or o' when using the hotrine hfevX ewv
$container->loadFromExtension('doctrine', array( 'dbal' => array( 'logging' => '%kernel.debug%', // ... ), // ... ));
fy defultD ymfonyP pplition hs three environments tht hndle most sesF yf ourseD sine n environment is nothing more thn string tht orresponds to set of on(gurtionD reting new environment is quite esyF upposeD for exmpleD tht efore deploymentD you need to enhmrk your pplitionF yne wy to enhmrk the pplition is to use nerEprodution settingsD ut with ymfonyP9s wepro(ler enledF his llows ymfonyP to reord informtion out your pplition while enhmrkingF he est wy to omplish this is vi new environment lledD for exmpleD enhmrkF trt y reting new on(gurtion (leX
ewv
TFPHF row to wster nd grete new invironments RHS
<!-- app/cong/cong_benchmark.xml --> <imports> <import resource="cong_prod.xml" /> </imports> <framework:cong> <framework:proler only-exceptions="false" /> </framework:cong>
r
// app/cong/cong_benchmark.php $loader->import('cong_prod.php') $container->loadFromExtension('framework', array( 'proler' => array('only-exceptions' => false), ));
end with this simple dditionD the pplition now supports new environment lled enhmrkF his new on(gurtion (le imports the on(gurtion from the prod environment nd modi(es itF his gurntees tht the new environment is identil to the prod environmentD exept for ny hnges expliitly mde hereF feuse you9ll wnt this environment to e essile vi rowserD you should lso rete front ontroller for itF gopy the weGppFphp (le to weGppenhmrkFphp nd edit the environment to e enhmrkX
RHT
TF
http://localhost/app_benchmark.php
X ome environmentsD like the dev environmentD re never ment to e essed on ny deployed server y the generl puliF his is euse ertin environmentsD for deugging purposesD my give too muh informtion out the pplition or underlying infrstrutureF o e sure these environments ren9t essileD the front ontroller is usully proteted from externl s ddresses vi the following ode t the top of the ontrollerX
if (!in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1'))) { die('You are not allowed to access this le. Check '.basename(__FILE__).' for more information.'); }
ymfonyP tkes dvntge of hing in mny wysX the pplition on(gurtionD routing on(gurtionD wig templtes nd more re hed to r ojets stored in (les on the (lesystemF fy defultD these hed (les re lrgely stored in the ppGhe diretoryF roweverD eh environment hes its own set of (lesX
app/cache/dev - cache directory for the *dev* environment app/cache/prod - cache directory for the *prod* environment
ometimesD when deuggingD it my e helpful to inspet hed (le to understnd how something is workingF hen doing soD rememer to look in the diretory of the environment you9re using @most ommonly dev while developing nd deuggingAF hile it n vryD the ppGheGdev diretory inludes the followingX
pphevheugrojetgontinerFphp E the hed servie ontiner tht represents the hed pplition on(gurtionY ppdevrlqenertorFphp E the r lss generted from the routing on(gurtion nd used when generting vsY ppdevrlwtherFphp E the r lss used for route mthing E look here to see the ompiled regulr expression logi used to mth inoming vs to di'erent routesY twigG E this diretory ontins ll the hed wig templtesF
RHU
sn the hpter row to wster nd grete new invironmentsD you lerned how to mnge your pplition on(gurtionF et timesD it my ene(t your pplition to store ertin redentils outside of your projet odeF htse on(gurtion is one suh exmpleF he )exiility of the symfony servie ontiner llows you to esily do thisF
6.21.1 Environment Variables
ymfony will gr ny environment vrile pre(xed with wpyx nd set it s prmeter in the servie ontinerF houle undersores re repled with periodD s period is not vlid hrter in n environment vrile nmeF por exmpleD if you9re using epheD environment vriles n e set using the following irtulrost on(gurtionX
<VirtualHost *:80> ServerName Symfony2 DocumentRoot "/path/to/symfony_2_app/web" DirectoryIndex index.php index.html SetEnv SYMFONY__DATABASE__USER user SetEnv SYMFONY__DATABASE__PASSWORD secret <Directory "/path/to/my_symfony_2_app/web"> AllowOverride All Allow from All </Directory> </VirtualHost>
X he exmple ove is for n ephe on(gurtionD using the etinv diretiveF roweverD this will work for ny we server whih supports the setting of environment vrilesF xow tht you hve delred n environment vrileD it will e present in the r 6ii glol vrileF ymfony then utomtilly sets ll 6ii vriles pre(xed with wpyx s prmeters in the servie ontinerF ou n now referene these prmeters wherever you need themF
RHV
TF
ewv
doctrine: dbal: driver pdo_mysql dbname: symfony2_project user: %database.user% password: %database.password%
wv
<!-- xmlns:doctrine="http://symfony.com/schema/dic/doctrine" --> <!-- xsi:schemaLocation="http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctr <doctrine:cong> <doctrine:dbal driver="pdo_mysql" dbname="symfony2_projet" user="%database.user%" password="%database.password%" /> </doctrine:cong>
r
$container->loadFromExtension('doctrine', array('dbal' => array( 'driver' => 'pdo_mysql', 'dbname' => 'symfony2_project', 'user' => '%database.user%', 'password' => '%database.password%', ));
6.21.2 Constants
he ontiner lso hs support for setting r onstnts s prmetersF o tke dvntge of this fetureD mp the nme of your onstnt to prmeter keyD nd de(ne the type s onstntF
</parameters> </container>
X his only works for wv on(gurtionF sf you9re not using wvD simply import n wv (le to tke dvntge of this funtionlityX
he imports diretive n e used to pull in prmeters stored elsewhereF smporting r (le gives you the )exiility to dd whtever is needed in the ontinerF he following imports (le nmed prmetersFphpF
ewv
// app/cong/cong.php $loader->import('parameters.php');
X e resoure (le n e one of mny typesF rD wvD ewvD sxsD nd losure resoures re ll supported y the imports diretiveF sn prmetersFphpD tell the servie ontiner the prmeters tht you wish to setF his is useful when importnt on(gurtion is in nonstndrd formtF he exmple elow inludes hrupl dtse9s on(gurtion in the symfony servie ontinerF
// app/cong/parameters.php
RIH
TF
ymfonyP9s ervie gontiner provides powerful wy of ontrolling the retion of ojetsD llowing you to speify rguments pssed to the onstrutor s well s lling methods nd setting prmetersF ometimesD howeverD this will not provide you with everything you need to onstrut your ojetsF por this situtionD you n use ftory to rete the ojet nd tell the servie ontiner to ll method on the ftory rther thn diretly instntiting the ojetF uppose you hve ftory tht on(gures nd returns new xewsletterwnger ojetX
namespace Acme\HelloBundle\Newletter; class NewsletterFactory { public function get() { $newsletterManager = new NewsletterManager(); // ... } return $newsletterManager;
o mke the xewsletterwnger ojet ville s servieD you n on(gure the servie ontiner to use the xewsletterptory ftory lssX
ewv
# src/Acme/HelloBundle/Resources/cong/services.yml parameters: # ... newsletter_manager.class: Acme\HelloBundle\Newsletter\NewsletterManager newsletter_factory.class: Acme\HelloBundle\Newsletter\NewsletterFactory services: newsletter_manager: class: %newsletter_manager.class% factory_class: %newsletter_factory.class% factory_method: get
wv
TFPPF row to se ptory to grete ervies RII
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <parameters> <!-- ... --> <parameter key="newsletter_manager.class">Acme\HelloBundle\Newsletter\NewsletterManager</par <parameter key="newsletter_factory.class">Acme\HelloBundle\Newsletter\NewsletterFactory</param </parameters> <services> <service id="newsletter_manager" class="%newsletter_manager.class%" factory-class="%newsletter_factory.class%" factory-method="get" /> </services>
r
// ... $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager' $container->setParameter('newsletter_factory.class', 'Acme\HelloBundle\Newsletter\NewsletterFactory'); $container->setDenition('newsletter_manager', new Denition( '%newsletter_manager.class%' ))->setFactoryClass( '%newsletter_factory.class%' )->setFactoryMethod( 'get' );
hen you speify the lss to use for the ftory @vi ftorylssA the method will e lled sttillyF sf the ftory itself should e instntited nd the resulting ojet9s method lled @s in this exmpleAD on(gure the ftory itself s servieX
ewv
# src/Acme/HelloBundle/Resources/cong/services.yml parameters: # ... newsletter_manager.class: Acme\HelloBundle\Newsletter\NewsletterManager newsletter_factory.class: Acme\HelloBundle\Newsletter\NewsletterFactory services: newsletter_factory: class: %newsletter_factory.class% newsletter_manager: class: %newsletter_manager.class%
RIP TF
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <parameters> <!-- ... --> <parameter key="newsletter_manager.class">Acme\HelloBundle\Newsletter\NewsletterManager</par <parameter key="newsletter_factory.class">Acme\HelloBundle\Newsletter\NewsletterFactory</param </parameters> <services> <service id="newsletter_factory" class="%newsletter_factory.class%"/> <service id="newsletter_manager" class="%newsletter_manager.class%" factory-service="newsletter_factory" factory-method="get" /> </services>
r
// ... $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager' $container->setParameter('newsletter_factory.class', 'Acme\HelloBundle\Newsletter\NewsletterFactory'); $container->setDenition('newsletter_factory', new Denition( '%newsletter_factory.class%' )) $container->setDenition('newsletter_manager', new Denition( '%newsletter_manager.class%' ))->setFactoryService( 'newsletter_factory' )->setFactoryMethod( 'get' );
X he ftory servie is spei(ed y its id nme nd not referene to the servie itselfF oD you do not need to use the d syntxF
RIQ
sf you need to pss rguments to the ftory methodD you n use the rguments options inside the servie ontinerF por exmpleD suppose the get method in the previous exmple tkes the templting servie s n rgumentX
ewv
# src/Acme/HelloBundle/Resources/cong/services.yml parameters: # ... newsletter_manager.class: Acme\HelloBundle\Newsletter\NewsletterManager newsletter_factory.class: Acme\HelloBundle\Newsletter\NewsletterFactory services: newsletter_factory: class: %newsletter_factory.class% newsletter_manager: class: %newsletter_manager.class% factory_service: newsletter_factory factory_method: get arguments: @templating
wv
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <parameters> <!-- ... --> <parameter key="newsletter_manager.class">Acme\HelloBundle\Newsletter\NewsletterManager</par <parameter key="newsletter_factory.class">Acme\HelloBundle\Newsletter\NewsletterFactory</param </parameters> <services> <service id="newsletter_factory" class="%newsletter_factory.class%"/> <service id="newsletter_manager" class="%newsletter_manager.class%" factory-service="newsletter_factory" factory-method="get" > <argument type="service" id="templating" /> </service> </services>
r
RIR
TF
// ... $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager' $container->setParameter('newsletter_factory.class', 'Acme\HelloBundle\Newsletter\NewsletterFactory'); $container->setDenition('newsletter_factory', new Denition( '%newsletter_factory.class%' )) $container->setDenition('newsletter_manager', new Denition( '%newsletter_manager.class%', array(new Reference('templating')) ))->setFactoryService( 'newsletter_factory' )->setFactoryMethod( 'get' );
es you dd more funtionlity to your pplitionD you my well strt to hve relted lsses tht shre some of the sme dependeniesF por exmple you my hve xewsletter wnger whih uses setter injetion to set its dependeniesX
namespace Acme\HelloBundle\Mail; use Acme\HelloBundle\Mailer; use Acme\HelloBundle\EmailFormatter; class NewsletterManager { protected $mailer; protected $emailFormatter; public function setMailer(Mailer $mailer) { $this->mailer = $mailer; } public function setEmailFormatter(EmailFormatter $emailFormatter) { $this->emailFormatter = $emailFormatter; } // ...
nd lso qreeting grd lss whih shres the sme dependeniesX TFPQF row to wnge gommon hependenies with rent ervies RIS
namespace Acme\HelloBundle\Mail; use Acme\HelloBundle\Mailer; use Acme\HelloBundle\EmailFormatter; class GreetingCardManager { protected $mailer; protected $emailFormatter; public function setMailer(Mailer $mailer) { $this->mailer = $mailer; } public function setEmailFormatter(EmailFormatter $emailFormatter) { $this->emailFormatter = $emailFormatter; } // ...
he servie on(g for these lsses would look something like thisX
ewv
# src/Acme/HelloBundle/Resources/cong/services.yml parameters: # ... newsletter_manager.class: Acme\HelloBundle\Mail\NewsletterManager greeting_card_manager.class: Acme\HelloBundle\Mail\GreetingCardManager services: my_mailer: # ... my_email_formatter: # ... newsletter_manager: class: %newsletter_manager.class% calls: - [ setMailer, [ @my_mailer ] ] - [ setEmailFormatter, [ @my_email_formatter] ] greeting_card_manager: class: %greeting_card_manager.class% calls: - [ setMailer, [ @my_mailer ] ] - [ setEmailFormatter, [ @my_email_formatter] ]
RIT TF
wv
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <parameters> <!-- ... --> <parameter key="newsletter_manager.class">Acme\HelloBundle\Mail\NewsletterManager</paramete <parameter key="greeting_card_manager.class">Acme\HelloBundle\Mail\GreetingCardManager</pa </parameters> <services> <service id="my_mailer" ... > <!-- ... --> </service> <service id="my_email_formatter" ... > <!-- ... --> </service> <service id="newsletter_manager" class="%newsletter_manager.class%"> <call method="setMailer"> <argument type="service" id="my_mailer" /> </call> <call method="setEmailFormatter"> <argument type="service" id="my_email_formatter" /> </call> </service> <service id="greeting_card_manager" class="%greeting_card_manager.class%"> <call method="setMailer"> <argument type="service" id="my_mailer" /> </call> <call method="setEmailFormatter"> <argument type="service" id="my_email_formatter" /> </call> </service> </services>
r
// ... $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Mail\NewsletterManager'); $container->setParameter('greeting_card_manager.class', 'Acme\HelloBundle\Mail\GreetingCardManager $container->setDenition('my_mailer', ... ); $container->setDenition('my_email_formatter', ... ); $container->setDenition('newsletter_manager', new Denition( '%newsletter_manager.class%'
TFPQF row to wnge gommon hependenies with rent ervies RIU
))->addMethodCall('setMailer', array( new Reference('my_mailer') ))->addMethodCall('setEmailFormatter', array( new Reference('my_email_formatter') )); $container->setDenition('greeting_card_manager', new Denition( '%greeting_card_manager.class%' ))->addMethodCall('setMailer', array( new Reference('my_mailer') ))->addMethodCall('setEmailFormatter', array( new Reference('my_email_formatter') ));
here is lot of repetition in oth the lsses nd the on(gurtionF his mens tht if you hngedD for exmpleD the wiler of imilpormtter lsses to e injeted vi the onstrutorD you would need to updte the on(g in two plesF vikewise if you needed to mke hnges to the setter methods you would need to do this in oth lssesF he typil wy to del with the ommon methods of these relted lsses would e to extrt them to super lssX
namespace Acme\HelloBundle\Mail; use Acme\HelloBundle\Mailer; use Acme\HelloBundle\EmailFormatter; abstract class MailManager { protected $mailer; protected $emailFormatter; public function setMailer(Mailer $mailer) { $this->mailer = $mailer; } public function setEmailFormatter(EmailFormatter $emailFormatter) { $this->emailFormatter = $emailFormatter; } // ...
// ...
ndX
ewv
# src/Acme/HelloBundle/Resources/cong/services.yml parameters: # ... newsletter_manager.class: Acme\HelloBundle\Mail\NewsletterManager greeting_card_manager.class: Acme\HelloBundle\Mail\GreetingCardManager mail_manager.class: Acme\HelloBundle\Mail\MailManager services: my_mailer: # ... my_email_formatter: # ... mail_manager: class: %mail_manager.class% abstract: true calls: - [ setMailer, [ @my_mailer ] ] - [ setEmailFormatter, [ @my_email_formatter] ] newsletter_manager: class: %newsletter_manager.class% parent: mail_manager greeting_card_manager: class: %greeting_card_manager.class% parent: mail_manager
wv
<services> <service id="my_mailer" ... > <!-- ... --> </service> <service id="my_email_formatter" ... > <!-- ... --> </service> <service id="mail_manager" class="%mail_manager.class%" abstract="true"> <call method="setMailer"> <argument type="service" id="my_mailer" /> </call> <call method="setEmailFormatter"> <argument type="service" id="my_email_formatter" /> </call> </service> <service id="newsletter_manager" class="%newsletter_manager.class%" parent="mail_manager"/> <service id="greeting_card_manager" class="%greeting_card_manager.class%" parent="mail_manag </services>
r
// ... $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Mail\NewsletterManager'); $container->setParameter('greeting_card_manager.class', 'Acme\HelloBundle\Mail\GreetingCardManager $container->setParameter('mail_manager.class', 'Acme\HelloBundle\Mail\MailManager'); $container->setDenition('my_mailer', ... ); $container->setDenition('my_email_formatter', ... ); $container->setDenition('mail_manager', new Denition( '%mail_manager.class%' ))->SetAbstract( true )->addMethodCall('setMailer', array( new Reference('my_mailer') ))->addMethodCall('setEmailFormatter', array( new Reference('my_email_formatter') )); $container->setDenition('newsletter_manager', new DenitionDecorator(
RPH TF
here my e times where you wnt to override wht lss is pssed in for dependeny of one hild servie onlyF portuntelyD y dding the method ll on(g for the hild servieD the dependenies set y the prent lss will e overriddenF o if you needed to pss di'erent dependeny just to the xewsletterwnger lssD the on(g would look like thisX
ewv
# src/Acme/HelloBundle/Resources/cong/services.yml parameters: # ... newsletter_manager.class: Acme\HelloBundle\Mail\NewsletterManager greeting_card_manager.class: Acme\HelloBundle\Mail\GreetingCardManager mail_manager.class: Acme\HelloBundle\Mail\MailManager services: my_mailer: # ... my_alternative_mailer: # ... my_email_formatter:
TFPQF row to wnge gommon hependenies with rent ervies RPI
# ... mail_manager: class: %mail_manager.class% abstract: true calls: - [ setMailer, [ @my_mailer ] ] - [ setEmailFormatter, [ @my_email_formatter] ] newsletter_manager: class: %newsletter_manager.class% parent: mail_manager calls: - [ setMailer, [ @my_alternative_mailer ] ] greeting_card_manager: class: %greeting_card_manager.class% parent: mail_manager
wv
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <parameters> <!-- ... --> <parameter key="newsletter_manager.class">Acme\HelloBundle\Mail\NewsletterManager</paramete <parameter key="greeting_card_manager.class">Acme\HelloBundle\Mail\GreetingCardManager</pa <parameter key="mail_manager.class">Acme\HelloBundle\Mail\MailManager</parameter> </parameters> <services> <service id="my_mailer" ... > <!-- ... --> </service> <service id="my_alternative_mailer" ... > <!-- ... --> </service> <service id="my_email_formatter" ... > <!-- ... --> </service> <service id="mail_manager" class="%mail_manager.class%" abstract="true"> <call method="setMailer"> <argument type="service" id="my_mailer" /> </call> <call method="setEmailFormatter"> <argument type="service" id="my_email_formatter" /> </call> </service> <service id="newsletter_manager" class="%newsletter_manager.class%" parent="mail_manager">
RPP TF
<call method="setMailer"> <argument type="service" id="my_alternative_mailer" /> </call> </service> <service id="greeting_card_manager" class="%greeting_card_manager.class%" parent="mail_manag </services>
r
// ... $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Mail\NewsletterManager'); $container->setParameter('greeting_card_manager.class', 'Acme\HelloBundle\Mail\GreetingCardManager $container->setParameter('mail_manager.class', 'Acme\HelloBundle\Mail\MailManager'); $container->setDenition('my_mailer', ... ); $container->setDenition('my_alternative_mailer', ... ); $container->setDenition('my_email_formatter', ... ); $container->setDenition('mail_manager', new Denition( '%mail_manager.class%' ))->SetAbstract( true )->addMethodCall('setMailer', array( new Reference('my_mailer') ))->addMethodCall('setEmailFormatter', array( new Reference('my_email_formatter') )); $container->setDenition('newsletter_manager', new DenitionDecorator( 'mail_manager' ))->setClass( '%newsletter_manager.class%' )->addMethodCall('setMailer', array( new Reference('my_alternative_mailer') )); $container->setDenition('newsletter_manager', new DenitionDecorator( 'mail_manager' ))->setClass( '%greeting_card_manager.class%' );
he qreetinggrdwnger will reeive the sme dependenies s eforeD ut the xewsletterwnger will e pssed the mylterntivemiler insted of the mymiler servieF
RPQ
st should e noted tht the overridden setter method in the previous exmple is tully lled twie E one per the prent de(nition nd one per the hild de(nitionF sn the previous exmpleD tht ws (neD sine the seond setwiler ll reples miler ojet set y the (rst llF sn some sesD howeverD this n e prolemF por exmpleD if the overridden method ll involves dding something to olletionD then two ojets will e dded to tht olletionF he following shows suh seD if the prent lss looks like thisX
namespace Acme\HelloBundle\Mail; use Acme\HelloBundle\Mailer; use Acme\HelloBundle\EmailFormatter; abstract class MailManager { protected $lters; public function setFilter($lter) { $this->lters[] = $lter; } // ...
ewv
# src/Acme/HelloBundle/Resources/cong/services.yml parameters: # ... newsletter_manager.class: Acme\HelloBundle\Mail\NewsletterManager mail_manager.class: Acme\HelloBundle\Mail\MailManager services: my_lter: # ... another_lter: # ... mail_manager: class: %mail_manager.class% abstract: true calls: - [ setFilter, [ @my_lter ] ] newsletter_manager:
RPR TF
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <parameters> <!-- ... --> <parameter key="newsletter_manager.class">Acme\HelloBundle\Mail\NewsletterManager</paramete <parameter key="mail_manager.class">Acme\HelloBundle\Mail\MailManager</parameter> </parameters> <services> <service id="my_lter" ... > <!-- ... --> </service> <service id="another_lter" ... > <!-- ... --> </service> <service id="mail_manager" class="%mail_manager.class%" abstract="true"> <call method="setFilter"> <argument type="service" id="my_lter" /> </call> </service> <service id="newsletter_manager" class="%newsletter_manager.class%" parent="mail_manager"> <call method="setFilter"> <argument type="service" id="another_lter" /> </call> </service> </services>
r
// src/Acme/HelloBundle/Resources/cong/services.php use Symfony\Component\DependencyInjection\Denition; use Symfony\Component\DependencyInjection\Reference; // ... $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Mail\NewsletterManager'); $container->setParameter('mail_manager.class', 'Acme\HelloBundle\Mail\MailManager'); $container->setDenition('my_lter', ... ); $container->setDenition('another_lter', ... ); $container->setDenition('mail_manager', new Denition( '%mail_manager.class%'
TFPQF row to wnge gommon hependenies with rent ervies RPS
))->SetAbstract( true )->addMethodCall('setFilter', array( new Reference('my_lter') )); $container->setDenition('newsletter_manager', new DenitionDecorator( 'mail_manager' ))->setClass( '%newsletter_manager.class%' )->addMethodCall('setFilter', array( new Reference('another_lter') ));
sn this exmpleD the setpilter of the newslettermnger servie will e lled twieD resulting in the 6(lters rry ontining oth my(lter nd nother(lter ojetsF his is gret if you just wnt to dd dditionl (lters to the sulssesF sf you wnt to reple the (lters pssed to the sulssD removing the prent setting from the on(g will prevent the se lss from lling to setpilterF
his entry is ll out sopesD somewht dvned topi relted to the ervie gontinerF sf you9ve ever gotten n error mentioning sopes when reting serviesD or need to rete servie tht depends on the request servieD then this entry is for youF
6.24.1 Understanding Scopes
he sope of servie ontrols how long n instne of servie is used y the ontinerF the hependeny snjetion omponent provides two generi sopesX
ontiner @the defult oneAX he sme instne is used eh time you request it from this ontinerF prototypeX e new instne is reted eh time you request the servieF
he prmeworkfundle lso de(nes third sopeX requestF his sopes is tied to the requestD mening new instne is reted for eh surequest nd is unville outside the request @for instne in the gvsAF opes dd onstrint on the dependenies of servieX servie nnot depend on servies from nrrower sopeF por exmpleD if you rete generi myfoo servieD ut try to injet the request omponentD you9ll reeive ymfonygomponenthependenysnjetionixeptionopeideningsnjetionixeption when ompiling the ontinerF ed the sider elow for more detilsF RPT TF
opes nd hependenies smgine you9ve on(gured mymiler servieF ou hven9t on(gured the sope of the servieD so it defults to ontinerF sn other wordsD everytime you sk the ontiner for the mymiler servieD you get the sme ojet kF his is usully how you wnt your servies to workF smgineD howeverD tht you need the request servie in your mymiler servieD mye euse you9re reding the v of the urrent requestF oD you dd it s onstrutor rgumentF vet9s look t why this presents prolemX hen requesting mymilerD n instne of mymiler @let9s ll it wilereA is reted nd the request servie is @let9s ll it equeste is pssed to itAF vife is good3 ou9ve now mde surequest in ymfonyD whih is fny wy of sying tht you9ve lledD for exmpleD the {7 render FFF 7} wig funtionD whih exeutes nother ontrollerF snternllyD the old request servie @equesteA is tully repled y new request instne @equestfAF his hppens in the kgroundD nd it9s totlly normlF sn your emedded ontrollerD you one gin sk for the mymiler servieF ine your servie is in the ontiner sopeD the sme instne @wilereA is just reEusedF fut here9s the prolemX the wilere instne still ontins the old equeste ojetD whih is now not the orret request ojet to hve @equestf is now the urrent request servieAF his is sutleD ut the misEmth ould use mjor prolemsD whih is why it9s not llowedF oD tht9s the reson why sopes existsD nd how they n use prolemsF ueep reding to (nd out the ommon solutionsF
ewv
sf your servie depends on soped servieD the est solution is to put it in the sme sope @or nrrower oneAF sullyD this mens putting your new servie in the request servieF fut this is not lwys possile @for instneD twig extension must e in the ontiner sope s the wig environment needs it s dependenyAF sn these sesD you should pss the entire ontiner into your servie nd retrieve your dependeny from the ontiner eh time we need it to e sure you hve the right instneX
namespace Acme\HelloBundle\Mail; use Symfony\Component\DependencyInjection\ContainerInterface; class Mailer { protected $container; public function __construct(ContainerInterface $container) { $this->container = $container; } public function sendEmail() { $request = $this->container->get('request'); // Do something using the request here
RPV TF
}
X ke re not to store the request in property of the ojet for future ll of the servie s it would e the sme issue desried in the (rst setion @exept tht symfony nnot detet tht you re wrongAF
he servie on(g for this lss would look something like thisX
ewv
# src/Acme/HelloBundle/Resources/cong/services.yml parameters: # ... my_mailer.class: Acme\HelloBundle\Mail\Mailer services: my_mailer: class: %my_mailer.class% arguments: - "@service_container" # scope: container can be omitted as it is the default
wv
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <parameters> <!-- ... --> <parameter key="my_mailer.class">Acme\HelloBundle\Mail\Mailer</parameter> </parameters> <services> <service id="my_mailer" class="%my_mailer.class%"> <argument type="service" id="service_container" /> </service> </services>
r
// src/Acme/HelloBundle/Resources/cong/services.php use Symfony\Component\DependencyInjection\Denition; use Symfony\Component\DependencyInjection\Reference; // ... $container->setParameter('my_mailer.class', 'Acme\HelloBundle\Mail\Mailer'); $container->setDenition('my_mailer', new Denition( '%my_mailer.class%',
TFPRF row to work with opes RPW
));
array(new Reference('service_container'))
X snjeting the whole ontiner into servie is generlly not good ide @only injet wht you needAF sn some rre sesD like when working with wig extensionsD its neessry to due shortoming in wig itselfF
6.25 How
to
use
PdoSessionStorage
to
store
Sessions
in
the
Database
he defult session storge of ymfonyP writes the session informtion to (le@sAF wost medium to lrge wesites use dtse to store the session vlues insted of (lesD euse dtses re esier to use nd sle in multiEweserver environmentF ymfonyP hs uiltEin solution for dtse session storge lled ymfonygomponentrttppoundtionessiontorgedoessiontorgeF o use itD you just need to hnge some prmeters in on(gFyml @or the on(gurtion formt of your hoieAX
ewv
# app/cong/cong.yml framework: session: # ... storage_id: session.storage.pdo parameters: pdo.db_options: db_table: session db_id_col: session_id db_data_col: session_value db_time_col: session_time services: pdo: class: PDO arguments: dsn: "mysql:dbname=mydatabase" user: myuser password: mypassword session.storage.pdo:
RQH TF
<!-- app/cong/cong.xml --> <framework:cong> <framework:session storage-id="session.storage.pdo" default-locale="en" lifetime="3600" auto-start="t </framework:cong> <parameters> <parameter key="pdo.db_options" type="collection"> <parameter key="db_table">session</parameter> <parameter key="db_id_col">session_id</parameter> <parameter key="db_data_col">session_value</parameter> <parameter key="db_time_col">session_time</parameter> </parameter> </parameters> <services> <service id="pdo" class="PDO"> <argument>mysql:dbname=mydatabase</argument> <argument>myuser</argument> <argument>mypassword</argument> </service>
<service id="session.storage.pdo" class="Symfony\Component\HttpFoundation\SessionStorage\PdoSes <argument type="service" id="pdo" /> <argument>%session.storage.options%</argument> <argument>%pdo.db_options%</argument> </service> </services>
r
// app/cong/cong.yml use Symfony\Component\DependencyInjection\Denition; use Symfony\Component\DependencyInjection\Reference; $container->loadFromExtension('framework', array( // ... 'session' => array( // ... 'storage_id' => 'session.storage.pdo', ), ));
RQI
$container->setParameter('pdo.db_options', array( 'db_table' => 'session', 'db_id_col' => 'session_id', 'db_data_col' => 'session_value', 'db_time_col' => 'session_time', )); $pdoDenition = new Denition('PDO', array( 'mysql:dbname=mydatabase', 'myuser', 'mypassword', )); $container->setDenition('pdo', $pdoDenition);
$storageDenition = new Denition('Symfony\Component\HttpFoundation\SessionStorage\PdoSessionStor new Reference('pdo'), '%session.storage.options%', '%pdo.db_options%', )); $container->setDenition('session.storage.pdo', $storageDenition);
dtleX he nme of the session tle in your dtse didolX he nme of the id olumn in your session tle @egre@PSSA or lrgerA ddtolX he nme of the vlue olumn in your session tle @i or gvyfA dtimeolX he nme of the time olumn in your session tle @sxiqiA
6.25.1 Sharing your Database Connection Information
ith the given on(gurtionD the dtse onnetion settings re de(ned for the session storge onnetion onlyF his is yu when you use seprte dtse for the session dtF fut if you9d like to store the session dt in the sme dtse s the rest of your projet9s dtD you n use the onnetion settings from the prmeterFini y referening the dtseE relted prmeters de(ned thereX
ewv
RQP
TF
wv
he vEttement for reting the needed htseEle ould look like the following @wyvAX
CREATE TABLE `session` ( `session_id` varchar(255) NOT NULL, `session_value` text NOT NULL, `session_time` int(11) NOT NULL, PRIMARY KEY (`session_id`), UNIQUE KEY `session_id_idx` (`session_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
e undle is diretory tht hs wellEde(ned struture nd n host nything from lsses to ontrollers nd we resouresF iven if undles re very )exileD you should follow some est prties if you wnt to distriute themF
6.26.1 Bundle Name
e undle is lso r nmespeF he nmespe must follow the tehnil interoperility stndrds for r SFQ nmespes nd lss nmesX it strts with vendor segmentD followed y zero or more tegory segmentsD nd it ends with the nmespe short nmeD whih must end with fundle su0xF
RQQ
ymfony houmenttionD PFH e nmespe eomes undle s soon s you dd undle lss to itF he undle lss nme must follow these simple rulesX
se only lphnumeri hrters nd undersoresY se gmelgsed nmeY se desriptive nd short nme @no more thn P wordsAY re(x the nme with the ontention of the vendor @nd optionlly the tegory nmespesAY u0x the nme with fundleF
rere re some vlid undle nmespes nd lss nmesX xmespe emefundleflogfundle emefundleoilflogfundle emeflogfundle fundle glss xme emeflogfundle emeoilflogfundle emeflogfundle
fy onventionD the getxme@A method of the undle lss should return the lss nmeF X sf you shre your undle pulilyD you must use the undle lss nme s the nme of the repository @emeflogfundle nd not flogfundle for instneAF
X ymfonyP ore fundles do not pre(x the with ymfony nd lwys dd fundle sunmespeY ymfonyfundleprmeworkfundleprmeworkfundleF
ih undle hs n lisD whih is the lowerEsed short version of the undle nme using undersores @mehello for emerellofundleD or mesoillog for emeoilflogfundle for instneAF his lis is used to enfore uniqueness within undle @see elow for some usge exmplesAF
6.26.2 Directory Structure
rellofundleFphpY esouresGmetGvsgixiX he full liense for the odeY esouresGdoGindexFrstX he root (le for the fundle doumenttionF
X hese onventions ensure tht utomted tools n rely on this defult struture to workF he depth of suEdiretories should e kept to the miniml for most used lsses nd (les @P levels t mximumAF wore levels n e de(ned for nonEstrtegiD lessEused (lesF he undle diretory is redEonlyF sf you need to write temporry (lesD store them under the heG or logG diretory of the host pplitionF ools n generte (les in the undle diretory strutureD ut only if the generted (les re going to e prt of the repositoryF he following lsses nd (les hve spei( emplementsX ype gommnds gontrollers ervie gontiner ixtensions ivent visteners gon(gurtion e esoures rnsltion (les empltes nit nd puntionl ests hiretory gommndG gontrollerG hependenysnjetionG iventvistenerG esouresGon(gG esouresGpuliG esouresGtrnsltionsG esouresGviewsG estsG
6.26.3 Classes
he undle diretory struture is used s the nmespe hierrhyF por instneD rellogontroller ontroller is stored in fundleGrellofundleGgontrollerGrellogontrollerFphp nd the fully quli(ed lss nme is fundlerellofundlegontrollerrellogontrollerF TFPTF fundle truture nd fest rties RQS
ymfony houmenttionD PFH ell lsses nd (les must follow the ymfonyP oding stndrdsF ome lsses should e seen s fdes nd should e s short s possileD like gommndsD relpersD vistenersD nd gontrollersF glsses tht onnet to the ivent hispther should e su0xed with vistenerF ixeptions lsses should e stored in n ixeption suEnmespeF
6.26.4 Vendors
e undle must not emed thirdEprty r lirriesF st should rely on the stndrd ymfonyP utoloding instedF e undle should not emed thirdEprty lirries written in tvriptD gD or ny other lngugeF
6.26.5 Tests
e undle should ome with test suite written with rnit nd stored under the estsG diretoryF ests should follow the following priniplesX
he test suite must e exeutle with simple phpunit ommnd run from smple pplitionY he funtionl tests should only e used to test the response output nd some pro(ling informtion if you hve someY he ode overge should t lest overs WS7 of the ode seF
X e test suite must not ontin ellestsFphp sriptsD ut must rely on the existene of phpunitFxmlFdist (leF
6.26.6 Documentation
ell lsses nd funtions must ome with full rhoF ixtensive doumenttion should lso e provided in the retruturedext formtD under the esouresGdoG diretoryY the esouresGdoGindexFrst (le is the only mndtory (le nd must e the entry point for the doumenttionF
RQT
TF
es est prtieD ontrollers in undle tht9s ment to e distriuted to others must not extend the ymfonyfundleprmeworkfundlegontrollergontroller se lssF hey n implement ymfonygomponenthependenysnjetiongontinerewresnterfe or extend ymfonygomponenthependenysnjetiongontinerewre instedF X sf you hve look t ymfonyfundleprmeworkfundlegontrollergontroller methodsD you will see tht they re only nie shortuts to ese the lerning urveF
6.26.8 Routing
sf the undle provides routesD they must e pre(xed with the undle lisF por n emeflogfundle for instneD ll routes must e pre(xed with melogF
6.26.9 Templates
sf undle provides templtesD they must use wigF e undle must not provide min lyoutD exept if it provides full working pplitionF
6.26.10 Translation Files
sf undle provides messge trnsltionsD they must e de(ned in the vspp formtY the domin should e nmed fter the undle nme @undleFhelloAF e undle must not override existing messges from nother undleF
6.26.11 Conguration
o provide more )exiilityD undle n provide on(gurle settings y using the ymfonyP uiltEin mehnismsF por simple on(gurtion settingsD rely on the defult prmeters entry of the ymfonyP on(gurtionF ymfonyP prmeters re simple keyGvlue pirsY vlue eing ny vlid r vlueF ih prmeter nme should strt with the undle lisD though this is just estEprtie suggestionF he rest of the prmeter nme will use period @FA to seprte di'erent prts @eFgF mehelloFemilFfromAF he end user n provide vlues in ny on(gurtion (leX
ewv
RQU
$container->getParameter('acme_hello.email.from');
iven if this mehnism is simple enoughD you re highly enourged to use the semnti on(gurtion desried in the ookookF X sf you re de(ning serviesD they should lso e pre(xed with the undle lisF
his rtile hs not een written yetD ut will soonF sf you9re interested in writing this entryD see gontriuting to the houmenttionF his topi is ment to show how you n mke one undle extend nother nd use this to override di'erent spets of tht undleF
RQV
TF
sf you open your pplition on(gurtion (le @usully ppGon(gGon(gFymlAD you9ll see numer of di'erent on(gurtion nmespesD suh s frmeworkD twigD nd dotrineF ih of these on(gures spei( undleD llowing you to on(gure things t high level nd then let the undle mke ll the lowElevelD omplex hnges tht resultF por exmpleD the following tells the prmeworkfundle to enle the form integrtionD whih involves the de(ning of quite few servies s well s integrtion of other relted omponentsX
ewv
true
RQW
ymfony houmenttionD PFH import ny on(gurtion resoures from your min pplition on(gurtionX the ixtension lss n hndle ll of thisF he seond option E whih you9ll lern out in this rtile E is muh more )exileD ut lso requires more time to setupF sf you9re wondering whih method you should useD it9s proly good ide to strt with method 5ID nd then hnge to 5P lter if you need toF he seond method hs severl spei( dvntgesX
wuh more powerful thn simply de(ning prmetersX spei( option vlue might trigger the retion of mny servie de(nitionsY eility to hve on(gurtion hierrhy mrt merging when severl on(gurtion (les @eFgF on(gdevFyml nd on(gFymlA override eh other9s on(gurtionY gon(gurtion vlidtion @if you use gon(gurtion glssAY shi utoEompletion when you rete n h nd developers use wvF
yverriding undle prmeters sf fundle provides n ixtension lssD then you should generlly not override ny servie ontiner prmeters from tht undleF he ide is tht if n ixtension lss is presentD every setting tht should e on(gurle should e present in the on(gurtion mde ville y tht lssF sn other words the extension lss de(nes ll the pulily supported on(gurtion settings for whih kwrd omptiility will e mintinedF
sf you do hoose to expose semnti on(gurtion for your undleD you9ll (rst need to rete new ixtension lssD whih will hndle the proessF his lss should live in the hependenysnjetion diretory of your undle nd its nme should e onstruted y repling the fundle post(x of the fundle lss nme with ixtensionF por exmpleD the ixtension lss of emerellofundle would e lled emerelloixtensionX
// Acme/HelloBundle/DependencyInjection/HelloExtension.php use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\ContainerBuilder; class AcmeHelloExtension extends Extension { public function load(array $congs, ContainerBuilder $container) { // where all of the heavy logic is done }
RRH TF
public function getXsdValidationBasePath() { return __DIR__.'/../Resources/cong/'; } public function getNamespace() { return 'http://www.example.com/symfony/schema/'; }
X he getsdlidtionfseth nd getxmespe methods re only required if the undle provides optionl h9s for the on(gurtionF he presene of the previous lss mens tht you n now de(ne n mehello on(gurtion nmespe in ny on(gurtion (leF he nmespe mehello is onstruted from the extension9s lss nme y removing the word ixtension nd then lowersing nd undersoring the rest of the nmeF sn other wordsD emerelloixtension eomes mehelloF ou n egin speifying on(gurtion under this nmespe immeditelyX
ewv
# app/cong/cong.yml acme_hello: ~
wv
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:acme_hello="http://www.example.com/symfony/schema/" xsi:schemaLocation="http://www.example.com/symfony/schema/ http://www.example.com/symfony/s <acme_hello:cong /> ... </container>
r
RRI
ymfony houmenttionD PFH X sf you follow the nming onventions lid out oveD then the lod@A method of your extension ode is lwys lled s long s your undle is registered in the uernelF sn other wordsD even if the user does not provide ny on(gurtion @iFeF the mehello entry doesn9t even pperAD the lod@A method will e lled nd pssed n empty 6on(gs rryF ou n still provide some sensile defults for your undle if you wntF
henever user inludes the mehello nmespe in on(gurtion (leD the on(gurtion under it it is dded to n rry of on(gurtions nd pssed to the lod@A method of your extension @ymfonyP utomtilly onverts wv nd ewv to n rryAF ke the following on(gurtionX
ewv
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:acme_hello="http://www.example.com/symfony/schema/" xsi:schemaLocation="http://www.example.com/symfony/schema/ http://www.example.com/symfony/s <acme_hello:cong foo="fooValue"> <acme_hello:bar>barValue</acme_hello:bar> </acme_hello:cong> </container>
r
// app/cong/cong.php $container->loadFromExtension('acme_hello', array( 'foo' => 'fooValue', 'bar' => 'barValue', ));
he rry pssed to your lod@A method will look like thisX
RRP
TF
array( array( 'foo' => 'fooValue', 'bar' => 'barValue', ), array( 'foo' => 'fooDevValue', 'baz' => 'newCongEntry', ), )
he order of the two rrys depends on whih one is set (rstF st9s your joD thenD to deide how these on(gurtions should e merged togetherF ou mightD for exmpleD hve lter vlues override previous vlues or somehow merge them togetherF vterD in the gon(gurtion glss setionD you9ll lern of truly roust wy to hndle thisF fut for nowD you might just merge them mnullyX
public function load(array $congs, ContainerBuilder $container) { $cong = array(); foreach ($congs as $subCong) { $cong = array_merge($cong, $subCong); } } // now use the at $cong array
X wke sure the ove merging tehnique mkes sense for your undleF his is just n exmpleD nd you should e reful to not use it lindlyF
RRQ
ithin lod@AD the 6ontiner vrile refers to ontiner tht only knows out this nmespe on(gurtion @iFeF it doesn9t ontin servie informtion loded from other undlesAF he gol of the lod@A method is to mnipulte the ontinerD dding nd on(guring ny methods or servies needed y your undleF voding ixternl gon(gurtion esoures yne ommon thing to do is to lod n externl on(gurtion (le tht my ontin the ulk of the servies needed y your undleF por exmpleD suppose you hve serviesFxml (le tht holds muh of your undle9s servie on(gurtionX
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\Cong\FileLocator; public function load(array $congs, ContainerBuilder $container) { // prepare your $cong variable $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/cong')); $loader->load('services.xml');
ou might even do this onditionllyD sed on one of the on(gurtion vluesF por exmpleD suppose you only wnt to lod set of servies if n enled option is pssed nd set to trueX
public function load(array $congs, ContainerBuilder $container) { // prepare your $cong variable $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/cong')); if (isset($cong['enabled']) && $cong['enabled']) { $loader->load('services.xml'); }
gon(guring ervies nd etting rmeters yne you9ve loded some servie on(gurtionD you my need to modify the on(gurtion sed on some of the input vluesF por exmpleD suppose you hve servie who9s (rst rgument is some string type tht it will use internllyF ou9d like this to e esily on(gured y the undle userD so in your servie on(gurtion (le @eFgF serviesFxmlAD you
RRR
TF
ymfony houmenttionD PFH de(ne this servie nd use lnk prmeter E mehelloFmyservietype E s its (rst rgumentX
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/servi <parameters> <parameter key="acme_hello.my_service_type" /> </parameters> <services> <service id="acme_hello.my_service" class="Acme\HelloBundle\MyService"> <argument>%acme_hello.my_service_type%</argument> </service> </services> </container>
fut why would you de(ne n empty prmeter nd then pss it to your serviec he nswer is tht you9ll set this prmeter in your extension lssD sed on the inoming on(gurtion vluesF upposeD for exmpleD tht you wnt to llow the user to de(ne this type option under key lled mytypeF edd the following to the lod@A method to do thisX
public function load(array $congs, ContainerBuilder $container) { // prepare your $cong variable $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/cong')); $loader->load('services.xml'); if (!isset($cong['my_type'])) { throw new \InvalidArgumentException('The "my_type" option must be set'); } } $container->setParameter('acme_hello.my_service_type', $cong['my_type']);
xowD the user n e'etively on(gure the servie y speifying the mytype on(gurtion vlueX
ewv
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:acme_hello="http://www.example.com/symfony/schema/" xsi:schemaLocation="http://www.example.com/symfony/schema/ http://www.example.com/symfony/s <acme_hello:cong my_type="foo"> <!-- ... --> </acme_hello:cong> </container>
r
RRT
TF
o frD you9ve done the merging of your on(gurtion rrys y hnd nd re heking for the presene of on(g vlues mnully using the isset@A r funtionF en optionl gon(gurtion system is lso ville whih n help with mergingD vlidtionD defult vluesD nd formt normliztionF X pormt normliztion refers to the ft tht ertin formts E lrgely wv E result in slightly di'erent on(gurtion rrys nd tht these rrys need to e normlized to mth everything elseF o tke dvntge of this systemD you9ll rete gon(gurtion lss nd uild tree tht de(nes your on(gurtion in tht lssX
// src/Acme/HelloBundle/DependencyExtension/Conguration.php namespace Acme\HelloBundle\DependencyInjection; use Symfony\Component\Cong\Denition\Builder\TreeBuilder; use Symfony\Component\Cong\Denition\CongurationInterface; class Conguration implements CongurationInterface { public function getCongTreeBuilder() { $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root('acme_hello'); $rootNode ->children() ->scalarNode('my_type')->defaultValue('bar')->end() ->end() ; } return $treeBuilder;
his is very simple exmpleD ut you n now use this lss in your lod@A method to merge your on(gurtion nd fore vlidtionF sf ny options other thn mytype re pssedD the user will e noti(ed with n exeption tht n unsupported option ws pssedX
use Symfony\Component\Cong\Denition\Processor; // ... public function load(array $congs, ContainerBuilder $container) { $processor = new Processor();
TFPVF row to expose emnti gon(gurtion for fundle RRU
he proessgon(gurtion@A method uses the on(gurtion tree you9ve de(ned in the gon(gurtion lss nd uses it to vlidteD normlize nd merge ll of the on(gurtion rrys togetherF he gon(gurtion lss n e muh more omplited thn shown hereD supporting rry nodesD prototype nodesD dvned vlidtionD wvEspei( normliztion nd dvned mergingF he est wy to see this in tion is to hekout out some of the ore gon(gurtion lssesD suh s the one from the prmeworkfundle gon(gurtion or the wigfundle gon(gurtionF
6.28.5 Extension Conventions
he extension must e stored in the hependenysnjetion suEnmespeY he extension must e nmed fter the undle nme nd su0xed with ixtension @emerelloixtension for emerellofundleAY he extension should provide n h shemF
sf you follow these simple onventionsD your extensions will e registered utomtilly y ymfonyPF sf notD override the fundle XmethodXymfonygomponentrttpuernelfundlefundleXXuild method in your undleX
use Acme\HelloBundle\DependencyInjection\UnconventionalExtensionClass; class AcmeHelloBundle extends Bundle { public function build(ContainerBuilder $container) { parent::build($container); // register extensions that do not follow the conventions manually $container->registerExtension(new UnconventionalExtensionClass());
sn this seD the extension lss must lso implement getelis@A method nd return unique lis nmed fter the undle @eFgF mehelloAF his is required euse the lss RRV TF
ymfony houmenttionD PFH nme doesn9t follow the stndrds y ending in ixtensionF edditionllyD the lod@A method of your extension will only e lled if the user spei(es the mehello lis in t lest one on(gurtion (leF yne ginD this is euse the ixtension lss doesn9t follow the stndrds set out oveD so nothing hppens utomtillyF
6.29
E F D wiftmilerfundleD E wiftmiler F X X
6.29.1
wiftmilerD F E trnsportX
ewv
# app/cong/cong.yml swiftmailer: transport: smtp encryption: ssl auth_mode: login host: smtp.gmail.com username: your_username password: your_password
wv
TFPWF
RRW
<!-xmlns:swiftmailer="http://symfony.com/schema/dic/swiftmailer" http://symfony.com/schema/dic/swiftmailer http://symfony.com/schema/dic/swiftmailer/swiftmailer-1.0.xs --> <swiftmailer:cong transport="smtp" encryption="ssl" auth-mode="login" host="smtp.gmail.com" username="your_username" password="your_password" />
r
// app/cong/cong.php $container->loadFromExtension('swiftmailer', array( 'transport' => "smtp", 'encryption' => "ssl", 'auth_mode' => "login", 'host' => "smtp.gmail.com", 'username' => "your_username", 'password' => "your_password", ));
wiftmiler D E F X
trnsport @smtpD milD sendmilD gmilA usernme pssword host port enryption @tlsD sslA uthmode @plinD loginD rmEmdSA spool
! type @ D (le E A ! pth @ A RSH TF
public function indexAction($name) { $message = \Swift_Message::newInstance() ->setSubject('Hello Email') ->setFrom('send@example.com') ->setTo('recipient@example.com') ->setBody($this->renderView('HelloBundle:Hello:email.txt.twig', array('name' => $name))) ; $this->get('mailer')->send($message); } return $this->render(...);
qmil row to ork with imils huring hevelopment row to pool imil
6.30 Gmail
D w E D qmil F wiftmiler F
TFQHF qmil
RSI
ewv
// app/cong/cong_dev.php $container->loadFromExtension('swiftmailer', array( 'transport' => "gmail", 'username' => "your_gmail_username", 'password' => "your_gmail_password", ));
3 X gmil D smtp enryptionD uthmode host qmilF
RSP
TF
hen you re reting n pplition whih sends emilsD you will often not wnt to tully send the emils to the spei(ed reipient while developmentF sf you re using the wiftmilerfundle with ymfonyPD you n esily hieve this through on(gurtion settings without hving to mke ny hnges to your pplition9s ode t llF here re two min hoies when it omes to hndling emils during developmentX @A disling the sending of emils ltogether or @A sending ll the emils to spei(ed ddressF
6.31.1 Disabling Sending
ou n disle sending emils y setting the disledelivery option to trueF his is the defult in the test environment in the tndrd distriutionF sf you do this in the test spei( on(g then emils will not e sent when you run testsD ut will ontinue to e sent in the prod nd dev environmentsX
ewv
RSQ
ou n lso hoose to hve ll emils sent to spei( ddressD insted of the ddress tully spei(ed when sending the messgeF his n e done vi the deliveryddress optionX
ewv
public function indexAction($name) { $message = \Swift_Message::newInstance() ->setSubject('Hello Email') ->setFrom('send@example.com') ->setTo('recipient@example.com') ->setBody($this->renderView('HelloBundle:Hello:email.txt.twig', array('name' => $name))) ; $this->get('mailer')->send($message); } return $this->render(...);
sn the dev environmentD the emil will insted e sent to devdexmpleFomF wiftmiler will dd n extr heder to the emilD EwiftEo ontining the repled ddressD so you will still e le to see who it would hve een sent toF RSR TF
X sn ddition to the to ddressesD this will lso stop the emil eing sent to ny gg nd fgg ddresses set for itF wiftmiler will dd dditionl heders to the emil with the overridden ddresses in themF hese re EwiftEg nd EwiftEf for the gg nd fgg ddresses respetivelyF
ou n view ny emils sent y pge when you re in the dev environment using the e heug oolrF he emil ion in the toolr will show how mny emils were sentF sf you lik itD report showing the detils of the emils will openF sf you9re sending n emil nd then redireting immeditely fterD you9ll need to set the intereptredirets option to true in the on(gdevFyml (le so tht you n see the emil in the we deug toolr efore eing rediretedF
hen you re using the wiftmilerfundle to send n emil from ymfonyP pplitionD it will defult to sending the emil immeditelyF ou myD howeverD wnt to void the performne hit of the ommunition etween wiftmiler nd the emil trnsportD whih ould use the user to wit for the next pge to lod while the emil is sendingF his n e voided y hoosing to spool the emils insted of sending them diretlyF his mens tht wiftmiler does not ttempt to send the emil ut insted sves the messge to somewhere suh s (leF enother proess n then red from the spool nd tke re of sending the emils in the spoolF gurrently only spooling to (le is supported y wiftmilerF sn order to use the spoolD use the following on(gurtionX
ewv
// app/cong/cong.php $container->loadFromExtension('swiftmailer', array( // ... 'spool' => array( 'type' => 'le', 'path' => '/path/to/spool', ) ));
X sf you wnt to store the spool somewhere with your projet diretoryD rememer tht you n use the 7kernelFrootdir7 prmeter to referene the projet9s rootX
path: %kernel.root_dir%/spool
xowD when your pp sends n emilD it will not tully e sent ut insted dded to the spoolF ending the messges from the spool is done seprtelyF here is onsole ommnd to send the messges in the spoolX
RST
TF
sf your pplition needs r uthentitionD pss the usernme nd pssword s server vriles to reteglient@AX
$client = static::createClient(array(), array( 'PHP_AUTH_USER' => 'username', 'PHP_AUTH_PW' => 'pa$$word', ));
ou n lso override it on per request sisX
$client->request('DELETE', '/post/12', array(), array( 'PHP_AUTH_USER' => 'username', 'PHP_AUTH_PW' => 'pa$$word', ));
sf you need to simulte n intertion etween di'erent glients @think of ht for instneAD rete severl glientsX
$harry = static::createClient(); $sally = static::createClient(); $harry->request('POST', '/say/sally/Hello'); $sally->request('GET', '/messages'); $this->assertEquals(201, $harry->getResponse()->getStatusCode()); $this->assertRegExp('/Hello/', $sally->getResponse()->getContent());
his works exept when your ode mintins glol stte or if it depends on thirdEprty lirries tht hs some kind of glol stteF sn suh seD you n insulte your lientsX
$harry = static::createClient(); $sally = static::createClient(); $harry->insulate(); $sally->insulate(); $harry->request('POST', '/say/sally/Hello'); $sally->request('GET', '/messages'); $this->assertEquals(201, $harry->getResponse()->getStatusCode()); $this->assertRegExp('/Hello/', $sally->getResponse()->getContent());
TFQQF row to simulte r euthentition in puntionl est RSU
ymfony houmenttionD PFH snsulted lients trnsprently exeute their requests in dedited nd len r proessD thus voiding ny sideEe'etsF X es n insulted lient is slowerD you n keep one lient in the min proessD nd insulte the other onesF
st9s highly reommended tht funtionl test only tests the esponseF fut if you write funtionl tests tht monitor your prodution serversD you might wnt to write tests on the pro(ling dt s it gives you gret wy to hek vrious things nd enfore some metrisF he ymfonyP ro(ler gthers lot of dt for eh requestF se this dt to hek the numer of dtse llsD the time spent in the frmeworkD FFF fut efore writing ssertionsD lwys hek tht the pro(ler is indeed ville @it is enled y defult in the test environmentAX
class HelloControllerTest extends WebTestCase { public function testIndex() { $client = static::createClient(); $crawler = $client->request('GET', '/hello/Fabien'); // Write some assertions about the Response // ... // Check that the proler is enabled if ($prole = $client->getProle()) { // check the number of requests $this->assertTrue($prole->getCollector('db')->getQueryCount() < 10); // check the time spent in the framework $this->assertTrue( $prole->getCollector('timer')->getTime() < 0.5);
sf test fils euse of pro(ling dt @too mny hf queries for instneAD you might wnt to use the e ro(ler to nlyze the request fter the tests (nishF st9s esy to hieve if you emed the token in the error messgeX
);
X he pro(ler store n e di'erent depending on the environment @espeilly if you use the vite storeD whih is the defult on(gured oneAF
X he pro(ler informtion is ville even if you insulte the lient or if you use n r lyer for your testsF
nit testing hotrine repositories in ymfony projet is not strightforwrd tskF sndeedD to lod repository you need to lod your entitiesD n entity mngerD nd some other stu' like onnetionF o test your repositoryD you hve two di'erent optionsX IF puntionl testX his inludes using rel dtse onnetion with rel dtse ojetsF st9s esy to setup nd n test nythingD ut is slower to exeuteF ee puntionl estingF PF nit testX nit testing is fster to run nd more preise in how you testF st does require little it more setupD whih is overed in this doumentF st n lso only test methods thtD for exmpleD uild queriesD not methods tht tully exeute themF
6.36.1 Unit Testing
es ymfony nd hotrine shre the sme testing frmeworkD it9s quite esy to implement unit tests in your ymfony projetF he yw omes with its own set of tools to ese the unit testing nd moking of everything you needD suh s onnetionD n entity mngerD etF fy using the testing omponents provided y hotrine E long with some si setup E you n leverge hotrine9s tools to unit test your repositoriesF ueep in mind tht if you wnt to test the tul exeution of your queriesD you9ll need funtionl test @see puntionl estingAF nit testing is only possile when testing method tht uilds queryF
RSW
ymfony houmenttionD PFH etup pirstD you need to dd the hotrineests nmespe to your utoloderX
// src/Acme/ProductBundle/Tests/Entity/ProductRepositoryTest.php namespace Acme\ProductBundle\Tests\Entity; use Doctrine\Tests\OrmTestCase; use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\ORM\Mapping\Driver\DriverChain; use Doctrine\ORM\Mapping\Driver\AnnotationDriver; class ProductRepositoryTest extends OrmTestCase { private $_em; protected function setUp() { $reader = new AnnotationReader(); $reader->setIgnoreNotImportedAnnotations(true); $reader->setEnableParsePhpImports(true); $metadataDriver = new AnnotationDriver( $reader, // provide the namespace of the entities you want to tests 'Acme\\ProductBundle\\Entity' ); $this->_em = $this->_getTestEntityManager(); $this->_em->getConguration() ->setMetadataDriverImpl($metadataDriver); // allows you to use the AcmeProductBundle:Product syntax $this->_em->getConguration()->setEntityNamespaces(array( 'AcmeProductBundle' => 'Acme\\ProductBundle\\Entity'
RTH TF
));
ou extend from hotrineestsyrmestgseD whih provide useful methods for unit testingY ou need to setup the ennottioneder to e le to prse nd lod the entitiesY ou rete the entity mnger y lling getestintitywngerD whih returns moked entity mnger with moked onnetionF
ht9s it3 ou9re redy to write units tests for your hotrine repositoriesF riting your nit est ememer tht hotrine repository methods n only e tested if they re uilding nd returning query @ut not tully exeuting queryAF ke the following exmpleX
// src/Acme/StoreBundle/Entity/ProductRepository namespace Acme\StoreBundle\Entity; use Doctrine\ORM\EntityRepository; class ProductRepository extends EntityRepository { public function createSearchByNameQueryBuilder($name) { return $this->createQueryBuilder('p') ->where('p.name LIKE :name', $name) } }
sn this exmpleD the method is returning ueryfuilder instneF ou n test the result of this method in vriety of wysX
class ProductRepositoryTest extends \Doctrine\Tests\OrmTestCase { /* ... */ public function testCreateSearchByNameQueryBuilder() { $queryBuilder = $this->_em->getRepository('AcmeProductBundle:Product') ->createSearchByNameQueryBuilder('foo'); $this->assertEquals('p.name LIKE :name', (string) $queryBuilder->getDqlPart('where'));
TFQTF row to test hotrine epositories RTI
sn this testD you disset the ueryfuilder ojetD looking tht eh prt is s you9d expetF sf you were dding other things to the query uilderD you might hek the dql prtsX seletD fromD joinD setD groupfyD hvingD or orderfyF sf you only hve rw uery ojet or prefer to test the tul queryD you n test the hv query string diretlyX
public function testCreateSearchByNameQueryBuilder() { $queryBuilder = $this->_em->getRepository('AcmeProductBundle:Product') ->createSearchByNameQueryBuilder('foo'); $query = $queryBuilder->getQuery(); // test DQL $this->assertEquals( 'SELECT p FROM Acme\ProductBundle\Entity\Product p WHERE p.name LIKE :name', $query->getDql() );
sf you need to tully exeute queryD you will need to oot the kernel to get vlid onnetionF sn this seD you9ll extend the eestgseD whih mkes ll of this quite esyX
// src/Acme/ProductBundle/Tests/Entity/ProductRepositoryFunctionalTest.php namespace Acme\ProductBundle\Tests\Entity; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class ProductRepositoryFunctionalTest extends WebTestCase { /** * @var \Doctrine\ORM\EntityManager */ private $_em; public function setUp() { $kernel = static::createKernel(); $kernel->boot();
RTP TF
yne user is uthentitedD their redentils re typilly stored in the sessionF his mens tht when the session ends they will e logged out nd hve to provide their login detils gin next time they wish to ess the pplitionF ou n llow users to hoose to sty logged in for longer thn the session lsts using ookie with the rememerme (rewll optionF he (rewll needs to hve seret key on(guredD whih is used to enrypt the ookie9s ontentF st lso hs severl options with defult vlues whih re shown hereX
ewv
# app/cong/security.yml rewalls: main: remember_me: key: aSecretKey lifetime: 3600 path: / domain: ~ # Defaults to the current domain from $_SERVER
wv
<!-- app/cong/security.xml --> <cong> <rewall> <remember-me key="aSecretKey" lifetime="3600" path="/" domain="" <!-- Defaults to the current domain from $_SERVER --> />
TFQUF row to dd ememer we vogin puntionlity RTQ
</rewall> </cong>
r
// app/cong/security.php $container->loadFromExtension('security', array( 'rewalls' => array( 'main' => array('remember_me' => array( 'key' => '/login_check', 'lifetime' => 3600, 'path' => '/', 'domain' => '', // Defaults to the current domain from $_SERVER )), ), ));
st9s good ide to provide the user with the option to use or not use the rememer me funtionlityD s it will not lwys e ppropriteF he usul wy of doing this is to dd hekox to the login formF fy giving the hekox the nme rememermeD the ookie will utomtilly e set when the hekox is heked nd the user suessfully logs inF oD your spei( login form might ultimtely look like thisX
wig
{# src/Acme/SecurityBundle/Resources/views/Security/login.html.twig #} {% if error %} <div>{{ error.message }}</div> {% endif %} <form action="{{ path('login_check') }}" method="post"> <label for="username">Username:</label> <input type="text" id="username" name="_username" value="{{ last_username }}" /> <label for="password">Password:</label> <input type="password" id="password" name="_password" /> <input type="checkbox" id="remember_me" name="_remember_me" checked /> <label for="remember_me">Keep me logged in</label> <input type="submit" name="login" /> </form>
r
<?php // src/Acme/SecurityBundle/Resources/views/Security/login.html.php ?> <?php if ($error): ?> <div><?php echo $error->getMessage() ?></div>
RTR TF
<?php endif; ?> <form action="<?php echo $view['router']->generate('login_check') ?>" method="post"> <label for="username">Username:</label> <input type="text" id="username" name="_username" value="<?php echo $last_username ?>" /> <label for="password">Password:</label> <input type="password" id="password" name="_password" /> <input type="checkbox" id="remember_me" name="_remember_me" checked /> <label for="remember_me">Keep me logged in</label> <input type="submit" name="login" /> </form>
he user will then utomtilly e logged in on susequent visits while the ookie remins vlidF
6.37.1 Forcing the User to Re-authenticate before accessing certain Resources
hen the user returns to your siteD heGshe is uthentited utomtilly sed on the informtion stored in the rememer me ookieF his llows the user to ess proteted resoures s if the user hd tully uthentited upon visiting the siteF sn some sesD howeverD you my wnt to fore the user to tully reEuthentite efore essing ertin resouresF por exmpleD you might llow rememer me user to see si ount informtionD ut then require them to tully reEuthentite efore modifying tht informtionF he seurity omponent provides n esy wy to do thisF sn ddition to roles expliitly ssigned to themD users re utomtilly given one of the following roles depending on how they re uthentitedX
serixsgeihexyxwyv E utomtilly ssigned to user who is in (rewll proteted prt of the site ut who hs not tully logged inF his is only possile if nonymous ess hs een llowedF serixsgeihiwiwfiih E utomtilly ssigned to user who ws uthentited vi rememer me ookieF serixsgeihpvv E utomtilly ssigned to user tht hs provided their login detils during the urrent sessionF
ou n use these to ontrol ess eyond the expliitly ssigned rolesF
RTS
ymfony houmenttionD PFH X sf you hve the serixsgeihiwiwfiih roleD then you lso hve the serixsgeihexyxwyv roleF sf you hve the serixsgeihpvv roleD then you lso hve the other two rolesF sn other wordsD these roles represent three levels of inresing strength of uthentitionF ou n use these dditionl roles for (ner grined ontrol over ess to prts of siteF por exmpleD you my wnt you user to e le to view their ount t Gount when uthentited y ookie ut to hve to provide their login detils to e le to edit the ount detilsF ou n do this y seuring spei( ontroller tions using these rolesF he edit tion in the ontroller ould e seured using the servie ontextF sn the following exmpleD the tion serixsgeihpvv roleF is only llowed if the user hs the
use Symfony\Component\Security\Core\Exception\AccessDeniedException // ... public function editAction() { if (false === $this->get('security.context')->isGranted( 'IS_AUTHENTICATED_FULLY' )) { throw new AccessDeniedException(); } } // ...
ou n lso hoose to instll nd use the optionl tweurityixtrfundleD whih n seure your ontroller using nnottionsX
sf nonEuthentited @or nonymously uthentited userA tries to ess the ount reD the user will e sked to uthentiteF
RTT TF
yne the user hs entered his usernme nd psswordD ssuming the user reeives the yvii role per your on(gurtionD the user will hve the serixsgeihpvv role nd e le to ess ny pge in the ount setionD inluding the editetion ontrollerF sf the user9s session endsD when the user returns to the siteD he will e le to ess every ount pge E exept for the edit pge E without eing fored to reEuthentiteF roweverD when he tries to ess the editetion ontrollerD he will e fored to reE uthentiteD sine he is notD yetD fully uthentitedF
por more informtion on seuring servies or methods in this wyD see row to seure ny ervie or wethod in your epplitionF
he ymfonyP seurity omponent provides severl lyers to uthentite usersF yne of the lyers is lled voterF e voter is dedited lss tht heks if the user hs the rights to e onneted to the pplitionF por instneD ymfonyP provides lyer tht heks if the user is fully uthentited or if it hs some expeted rolesF st is sometimes useful to rete ustom voter to hndle spei( se not hndled y the frmeworkF sn this setionD you9ll lern how to rete voter tht will llow you to lklist users y their sF
6.38.1 The Voter Interface
e ustom voter must implement ymfonygomponenteuritygoreeuthoriztionoterotersnterfeD whih requires the following three methodsX
interface VoterInterface { function supportsAttribute($attribute); function supportsClass($class); function vote(TokenInterface $token, $object, array $attributes); }
he supportsettriute@A method is used to hek if the voter supports the given user ttriute @iFeX roleD n lD etFAF he supportsglss@A method is used to hek if the voter supports the urrent user token lssF he vote@A method must implement the usiness logi tht veri(es whether or not the user is grnted essF his method must return one of the following vluesX TFQVF row to implement your own oter to lklist s eddresses RTU
otersnterfeXXeggiqexihX he user is llowed to ess the pplition otersnterfeXXeggiefesxX he voter nnot deide if the user is grnted or not otersnterfeXXeggihixsihX he user is not llowed to ess the pplition
sn this exmpleD we will hek if the user9s s ddress mthes ginst list of lklisted ddressesF sf the user9s s is lklistedD we will return otersnterfeXXeggihixsihD otherwise we will return otersnterfeXXeggiefesx s this voter9s purpose is only to deny essD not to grnt essF
6.38.2 Creating a Custom Voter
o lklist user sed on its sD we n use the request servie nd ompre the s ddress ginst set of lklisted s ddressesX
namespace Acme\DemoBundle\Security\Authorization\Voter; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; class ClientIpVoter implements VoterInterface { public function __construct(ContainerInterface $container, array $blacklistedIp = array()) { $this->container = $container; $this->blacklistedIp = $blacklistedIp; } public function supportsAttribute($attribute) { // we won't check against a user attribute, so we return true return true; } public function supportsClass($class) { // our voter supports all type of token classes, so we return true return true; } function vote(TokenInterface $token, $object, array $attributes) { $request = $this->container->get('request'); if (in_array($this->request->getClientIp(), $this->blacklistedIp)) {
RTV TF
} }
return VoterInterface::ACCESS_DENIED;
return VoterInterface::ACCESS_ABSTAIN;
ht9s it3 he voter is doneF he next step is to injet the voter into the seurity lyerF his n e done esily through the servie ontinerF
6.38.3 Declaring the Voter as a Service
o injet the voter into the seurity lyerD we must delre it s servieD nd tg it s seurityFvoterX
ewv
# src/Acme/AcmeBundle/Resources/cong/services.yml services: security.access.blacklist_voter: class: Acme\DemoBundle\Security\Authorization\Voter\ClientIpVoter arguments: [@service_container, [123.123.123.123, 171.171.171.171]] public: false tags: { name: security.voter }
wv
<!-- src/Acme/AcmeBundle/Resources/cong/services.xml --> <service id="security.access.blacklist_voter" class="Acme\DemoBundle\Security\Authorization\Voter\ClientIpVoter" public="false"> <argument type="service" id="service_container" strict="false" /> <argument type="collection"> <argument>123.123.123.123</argument> <argument>171.171.171.171</argument> </argument> <tag name="security.voter" /> </service>
r
$denition = new Denition( 'Acme\DemoBundle\Security\Authorization\Voter\ClientIpVoter', array( new Reference('service_container'), array('123.123.123.123', '171.171.171.171'), ), ); $denition->addTag('security.voter'); $denition->setPublic(false); $container->setDenition('security.access.blacklist_voter', $denition);
X fe sure to import this on(gurtion (le from your min pplition on(gurtion (le @eFgF ppGon(gGon(gFymlAF por more informtion see smporting gon(gurtion with importsF o red more out de(ning servies in generlD see the ervie gontiner hpterF
sn order for the new voter to tke e'etD we need to hnge the defult ess deision strtegyD whihD y defultD grnts ess if ny voter grnts essF sn our seD we will hoose the unnimous strtegyF nlike the 0rmtive strtegy @the defultAD with the unnimous strtegyD if only one voter denies ess @eFgF the glientspoterAD ess is not grnted to the end userF o do thtD override the defult essdeisionmnger setion of your pplition on(gurtion (le with the following odeF
ewv
# app/cong/security.yml security: access_decision_manager: # Strategy can be: armative, unanimous or consensus strategy: unanimous
ht9s it3 xowD when deiding whether or not user should hve essD the new voter will deny ess to ny user in the list of lklisted ssF
sn omplex pplitionsD you will often fe the prolem tht ess deisions nnot only e sed on the person @okenA who is requesting essD ut lso involve domin ojet RUH TF
ymfony houmenttionD PFH tht ess is eing requested forF his is where the egv system omes inF smgine you re designing log system where your users n omment on your postsF xowD you wnt user to e le to edit his own ommentsD ut not those of other usersY esidesD you yourself wnt to e le to edit ll ommentsF sn this senrioD gomment would e our domin ojet tht you wnt to restrit ess toF ou ould tke severl pprohes to omplish this using ymfonyPD two si pprohes re @nonEexhustiveAX
infore seurity in your usiness methodsX fsillyD tht mens keeping referene inside eh gomment to ll users who hve essD nd then ompre these users to the provided okenF infore seurity with rolesX sn this pprohD you would dd role for eh gomment ojetD iFeF yvigywwixID yvigywwixPD etF
foth pprohes re perfetly vlidF roweverD they ouple your uthoriztion logi to your usiness ode whih mkes it less reusle elsewhereD nd lso inreses the di0ulty of unit testingF fesidesD you ould run into performne issues if mny users would hve ess to single domin ojetF portuntelyD there is etter wyD whih we will tlk out nowF
6.39.1 Bootstrapping
xowD efore we (nlly n get into tionD we need to do some ootstrppingF pirstD we need to on(gure the onnetion the egv system is supposed to useX
ewv
RUI
ymfony houmenttionD PFH X he egv system requires t lest one hotrine hfev onnetion to e on(guredF roweverD tht does not men tht you hve to use hotrine for mpping your domin ojetsF ou n use whtever mpper you like for your ojetsD e it hotrine ywD wongo yhwD ropelD or rw vD the hoie is yoursF efter the onnetion is on(guredD we hve to import the dtse strutureF portuntelyD we hve tsk for thisF imply run the following ommndX
goming k to our smll exmple from the eginningD let9s implement egv for itF greting n egvD nd dding n egi
use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Acl\Domain\ObjectIdentity; use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity; use Symfony\Component\Security\Acl\Permission\MaskBuilder; // ... // BlogController.php public function addCommentAction(Post $post) { $comment = new Comment(); // setup $form, and bind data // ... if ($form->isValid()) { $entityManager = $this->get('doctrine.orm.default_entity_manager'); $entityManager->persist($comment); $entityManager->ush(); // creating the ACL $aclProvider = $this->get('security.acl.provider'); $objectIdentity = ObjectIdentity::fromDomainObject($comment); $acl = $aclProvider->createAcl($objectIdentity); // retrieving the security identity of the currently logged-in user $securityContext = $this->get('security.context'); $user = $securityContext->getToken()->getUser(); $securityIdentity = UserSecurityIdentity::fromAccount($user);
RUP TF
here re ouple of importnt implementtion deisions in this ode snippetF por nowD s only wnt to highlight twoX pirstD you my hve notied tht Ebreteel@A does not ept domin ojets diretlyD ut only implementtions of the yjetsdentitysnterfeF his dditionl step of indiretion llows you to work with egvs even when you hve no tul domin ojet instne t hndF his will e extremely helpful if you wnt to hek permissions for lrge numer of ojets without tully hydrting these ojetsF he other interesting prt is the Ebinsertyjetee@A llF sn our exmpleD we re grnting the user who is urrently logged in owner ess to the gommentF he wskfuilderXXweuyxi is preEde(ned integer itmskY don9t worry the msk uilder will strt wy most of the tehnil detilsD ut using this tehnique we n store mny di'erent permissions in one dtse row whih gives us onsiderle oost in performneF X he order in whih egis re heked is signi(ntF es generl ruleD you should ple more spei( entries t the eginningF
gheking eess
// BlogController.php public function editCommentAction(Comment $comment) { $securityContext = $this->get('security.context'); // check for edit access if (false === $securityContext->isGranted('EDIT', $comment)) { throw new AccessDeniedException(); } // retrieve actual comment object, and do your editing here // ...
sn this exmpleD we hek whether the user hs the ihs permissionF snternllyD ymfonyP mps the permission to severl integer itmsksD nd heks whether the user hs ny of TFQWF eess gontrol vists @egvsA RUQ
ymfony houmenttionD PFH themF X ou n de(ne up to QP se permissions @depending on your y r might vry etween QH to QPAF sn dditionD you n lso de(ne umultive permissionsF
sn our (rst exmple oveD we only grnted the user the yxi se permissionF hile this e'etively lso llows the user to perform ny opertion suh s viewD editD etF on the domin ojetD there re ses where we wnt to grnt these permissions expliitlyF he wskfuilder n e used for reting it msks esily y omining severl se permissionsX
$builder = new MaskBuilder(); $builder ->add('view') ->add('edit') ->add('delete') ->add('undelete') ; $mask = $builder->get(); // int(15)
his integer itmsk n then e used to grnt user the se permissions you dded oveX
he im of this hpter is to give more inEdepth view of the egv systemD nd lso explin some of the design deisions ehind itF
6.40.1 Design Concepts
ymfonyP9s ojet instne seurity pilities re sed on the onept of n eess gontrol vistF ivery domin ojet instne hs its own egvF he egv instne holds detiled list of eess gontrol intries @egisA whih re used to mke ess deisionsF ymfonyP9s egv system fouses on two min ojetivesX
providing wy to e0iently retrieve lrge mount of egvsGegis for your domin ojetsD nd to modify themY
RUR TF
providing wy to esily mke deisions of whether person is llowed to perform n tion on domin ojet or notF
es indited y the (rst pointD one of the min pilities of ymfonyP9s egv system is highEperformne wy of retrieving egvsGegisF his is extremely importnt sine eh egv might hve severl egisD nd inherit from nother egv in treeElike fshionF hereforeD we spei(lly do not leverge ny ywD ut the defult implementtion interts with your onnetion diretly using hotrine9s hfevF yjet sdentities he egv system is ompletely deoupled from your domin ojetsF hey don9t even hve to e stored in the sme dtseD or on the sme serverF sn order to hieve this deouplingD in the egv system your ojets re represented through ojet identity ojetsF iverytimeD you wnt to retrieve the egv for domin ojetD the egv system will (rst rete n ojet identity from your domin ojetD nd then pss this ojet identity to the egv provider for further proessingF eurity sdentities his is nlog to the ojet identityD ut represents userD or role in your pplitionF ih roleD or user hs its own seurity identityF
6.40.2 Database Table Structure
he defult implementtion uses (ve dtse tles s listed elowF he tles re ordered from lest rows to most rows in typil pplitionX
lseurityidentitiesX his tle reords ll seurity identities @shA whih hold egisF he defult implementtion ships with two seurity identitiesX oleeuritysdentityD nd sereuritysdentity llssesX his tle mps lss nmes to unique id whih n e referened from other tlesF lojetidentitiesX ih row in this tle represents single domin ojet instneF lojetidentitynestorsX his tle llows us to determine ll the nestors of n egv in very e0ient wyF lentriesX his tle ontins ll egisF his is typilly the tle with the most rowsF st n ontin tens of millions without signi(ntly impting performneF
RUS
eess ontrol entries n hve di'erent sopes in whih they pplyF sn ymfonyPD we hve silly two di'erent sopesX
glssEopeX hese entries pply to ll ojets with the sme lssF yjetEopeX his ws the sope we solely used in the previous hpterD nd it only pplies to one spei( ojetF
ometimesD you will (nd the need to pply n egi only to spei( (eld of the ojetF vet9s sy you wnt the sh only to e viewle y n dministrtorD ut not y your ustomer servieF o solve this ommon prolemD we hve dded two more suEsopesX
glssEpieldEopeX hese entries pply to ll ojets with the sme lssD ut only to spei( (eld of the ojetsF yjetEpieldEopeX hese entries pply to spei( ojetD nd only to spei( (eld of tht ojetF
6.40.4 Pre-Authorization Decisions
por preEuthoriztion deisionsD tht is deisions efore ny methodD or seure tion is invokedD we rely on the proven eessheisionwnger servie tht is lso used for rehing uthoriztion deisions sed on rolesF tust like rolesD the egv system dds severl new ttriutes whih my e used to hek for di'erent permissionsF
RUT
TF
ymfony houmenttionD PFH fuiltEin ermission wp ettriute sntended wening si hether someone is llowed to view the domin ojetF snteger fitmsks siD ihsD yieyD weiD or yxi ihsD yieyD weiD or yxi hiviiD yieyD weiD or yxi xhiviiD yieyD weiD or yxi yieyD weiD or yxi weiD or yxi yxi
ihs hether someone is llowed to mke hnges to the domin ojetF hivii hether someone is llowed to delete the domin ojetF
xhivii hether someone is llowed to restore previously deleted domin ojetF yiey hether someone is llowed to perform ll of the ove tionsF wei hether someone is llowed to perform ll of the ove tionsD nd in ddition is llowed to grnt ny of the ove permissions to othersF yxi hether someone owns the domin ojetF en owner n perform ny of the ove tionsF ermission ettriutes vsF ermission fitmsks
ettriutes re used y the eessheisionwngerD just like roles re ttriutes used y the eessheisionwngerF yftenD these ttriutes represent in ft n ggregte of integer itmsksF snteger itmsks on the other hndD re used y the egv system internlly to e0iently store your users9 permissions in the dtseD nd perform ess heks using extremely fst itmsk opertionsF ixtensiility he ove permission mp is y no mens sttiD nd theoretilly ould e ompletely repled t willF roweverD it should over most prolems you enounterD nd for interoperility with other undlesD we enourge you to stik to the mening we hve envisged for themF
RUU
ost uthoriztion deisions re mde fter seure method hs een invokedD nd typilly involve the domin ojet whih is returned y suh methodF efter invotion providers lso llow to modifyD or (lter the domin ojet efore it is returnedF hue to urrent limittions of the r lngugeD there re no postEuthoriztion pilities uild into the ore eurity omponentF roweverD there is n experimentl tweurityixtrfundle whih dds these pilitiesF ee its doumenttion for further informtion on how this is omplishedF
6.40.6 Process for Reaching Authorization Decisions
he egv lss provides two methods for determining whether seurity identity hs the required itmsksD isqrnted nd ispieldqrntedF hen the egv reeives n uthoriztion request through one of these methodsD it delegtes this request to n implementtion of ermissionqrntingtrtegyF his llows you to reple the wy ess deisions re rehed without tully modifying the egv lss itselfF he ermissionqrntingtrtegy (rst heks ll your ojetEsope egis if none is pplileD the lssEsope egis will e hekedD if none is pplileD then the proess will e repeted with the egis of the prent egvF sf no prent egv existsD n exeption will e thrownF
ou n fore res of your site to use the r protool in the seurity on(gF his is done through the essontrol rules using the requireshnnel optionF por exmpleD if you wnt to fore ll vs strting with Gseure to use r then you ould use the following on(gX
ewv
RUV
TF
'access_control' => array( array('path' => '^/secure', 'role' => 'ROLE_ADMIN', 'requires_channel' => 'https' ), ),
he login form itself needs to llow nonymous ess otherwise users will e unle to uthentiteF o fore it to use r you n still use essontrol rules y using the serixsgeihexyxwyv roleX
ewv
'access_control' => array( array('path' => '^/login', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', 'requires_channel' => 'https' ), ),
st is lso possile to speify using r in the routing on(gurtion see row to fore routes to lwys use r for more detilsF
sing form login for uthentition is ommonD nd )exileD method for hndling uthentition in ymfonyPF retty muh every spet of the form login n e ustomizedF he fullD defult on(gurtion is shown in the next setionF
RUW
ewv
# app/cong/security.yml security: rewalls: main: form_login: # the user is redirected here when he/she needs to login login_path: /login # if true, forward the user to the login form instead of redirecting use_forward: false # submit the login form here check_path: /login_check # by default, the login form *must* be a POST, not a GET post_only: true # login success redirecting options (read further below) always_use_default_target_path: false default_target_path: / target_path_parameter: _target_path use_referer: false # login failure redirecting options (read further below) failure_path: null failure_forward: false # eld names for the username and password elds username_parameter: _username password_parameter: _password # csrf token options csrf_parameter: intention:
wv
_csrf_token authenticate
always_use_default_target_path="false" default_target_path="/" target_path_parameter="_target_path" use_referer="false" failure_path="null" failure_forward="false" username_parameter="_username" password_parameter="_password" csrf_parameter="_csrf_token" intention="authenticate" post_only="true"
// app/cong/security.php $container->loadFromExtension('security', array( 'rewalls' => array( 'main' => array('form_login' => array( 'check_path' => '/login_check', 'login_path' => '/login', 'user_forward' => false, 'always_use_default_target_path' => false, 'default_target_path' => '/', 'target_path_parameter' => _target_path, 'use_referer' => false, 'failure_path' => null, 'failure_forward' => false, 'username_parameter' => '_username', 'password_parameter' => '_password', 'csrf_parameter' => '_csrf_token', 'intention' => 'authenticate', 'post_only' => true, )), ), ));
ou n hnge where the login form redirets fter suessful login using the vrious on(g optionsF fy defult the form will rediret to the v the user requested @iFeF the v whih triggered the login form eing shownAF por exmpleD if the user requested httpXGGwwwFexmpleFomGdminGpostGIVGedit then fter heGshe will eventully e sent k TFRPF row to ustomize your porm vogin RVI
ymfony houmenttionD PFH to httpXGGwwwFexmpleFomGdminGpostGIVGedit fter suessfully logging inF his is done y storing the requested v in the sessionF sf no v is present in the session @perhps the user went diretly to the login pgeAD then the user is redireted to the defult pgeD whih is G @iFeF the homepgeA y defultF ou n hnge this ehvior in severl wysF X es mentionedD y defult the user is redireted k to the pge he originlly requestedF ometimesD this n use prolemsD like if kground ete request ppers to e the lst visited vD using the user to e redireted thereF por informtion on ontrolling this ehviorD see row to hnge the hefult rget th fehviorF
ghnging the hefult ge pirstD the defult pge n e set @iFeF the pge the user is redireted to if no previous pge ws stored in the sessionAF o set it to Gdmin use the following on(gX
ewv
<!-- app/cong/security.xml --> <cong> <rewall> <form-login default_target_path="/admin" /> </rewall> </cong>
r
// app/cong/security.php $container->loadFromExtension('security', array( 'rewalls' => array( 'main' => array('form_login' => array( // ... 'default_target_path' => '/admin', )),
RVP
TF
));
),
xowD when no v is set in the session users will e sent to GdminF elwys ediret to the hefult ge ou n mke it so tht users re lwys redireted to the defult pge regrdless of wht v they hd requested previously y setting the lwysusedefulttrgetpth option to trueX
ewv
<!-- app/cong/security.xml --> <cong> <rewall> <form-login always_use_default_target_path="true" /> </rewall> </cong>
r
// app/cong/security.php $container->loadFromExtension('security', array( 'rewalls' => array( 'main' => array('form_login' => array( // ... 'always_use_default_target_path' => true, )), ), ));
RVQ
ymfony houmenttionD PFH sing the eferring v sn se no previous v ws stored in the sessionD you my wish to try using the ripii instedD s this will often e the smeF ou n do this y setting usereferer to true @it defults to flseAX
ewv
true
<!-- app/cong/security.xml --> <cong> <rewall> <form-login use_referer="true" /> </rewall> </cong>
r
// app/cong/security.php $container->loadFromExtension('security', array( 'rewalls' => array( 'main' => array('form_login' => array( // ... 'use_referer' => true, )), ), ));
gontrol the ediret v from inside the porm ou n lso override where the user is redireted to vi the form itself y inluding hidden (eld with the nme trgetpthF por exmpleD to rediret to the v de(ned y some ount routeD use the followingX
wig
RVR
TF
{# src/Acme/SecurityBundle/Resources/views/Security/login.html.twig #} {% if error %} <div>{{ error.message }}</div> {% endif %} <form action="{{ path('login_check') }}" method="post"> <label for="username">Username:</label> <input type="text" id="username" name="_username" value="{{ last_username }}" /> <label for="password">Password:</label> <input type="password" id="password" name="_password" /> <input type="hidden" name="_target_path" value="account" /> <input type="submit" name="login" /> </form>
r
<?php // src/Acme/SecurityBundle/Resources/views/Security/login.html.php ?> <?php if ($error): ?> <div><?php echo $error->getMessage() ?></div> <?php endif; ?> <form action="<?php echo $view['router']->generate('login_check') ?>" method="post"> <label for="username">Username:</label> <input type="text" id="username" name="_username" value="<?php echo $last_username ?>" /> <label for="password">Password:</label> <input type="password" id="password" name="_password" /> <input type="hidden" name="_target_path" value="account" /> <input type="submit" name="login" /> </form>
xowD the user will e redireted to the vlue of the hidden form (eldF he vlue ttriute n e reltive pthD solute vD or route nmeF ou n even hnge the nme of the hidden form (eld y hnging the trgetpthprmeter option to nother vlueF
ewv
wv
<!-- app/cong/security.xml --> <cong> <rewall> <form-login target_path_parameter="redirect_url" /> </rewall> </cong>
r
// app/cong/security.php $container->loadFromExtension('security', array( 'rewalls' => array( 'main' => array('form_login' => array( 'target_path_parameter' => redirect_url, )), ), ));
edireting on vogin pilure sn ddition to rediret the user fter suessful loginD you n lso set the v tht the user should e redireted to fter filed login @eFgF n invlid usernme or pssword ws sumittedAF fy defultD the user is redireted k to the login form itselfF ou n set this to di'erent v with the following on(gX
ewv
failure_path="login_failure"
// app/cong/security.php $container->loadFromExtension('security', array( 'rewalls' => array( 'main' => array('form_login' => array( // ... 'failure_path' => login_failure, )), ), ));
sn the seurity hpterD you n see how to seure ontroller y requesting the seurityFontext servie from the ervie gontiner nd heking the urrent user9s roleX
use Symfony\Component\Security\Core\Exception\AccessDeniedException // ... public function helloAction($name) { if (false === $this->get('security.context')->isGranted('ROLE_ADMIN')) { throw new AccessDeniedException(); } } // ...
ou n lso seure ny servie in similr wy y injeting the seurityFontext servie into itF por generl introdution to injeting dependenies into servies see the ervie gontiner hpter of the ookF por exmpleD suppose you hve xewsletterwnger lss tht sends out emils nd you wnt to restrit its use to only users who hve some yvixiviiehwsx roleF fefore you dd seurityD the lss looks something like thisX
our gol is to hek the user9s role when the sendxewsletter@A method is lledF he (rst step towrds this is to injet the seurityFontext servie into the ojetF ine it won9t mke sense not to perform the seurity hekD this is n idel ndidte for onstrutor injetionD whih gurntees tht the seurity ontext ojet will e ville inside the xewsletterwnger lssX
namespace Acme\HelloBundle\Newsletter; use Symfony\Component\Security\Core\SecurityContextInterface; class NewsletterManager { protected $securityContext; public function __construct(SecurityContextInterface $securityContext) { $this->securityContext = $securityContext; } } // ...
ewv
# src/Acme/HelloBundle/Resources/cong/services.yml parameters: newsletter_manager.class: Acme\HelloBundle\Newsletter\NewsletterManager services: newsletter_manager: class: %newsletter_manager.class% arguments: [@security.context]
wv
<parameter key="newsletter_manager.class">Acme\HelloBundle\Newsletter\NewsletterManager</par </parameters> <services> <service id="newsletter_manager" class="%newsletter_manager.class%"> <argument type="service" id="security.context"/> </service> </services>
r
namespace Acme\HelloBundle\Newsletter; use Symfony\Component\Security\Core\Exception\AccessDeniedException use Symfony\Component\Security\Core\SecurityContextInterface; // ... class NewsletterManager { protected $securityContext; public function __construct(SecurityContextInterface $securityContext) { $this->securityContext = $securityContext; } public function sendNewsletter() { if (false === $this->securityContext->isGranted('ROLE_NEWSLETTER_ADMIN')) { throw new AccessDeniedException(); } //-TFRQF row to seure ny ervie or wethod in your epplition RVW
} } // ...
sf the urrent user does not hve the yvixiviiehwsxD they will e prompted to log inF
6.43.1 Securing Methods Using Annotations
ou n lso seure method lls in ny servie with nnottions y using the optionl tweurityixtrfundle undleF his undle is inluded in the ymfonyP tndrd histriutionF o enle the nnottions funtionlityD tg the servie you wnt to seure with the seurityFseureservie tg @you n lso utomtilly enle this funtionlity for ll serviesD see the sider elowAX
ewv
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <!-- ... --> <services> <service id="newsletter_manager" class="%newsletter_manager.class%"> <!-- ... --> <tag name="security.secure_service" /> </service> </services>
r
RWH
TF
$denition = new Denition( '%newsletter_manager.class%', array(new Reference('security.context')) )); $denition->addTag('security.secure_service'); $container->setDenition('newsletter_manager', $denition);
ou n then hieve the sme results s ove using n nnottionX
namespace Acme\HelloBundle\Newsletter; use JMS\SecurityExtraBundle\Annotation\Secure; // ... class NewsletterManager { /** * @Secure(roles="ROLE_NEWSLETTER_ADMIN") */ public function sendNewsletter() { //-} } // ...
X he nnottions work euse proxy lss is reted for your lss whih performs the seurity heksF his mens thtD whilst you n use nnottions on puli nd proteted methodsD you nnot use them with privte methods or methods mrked (nlF he tweurityixtrfundle lso llows you to seure the prmeters nd return vlues of methodsF por more informtionD see the tweurityixtrfundle doumenttionF
RWI
ymfony houmenttionD PFH etivting the ennottions puntionlity for ll ervies hen seuring the method of servie @s shown oveAD you n either tg eh servie individullyD or tivte the funtionlity for ll servies t oneF o do soD set the seurellservies on(gurtion option to trueX ewv
<!-- app/cong/cong.xml --> <srv:container xmlns="http://symfony.com/schema/dic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:srv="http://symfony.com/schema/dic/services" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/service <jms_security_extra secure_controllers="true" secure_all_services="true" /> </srv:container>
r
6.44 How to load Security Users from the Database (the entity Provider)
his rtile hs not een written yetD ut will soonF sf you9re interested in writing this entryD see gontriuting to the houmenttionF his topi is ment to e full working exmple of how to use the entity user provider with the seurity omponentF st should show how to rete the ser lssD implement the methodsD mppingD et E everything you9ll need to get fullyEfuntionlity entity user provider workingF
RWP
TF
his rtile hs not een written yetD ut will soonF sf you9re interested in writing this entryD see gontriuting to the houmenttionF his topi is ment to show how ustom user provider n e retedF yne potentil exmple E though etter exmple is welomed E is to show how ustom ser lss n e reted nd then populted vi ustom user provider tht lods users y mking n es servie ll out to some externl siteF
sf you hve red the hpter on eurityD you understnd the distintion ymfonyP mkes etween uthentition nd uthoriztion in the implementtion of seurityF his hpter disusses the ore lsses involved in the uthentition proessD nd how to implement ustom uthentition providerF feuse uthentition nd uthoriztion re seprte oneptsD this extension will e userEprovider gnostiD nd will funtion with your pplition9s user providersD my they e sed in memoryD dtseD or wherever else you hoose to store themF
6.46.1 Meet WSSE
he following hpter demonstrtes how to rete ustom uthentition provider for i uthentitionF he seurity protool for i provides severl seurity ene(tsX IF sernme G ssword enryption PF fe gurding ginst reply ttks QF xo we server on(gurtion required i is very useful for the seuring of we serviesD my they e ye or iF here is plenty of gret doumenttion on iD ut this rtile will fous not on the seurity protoolD ut rther the mnner in whih ustom protool n e dded to your ymfonyP pplitionF he sis of i is tht request heder is heked for enrypted redentilsD veri(ed using timestmp nd noneD nd uthentited for the requested user using pssword digestF X i lso supports pplition key vlidtionD whih is useful for we serviesD ut is outside the sope of this hpterF
RWQ
he role of the token in the ymfonyP seurity ontext is n importnt oneF e token represents the user uthentition dt present in the requestF yne request is uthentitedD the token retins the user9s dtD nd delivers this dt ross the seurity ontextF pirstD we will rete our token lssF his will llow the pssing of ll relevnt informtion to our uthentition providerF
// src/Acme/DemoBundle/Security/Authentication/Token/WsseUserToken.php namespace Acme\DemoBundle\Security\Authentication\Token; use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; class WsseUserToken extends AbstractToken { public $created; public $digest; public $nonce; public function getCredentials() { return ''; }
X he sseseroken lss extends the seurity omponent9s ymfonygomponenteuritygoreeuthentitionokenestrtoken lssD whih provides si token funtionlityF smplement the ymfonygomponenteuritygoreeuthentitionokenokensnterfe on ny lss to use s tokenF
xextD you need listener to listen on the seurity ontextF he listener is responsile for (elding requests to the (rewll nd lling the uthentition providerF e listener must e n instne of ymfonygomponenteurityrttppirewllvistenersnterfeF e seurity listener should hndle the ymfonygomponentrttpuerneliventqetesponseivent eventD nd set n uthentited token in the seurity ontext if suessfulF
use Symfony\Component\Security\Http\Firewall\ListenerInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Acme\DemoBundle\Security\Authentication\Token\WsseUserToken; class WsseListener implements ListenerInterface { protected $securityContext; protected $authenticationManager;
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $aut { $this->securityContext = $securityContext; $this->authenticationManager = $authenticationManager; } public function handle(GetResponseEvent $event) { $request = $event->getRequest(); if (!$request->headers->has('x-wsse')) { return; }
$wsseRegex = '/UsernameToken Username="([^"]+)", PasswordDigest="([^"]+)", Nonce="([^"]+)", Crea if (preg_match($wsseRegex, $request->headers->get('x-wsse'), $matches)) { $token = new WsseUserToken(); $token->setUser($matches[1]); $token->digest = $matches[2]; $token->nonce = $matches[3]; $token->created = $matches[4]; try { $returnValue = $this->authenticationManager->authenticate($token); if ($returnValue instanceof TokenInterface) { return $this->securityContext->setToken($returnValue); } else if ($returnValue instanceof Response) { return $event->setResponse($returnValue); } } catch (AuthenticationException $e) { // you might log something here }
TFRTF row to rete ustom euthentition rovider RWS
his listener heks the request for the expeted Ei hederD mthes the vlue returned for the expeted i informtionD retes token using tht informtionD nd psses the token on to the uthentition mngerF sf the proper informtion is not providedD or the uthentition mnger throws n ymfonygomponenteuritygoreixeptioneuthentitionixeptionD RHQ esponse is returnedF
X e lss not used oveD the ymfonygomponenteurityrttppirewllestrteuthenti lssD is very useful se lss whih provides ommonly needed funtionlity for seurity extensionsF his inludes mintining the token in the sessionD providing suess G filure hndlersD login form urlsD nd moreF es i does not require mintining uthentition sessions or login formsD it won9t e used for this exmpleF
he uthentition provider will do the veri(tion of the sseserokenF xmelyD the provider will verify the greted heder vlue is vlid within (ve minutesD the xone heder vlue is unique within (ve minutesD nd the sswordhigest heder vlue mthes with the user9s psswordF
// src/Acme/DemoBundle/Security/Authentication/Provider/WsseProvider.php namespace Acme\DemoBundle\Security\Authentication\Provider; use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\NonceExpiredException; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Acme\DemoBundle\Security\Authentication\Token\WsseUserToken; class WsseProvider implements AuthenticationProviderInterface { private $userProvider; private $cacheDir; public function __construct(UserProviderInterface $userProvider, $cacheDir)
RWT TF
{ }
if ($user && $this->validateDigest($token->digest, $token->nonce, $token->created, $user->getPassword() $authenticatedToken = new WsseUserToken($user->getRoles()); $authenticatedToken->setUser($user); } } return $authenticatedToken;
protected function validateDigest($digest, $nonce, $created, $secret) { // Expire timestamp after 5 minutes if (time() - strtotime($created) > 300) { return false; }
// Validate nonce is unique within 5 minutes if (le_exists($this->cacheDir.'/'.$nonce) && le_get_contents($this->cacheDir.'/'.$nonce) + 300 >= tim throw new NonceExpiredException('Previously used nonce detected'); } le_put_contents($this->cacheDir.'/'.$nonce, time()); // Validate Secret $expected = base64_encode(sha1(base64_decode($nonce).$created.$secret, true)); } return $digest === $expected;
X he ymfonygomponenteuritygoreeuthentitionrovidereuthentitionrovider requires n uthentite method on the user tokenD nd supports methodD whih tells the TFRTF row to rete ustom euthentition rovider RWU
ymfony houmenttionD PFH uthentition mnger whether or not to use this provider for the given tokenF sn the se of multiple providersD the uthentition mnger will then move to the next provider in the listF
ou hve reted ustom tokenD ustom listenerD nd ustom providerF xow you need to tie them ll togetherF row do you mke your provider ville to your seurity on(gurtionc he nswer is y using ftoryF e ftory is where you hook into the seurity omponentD telling it the nme of your provider nd ny on(gurtion options ville for itF pirstD you must rete lss whih implements ymfonyfundleeurityfundlehependenysnjetioneurityptoryeurityptorysnterfeF
// src/Acme/DemoBundle/DependencyInjection/Security/Factory/WsseFactory.php namespace Acme\DemoBundle\DependencyInjection\Security\Factory; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\DenitionDecorator; use Symfony\Component\Cong\Denition\Builder\NodeDenition; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; class WsseFactory implements SecurityFactoryInterface { public function create(ContainerBuilder $container, $id, $cong, $userProvider, $defaultEntryPoint) { $providerId = 'security.authentication.provider.wsse.'.$id; $container ->setDenition($providerId, new DenitionDecorator('wsse.security.authentication.provider')) ->replaceArgument(0, new Reference($userProvider)) ;
$listenerId = 'security.authentication.listener.wsse.'.$id; $listener = $container->setDenition($listenerId, new DenitionDecorator('wsse.security.authentication.liste } return array($providerId, $listenerId, $defaultEntryPoint);
return 'wsse';
rete methodD whih dds the listener nd uthentition provider to the hs ontiner for the pproprite seurity ontextY getosition methodD whih must e of type preuthD formD httpD nd rememerme nd de(nes the position t whih the provider is lledY getuey method whih de(nes the on(gurtion key used to referene the providerY ddgon(gurtion methodD whih is used to de(ne the on(gurtion options underneth the on(gurtion key in your seurity on(gurtionF etting on(gurtion options re explined lter in this hpterF
X e lss not used in this exmpleD ymfonyfundleeurityfundlehependenysnjetione is very useful se lss whih provides ommonly needed funtionlity for seurity ftoriesF st my e useful when de(ning n uthentition provider of di'erent typeF xow tht you hve reted ftory lssD the wsse key n e used s (rewll in your seurity on(gurtionF X ou my e wondering why do we need speil ftory lss to dd listeners nd providers to the dependeny injetion ontinercF his is very good questionF he reson is you n use your (rewll multiple timesD to seure multiple prts of your pplitionF feuse of thisD eh time your (rewll is usedD new servie is reted in the hs ontinerF he ftory is wht retes these new serviesF
6.46.6 Conguration
st9s time to see your uthentition provider in tionF ou will need to do few things in order to mke this workF he (rst thing is to dd the servies ove to the hs ontinerF our ftory lss ove mkes referene to servie ids tht do not exist yetX wsseFseurityFuthentitionFprovider nd wsseFseurityFuthentitionFlistenerF st9s time to de(ne those serviesF
ewv
TFRTF row to rete ustom euthentition rovider RWW
# src/Acme/DemoBundle/Resources/cong/services.yml services: wsse.security.authentication.provider: class: Acme\DemoBundle\Security\Authentication\Provider\WsseProvider arguments: ['', %kernel.cache_dir%/security/nonces] wsse.security.authentication.listener: class: Acme\DemoBundle\Security\Firewall\WsseListener arguments: [@security.context, @security.authentication.manager]
wv
<!-- src/Acme/DemoBundle/Resources/cong/services.xml --> <services> <service id="wsse.security.authentication.provider" class="Acme\DemoBundle\Security\Authentication\Provider\WsseProvider" public="false"> <argument /> <!-- User Provider --> <argument>%kernel.cache_dir%/security/nonces</argument> </service> <service id="wsse.security.authentication.listener" class="Acme\DemoBundle\Security\Firewall\WsseListener" public="false"> <argument type="service" id="security.context"/> <argument type="service" id="security.authentication.manager" /> </service> </services>
r
// src/Acme/DemoBundle/Resources/cong/services.php use Symfony\Component\DependencyInjection\Denition; use Symfony\Component\DependencyInjection\Reference; $container->setDenition('wsse.security.authentication.provider', new Denition( 'Acme\DemoBundle\Security\Authentication\Provider\WsseProvider', array('', '%kernel.cache_dir%/security/nonces') )); $container->setDenition('wsse.security.authentication.listener', new Denition( 'Acme\DemoBundle\Security\Firewall\WsseListener', array( new Reference('security.context'), new Reference('security.authentication.manager')) ));
xow tht your servies re de(nedD tell your seurity ontext out your ftoryF ptories must e inluded in n individul on(gurtion (leD t the time of this writingF ou need to SHH TF
ymfony houmenttionD PFH rete (le with your ftory servie in itD nd then use the ftories key in your on(gurtion to import itF
<!-- src/Acme/DemoBundle/Resources/cong/security_factories.xml --> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/servi <services> <service id="security.authentication.factory.wsse" class="Acme\DemoBundle\DependencyInjection\Security\Factory\WsseFactory" public="false"> <tag name="security.listener.factory" /> </service> </services> </container>
ewv
ymfony houmenttionD PFH gongrtultions3 ou hve written your very own ustom seurity uthentition provider3
6.46.7 A Little Extra
row out mking your i uthentition provider it more exitingc he possiilities re endlessF hy don9t you strt y dding some spkle to tht shinec gon(gurtion ou n dd ustom options under the wsse key in your seurity on(gurtionF por instneD the time llowed efore expiring the greted heder itemD y defultD is S minutesF wke this on(gurleD so di'erent (rewlls n hve di'erent timeout lengthsF ou will (rst need to edit sseptory nd de(ne the new option in the ddgon(gurtion methodF
class WsseFactory implements SecurityFactoryInterface { # ... public function addConguration(NodeDenition $node) { $node ->children() ->scalarNode('lifetime')->defaultValue(300) ->end() ; }
xowD in the rete method of the ftoryD the 6on(g rgument will ontin lifetime9 keyD set to S minutes @QHH seondsA unless otherwise set in the on(gurtionF ss this rgument to your uthentition provider in order to put it to useF
class WsseFactory implements SecurityFactoryInterface { public function create(ContainerBuilder $container, $id, $cong, $userProvider, $defaultEntryPoint) { $providerId = 'security.authentication.provider.wsse.'.$id; $container ->setDenition($providerId, new DenitionDecorator('wsse.security.authentication.provider')) ->replaceArgument(0, new Reference($userProvider)) ->replaceArgument(2, $cong['lifetime']) ; // ...
SHP TF
} // ...
X ou9ll lso need to dd third rgument to the wsseFseurityFuthentitionFprovider servie on(gurtionD whih n e lnkD ut will e (lled in with the lifetime in the ftoryF he sserovider lss will lso now need to ept third onstrutor rgument E the lifetime E whih it should use insted of the hrdEoded QHH seondsF hese two steps re not shown hereF he lifetime of eh wsse request is now on(gurleD nd n e set to ny desirle vlue per (rewllF
fy defultD the seurity omponent retins the informtion of the lst request s in session vrile nmed seurityFtrgetpthF pon suessful loginD the user is redireted to this pthD s to help her ontinue from the lst known pge she visitedF yn some osionsD this is unexpetedF por exmple when the lst request s ws n r y ginst route whih is on(gured to llow only y methodD the user is redireted to this route only to get RHR errorF o get round this ehviorD you would simply need to extend the ixeptionvistener lss nd override the defult method nmed setrgetth@AF pirstD override the seurityFexeptionlistenerFlss prmeter in your on(gurtion (leF his n e done from your min on(gurtion (le @in ppGon(gA or from on(gurtion (le eing imported from undleX
ewv
wv
<!-- src/Acme/HelloBundle/Resources/cong/services.xml --> <parameters> <!-- ... --> <parameter key="security.exception_listener.class">Acme\HelloBundle\Security\Firewall\ExceptionLis </parameters>
r
// src/Acme/HelloBundle/Security/Firewall/ExceptionListener.php namespace Acme\HelloBundle\Security\Firewall; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Http\Firewall\ExceptionListener as BaseExceptionListener; class ExceptionListener extends BaseExceptionListener { protected function setTargetPath(Request $request) { // Do not save target path for XHR and non-GET requests // You can add any more logic here you want if ($request->isXmlHttpRequest() || 'GET' !== $request->getMethod()) { return; } } $request->getSession()->set('_security.target_path', $request->getUri());
feuse ymfonyP9s he uses the stndrd r he hedersD the ymfonyP everse roxy n esily e repled with ny other reverse proxyF rnish is powerfulD openEsoureD r elertor ple of serving hed ontent quikly nd inluding support for idge ide snludesF
SHR
TF
es seen previouslyD ymfonyP is smrt enough to detet whether it tlks to reverse proxy tht understnds is or notF st works out of the ox when you use the ymfonyP reverse proxyD ut you need speil on(gurtion to mke it work with rnishF hnkfullyD ymfonyP relies on yet nother stndrd written y ekm @idge erhitetureAD so the % on(gurtion tips in this hpter n e useful even if you don9t use ymfonyPF X rnish only supports the sr ttriute for is tgs @onerror nd lt ttriutes re ignoredAF pirstD on(gure rnish so tht it dvertises its is support y dding urrogteEgpility heder to requests forwrded to the kend pplitionX
sub vcl_fetch { if (beresp.http.Surrogate-Control ~ "ESI/1.0") { unset beresp.http.Surrogate-Control; // for Varnish >= 3.0 set beresp.do_esi = true; // for Varnish < 3.0 // esi;
X gompression with is ws not supported in rnish until version QFH @red qs nd rnishAF sf you9re not using rnish QFHD put we server in front of rnish to perform the ompressionF
ou should never need to invlidte hed dt euse invlidtion is lredy tken into ount ntively in the r he models @see ghe snvlidtionAF tillD rnish n e on(gured to ept speil r qi method tht will invlidte the he for given resoureX
SHS
sub vcl_hit { if (req.request == "PURGE") { set obj.ttl = 0s; error 200 "Purged"; } } sub vcl_miss { if (req.request == "PURGE") { error 404 "Not purged"; } }
X ou must protet the qi r method somehow to void rndom people purging your hed dtF
iven if ymfonyP defults to wig for its templte engineD you n still use plin r ode if you wntF foth templting engines re supported eqully in ymfonyPF ymfonyP dds some nie fetures on top of r to mke writing templtes with r more powerfulF
6.49.1 Rendering PHP Templates
sf you wnt to use the r templting engineD (rstD mke sure to enle it in your pplition on(gurtion (leX
ewv
<!-- app/cong/cong.xml --> <framework:cong ... > <!-- ... --> <framework:templating ... > <framework:engine id="twig" /> <framework:engine id="php" />
SHT
TF
</framework:templating> </framework:cong>
r
$container->loadFromExtension('framework', array( // ... 'templating' => array( 'engines' => array('twig', 'php'), ), ));
ou n now render r templte insted of wig one simply y using the Fphp extension in the templte nme insted of FtwigF he ontroller elow renders the indexFhtmlFphp templteX
wore often thn notD templtes in projet shre ommon elementsD like the wellEknown heder nd footerF sn ymfonyPD we like to think out this prolem di'erentlyX templte n e deorted y nother oneF he indexFhtmlFphp templte is deorted y lyoutFhtmlFphpD thnks to the extend@A llX
<!-- src/Acme/HelloBundle/Resources/views/Hello/index.html.php --> <?php $view->extend('AcmeHelloBundle::layout.html.php') ?> Hello <?php echo $name ?>!
he rellofundleXXlyoutFhtmlFphp nottion sounds fmilirD doesn9t itc st is the sme nottion used to referene templteF he XX prt simply mens tht the ontroller element is emptyD so the orresponding (le is diretly stored under viewsGF xowD let9s hve look t the lyoutFhtmlFphp (leX
SHU
<!-- app/Resources/views/base.html.php --> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title><?php $view['slots']->output('title', 'Hello Application') ?></title> </head> <body> <?php $view['slots']->output('_content') ?> </body> </html>
por oth lyoutsD the 6view9slots9Eboutput@9ontent9A expression is repled y the ontent of the hild templteD indexFhtmlFphp nd lyoutFhtmlFphp respetively @more on slots in the next setionAF es you n seeD ymfonyP provides methods on mysterious 6view ojetF sn templteD the 6view vrile is lwys ville nd refers to speil ojet tht provides unh of methods tht mkes the templte engine tikF
6.49.3 Working with Slots
e slot is snippet of odeD de(ned in templteD nd reusle in ny lyout deorting the templteF sn the indexFhtmlFphp templteD de(ne title slotX
<!-- src/Acme/HelloBundle/Resources/views/Hello/index.html.php --> <?php $view->extend('AcmeHelloBundle::layout.html.php') ?> <?php $view['slots']->set('title', 'Hello World Application') ?> Hello <?php echo $name ?>!
he se lyout lredy hs the ode to output the title in the hederX
<!-- app/Resources/views/layout.html.php --> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title><?php $view['slots']->output('title', 'Hello Application') ?></title> </head>
SHV TF
ymfony houmenttionD PFH he output@A method inserts the ontent of slot nd optionlly tkes defult vlue if the slot is not de(nedF end ontent is just speil slot tht ontins the rendered hild templteF por lrge slotsD there is lso n extended syntxX
<?php $view['slots']->start('title') ?> Some large amount of HTML <?php $view['slots']->stop() ?>
he est wy to shre snippet of templte ode is to de(ne templte tht n then e inluded into other templtesF grete helloFhtmlFphp templteX
<!-- src/Acme/HelloBundle/Resources/views/Hello/index.html.php --> <?php $view->extend('AcmeHelloBundle::layout.html.php') ?> <?php echo $view->render('AcmeHello:Hello:hello.html.php', array('name' => $name)) ?>
he render@A method evlutes nd returns the ontent of nother templte @this is the ext sme method s the one used in the ontrollerAF
6.49.5 Embedding other Controllers
end wht if you wnt to emed the result of nother ontroller in templtec ht9s very useful when working with ejxD or when the emedded templte needs some vrile not ville in the min templteF sf you rete fny tionD nd wnt to inlude it into the indexFhtmlFphp templteD simply use the following odeX
<!-- src/Acme/HelloBundle/Resources/views/Hello/index.html.php --> <?php echo $view['actions']->render('HelloBundle:Hello:fancy', array('name' => $name, 'color' => 'green')) ?>
rereD the rellofundleXrelloXfny string refers to the fny tion of the rello ontrollerX
// src/Acme/HelloBundle/Controller/HelloController.php
SHW
class HelloController extends Controller { public function fancyAction($name, $color) { // create some object, based on the $color variable $object = ...; } } return $this->render('HelloBundle:Hello:fancy.html.php', array('name' => $name, 'object' => $object));
// ...
fut where is the 6view9tions9 rry element de(nedc vike 6view9slots9D it9s lled templte helperD nd the next setion tells you more out thoseF
6.49.6 Using Template Helpers
he ymfonyP templting system n e esily extended vi helpersF relpers re r ojets tht provide fetures useful in templte ontextF tions nd slots re two of the uiltEin ymfonyP helpersF greting vinks etween ges peking of we pplitionsD reting links etween pges is mustF snsted of hrdoding vs in templtesD the router helper knows how to generte vs sed on the routing on(gurtionF ht wyD ll your vs n e esily updted y hnging the on(gurtionX
<a href="<?php echo $view['router']->generate('hello', array('name' => 'Thomas')) ?>"> Greet Thomas! </a>
he generte@A method tkes the route nme nd n rry of prmeters s rgumentsF he route nme is the min key under whih routes re referened nd the prmeters re the vlues of the pleholders de(ned in the route ptternX
# src/Acme/HelloBundle/Resources/cong/routing.yml hello: # The route name pattern: /hello/{name} defaults: { _controller: AcmeHelloBundle:Hello:index }
SIH
TF
ymfony houmenttionD PFH sing essetsX imgesD tvriptsD nd stylesheets ht would the snternet e without imgesD tvriptsD nd stylesheetsc ymfonyP provides the ssets tg to del with them esilyX
<link href="<?php echo $view['assets']->getUrl('css/blog.css') ?>" rel="stylesheet" type="text/css" /> <img src="<?php echo $view['assets']->getUrl('images/logo.png') ?>" />
he ssets helper9s min purpose is to mke your pplition more portleF hnks to this helperD you n move the pplition root diretory nywhere under your we root diretory without hnging nything in your templte9s odeF
6.49.7 Output Escaping
hen using r templtesD espe vriles whenever they re displyed to the userX
henever you use n unde(ned lssD r uses the utoloding mehnism to delegte the loding of (le de(ning the lssF ymfonyP provides universl utoloderD whih is le to lod lsses from (les tht implement one of the following onventionsX
he tehnil interoperility stndrds for r SFQ nmespes nd lss nmesY he ie nming onvention for lssesF
sf your lsses nd the thirdEprty lirries you use for your projet follow these stndrdsD the ymfonyP utoloder is the only utoloder you will ever needF
6.50.1 Usage
PFIX he usesnludeth method ws dded in ymfony PFIF egistering the ymfonygomponentglssvoderniverslglssvoder utoloder is strightforwrdX
SII
require_once '/path/to/src/Symfony/Component/ClassLoader/UniversalClassLoader.php'; use Symfony\Component\ClassLoader\UniversalClassLoader; $loader = new UniversalClassLoader(); // You can search the include_path as a last resort. $loader->useIncludePath(true); $loader->register();
por minor performne gins lss pths n e hed in memory using eg y registering the ymfonygomponentglssvoderepniverslglssvoderX
require_once '/path/to/src/Symfony/Component/ClassLoader/UniversalClassLoader.php'; require_once '/path/to/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php'; use Symfony\Component\ClassLoader\ApcUniversalClassLoader; $loader = new ApcUniversalClassLoader('apc.prex.'); $loader->register();
he utoloder is useful only if you dd some lirries to utolodF X he utoloder is utomtilly registered in ymfonyP pplition @see ppGutolodFphpAF sf the lsses to utolod use nmespesD use the XmethodXymfonygomponentglssvoderniverslglssvoderXXregisterxmespe or XmethodXymfonygomponentglssvoderniverslglssvoderXXregisterxmespes methodsX
$loader->registerNamespace('Symfony', __DIR__.'/vendor/symfony/src'); $loader->registerNamespaces(array( 'Symfony' => __DIR__.'/../vendor/symfony/src', 'Monolog' => __DIR__.'/../vendor/monolog/src', ));
por lsses tht follow the ie nming onventionD use the XmethodXymfonygomponentglssvoderniverslglssvoderXXregisterre(x or XmethodXymfonygomponentglssvoderniverslglssvoderXXregisterre(xes methodsX
$loader->registerPrex('Twig_', __DIR__.'/vendor/twig/lib');
SIP
TF
$loader->registerNamespaces(array( 'Doctrine\\Common' => __DIR__.'/vendor/doctrine-common/lib', 'Doctrine\\DBAL\\Migrations' => __DIR__.'/vendor/doctrine-migrations/lib', 'Doctrine\\DBAL' => __DIR__.'/vendor/doctrine-dbal/lib', 'Doctrine' => __DIR__.'/vendor/doctrine/lib', ));
sn this exmpleD if you try to use lss in the hotrinegommon nmespe or one of its hildrenD the utoloder will (rst look for the lss under the dotrineEommon diretoryD nd it will then fllk to the defult hotrine diretory @the lst one on(guredA if not foundD efore giving upF he order of the registrtions is signi(nt in this seF
use Symfony\Component\Finder\Finder; $nder = new Finder(); $nder->les()->in(__DIR__); foreach ($nder as $le) { print $le->getRealpath()."\n"; }
he 6(le is n instne of XphplssXplpilesnfoF TFSIF row to lote piles SIQ
ymfony houmenttionD PFH he ove ode prints the nmes of ll the (les in the urrent diretory reursivelyF he pinder lss uses )uent interfeD so ll methods return the pinder instneF X e pinder instne is r stertorF oD insted of iterting over the pinder with forehD you n lso onvert it to n rry with the XphpfuntionXitertortorry methodD or get the numer of items with XphpfuntionXitertorountF
6.51.2 Criteria
votion he lotion is the only mndtory riteriF st tells the (nder whih diretory to use for the serhX
$nder->in(__DIR__);
erh in severl lotions y hining lls to XmethodXymfonygomponentpinderpinderXXinX
$nder->les()->in(__DIR__)->in('/elsewhere');
ixlude diretories from mthing with the XmethodXymfonygomponentpinderpinderXXexlude methodX
$nder->in(__DIR__)->exclude('ruby');
es the pinder uses r itertorsD you n pss ny v with supported protoolX
$nder->in('ftp://example.com/pub/');
end it lso works with userEde(ned stremsX
use Symfony\Component\Finder\Finder; $s3 = new \Zend_Service_Amazon_S3($key, $secret); $s3->registerStreamWrapper("s3"); $nder = new Finder(); $nder->name('photos*')->size('< 100K')->date('since 1 hour ago'); foreach ($nder->in('s3://bucket-name') as $le) { // do something } print $le->getFilename()."\n";
X ed the trems doumenttion to lern how to rete your own stremsF SIR TF
piles or hiretories fy defultD the pinder returns (les nd diretoriesY the XmethodXymfonygomponentpinderpinderXX(les XmethodXymfonygomponentpinderpinderXXdiretories methods ontrol thtX ut nd
$nder->les(); $nder->directories();
sf you wnt to follow linksD use the followvinks@A methodX
$nder->les()->followLinks();
fy defultD the itertor ignores populr g (lesF his n e hnged with the ignoreg@A methodX
$nder->ignoreVCS(false);
orting ort the result y nme or y type @diretories (rstD then (lesAX
$nder->sortByName(); $nder->sortByType();
X xotie tht the sortB methods need to get ll mthing elements to do their josF por lrge itertorsD it is slowF ou n lso de(ne your own sorting lgorithm with sort@A methodX
$sort = function (\SplFileInfo $a, \SplFileInfo $b) { return strcmp($a->getRealpath(), $b->getRealpath()); }; $nder->sort($sort);
SIS
ymfony houmenttionD PFH pile xme estrit (les y nme with the XmethodXymfonygomponentpinderpinderXXnme methodX
$nder->les()->name('*.php');
he nme@A method epts glosD stringsD or regexesX
$nder->les()->name('/\.php$/');
he notxmes@A method exludes (les mthing ptternX
$nder->les()->notName('*.rb');
pile ize estrit (les y size with the XmethodXymfonygomponentpinderpinderXXsize methodX
$nder->les()->size('< 1.5K');
estrit y size rnge y hining llsX
$nder->date('since yesterday');
he omprison opertor n e ny of the followingX bD baD `D `a9D aa9F ou n lso use sine or fter s n lis for bD nd until or efore s n lis for `F he trget vlue n e ny dte supported y the strtotime funtionF
SIT
TF
ymfony houmenttionD PFH hiretory hepth fy defultD the pinder reursively trverse diretoriesF estrit the depth of trversing with XmethodXymfonygomponentpinderpinderXXdepthX
$lter = function (\SplFileInfo $le) { if (strlen($le) > 10) { return false; } }; $nder->les()->lter($lter);
he (lter@A method tkes glosure s n rgumentF por eh mthing (leD it is lled with the (le s XphplssXplpilesnfo instneF he (le is exluded from the result set if the glosure returns flseF
ymfonyP ships with gonsole omponentD whih llows you to rete ommndEline ommndsF our onsole ommnds n e used for ny reurring tskD suh s ronjosD importsD or other th josF
6.52.1 Creating a basic Command
o mke the onsole ommnds ville utomtilly with ymfonyPD rete gommnd diretory inside your undle nd rete php (le su0xed with gommndFphp for eh ommnd tht you wnt to provideF por exmpleD if you wnt to extend the emehemofundle @ville in the ymfony tndrd iditionA to greet us from the ommnd lineD rete qreetgommndFphp nd dd the following to itX
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class GreetCommand extends ContainerAwareCommand { protected function congure() { $this ->setName('demo:greet') ->setDescription('Greet someone') ->addArgument('name', InputArgument::OPTIONAL, 'Who do you want to greet?') ->addOption('yell', null, InputOption::VALUE_NONE, 'If set, the task will yell in uppercase letters') ; } protected function execute(InputInterface $input, OutputInterface $output) { $name = $input->getArgument('name'); if ($name) { $text = 'Hello '.$name; } else { $text = 'Hello'; } if ($input->getOption('yell')) { $text = strtoupper($text); } } $output->writeln($text);
Hello Fabien
ou n lso use the EEyell option to mke everything upperseX
HELLO FABIEN
goloring the yutput henever you output textD you n surround the text with tgs to olor its outputF por exmpleX
// green text $output->writeln('<info>foo</info>'); // yellow text $output->writeln('<comment>foo</comment>'); // black text on a cyan background $output->writeln('<question>foo</question>'); // white text on a red background $output->writeln('<error>foo</error>');
he most interesting prt of the ommnds re the rguments nd options tht you n mke villeF erguments re the strings E seprted y spes E tht ome fter the ommnd nme itselfF hey re orderedD nd n e optionl or requiredF por exmpleD dd n optionl lstnme rgument to the ommnd nd mke the nme rgument requiredX
$this // ... ->addArgument('name', InputArgument::REQUIRED, 'Who do you want to greet?') ->addArgument('last_name', InputArgument::OPTIONAL, 'Your last name?') // ...
ou now hve ess to lstnme rgument in your ommndX
SIW
nlike rgumentsD options re not ordered @mening you n speify them in ny orderA nd re spei(ed with two dshes @eFgF EEyell E you n lso delre oneEletter shortut tht you n ll with single dsh like EyAF yptions re lwys optionlD nd n e setup to ept vlue @eFgF dirasrA or simply s oolen )g without vlue @eFgF yellAF X st is lso possile to mke n option optionlly ept vlue @so tht EEyell or yellaloud workAF yptions n lso e on(gured to ept n rry of vluesF por exmpleD dd new option to the ommnd tht n e used to speify how mny times in row the messge should e printedX
$this // ... ->addOption('iterations', null, InputOption::VALUE_REQUIRED, 'How many times should the message be p
xextD use this in the ommnd to print the messge multiple timesX
app/console demo:greet Fabien --iterations=5 --yell app/console demo:greet Fabien --yell --iterations=5
hen reting ommndsD you hve the ility to ollet more informtion from the user y sking himGher questionsF por exmpleD suppose you wnt to on(rm n tion efore tully exeuting itF edd the following to your ommndX
SPH
TF
return;
sn this seD the user will e sked gontinue with this tionD nd unless they nswer with yD the tsk will stop runningF he third rgument to skgon(rmtion is the defult vlue to return if the user doesn9t enter ny inputF ou n lso sk questions with more thn simple yesGno nswerF por exmpleD if you needed to know the nme of somethingD you might do the followingX
$dialog = $this->getHelperSet()->get('dialog'); $name = $dialog->ask($output, 'Please enter the name of the widget', 'foo');
ymfonyP provides severl tools to help you test your ommndsF he most useful one is the ymfonygomponentgonsoleestergommndester lssF st uses speil input nd output lsses to ese testing without rel onsoleX
use Symfony\Component\Console\Tester\CommandTester; use Symfony\Bundle\FrameworkBundle\Console\Application; class ListCommandTest extends \PHPUnit_Framework_TestCase { public function testExecute() { // mock the Kernel or create one depending on your needs $application = new Application($kernel); $command = $application->nd('demo:greet'); $commandTester = new CommandTester($command); $commandTester->execute(array('command' => $command->getFullName())); $this->assertRegExp('/.../', $commandTester->getDisplay()); } // ...
he XmethodXymfonygomponentgonsoleestergommndesterXXgethisply method returns wht would hve een displyed during norml ll from the onsoleF X ou n lso test whole onsole ymfonygomponentgonsoleesterepplitionesterF pplition y using
SPI
fy using ymfonyfundleprmeworkfundlegommndgontinerewregommnd s the se lss for the ommnd @insted of the more si ymfonygomponentgonsolegommndgommndAD you hve ess to the servie ontinerF sn other wordsD you hve ess to ny on(gured servieF por exmpleD you ould esily extend the tsk to e trnsltleX
protected function execute(InputInterface $input, OutputInterface $output) { $name = $input->getArgument('name'); $translator = $this->getContainer()->get('translator'); if ($name) { $output->writeln($translator->trans('Hello %name%!', array('%name%' => $name))); } else { $output->writeln($translator->trans('Hello!')); } }
sf ommnd depends on nother one eing run efore itD insted of sking the user to rememer the order of exeutionD you n ll it diretly yourselfF his is lso useful if you wnt to rete met ommnd tht just runs unh of other ommnds @for instneD ll ommnds tht need to e run when the projet9s ode hs hnged on the prodution serversX lering the heD generting hotrineP proxiesD dumping esseti ssetsD FFFAF glling ommnd from nother one is strightforwrdX
protected function execute(InputInterface $input, OutputInterface $output) { $command = $this->getApplication()->nd('demo:greet'); $arguments = array( 'command' => 'demo:greet', 'name' => 'Fabien', '--yell' => true, ); $input = new ArrayInput($arguments); $returnCode = $command->run($input, $output); } // ...
ymfony houmenttionD PFH ommnd you wnt to exeute y pssing the ommnd nmeF henD you need to rete new ymfonygomponentgonsolesnputerrysnput with the rguments nd options you wnt to pss to the ommndF iventullyD lling the run@A method tully exeutes the ommnd nd returns the returned ode from the ommnd @H if everything went (neD ny other integer otherwiseAF X wost of the timeD lling ommnd from ode tht is not exeuted on the ommnd line is not good ide for severl resonsF pirstD the ommnd9s output is optimized for the onsoleF fut more importntD you n think of ommnd s eing like ontrollerY it should use the model to do something nd disply feedk to the userF oD insted of lling ommnd from the eD reftor your ode nd move the logi to new lssF
6.53 How
to
optimize
your
development
Environment
for
debugging
hen you work on ymfony projet on your lol mhineD you should use the dev environment @ppdevFphp front ontrollerAF his environment on(gurtion is optimized for two min purposesX
qive the developer urte feedk whenever something goes wrong @we deug toolrD nie exeption pgesD pro(lerD FFFAY fe s similr s possile s the prodution environment to void prolems when deploying the projetF
6.53.1 Disabling the Bootstrap File and Class Caching
end to mke the prodution environment s fst s possileD ymfony retes ig r (les in your he ontining the ggregtion of r lsses your projet needs for every requestF roweverD this ehvior n onfuse your shi or your deuggerF his reipe shows you how you n twek this hing mehnism to mke it friendlier when you need to deug ode tht involves ymfony lssesF he ppdevFphp front ontroller reds s follows y defultX
SPQ
// ...
// require_once __DIR__.'/../app/bootstrap.php.cache'; require_once __DIR__.'/../vendor/symfony/src/Symfony/Component/ClassLoader/UniversalClassLoader.php'; require_once __DIR__.'/../app/autoload.php'; require_once __DIR__.'/../app/AppKernel.php'; use Symfony\Component\HttpFoundation\Request; $kernel = new AppKernel('dev', true); // $kernel->loadClassCache(); $kernel->handle(Request::createFromGlobals())->send();
X sf you disle the r hesD don9t forget to revert fter your deugging sessionF ome shis do not like the ft tht some lsses re stored in di'erent lotionsF o void prolemsD you n either tell your shi to ignore the r he (lesD or you n hnge the extension used y ymfony for these (lesX
$kernel->loadClassCache('classes', '.php.cache');
6.54 Monolog
D @A E @loggerAF @A @ AF
SPR
TF
ymfony houmenttionD PFH X D E F tremrndlerD @E ppGlogsGprodFlog prodution ppGlogsGdevFlog E AF wonolog D E prodution X pingersgrossedrndlerF D E @iy A F D X
$logger = $this->get('logger'); $logger->info('We just got the logger'); $logger->err('An error occurred');
F F
ewv
monolog: handlers: syslog: type: stream path: /var/log/symfony.log level: error main: type: ngerscrossed action_level: warning handler: le le: type: stream level: debug
wv
http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/mon <monolog:cong> <monolog:handler name="syslog" type="stream" path="/var/log/symfony.log" level="error" /> <monolog:handler name="main" type="ngerscrossed" action-level="warning" handler="le" /> <monolog:handler name="le" type="stream" level="debug" /> </monolog:cong> </container>
D F X (le D E prodution F
X wonologfundle E D F D FF E F
ewv
SPT TF
services: my_formatter: class: Monolog\Formatter\JsonFormatter monolog: handlers: le: type: stream level: debug formatter: my_formatter
wv
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:monolog="http://symfony.com/schema/dic/monolog" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/mon <services> <service id="my_formatter" class="Monolog\Formatter\JsonFormatter" /> </services> <monolog:cong> <monolog:handler name="le" type="stream" level="debug" formatter="my_formatter" /> </monolog:cong> </container>
6.54.2
wonolog F E F E F roessors re on(gured using the monologFproessor hsg tgF ee the referene out itF edding essionGequest oken ometimes it is hrd to tell whih entries in the log elong to whih session ndGor requestF he following exmple will dd unique token for eh request using proessorF TFSRF wonolog SPU
namespace Acme\MyBundle; use Symfony\Component\HttpFoundation\Session; class SessionRequestProcessor { private $session; private $token; public function __construct(Session $session) { $this->session = $session; } public function processRecord(array $record) { if (null === $this->token) { try { $this->token = substr($this->session->getId(), 0, 8); } catch (\RuntimeException $e) { $this->token = '????????'; } $this->token .= '-' . substr(uniqid(), -8); } $record['extra']['token'] = $this->token; } return $record;
ewv
services: monolog.formatter.session_request: class: Monolog\Formatter\LineFormatter arguments: - "[%%datetime%%] [%%extra.token%%] %%channel%%.%%level_name%%: %%message%%\n" monolog.processor.session_request: class: Acme\MyBundle\SessionRequestProcessor arguments: [ @session ] tags: - { name: monolog.processor, method: processRecord } monolog: handlers: main:
SPV TF
o llow multiple lsses to dd methods to nother oneD you n de(ne the mgi ll@A method in the lss you wnt to e extended like thisX
class Foo { // ... public function __call($method, $arguments) { // create an event named 'foo.method_is_not_found' $event = new HandleUndenedMethodEvent($this, $method, $arguments); $this->dispatcher->dispatch($this, 'foo.method_is_not_found', $event); // no listener was able to process the event? The method does not exist if (!$event->isProcessed()) { throw new \Exception(sprintf('Call to undened method %s::%s.', get_class($this), $method)); } // return the listener returned value return $event->getReturnValue();
his uses speil rndlende(nedwethodivent tht should lso e retedF his is generi lss tht ould e reused eh time you need to use this pttern of lss extensionX
use Symfony\Component\EventDispatcher\Event; class HandleUndenedMethodEvent extends Event { protected $subject; protected $method; protected $arguments; protected $returnValue;
TFSSF row to extend glss without using snheritne SPW
protected $isProcessed = false; public function __construct($subject, $method, $arguments) { $this->subject = $subject; $this->method = $method; $this->arguments = $arguments; } public function getSubject() { return $this->subject; } public function getMethod() { return $this->method; } public function getArguments() { return $this->arguments; } /** * Sets the value to return and stops other listeners from being notied */ public function setReturnValue($val) { $this->returnValue = $val; $this->isProcessed = true; $this->stopPropagation(); } public function getReturnValue($val) { return $this->returnValue; } public function isProcessed() { return $this->isProcessed; }
xextD rete lss tht will listen to the fooFmethodisnotfound event nd dd the method r@AX SQH TF
class Bar { public function onFooMethodIsNotFound(HandleUndenedMethodEvent $event) { // we only want to respond to the calls to the 'bar' method if ('bar' != $event->getMethod()) { // allow another listener to take care of this unknown method return; } // the subject object (the foo instance) $foo = $event->getSubject(); // the bar method arguments $arguments = $event->getArguments(); // do something // ... // set the return value $event->setReturnValue($someValue);
pinllyD dd the new r method to the poo lss y register n instne of fr with the fooFmethodisnotfound eventX
6.56 How
to
customize
Method
Behavior
without
using
Inheritance
6.56.1 Doing something before or after a Method Call
sf you wnt to do something just eforeD or just fter method is lledD you n dispth n event respetively t the eginning or t the end of the methodX
// do something before the method $event = new FilterBeforeSendEvent($foo, $bar); $this->dispatcher->dispatch('foo.pre_send', $event); // get $foo and $bar from the event, they may have been modied $foo = $event->getFoo(); $bar = $event->getBar(); // the real method implementation is here // $ret = ...; // do something after the method $event = new FilterSendReturnValue($ret); $this->dispatcher->dispatch('foo.post_send', $event); } return $event->getReturnValue();
sn this exmpleD two events re thrownX fooFpresendD efore the method is exeutedD nd fooFpostsend fter the method is exeutedF ih uses ustom ivent lss to ommunite informtion to the listeners of the two eventsF hese event lsses would need to e reted y you nd should llowD in this exmpleD the vriles 6fooD 6r nd 6ret to e retrieved nd set y the listenersF por exmpleD ssuming the pilterendeturnlue hs seteturnlue methodD one listener might look like thisX
public function onFooPostSend(FilterSendReturnValue $event) { $ret = $event->getReturnValue(); // modify the original ``$ret`` value } $event->setReturnValue($ret);
ivery equest hs formt @eFgF htmlD jsonAD whih is used to determine wht type of ontent to return in the esponseF sn ftD the request formtD essile vi XmethodXymfonygomponentrttppoundtionequestXXgetequestpormtD is used to set the wswi type of the gontentEype heder on the esponse ojetF snternllyD ymfony ontins mp of the most ommon formts @eFgF htmlD jsonA nd their ssoited wswi types @eFgF textGhtmlD pplitionGjsonAF yf ourseD dditionl formtEwswi type entries n esily e ddedF his doument will show how you n dd the jsonp formt nd SQP TF
he key to de(ning new wswi type is to rete lss tht will listen to the kernelFrequest event dispthed y the ymfony kernelF he kernelFrequest event is dispthed erly in ymfony9s request hndling proess nd llows you to modify the request ojetF grete the following lssD repling the pth with pth to undle in your projetX
// src/Acme/DemoBundle/RequestListener.php namespace Acme\DemoBundle; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; class RequestListener { public function onKernelRequest(GetResponseEvent $event) { $event->getRequest()->setFormat('jsonp', 'application/javascript'); } }
es for ny other listenerD you need to dd it in one of your on(gurtion (le nd register it s listener y dding the kernelFeventlistener tgX
wv
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services <service id="acme.demobundle.listener.request" class="Acme\DemoBundle\RequestListener"> <tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" /> </service> </container>
ewv
SQQ
# app/cong/cong.yml services: acme.demobundle.listener.request: class: Acme\DemoBundle\RequestListener tags: - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
r
# app/cong/cong.php $denition = new Denition('Acme\DemoBundle\RequestListener'); $denition->addTag('kernel.event_listener', array('event' => 'kernel.request', 'method' => 'onKernelRequ $container->setDenition('acme.demobundle.listener.request', $denition);
et this pointD the meFdemoundleFlistenerFrequest servie hs een on(gured nd will e noti(ed when the ymfony kernel dispthes the kernelFrequest eventF X ou n lso register the listener in on(gurtion extension lss @see smporting gon(gurtion vi gontiner ixtensions for more informtionAF
he ymfonyP ro(ler delegtes dt olleting to dt olletorsF ymfonyP omes undled with few of themD ut you n esily rete your ownF
6.58.1 Creating a Custom Data Collector
the
interface DataCollectorInterface { /** * Collects data for the given Request and Response. * * @param Request $request A Request instance * @param Response $response A Response instance * @param \Exception $exception An Exception instance */ function collect(Request $request, Response $response, \Exception $exception = null); /** * Returns the name of the collector.
SQR TF
he getxme@A method must return unique nmeF his is used to ess the informtion lter on @see row to use the ro(ler in puntionl est for instneAF he ollet@A method is responsile for storing the dt it wnts to give ess to in lol propertiesF X es the pro(ler serilizes dt olletor instnesD you should not store ojets tht nnot e serilized @like hy ojetsAD or you need to provide your own serilize@A methodF
wost of the timeD it is onvenient to extend ymfonygomponentrttpuernelhtgolletorhtgolletor nd populte the 6thisEbdt property @it tkes re of serilizing the 6thisEbdt propertyAX
class MemoryDataCollector extends DataCollector { public function collect(Request $request, Response $response, \Exception $exception = null) { $this->data = array( 'memory' => memory_get_peak_usage(true), ); } public function getMemory() { return $this->data['memory']; } public function getName() { return 'memory'; }
ewv
SQS
hen you wnt to disply the dt olleted y your ht golletor in the we deug toolr or the we pro(lerD rete wig templte following this skeletonX
{% extends 'WebProlerBundle:Proler:layout.html.twig' %} {% block toolbar %} {# the web debug toolbar content #} {% endblock %} {% block head %} {# if the web proler panel needs some specic JS or CSS les #} {% endblock %} {% block menu %} {# the menu content #} {% endblock %} {% block panel %} {# the panel content #} {% endblock %}
ih lok is optionlF he toolr lok is used for the we deug toolr nd menu nd pnel re used to dd pnel to the we pro(lerF ell loks hve ess to the olletor ojetF SQT TF
ymfony houmenttionD PFH X fuiltEin templtes use seTR enoded imge for the toolr @`img sra4sra4dtXimgeGpngYseTRDFFF4AF ou n esily lulte the seTR vlue for n imge with this little sriptX eho seTRenode@(legetontents@6ii9rgv9IAAYF o enle the templteD dd templte ttriute to the dtolletor tg in your on(gurtionF por exmpleD ssuming your templte is in some emeheugfundleX
ewv
services: data_collector.your_collector_name: class: Acme\DebugBundle\Collector\Class\Name tags: - { name: data_collector, template: "AcmeDebug:Collector:templatename", id: "your_collector_n
wv
$container ->register('data_collector.your_collector_name', 'Acme\DebugBundle\Collector\Class\Name') ->addTag('data_collector', array('template' => 'AcmeDebugBundle:Collector:templatename', 'id' => 'y ;
etting up ontroller to t s ye server is simple with ouple toolsF ou mustD of ourseD hve the r ye extension instlledF es the r ye extension n not urrently generte hvD you must either rete one from srth or use Qrd prty genertorF X here re severl ye server implementtions ville for use with rF end ye nd xuye re two exmplesF elthough we use the r ye extension in our exmplesD the generl ide should still e pplile to other implementtionsF ye works y exposing the methods of r ojet to n externl entity @iFeF the person using the ye servieAF o strtD rete lss E relloervie E whih represents the funtionlity tht you9ll expose in your ye servieF sn this seD the ye servie will llow the lient to ll method lled helloD whih hppens to send n emil ddressX TFSWF row to grete ye e ervie in ymfonyP gontroller SQU
namespace Acme\SoapBundle; class HelloService { private $mailer; public function __construct(\Swift_Mailer $mailer) { $this->mailer = $mailer; } public function hello($name) { $message = \Swift_Message::newInstance() ->setTo('me@example.com') ->setSubject('Hello Service') ->setBody($name . ' says hi!'); $this->mailer->send($message); return 'Hello, ' . $name;
} }
xextD you n trin ymfony to e le to rete n instne of this lssF ine the lss sends n eEmilD it9s een designed to ept wiftwiler instneF sing the ervie gontinerD we n on(gure ymfony to onstrut relloervie ojet properlyX
ewv
<!-- app/cong/cong.xml --> <services> <service id="hello_service" class="Acme\DemoBundle\Services\HelloService"> <argument>mailer</argument> </service> </services>
SQV
TF
ymfony houmenttionD PFH felow is n exmple of ontroller tht is ple of hndling ye requestF sf indexetion@A is essile vi the route GsopD then the hv doument n e retrieved vi GsopcwsdlF
namespace Acme\SoapBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class HelloServiceController extends Controller { public function indexAction() { $server = new \SoapServer('/path/to/hello.wsdl'); $server->setObject($this->get('hello_service')); $response = new Response(); $response->headers->set('Content-Type', 'text/xml; charset=ISO-8859-1'); ob_start(); $server->handle(); $response->setContent(ob_get_clean()); } return $response;
ke note of the lls to ostrt@A nd ogetlen@AF hese methods ontrol output u'ering whih llows you to trp the ehoed output of 6serverEbhndle@AF his is neessry euse ymfony expets your ontroller to return esponse ojet with the output s its ontentF ou must lso rememer to set the gontentEype heder to textGxmlD s this is wht the lient will expetF oD you use ostrt@A to strt u'ering the hy nd use ogetlen@A to dump the ehoed output into the ontent of the esponse nd ler the output u'erF pinllyD you9re redy to return the esponseF felow is n exmple lling the servie using xuye lientF his exmple ssumes the indexetion in the ontroller ove is essile vi the route GsopX
xmlns:tns="urn:arnleadservicewsdl" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="urn:helloservicewsdl"> <types> <xsd:schema targetNamespace="urn:hellowsdl"> <xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/" /> <xsd:import namespace="http://schemas.xmlsoap.org/wsdl/" /> </xsd:schema> </types> <message name="helloRequest"> <part name="name" type="xsd:string" /> </message> <message name="helloResponse"> <part name="return" type="xsd:string" /> </message> <portType name="hellowsdlPortType"> <operation name="hello"> <documentation>Hello World</documentation> <input message="tns:helloRequest"/> <output message="tns:helloResponse"/> </operation> </portType> <binding name="hellowsdlBinding" type="tns:hellowsdlPortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="hello"> <soap:operation soapAction="urn:arnleadservicewsdl#hello" style="rpc"/> <input> <soap:body use="encoded" namespace="urn:hellowsdl" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <soap:body use="encoded" namespace="urn:hellowsdl" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> </binding> <service name="hellowsdl"> <port name="hellowsdlPort" binding="tns:hellowsdlBinding"> <soap:address location="http://example.com/app.php/soap" /> </port> </service> </denitions>
SRH
TF
he ymfonyP frmework emodies signi(nt evolution when ompred with the (rst version of the frmeworkF portuntelyD with the wg rhiteture t its oreD the skills used to mster symfonyI projet ontinue to e very relevnt when developing in ymfonyPF ureD ppFyml is goneD ut routingD ontrollers nd templtes ll reminF sn this hpterD we9ll wlk through the di'erenes etween symfonyI nd ymfonyPF es you9ll seeD mny tsks re tkled in slightly di'erent wyF ou9ll ome to ppreite these minor di'erenes s they promote stleD preditleD testle nd deoupled ode in your ymfonyP pplitionsF oD sit k nd relx s we tke you from then to nowF
6.60.1 Directory Structure
hen looking t ymfonyP projet E for exmpleD the ymfonyP tndrd E you9ll notie very di'erent diretory struture thn in symfonyIF he di'erenesD howeverD re somewht super(ilF he ppG hiretory sn symfonyID your projet hs one or more pplitionsD nd eh lives inside the ppsG diretory @eFgF ppsGfrontendAF fy defult in ymfonyPD you hve just one pplition represented y the ppG diretoryF vike in symfonyID the ppG diretory ontins on(gurtion spei( to tht pplitionF st lso ontins pplitionEspei( heD log nd templte diretories s well s uernel lss @eppuernelAD whih is the se ojet tht represents the pplitionF nlike symfonyID lmost no r ode lives in the ppG diretoryF his diretory is not ment to house modules or lirry (les s it did in symfonyIF snstedD it9s simply the home of on(gurtion nd other resoures @templtesD trnsltion (lesAF he srG hiretory ut simplyD your tul ode goes hereF sn ymfonyPD ll tul pplitionEode lives inside undle @roughly equivlent to symfonyI pluginA ndD y defultD eh undle lives inside the sr diretoryF sn tht wyD the sr diretory is it like the plugins diretory in symfonyID ut muh more )exileF edditionllyD while your undles will live in the srG diretoryD thirdE prty undles my live in the vendorGundlesG diretoryF o get etter piture of the srG diretoryD let9s (rst think of symfonyI pplitionF pirstD prt of your ode likely lives inside one or more pplitionsF wost ommonly these inlude modulesD ut ould lso inlude ny other r lsses you put in your pplitionF ou TFTHF ymfonyP symfony I SRI
ymfony houmenttionD PFH my hve lso reted shemFyml (le in the on(g diretory of your projet nd uilt severl model (lesF pinllyD to help with some ommon funtionlityD you9re using severl thirdEprty plugins tht live in the pluginsG diretoryF sn other wordsD the ode tht drives your pplition lives in mny di'erent plesF sn ymfonyPD life is muh simpler euse ll ymfonyP ode must live in undleF sn our pretend symfonyI projetD ll the ode ould e moved into one or more plugins @whih is very good prtieD in ftAF essuming tht ll modulesD r lssesD shemD routing on(gurtionD et were moved into pluginD the symfonyI pluginsG diretory would e very similr to the ymfonyP srG diretoryF ut simply ginD the srG diretory is where your odeD ssetsD templtes nd most nything else spei( to your projet will liveF he vendorG hiretory he vendorG diretory is silly equivlent to the liGvendorG diretory in symfonyID whih ws the onventionl diretory for ll vendor lirries nd undlesF fy defultD you9ll (nd the ymfonyP lirry (les in this diretoryD long with severl other dependent lirries suh s hotrinePD wig nd wiftmilerF Qrd prty ymfonyP undles usully live in the vendorGundlesGF he weG hiretory xot muh hs hnged in the weG diretoryF he most notiele di'erene is the sene of the ssGD jsG nd imgesG diretoriesF his is intentionlF vike with your r odeD ll ssets should lso live inside undleF ith the help of onsole ommndD the esouresGpuliG diretory of eh undle is opied or symolillyElinked to the weGundlesG diretoryF his llows you to keep ssets orgnized inside your undleD ut still mke them ville to the puliF o mke sure tht ll undles re villeD run the following ommndX
6.60.2 Autoloading
yne of the dvntges of modern frmeworks is never needing to worry out requiring (lesF fy mking use of n utoloderD you n refer to ny lss in your projet nd trust tht it9s villeF eutoloding hs hnged in ymfonyP to e more universlD fsterD nd independent of needing to ler your heF SRP TF
ymfony houmenttionD PFH sn symfonyID utoloding ws done y serhing the entire projet for the presene of r lss (les nd hing this informtion in gint rryF ht rry told symfonyI extly whih (le ontined eh lssF sn the prodution environmentD this used you to need to ler the he when lsses were dded or movedF sn ymfonyPD new lss E niverslglssvoder E hndles this proessF he ide ehind the utoloder is simpleX the nme of your lss @inluding the nmespeA must mth up with the pth to the (le ontining tht lssF ke the prmeworkixtrfundle from the ymfonyP tndrd idition s n exmpleX
namespace Sensio\Bundle\FrameworkExtraBundle; use Symfony\Component\HttpKernel\Bundle\Bundle; // ... class SensioFrameworkExtraBundle extends Bundle { // ...
he (le itself lives t vendorGundleGensioGfundleGprmeworkixtrfundleGensioprmeworkixtrfundl es you n seeD the lotion of the (le follows the nmespe of the lssF pei(llyD the nmespeD ensiofundleprmeworkixtrfundleD spells out the diretory tht the (le should live in @vendorGundleGensioGfundleGprmeworkixtrfundleAF his is euseD in the ppGutolodFphp (leD you9ll on(gure ymfony to look for the ensio nmespe in the vendorGundle diretoryX
ymfony houmenttionD PFH de(ned in the ppGutolodFphpF fy defult you do not need to expliitly on(gure the lotion of undles tht live in the srG diretoryF he niverslglssvoder is on(gured to fllk to the srG diretory using its registerxmespepllks methodX
sn symfonyID the onsole is in the root diretory of your projet nd is lled symfonyX
php symfony
sn ymfonyPD the onsole is now in the pp suEdiretory nd is lled onsoleX
php app/console
6.60.4 Applications
sn symfonyI projetD it is ommon to hve severl pplitionsX one for the frontend nd one for the kend for instneF sn ymfonyP projetD you only need to rete one pplition @ log pplitionD n intrnet pplitionD FFFAF wost of the timeD if you wnt to rete seond pplitionD you might insted rete nother projet nd shre some undles etween themF end if you need to seprte the frontend nd the kend fetures of some undlesD you n rete suEnmespes for ontrollersD suEdiretories for templtesD di'erent semnti on(gurtionsD seprte routing on(gurtionsD nd so onF yf ourseD there9s nothing wrong with hving multiple pplitions in your projetD tht9s entirely up to youF e seond pplition would men new diretoryD eFgF myppGD with the sme si setup s the ppG diretoryF X D F
SRR
TF
sn symfonyI projetD plugin ould ontin on(gurtionD modulesD r lirriesD ssets nd nything else relted to your projetF sn ymfonyPD the ide of plugin is repled y the undleF e undle is even more powerful thn plugin euse the ore ymfonyP frmework is rought in vi series of undlesF sn ymfonyPD undles re (rstElss itizens tht re so )exile tht even ore ode itself is undleF sn symfonyID plugin must e enled inside the rojetgon(gurtion lssX
// app/AppKernel.php public function registerBundles() { $bundles = array( new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), new Symfony\Bundle\TwigBundle\TwigBundle(), // ... new Acme\DemoBundle\AcmeDemoBundle(), ); } return $bundles;
outing @routingFymlA nd gon(gurtion @on(gFymlA sn symfonyID the routingFyml nd ppFyml on(gurtion (les were utomtilly loded inside ny pluginF sn ymfonyPD routing nd pplition on(gurtion inside undle must e inluded mnullyF por exmpleD to inlude routing resoure from undle lled emehemofundleD you n do the followingX
ork)ow
! row to grete nd store ymfonyP rojet in git
gontrollers
! ! row to de(ne gontrollers s ervies
outing
! row to fore routes to lwys use r ! row to llow G hrter in route prmeter
ymfony houmenttionD PFH ! row to epply n esseti pilter to pei( pile ixtension
porms nd lidtion
! row to ustomize porm endering ! row to grete gustom porm pield ype ! row to rete gustom lidtion gonstrint ! @dotrineA row to hndle pile plods with hotrine
fundles
! fundle truture nd fest rties ! row to use fundle snheritne to yverride prts of fundle ! row to expose emnti gon(gurtion for fundle
imiling
! ! qmil ! row to ork with imils huring hevelopment ! row to pool imil TFTHF ymfonyP symfony I SRU
esting
! row to simulte r euthentition in puntionl est ! row to test the sntertion of severl glients ! row to use the ro(ler in puntionl est ! row to test hotrine epositories
eurity
! row to dd ememer we vogin puntionlity ! row to implement your own oter to lklist s eddresses ! eess gontrol vists @egvsA ! edvned egv gonepts ! row to fore r or r for hi'erent vs ! row to ustomize your porm vogin ! row to seure ny ervie or wethod in your epplition ! row to lod eurity sers from the htse @the entity roviderA ! row to rete ustom ser rovider ! row to rete ustom euthentition rovider ! row to hnge the hefult rget th fehvior
ghing
! row to use rnish to speedup my esite
emplting
! row to use r insted of wig for empltes
e ervies
! row to grete ye e ervie in ymfonyP gontroller
ixtending ymfony
SRV TF
ymfony houmenttionD PFH ! row to extend glss without using snheritne ! row to ustomize wethod fehvior without using snheritne ! row to register new equest pormt nd wime ype ! row to rete ustom ht golletor
ork)ow
! row to grete nd store ymfonyP rojet in git
gontrollers
! ! row to de(ne gontrollers s ervies
outing
! row to fore routes to lwys use r ! row to llow G hrter in route prmeter
porms nd lidtion
! row to ustomize porm endering ! row to grete gustom porm pield ype TFTHF ymfonyP symfony I SRW
ymfony houmenttionD PFH ! row to rete gustom lidtion gonstrint ! @dotrineA row to hndle pile plods with hotrine
fundles
! fundle truture nd fest rties ! row to use fundle snheritne to yverride prts of fundle ! row to expose emnti gon(gurtion for fundle
imiling
! ! qmil ! row to ork with imils huring hevelopment ! row to pool imil
esting
! row to simulte r euthentition in puntionl est ! row to test the sntertion of severl glients ! row to use the ro(ler in puntionl est ! row to test hotrine epositories
eurity
! row to dd ememer we vogin puntionlity ! row to implement your own oter to lklist s eddresses ! eess gontrol vists @egvsA ! edvned egv gonepts ! row to fore r or r for hi'erent vs ! row to ustomize your porm vogin SSH TF
ymfony houmenttionD PFH ! row to seure ny ervie or wethod in your epplition ! row to lod eurity sers from the htse @the entity roviderA ! row to rete ustom ser rovider ! row to rete ustom euthentition rovider ! row to hnge the hefult rget th fehvior
ghing
! row to use rnish to speedup my esite
emplting
! row to use r insted of wig for empltes
e ervies
! row to grete ye e ervie in ymfonyP gontroller
ixtending ymfony
! row to extend glss without using snheritne ! row to ustomize wethod fehvior without using snheritne ! row to register new equest pormt nd wime ype ! row to rete ustom ht golletor
SSI
SSP
TF
IV
SSQ
SSS
SST
Reference Documents
his referene doument is work in progressF st should e urteD ut ll options re not yet fully overedF he prmeworkfundle ontins most of the se frmework funtionlity nd n e on(gured under the frmework key in your pplition on(gurtionF his inludes settings relted to sessionsD trnsltionD formsD vlidtionD routing nd moreF
7.1.1 Conguration
srfprotetion
! enled ! (eldnme
session
! lifetime
templting
SSU
ymfony houmenttionD PFH ! ssetsseurls ! ssetsversion ! ssetsversionformt hrset typeX string defultX pEV he hrter set tht9s used throughout the frmeworkF st eomes the servie ontiner prmeter nmed kernelFhrsetF seret typeX string required his is string tht should e unique to your pplitionF sn prtieD it9s used for generting the gp tokensD ut it ould e used in ny other ontext where hving unique string is usefulF st eomes the servie ontiner prmeter nmed kernelFseretF ide typeX string defultX null sf you9re using n shi like extwte or w imD then ymfony n turn ll of the (le pths in n exeption messge into linkD whih will open tht (le in your shiF sf you use extwte or w imD you n simply use one of the following uiltEin vluesX
textmte mvim
ou n lso speify ustom (le link stringF sf you do thisD ll perentge signs @7A must e douled to espe tht hrterF por exmpleD the full extwte string would look like thisX
SSV
UF eferene houments
ymfony houmenttionD PFH test typeX foolen sf this on(gurtion prmeter is presentD then the servies relted to testing your pplition re lodedF his setting should e present in your test environment @usully vi ppGon(gGon(gtestFymlAF por more informtionD see F form
csrf_protection
session
lifetime
typeX integer defultX VTRHH his determines the lifetime of the session E in seondsF templting
assets_base_urls
defultX { httpX D httpsX } his option llows you to de(ne se v9s to e used for ssets referened from http nd https pgesF e string vlue my e provided in lieu of singleEelement rryF sf multiple se v9s re providedD ymfonyP will selet one from the olletion eh time it genertes n sset9s pthF por your onvenieneD ssetsseurls n e set diretly with string or rry of stringsD whih will e utomtilly orgnized into olletions of se v9s for http nd https requestsF sf v strts with httpsXGG or is protoolEreltive @iFeF strts with GGA it will e dded to oth olletionsF v9s strting with httpXGG will only e dded to the http olletionF PFIF
assets_version
typeX string his option is used to ust the he on ssets y glolly dding query prmeter to ll rendered sset pths @eFgF GimgesGlogoFpngcvPAF his pplies only to ssets rendered vi the wig sset funtion @or r equivlentA s well s ssets rendered with essetiF UFIF prmeworkfundle gon(gurtion @frmeworkA SSW
ymfony houmenttionD PFH por exmpleD suppose you hve the followingX
wig
ewv
// app/cong/cong.php $container->loadFromExtension('framework', array( // ... 'templating' => array( 'engines' => array('twig'), 'assets_version' => 'v2', ), ));
xowD the sme sset will e rendered s GimgesGlogoFpngcvP sf you use this fetureD you must mnully inrement the ssetsversion vlue efore eh deployment so tht the query prmeters hngeF ou n lso ontrol how the query string works vi the ssetsversionformt optionF
assets_version_format
typeX string defultX 77sc77s
STH
UF eferene houments
ymfony houmenttionD PFH his spei(es sprintf@A pttern tht will e used with the ssetsversion option to onstrut n sset9s pthF fy defultD the pttern dds the sset9s version s query stringF por exmpleD if ssetsversionformt is set to 77scversiona77s nd ssetsversion is set to SD the sset9s pth would e GimgesGlogoFpngcversionaSF X ell perentge signs @7A in the formt string must e douled to espe the hrterF ithout espingD vlues might indvertently e interpretted s ervie rmetersF
X ome ghx9s do not support heEusting vi query stringsD so injeting the version into the tul (le pth is neessryF hnkfullyD ssetsversionformt is not limited to produing versioned query stringsF he pttern reeives the sset9s originl pth nd version s its (rst nd seond prmetersD respetivelyF ine the sset9s pth is one prmeterD we nnot modify it inEple @eFgF GimgesGlogoEvSFpngAY howeverD we n pre(x the sset9s pth using pttern of versionE 77P6sG77I6sD whih would result in the pth versionESGimgesGlogoFpngF v rewrite rules ould then e used to disregrd the version pre(x efore serving the ssetF elterntivelyD you ould opy ssets to the pproprite version pth s prt of your deployment proess nd forgo ny v rewritingF he ltter option is useful if you would like older sset versions to remin essile t their originl vF
ewv
framework: # general conguration charset: ~ secret: ~ # Required ide: ~ test: ~ # form conguration form: enabled: true csrf_protection: enabled: true eld_name: _token # esi conguration esi:
UFIF prmeworkfundle gon(gurtion @frmeworkA STI
enabled:
true
# proler conguration proler: only_exceptions: false only_master_requests: false dsn: sqlite:%kernel.cache_dir%/proler.db username: password: lifetime: 86400 matcher: ip: ~ path: ~ service: ~ # router conguration router: resource: ~ # Required type: ~ http_port: 80 https_port: 443 # session conguration session: auto_start: ~ default_locale: en storage_id: session.storage.native name: ~ lifetime: 86400 path: ~ domain: ~ secure: ~ httponly: ~ # templating conguration templating: assets_version: ~ assets_version_format: "%%s?%%s" assets_base_urls: http: [] ssl: [] cache: ~ engines: # Required form: resources: [FrameworkBundle:Form] # Example:
STP UF eferene houments
[]
# Prototype name: version: ~ version_format: ~ base_urls: http: [] ssl: [] # translator conguration translator: enabled: true fallback: en # validation conguration validation: enabled: true cache: ~ enable_annotations: false # annotation conguration annotations: cache: le le_cache_dir: %kernel.cache_dir%/annotations debug: true
ewv
assetic: debug: true use_controller: true read_from: %kernel.root_dir%/../web write_to: %assetic.read_from% java: /usr/bin/java node: /usr/bin/node sass: /usr/bin/sass bundles:
UFPF essetifundle gon(gurtion eferene STQ
# Defaults (all currently registered bundles): - FrameworkBundle - SecurityBundle - TwigBundle - MonologBundle - SwiftmailerBundle - DoctrineBundle - AsseticBundle - ... assets: # Prototype name: inputs: lters: options: # Prototype name:
[]
[]
lters:
[]
[]
[]
ewv
doctrine: dbal: default_connection: default connections: default: dbname: database host: localhost port: 1234 user: user password: secret
STR UF eferene houments
driver: pdo_mysql driver_class: MyNamespace\MyDriverImpl options: foo: bar path: %kernel.data_dir%/data.sqlite memory: true unix_socket: /tmp/mysql.sock wrapper_class: MyDoctrineDbalConnectionWrapper charset: UTF8 logging: %kernel.debug% platform_service: MyOwnDatabasePlatformService mapping_types: enum: string conn1: # ... types: custom: Acme\HelloBundle\MyCustomType orm: auto_generate_proxy_classes: false proxy_namespace: Proxies proxy_dir: %kernel.cache_dir%/doctrine/orm/Proxies default_entity_manager: default # The rst dened is used if not set entity_managers: default: # The name of a DBAL connection (the one marked as default is used if not set) connection: conn1 mappings: # Required AcmeHelloBundle: ~ class_metadata_factory_name: Doctrine\ORM\Mapping\ClassMetadataFactory # All cache drivers have to be array, apc, xcache or memcache metadata_cache_driver: array query_cache_driver: array result_cache_driver: type: memcache host: localhost port: 11211 instance_class: Memcache class: Doctrine\Common\Cache\MemcacheCache dql: string_functions: test_string: Acme\HelloBundle\DQL\StringFunction numeric_functions: test_numeric: Acme\HelloBundle\DQL\NumericFunction datetime_functions: test_datetime: Acme\HelloBundle\DQL\DatetimeFunction em2: # ...
UFQF gon(gurtion eferene STS
wv
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:doctrine="http://symfony.com/schema/dic/doctrine" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctrine/doct <doctrine:cong> <doctrine:dbal default-connection="default"> <doctrine:connection name="default" dbname="database" host="localhost" port="1234" user="user" password="secret" driver="pdo_mysql" driver-class="MyNamespace\MyDriverImpl" path="%kernel.data_dir%/data.sqlite" memory="true" unix-socket="/tmp/mysql.sock" wrapper-class="MyDoctrineDbalConnectionWrapper" charset="UTF8" logging="%kernel.debug%" platform-service="MyOwnDatabasePlatformService" > <doctrine:option key="foo">bar</doctrine:option> <doctrine:mapping-type name="enum">string</doctrine:mapping-type> </doctrine:connection> <doctrine:connection name="conn1" /> <doctrine:type name="custom">Acme\HelloBundle\MyCustomType</doctrine:type> </doctrine:dbal>
<doctrine:orm default-entity-manager="default" auto-generate-proxy-classes="false" proxy-namespac <doctrine:entity-manager name="default" query-cache-driver="array" result-cache-driver="array" <doctrine:metadata-cache-driver type="memcache" host="localhost" port="11211" instance-c <doctrine:mapping name="AcmeHelloBundle" /> <doctrine:dql> <doctrine:string-function name="test_string>Acme\HelloBundle\DQL\StringFunction</d <doctrine:numeric-function name="test_numeric>Acme\HelloBundle\DQL\NumericFuncti <doctrine:datetime-function name="test_datetime>Acme\HelloBundle\DQL\DatetimeFun </doctrine:dql> </doctrine:entity-manager> <doctrine:entity-manager name="em2" connection="conn2" metadata-cache-driver="apc"> <doctrine:mapping name="DoctrineExtensions" type="xml"
STT UF eferene houments
his following on(gurtion exmple shows ll the on(gurtion defults tht the yw resolves toX
doctrine: orm: auto_mapping: true # the standard distribution overrides this to be true in debug, false otherwise auto_generate_proxy_classes: false proxy_namespace: Proxies proxy_dir: %kernel.cache_dir%/doctrine/orm/Proxies default_entity_manager: default metadata_cache_driver: array query_cache_driver: array result_cache_driver: array
here re lots of other on(gurtion options tht you n use to overwrite ertin lssesD ut those re for very dvned useEses onlyF ghing hrivers por the hing drivers you n speify the vlues rryD pD memhe or xheF he following exmple shows n overview of the hing on(gurtionsX
doctrine: orm: auto_mapping: true metadata_cache_driver: apc query_cache_driver: xcache result_cache_driver: type: memcache host: localhost port: 11211 instance_class: Memcache
UFQF gon(gurtion eferene STU
ymfony houmenttionD PFH wpping gon(gurtion ixpliit de(nition of ll the mpped entities is the only neessry on(gurtion for the yw nd there re severl on(gurtion options tht you n ontrolF he following on(gurtion options exist for mppingX
type yne of nnottionD xmlD ymlD php or sttiphpF his spei(es whih type of metdt type your mpping usesF dir th to the mpping or entity (les @depending on the driverAF sf this pth is reltive it is ssumed to e reltive to the undle rootF his only works if the nme of your mpping is undle nmeF sf you wnt to use this option to speify solute pths you should pre(x the pth with the kernel prmeters tht exist in the hsg @for exmple 7kernelFrootdir7AF pre(x e ommon nmespe pre(x tht ll entities of this mpping shreF his pre(x should never on)it with pre(xes of other de(ned mppings otherwise some of your entities nnot e found y hotrineF his option defults to the undle nmespe C intityD for exmple for n pplition undle lled emerellofundle pre(x would e emerellofundleintityF lis hotrine o'ers wy to lis entity nmespes to simplerD shorter nmes to e used in hv queries or for epository essF hen using undle the lis defults to the undle nmeF isundle his option is derived vlue from dir nd y defult is set to true if dir is reltive proved y (leexists@A hek tht returns flseF st is flse if the existene hek returns trueF sn this se n solute pth ws spei(ed nd the metdt (les re most likely in diretory outside of undleF
7.3.2 Doctrine DBAL Conguration
X hotrinefundle supports ll prmeters tht defult hotrine drivers eptD onverted to the wv or ewv nming stndrds tht ymfony enforesF ee the hotrine hfev doumenttion for more informtionF fesides defult hotrine optionsD there re some ymfonyErelted ones tht you n on(gureF he following lok shows ll possile on(gurtion keysX
ewv
user: user password: secret driver: pdo_mysql driver_class: MyNamespace\MyDriverImpl options: foo: bar path: %kernel.data_dir%/data.sqlite memory: true unix_socket: /tmp/mysql.sock wrapper_class: MyDoctrineDbalConnectionWrapper charset: UTF8 logging: %kernel.debug% platform_service: MyOwnDatabasePlatformService mapping_types: enum: string types: custom: Acme\HelloBundle\MyCustomType
wv
<!-- xmlns:doctrine="http://symfony.com/schema/dic/doctrine" --> <!-- xsi:schemaLocation="http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctr <doctrine:cong> <doctrine:dbal name="default" dbname="database" host="localhost" port="1234" user="user" password="secret" driver="pdo_mysql" driver-class="MyNamespace\MyDriverImpl" path="%kernel.data_dir%/data.sqlite" memory="true" unix-socket="/tmp/mysql.sock" wrapper-class="MyDoctrineDbalConnectionWrapper" charset="UTF8" logging="%kernel.debug%" platform-service="MyOwnDatabasePlatformService" > <doctrine:option key="foo">bar</doctrine:option> <doctrine:mapping-type name="enum">string</doctrine:mapping-type> <doctrine:type name="custom">Acme\HelloBundle\MyCustomType</doctrine:type> </doctrine:dbal> </doctrine:cong>
sf you wnt to on(gure multiple onnetions in ewvD put them under the onnetions key UFQF gon(gurtion eferene STW
doctrine: dbal: default_connection: default connections: default: dbname: Symfony2 user: root password: null host: localhost customer: dbname: customer user: root password: null host: localhost
he dtseonnetion servie lwys refers to the defult onnetionD whih is the (rst one de(ned or the one on(gured vi the defultonnetion prmeterF ih onnetion is lso essile vi the dotrineFdlFnmeonnetion servie where nme if the nme of the onnetionF
he seurity system is one of the most powerful prts of ymfonyPD nd n lrgely e ontrolled vi its on(gurtionF
7.4.1 Full Default Conguration
he following is the full defult on(gurtion for the seurity systemF ih prt will e explined in the next setionF
ewv
# app/cong/security.yml security: access_denied_url: /foo/error403 always_authenticate_before_granting: false # strategy can be: none, migrate, invalidate session_xation_strategy: migrate access_decision_manager:
SUH UF eferene houments
strategy: armative allow_if_all_abstain: false allow_if_equal_granted_denied: true acl: connection: default # any name congured in doctrine.dbal section tables: class: acl_classes entry: acl_entries object_identity: acl_object_identities object_identity_ancestors: acl_object_identity_ancestors security_identity: acl_security_identities cache: id: service_id prex: sf2_acl_ voter: allow_if_object_identity_unavailable: true encoders: somename: class: Acme\DemoBundle\Entity\User Acme\DemoBundle\Entity\User: sha512 Acme\DemoBundle\Entity\User: plaintext Acme\DemoBundle\Entity\User: algorithm: sha512 encode_as_base64: true iterations: 5000 Acme\DemoBundle\Entity\User: id: my.custom.encoder.service.id providers: memory: name: memory users: foo: { password: foo, roles: ROLE_USER } bar: { password: bar, roles: [ROLE_USER, ROLE_ADMIN] } entity: entity: { class: SecurityBundle:User, property: username } factories: MyFactory: %kernel.root_dir%/../src/Acme/DemoBundle/Resources/cong/security_factories.xml rewalls: somename: pattern: .* request_matcher: some.service.id access_denied_url: /foo/error403
UFRF eurity gon(gurtion eferene SUI
access_denied_handler: some.service.id entry_point: some.service.id provider: name context: name stateless: false x509: provider: name http_basic: provider: name http_digest: provider: name form_login: check_path: /login_check login_path: /login use_forward: false always_use_default_target_path: false default_target_path: / target_path_parameter: _target_path use_referer: false failure_path: /foo failure_forward: false failure_handler: some.service.id success_handler: some.service.id username_parameter: _username password_parameter: _password csrf_parameter: _csrf_token csrf_page_id: form_login csrf_provider: my.csrf_provider.id post_only: true remember_me: false remember_me: token_provider: name key: someS3cretKey name: NameOfTheCookie lifetime: 3600 # in seconds path: /foo domain: somedomain.foo secure: true httponly: true always_remember_me: false remember_me_parameter: _remember_me logout: path: /logout target: / invalidate_session: false delete_cookies: a: { path: null, domain: null }
SUP UF eferene houments
b: { path: null, domain: null } handlers: [some.service.id, another.service.id] success_handler: some.service.id anonymous: ~ access_control: path: ^/foo host: mydomain.foo ip: 192.0.0.0/8 roles: [ROLE_A, ROLE_B] requires_channel: https role_hierarchy: ROLE_SUPERADMIN: ROLE_ADMIN ROLE_SUPERADMIN: 'ROLE_ADMIN, ROLE_USER' ROLE_SUPERADMIN: [ROLE_ADMIN, ROLE_USER] anything: { id: ROLE_SUPERADMIN, value: 'ROLE_USER, ROLE_ADMIN' } anything: { id: ROLE_SUPERADMIN, value: [ROLE_USER, ROLE_ADMIN] }
hen using the formlogin uthentition listener eneth (rewllD there re severl ommon options for on(guring the form login experieneX he vogin porm nd roess
loginpth @typeX stringD defultX GloginA his is the v tht the user will e redireted to @unless useforwrd is set to trueA when heGshe tries to ess proteted resoure ut isn9t fully uthentitedF
his v must e essile y normlD unEuthentited userD else you my rete rediret loopF por detilsD see evoid gommon itfllsF
hekpth @typeX stringD defultX GloginhekA his is the v tht your login form must sumit toF he (rewll will interept ny requests @y requests onlyD e defultA to this v nd proess the sumitted login redentilsF
fe sure tht this v is overed y your min (rewll @iFeF don9t rete seprte (rewll just for hekpth vAF
useforwrd @typeX foolenD defultX flseA sf you9d like the user to e forwrded to the login form insted of eing rediretedD set this option to trueF usernmeprmeter @typeX stringD defultX usernmeA his is the (eld nme tht you should give to the usernme (eld of your login formF hen you sumit the form
UFRF eurity gon(gurtion eferene SUQ
ymfony houmenttionD PFH to hekpthD the seurity system will look for y prmeter with this nmeF
psswordprmeter @typeX stringD defultX psswordA his is the (eld nme tht you should give to the pssword (eld of your login formF hen you sumit the form to hekpthD the seurity system will look for y prmeter with this nmeF postonly @typeX foolenD defultX trueA fy defultD you must sumit your login form to the hekpth v s y requestF fy setting this option to trueD you n send qi request to the hekpth vF
edireting fter vogin
lwysusedefulttrgetpth @typeX foolenD defultX flseA defulttrgetpth @typeX stringD defultX GA trgetpthprmeter @typeX stringD defultX trgetpthA usereferer @typeX foolenD defultX flseA
ewv
swiftmailer: transport: smtp username: ~ password: ~ host: localhost port: false encryption: ~ auth_mode: ~ spool: type: le path: %kernel.cache_dir%/swiftmailer/spool sender_address: ~ antiood: threshold: 99 sleep: 0 delivery_address: ~ disable_delivery: ~ logging: true
SUR
UF eferene houments
ewv
twig: form: resources: # Default: - div_layout.html.twig # Example: - MyBundle::form.html.twig globals: # Examples: foo: pi: "@bar" 3.14
# Prototype key: id: ~ type: ~ value: ~ autoescape: ~ base_template_class: ~ # Example: Twig_Template cache: %kernel.cache_dir%/twig charset: %kernel.charset% debug: %kernel.debug% strict_variables: ~ auto_reload: ~ exception_controller: Symfony\Bundle\TwigBundle\Controller\ExceptionController::showAction
wv
<twig:cong auto-reload="%kernel.debug%" autoescape="true" base-template-class="Twig_Template" <twig:form> <twig:resource>MyBundle::form.html.twig</twig:resource> </twig:form> <twig:global key="foo" id="bar" type="service" /> <twig:global key="pi">3.14</twig:global>
UFTF wigfundle gon(gurtion eferene SUS
</twig:cong> </container>
r
$container->loadFromExtension('twig', array( 'form' => array( 'resources' => array( 'MyBundle::form.html.twig', ) ), 'globals' => array( 'foo' => '@bar', 'pi' => 3.14, ), 'auto_reload' => '%kernel.debug%', 'autoescape' => true, 'base_template_class' => 'Twig_Template', 'cache' => '%kernel.cache_dir%/twig', 'charset' => '%kernel.charset%', 'debug' => '%kernel.debug%', 'strict_variables' => false, ));
7.6.1 Conguration
exeptionontroller typeX string defultX ymfonyfundlewigfundlegontrollerixeptiongontrollerXXshowetion his is the ontroller tht is tivted fter n exeption is thrown nywhere in your pplitionF he defult ontroller @ymfonyfundlewigfundlegontrollerixeptiongontrollerA is wht9s responsile for rendering spei( templtes under di'erent error onditions @see E AF wodifying this option is dvnedF sf you need to ustomize n error pge you should use the previous linkF sf you need to perform some ehvior on n exeptionD you should dd listener to the kernelFexeption event @see inling gustom vistenersAF
ewv
SUT
UF eferene houments
monolog: handlers: # Examples: syslog: type: path: level: bubble: formatter: main: type: action_level: buer_size: handler: custom: type: id:
stream /var/log/symfony.log ERROR false my_formatter ngerscrossed WARNING 30 custom service my_handler
# Prototype name: type: ~ # Required id: ~ priority: 0 level: DEBUG bubble: true path: %kernel.logs_dir%/%kernel.environment%.log ident: false facility: user max_les: 0 action_level: WARNING stop_buering: true buer_size: 0 handler: ~ members: [] from_email: ~ to_email: ~ subject: ~ email_prototype: id: ~ # Required (when the email_prototype is used) method: ~ formatter: ~
wv
xmlns:monolog="http://symfony.com/schema/dic/monolog" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/mon <monolog:cong> <monolog:handler name="syslog" type="stream" path="/var/log/symfony.log" level="error" bubble="false" formatter="my_formatter" /> <monolog:handler name="main" type="ngerscrossed" action-level="warning" handler="custom" /> <monolog:handler name="custom" type="service" id="my_handler" /> </monolog:cong> </container>
X hen the pro(ler is enledD hndler is dded to store the logs9 messges in the pro(lerF he pro(ler uses the nme deug so it is reserved nd nnot e used in the on(gurtionF
ewv
web_proler: # display secondary information to make the toolbar shorter verbose: true # display the web debug toolbar at the bottom of pages with a summary of proler info
SUV UF eferene houments
toolbar:
false
# gives you the opportunity to look at the collected data before following the redirect intercept_redirects: false
e dte (eld tht speilizes in hndling irthdte dtF gn e rendered s single text oxD three text oxes @monthD dyD nd yerAD or three selet oxesF his type is essentilly the sme s the dte typeD ut with more pproprite defult for the yers optionF he yers option defults to IPH yers go to the urrent yerF nderlying ht ype endered s yptions snherited options n e hteimeD stringD timestmpD or rry @see the input optionA n e three selet oxes or I or Q text oxesD sed on the widget option
yers
widget input months dys formt pttern dttimezone usertimezone
dte ymfonygomponentpormixtensiongoreypefirthd
years
typeX rry defultX IPH yers go to the urrent yer
SUW
ymfony houmenttionD PFH vist of yers ville to the yer (eld typeF his option is only relevnt when the widget option is set to hoieF snherited options hese options inherit from the dte typeX
widget
typeX string defultX hoie he si wy in whih this (eld should e renderedF gn e one of the followingX
hoieX renders three selet inputsF he order of the selets is de(ned in the pttern optionF textX renders three (eld input of type text @monthD dyD yerAF singletextX renders single input of type textF ser9s input is vlidted sed on the formt optionF
input
typeX string defultX dtetime he formt of the input dt E iFeF the formt tht the dte is stored on your underlying ojetF lid vlues reX
string @eFgF PHIIEHTEHSA dtetime @ hteime ojetA rry @eFgF rry@9yer9 ab PHIID 9month9 ab HTD 9dy9 ab HSAA timestmp @eFgF IQHUPQPHHHA
he vlue tht omes k from the form will lso e normlized k into this formtF
months
typeX rry defultX I to IP vist of months ville to the month (eld typeF his option is only relevnt when the widget option is set to hoieF
SVH
UF eferene houments
days
typeX rry defultX I to QI vist of dys ville to the dy (eld typeF his option is only relevnt when the widget option is set to hoieX
pattern
typeX string his option is only relevnt when the widget is set to hoieF he defult pttern is sed o' the formt optionD nd tries to mth the hrters wD dD nd y in the formt ptternF sf no mth is foundD the defult is the string {{ yer }}E{{ month }}E{{ dy }}F okens for this option inludeX
{{ yer }}X epled with the yer widget {{ month }}X epled with the month widget {{ dy }}X epled with the dy widget
data_timezone
typeX string defultX system defult timezone imezone tht the input dt is stored inF his must e one of the r supported timezones
user_timezone
typeX string defultX system defult timezone imezone for how the dt should e shown to the user @nd therefore lso the dt tht the user sumitsAF his must e one of the r supported timezones UFWF porm ypes eferene SVI
gretes single input hekoxF his should lwys e used for (eld tht hs foolen vlueX if the ox is hekedD the (eld will e set to trueD if the ox is unhekedD the vlue will e set to flseF endered s yptions snherited options input text (eld
vlue
required lel redonly erroruling
(eld ymfonygomponentpormixtensiongoreypeghek
$builder->add('public', 'checkbox', array( 'label' => 'Show this entry publicly?', 'required' => false, ));
pield yptions
value
typeX mixed defultX I he vlue tht9s tully used s the vlue for the hekoxF his does not 'et the vlue tht9s set on your ojetF snherited options hese options inherit from the (eld typeX
required
typeX foolen defultX true
SVP
UF eferene houments
ymfony houmenttionD PFH sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.3 choice Field Type
e multiEpurpose (eld used to llow the user to hoose one or more optionsF st n e rendered s selet tgD rdio uttonsD or hekoxesF o use this (eldD you must speify either the hoielist or hoies optionF
SVQ
hoies hoielist multiple expnded preferredhoies emptyvlue required lel redonly erroruling
snherited options
he esiest wy to use this (eld is to speify the hoies diretly vi the hoies optionF he key of the rry eomes the vlue tht9s tully set on your underlying ojet @eFgF mAD while the vlue is wht the user sees on the form @eFgF wleAF
$builder->add('gender', 'choice', array( 'choices' => array('m' => 'Male', 'f' => 'Female'), 'required' => false, ));
fy setting multiple to trueD you n llow the user to hoose multiple vluesF he widget will e rendered s multiple selet tg or series of hekoxes depending on the expnded optionX
$builder->add('availability', 'choice', array( 'choices' => array( 'morning' => 'Morning', 'afternoon' => 'Afternoon', 'evening' => 'Evening', ), 'multiple' => true, ));
ou n lso use the hoielist optionD whih tkes n ojet tht n speify the hoies for your widgetF
SVR
UF eferene houments
ymfony houmenttionD PFH elet tgD ghekoxes or dio futtons his (eld my e rendered s one of severl di'erent rwv (eldsD depending on the expnded nd multiple optionsX element type selet tg selet tg @with multiple ttriuteA rdio uttons hekoxes pield yptions expnded flse flse true true multiple flse true flse true
choices
typeX rry defultX rry@A his is the most si wy to speify the hoies tht should e used y this (eldF he hoies option is n rryD where the rry key is the item vlue nd the rry vlue is the item9s lelX
$builder->add('gender', 'choice', array( 'choices' => array('m' => 'Male', 'f' => 'Female') )); choice_list
typeX ymfonygomponentpormixtensiongoreghoievistghoievistsnterfe his is one wy of speifying the options to e used for this (eldF he hoielist option must e n instne of the ghoievistsnterfeF por more dvned sesD ustom lss tht implements the interfe n e reted to supply the hoiesF
multiple
typeX foolen defultX flse sf trueD the user will e le to selet multiple options @s opposed to hoosing just one optionAF hepending on the vlue of the expnded optionD this will render either selet tg or hekoxes if true nd selet tg or rdio uttons if flseF he returned vlue will e n rryF
SVS
expanded
typeX foolen defultX flse sf set to trueD rdio uttons or hekoxes will e rendered @depending on the multiple vlueAF sf flseD selet element will e renderedF
preferred_choices
typeX rry defultX rry@A sf this option is spei(edD then suEset of ll of the options will e moved to the top of the selet menuF he following would move the fz option to the topD with visul seprtor etween it nd the rest of the optionsX
$builder->add('foo_choices', 'choice', array( 'choices' => array('foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz'), 'preferred_choices' => array('baz'), ));
xote tht preferred hoies re only meningful when rendering s selet element @iFeF expnded is flseAF he preferred hoies nd norml hoies re seprted visully y set of dotted lines @iFeF EEEEEEEEEEEEEEEEEEEAF his n e ustomized when rendering the (eldX
wig
// a blank (with no text) option will be added $builder->add('states', 'choice', array( 'required' => false, ));
snherited options hese options inherit from the (eld typeX
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
SVU
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.4 collection Field Type
ee ymfonygomponentpormixtensiongoreypegolletionypeF
7.9.5 country Field Type
he ountry type is suset of the ghoieype tht displys ountries of the worldF es n dded onusD the ountry nmes re displyed in the lnguge of the userF he vlue for eh ountry is the twoEletter ountry odeF X he lole of your user is guessed using voleXXgethefult@A nlike the hoie typeD you don9t need to speify hoies or hoielist option s the (eld type utomtilly uses ll of the ountries of the worldF ou n speify either of these options mnullyD ut then you should just use the hoie type diretlyF endered s snherited options n e vrious tgs @see elet tgD ghekoxes or dio futtonsA
rent type glss snherited options hese options inherit from the hoie typeX SVV
hoie ymfonygomponentpormixtensiongoreypegountr
UF eferene houments
multiple
typeX foolen defultX flse sf trueD the user will e le to selet multiple options @s opposed to hoosing just one optionAF hepending on the vlue of the expnded optionD this will render either selet tg or hekoxes if true nd selet tg or rdio uttons if flseF he returned vlue will e n rryF
expanded
typeX foolen defultX flse sf set to trueD rdio uttons or hekoxes will e rendered @depending on the multiple vlueAF sf flseD selet element will e renderedF
preferred_choices
typeX rry defultX rry@A sf this option is spei(edD then suEset of ll of the options will e moved to the top of the selet menuF he following would move the fz option to the topD with visul seprtor etween it nd the rest of the optionsX
$builder->add('foo_choices', 'choice', array( 'choices' => array('foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz'), 'preferred_choices' => array('baz'), ));
xote tht preferred hoies re only meningful when rendering s selet element @iFeF expnded is flseAF he preferred hoies nd norml hoies re seprted visully y set of dotted lines @iFeF EEEEEEEEEEEEEEEEEEEAF his n e ustomized when rendering the (eldX
wig
SVW
ymfony houmenttionD PFH his option determines whether or not speil empty option @eFgF ghoose n optionA will pper t the top of selet widgetF his option only pplies if oth the expnded nd multiple options re set to flseF
// a blank (with no text) option will be added $builder->add('states', 'choice', array( 'required' => false, )); error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF hese options inherit from the (eld typeX
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
SWH
UF eferene houments
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
he srf type is hidden input (eld ontining gp tokenF endered s yptions input hidden (eld
hidden ymfonygomponentpormixtensiongsrfypegsrfyp
csrf_provider
typeX ymfonygomponentpormgsrfrovidergsrfrovidersnterfe he gsrfrovidersnterfe ojet tht should generte the gp tokenF sf not setD this defults to the defult providerF
intention
typeX string en optionl unique identi(er used to generte the gp tokenF UFWF porm ypes eferene SWI
property_path
typeX ny defultX the (eld9s vlue pields disply property vlue of the form9s domin ojet y defultF hen the form is sumittedD the sumitted vlue is written k into the ojetF sf you wnt to override the property tht (eld reds from nd writes toD you n set the propertypth optionF sts defult vlue is the (eld9s nmeF
7.9.7 date Field Type
e (eld tht llows the user to modify dte informtion vi vriety of di'erent rwv elementsF he underlying dt used for this (eld type n e hteime ojetD stringD timestmp or n rryF es long s the input option is set orretlyD the (eld will tke re of ll of the detilsF he (eld n e rendered s single text oxD three text oxes @monthD dyD nd yerA or three selet oxes @see the widget optionAF nderlying ht ype endered s yptions n e hteimeD stringD timestmpD or rry @see the input optionA single text ox or three selet (elds
widget input emptyvlue yers months dys formt pttern dttimezone usertimezone
his (eld type is highly on(gurleD ut esy to useF he most importnt options re input nd widgetF
SWP
UF eferene houments
ymfony houmenttionD PFH uppose tht you hve pulishedet (eld whose underlying dte is hteime ojetF he following on(gures the dte type for tht (eld s three di'erent hoie (eldsX
$builder->add('publishedAt', 'date', array( 'input' => 'datetime', 'widget' => 'choice', ));
he input option must e hnged to mth the type of the underlying dte dtF por exmpleD if the pulishedet (eld9s dt were unix timestmpD you9d need to set input to timestmpX
$builder->add('publishedAt', 'date', array( 'input' => 'timestamp', 'widget' => 'choice', ));
he (eld lso supports n rry nd string s vlid input option vluesF pield yptions
widget
typeX string defultX hoie he si wy in whih this (eld should e renderedF gn e one of the followingX
hoieX renders three selet inputsF he order of the selets is de(ned in the pttern optionF textX renders three (eld input of type text @monthD dyD yerAF singletextX renders single input of type textF ser9s input is vlidted sed on the formt optionF
input
typeX string defultX dtetime he formt of the input dt E iFeF the formt tht the dte is stored on your underlying ojetF lid vlues reX
string @eFgF PHIIEHTEHSA dtetime @ hteime ojetA rry @eFgF rry@9yer9 ab PHIID 9month9 ab HTD 9dy9 ab HSAA timestmp @eFgF IQHUPQPHHHA
UFWF porm ypes eferene SWQ
ymfony houmenttionD PFH he vlue tht omes k from the form will lso e normlized k into this formtF
empty_value
typeX string|rry sf your widget option is set to hoieD then this (eld will e represented s series of selet oxesF he emptyvlue option n e used to dd lnk entry to the top of eh selet oxX
$builder->add('dueDate', 'date', array( 'empty_value' => array('year' => 'Year', 'month' => 'Month', 'day' => 'Day') )); years
typeX rry defultX (ve yers efore to (ve yers fter the urrent yer vist of yers ville to the yer (eld typeF his option is only relevnt when the widget option is set to hoieF
months
typeX rry defultX I to IP vist of months ville to the month (eld typeF his option is only relevnt when the widget option is set to hoieF
days
typeX rry defultX I to QI vist of dys ville to the dy (eld typeF his option is only relevnt when the widget option is set to hoieX
SWR
UF eferene houments
format
typeX integer or string defultX sntlhtepormtterXXwihsw yption pssed to the sntlhtepormtter lssD used to trnsform user input into the proper formtF his is ritil when the widget option is set to singletextD nd will de(ne how to trnsform the inputF fy defultD the formt is determined sed on the urrent user loleY you n override it y pssing the formt s stringF
pattern
typeX string his option is only relevnt when the widget is set to hoieF he defult pttern is sed o' the formt optionD nd tries to mth the hrters wD dD nd y in the formt ptternF sf no mth is foundD the defult is the string {{ yer }}E{{ month }}E{{ dy }}F okens for this option inludeX
{{ yer }}X epled with the yer widget {{ month }}X epled with the month widget {{ dy }}X epled with the dy widget
data_timezone
typeX string defultX system defult timezone imezone tht the input dt is stored inF his must e one of the r supported timezones
user_timezone
typeX string defultX system defult timezone imezone for how the dt should e shown to the user @nd therefore lso the dt tht the user sumitsAF his must e one of the r supported timezones
7.9.8 datetime Field Type
his (eld type llows the user to modify dt tht represents spei( dte nd time @eFgF IWVREHTEHS IPXISXQHAF gn e rendered s text input or selet tgsF he underlying formt of the dt n e hteime ojetD stringD timestmp or n rryF
SWS
ymfony houmenttionD PFH nderlying ht ype endered s yptions n e hteimeD stringD timestmpD or rry @see the input optionA single text ox or three selet (elds
form ymfonygomponentpormixtensiongoreypehte
date_widget
typeX string defultX hoie he(nes the widget option for the dte type
time_widget
typeX string defultX hoie he(nes the widget option for the time type
input
typeX string defultX dtetime he formt of the input dt E iFeF the formt tht the dte is stored on your underlying ojetF lid vlues reX
string @eFgF PHIIEHTEHS IPXISXHHA dtetime @ hteime ojetA rry @eFgF rry@PHIID HTD HSD IPD ISD HAA timestmp @eFgF IQHUPUTIHHA
he vlue tht omes k from the form will lso e normlized k into this formtF
SWT
UF eferene houments
date_format
typeX integer or string defultX sntlhtepormtterXXwihsw he(nes the formt option tht will e pssed down to the dte (eldF
hours
typeX integer defultX I to PQ vist of hours ville to the hours (eld typeF his option is only relevnt when the widget option is set to hoieF
minutes
typeX integer defultX I to SW vist of minutes ville to the minutes (eld typeF his option is only relevnt when the widget option is set to hoieF
seconds
typeX integer defultX I to SW vist of seonds ville to the seonds (eld typeF his option is only relevnt when the widget option is set to hoieF
years
typeX rry defultX (ve yers efore to (ve yers fter the urrent yer vist of yers ville to the yer (eld typeF his option is only relevnt when the widget option is set to hoieF
months
typeX rry defultX I to IP vist of months ville to the month (eld typeF his option is only relevnt when the widget option is set to hoieF
SWU
days
typeX rry defultX I to QI vist of dys ville to the dy (eld typeF his option is only relevnt when the widget option is set to hoieX
data_timezone
typeX string defultX system defult timezone imezone tht the input dt is stored inF his must e one of the r supported timezones
user_timezone
typeX string defultX system defult timezone imezone for how the dt should e shown to the user @nd therefore lso the dt tht the user sumitsAF his must e one of the r supported timezones
7.9.9 email Field Type
he emil (eld is text (eld tht is rendered using the rwvS `input typea4emil4Gb tgF
SWV
UF eferene houments
ymfony houmenttionD PFH endered s snherited options input emil (eld @ text oxA
rent type glss snherited yptions hese options inherit from the (eld typeX
(eld ymfonygomponentpormixtensiongoreypeimil
max_length
typeX integer his option is used to dd mxlength ttriuteD whih is used y some rowsers to limit the mount of text in (eldF
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
SWW
trim
typeX foolen defultX true sf trueD the whitespe of the sumitted string vlue will e stripped vi the trim@A funtion when the dt is oundF his gurntees tht if vlue is sumitted with extr whitespeD it will e removed efore the vlue is merged k onto the underlying ojetF
read_only
typeX foolen defultX flse sf this option is trueD the (eld will e rendered with the disled ttriute so tht the (eld is not editleF
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.10 entity Field Type
e speil hoie (eld tht9s designed to lod options from hotrine entityF por exmpleD if you hve gtegory entityD you ould use this (eld to disply selet (eld of llD or someD of the gtegory ojets from the dtseF
THH
UF eferene houments
ymfony houmenttionD PFH endered s yptions n e vrious tgs @see elet tgD ghekoxes or dio futtonsA
lss property queryuilder em required lel multiple expnded preferredhoies emptyvlue redonly erroruling
snherited options
hoie ymfonyfridgehotrinepormypeintityype
he entity type hs just one required optionX the entity whih should e listed inside the hoie (eldX
));
elet tgD ghekoxes or dio futtons his (eld my e rendered s one of severl di'erent rwv (eldsD depending on the expnded nd multiple optionsX element type selet tg selet tg @with multiple ttriuteA rdio uttons hekoxes pield yptions expnded flse flse true true multiple flse true flse true
class
typeX string required he lss of your entity @eFgF emetorefundleXgtegoryAF his n e fullyEquli(ed lss nme @eFgF emetorefundleintitygtegoryA or the short lis nme @s shown priorAF
property
typeX string his is the property tht should e used for displying the entities s text in the rwv elementF sf left lnkD the entity ojet will e st into string nd so must hve totring@A methodF
query_builder
typeX hotrineywueryfuilder or glosure sf spei(edD this is used to query the suset of options @nd their orderA tht should e used for the (eldF he vlue of this option n either e ueryfuilder ojet or glosureF sf using glosureD it should tke single rgumentD whih is the intityepository of the entityF
THP
UF eferene houments
em
typeX string defultX the defult entity mnger sf spei(edD the spei(ed entity mnger will e used to lod the hoies insted of the defult entity mngerF snherited options hese options inherit from the hoie typeX
multiple
typeX foolen defultX flse sf trueD the user will e le to selet multiple options @s opposed to hoosing just one optionAF hepending on the vlue of the expnded optionD this will render either selet tg or hekoxes if true nd selet tg or rdio uttons if flseF he returned vlue will e n rryF
expanded
typeX foolen defultX flse sf set to trueD rdio uttons or hekoxes will e rendered @depending on the multiple vlueAF sf flseD selet element will e renderedF
preferred_choices
typeX rry defultX rry@A sf this option is spei(edD then suEset of ll of the options will e moved to the top of the selet menuF he following would move the fz option to the topD with visul seprtor etween it nd the rest of the optionsX
$builder->add('foo_choices', 'choice', array( 'choices' => array('foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz'), 'preferred_choices' => array('baz'), ));
xote tht preferred hoies re only meningful when rendering s selet element @iFeF expnded is flseAF he preferred hoies nd norml hoies re seprted visully y set of dotted lines @iFeF EEEEEEEEEEEEEEEEEEEAF his n e ustomized when rendering the (eldX UFWF porm ypes eferene THQ
wig
// a blank (with no text) option will be added $builder->add('states', 'choice', array( 'required' => false, ));
hese options inherit from the (eld typeX
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF THR UF eferene houments
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.11 le Field Type
he (le type represents (le input in your formF endered s snherited options input (le (eld required lel redonly erroruling
rent type glss fsi sge vet9s sy you hve this form de(nitionX
form ymfonygomponentpormixtensiongoreypepiley
THS
$builder->add('attachment', 'le');
X hon9t forget to dd the entype ttriute in the form tgX `form tiona454methoda4post4{{ formentype@formA }}bF hen the form is sumittedD the tthment (eld will e n instne of ymfonygomponentrttppoundtionpileplodedpileF st n e used to move the tthment (le to permnent lotionX
use Symfony\Component\HttpFoundation\File\UploadedFile; public function uploadAction() { // ... if ($form->isValid()) { $someNewFilename = ... $form['attachment']->getData()->move($dir, $someNewFilename); } } // ...
// ...
he move@A method tkes diretory nd (le nme s its rgumentsF ou might lulte the (lenme in one of the following wysX
// use the original le name $le->move($dir, $le->getClientOriginalName()); // compute a random name and try to guess the extension (more secure) $extension = $le->guessExtension(); if (!$extension) { // extension cannot be guessed $extension = 'bin'; } $le->move($dir, rand(1, 99999).'.'.$extension);
sing the originl nme vi getglientyriginlxme@A is not sfe s it ould hve een mnipulted y the endEuserF woreoverD it n ontin hrters tht re not llowed in (le nmesF ou should snitize the nme efore using it diretlyF ed the ookook for n exmple of how to mnge (le uplod ssoited with hotrine entityF
THT
UF eferene houments
ymfony houmenttionD PFH snherited options hese options inherit from the (eld typeX
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.12 The Abstract eld Type
he (eld form type is not n tul (eld type you useD ut rther funtions s the prent (eld type for mny other (eldsF UFWF porm ypes eferene THU
ymfony houmenttionD PFH he (eld type prede(nes ouple of optionsX dt typeX mixed defultX hefults to (eld of the underlying ojet @if there is oneA hen you rete formD eh (eld initilly displys the vlue of the orresponding property of the form9s domin ojet @if n ojet is ound to the formAF sf you wnt to override the initil vlue for the form or just nd individul (eldD you n set it in the dt optionX
disled typeX foolenD defultX flse sf you don9t wnt user to modify the vlue of (eldD you n set the disled option to trueF eny sumitted vlue will e ignoredF
use Symfony\Component\Form\TextField $eld = new TextField('status', array( 'data' => 'Old data', 'disabled' => true, )); $eld->submit('New data'); // prints "Old data" echo $eld->getData();
trim typeX foolen defultX true sf trueD the whitespe of the sumitted string vlue will e stripped vi the trim@A funtion when the dt is oundF his gurntees tht if vlue is sumitted with extr whitespeD it will e removed efore the vlue is merged k onto the underlying ojetF
THV
UF eferene houments
ymfony houmenttionD PFH propertypth typeX ny defultX the (eld9s vlue pields disply property vlue of the form9s domin ojet y defultF hen the form is sumittedD the sumitted vlue is written k into the ojetF sf you wnt to override the property tht (eld reds from nd writes toD you n set the propertypth optionF sts defult vlue is the (eld9s nmeF
7.9.13 form Field Type
ee ymfonygomponentpormixtensiongoreypepormypeF
7.9.14 hidden Field Type
he hidden type represents hidden input (eldF endered s rent type glss input hidden (eld (eld ymfonygomponentpormixtensiongoreyperiddenype
enders n input numer (eldF fsillyD this is text (eld tht9s good t hndling dt tht9s in n integer formF he input numer (eld looks like text oxD exept tht E if the user9s rowser supports rwvS E it will hve some extr frontend funtionlityF his (eld hs di'erent options on how to hndle input vlues tht ren9t integersF fy defultD ll nonEinteger vlues @eFgF TFUVA will round down @eFgF TAF endered s yptions input text (eld
roundingmode grouping
required lel redonly erroruling
snherited options
(eld ymfonygomponentpormixtensiongoreypesnteger
THW
rounding_mode
typeX integer defultX sntegerovolizedtringrnsformerXXyxhhyx fy defultD if the user enters nonEinteger numerD it will e rounded downF here re severl other rounding methodsD nd eh is onstnt on the ymfonygomponentpormixtensiongorehtrnsformersntegerovolizedtringrnsformerX
sntegerovolizedtringrnsformerXXyxhhyx ounding mode to round towrds zeroF sntegerovolizedtringrnsformerXXyxhpvyy ounding mode to round towrds negtive in(nityF sntegerovolizedtringrnsformerXXyxh ounding mode to round wy from zeroF sntegerovolizedtringrnsformerXXyxhgisvsxq ounding mode to round towrds positive in(nityF
grouping
typeX integer defultX flse he vlue set s the xumerpormtterXXqysxqih ttriute when using the r xumerpormtter lssF snherited options hese options inherit from the (eld typeX
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
TIH
UF eferene houments
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.16 language Field Type
he lnguge type is suset of the ghoieype tht llows the user to selet from lrge list of lngugesF es n dded onusD the lnguge nmes re displyed in the lnguge of the userF he vlue for eh lole is either the two letter syTQWEI lnguge ode @eFgF frAF X he lole of your user is guessed using voleXXgethefult@A nlike the hoie typeD you don9t need to speify hoies or hoielist option s the (eld type utomtilly uses lrge list of lngugesF ou n speify either of these options mnullyD ut then you should just use the hoie type diretlyF
TII
ymfony houmenttionD PFH endered s snherited options n e vrious tgs @see elet tgD ghekoxes or dio futtonsA
rent type glss snherited yptions hese options inherit from the hoie typeX
hoie ymfonygomponentpormixtensiongoreypevngu
multiple
typeX foolen defultX flse sf trueD the user will e le to selet multiple options @s opposed to hoosing just one optionAF hepending on the vlue of the expnded optionD this will render either selet tg or hekoxes if true nd selet tg or rdio uttons if flseF he returned vlue will e n rryF
expanded
typeX foolen defultX flse sf set to trueD rdio uttons or hekoxes will e rendered @depending on the multiple vlueAF sf flseD selet element will e renderedF
preferred_choices
typeX rry defultX rry@A sf this option is spei(edD then suEset of ll of the options will e moved to the top of the selet menuF he following would move the fz option to the topD with visul seprtor etween it nd the rest of the optionsX
TIP
UF eferene houments
$builder->add('foo_choices', 'choice', array( 'choices' => array('foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz'), 'preferred_choices' => array('baz'), ));
xote tht preferred hoies re only meningful when rendering s selet element @iFeF expnded is flseAF he preferred hoies nd norml hoies re seprted visully y set of dotted lines @iFeF EEEEEEEEEEEEEEEEEEEAF his n e ustomized when rendering the (eldX
wig
// a blank (with no text) option will be added $builder->add('states', 'choice', array( 'required' => false, ));
TIQ
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF hese options inherit from the (eld typeX
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
he lole type is suset of the ghoieype tht llows the user to selet from lrge list of loles @lngugeCountryAF es n dded onusD the lole nmes re displyed in the lnguge of the userF
TIR
UF eferene houments
ymfony houmenttionD PFH he vlue for eh lole is either the two letter syTQWEI lnguge ode @eFgF frAD or the lnguge ode followed y n undersore @AD then the syQITT ountry ode @eFgF frp for prenhGprneAF X he lole of your user is guessed using voleXXgethefult@A nlike the hoie typeD you don9t need to speify hoies or hoielist option s the (eld type utomtilly uses lrge list of lolesF ou n speify either of these options mnullyD ut then you should just use the hoie type diretlyF endered s snherited options n e vrious tgs @see elet tgD ghekoxes or dio futtonsA
rent type glss snherited options hese options inherit from the hoie typeX
hoie ymfonygomponentpormixtensiongoreypevngu
multiple
typeX foolen defultX flse sf trueD the user will e le to selet multiple options @s opposed to hoosing just one optionAF hepending on the vlue of the expnded optionD this will render either selet tg or hekoxes if true nd selet tg or rdio uttons if flseF he returned vlue will e n rryF
expanded
typeX foolen defultX flse
TIS
ymfony houmenttionD PFH sf set to trueD rdio uttons or hekoxes will e rendered @depending on the multiple vlueAF sf flseD selet element will e renderedF
preferred_choices
typeX rry defultX rry@A sf this option is spei(edD then suEset of ll of the options will e moved to the top of the selet menuF he following would move the fz option to the topD with visul seprtor etween it nd the rest of the optionsX
$builder->add('foo_choices', 'choice', array( 'choices' => array('foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz'), 'preferred_choices' => array('baz'), ));
xote tht preferred hoies re only meningful when rendering s selet element @iFeF expnded is flseAF he preferred hoies nd norml hoies re seprted visully y set of dotted lines @iFeF EEEEEEEEEEEEEEEEEEEAF his n e ustomized when rendering the (eldX
wig
ymfony houmenttionD PFH sf you leve the emptyvlue option unsetD then lnk @with no textA option will utomtilly e dded if nd only if the required option is flseX
// a blank (with no text) option will be added $builder->add('states', 'choice', array( 'required' => false, )); error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF hese options inherit from the (eld typeX
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
TIU
enders n input text (eld nd speilizes in hndling sumitted money dtF his (eld type llows you to speify urrenyD whose symol is rendered next to the text (eldF here re lso severl other options for ustomizing how the input nd output of the dt is hndledF endered s yptions input text (eld
snherited options
(eld ymfonygomponentpormixtensiongoreypewoney
currency
typeX string defultX i pei(es the urreny tht the money is eing spei(ed inF his determines the urreny symol tht should e shown y the text oxF hepending on the urreny E the urreny symol my e shown efore or fter the input text (eldF his n lso e set to flse to hide the urreny symolF
divisor
typeX integer defultX I sfD for some resonD you need to divide your strting vlue y numer efore rendering it to the userD you n use the divisor optionF por exmpleX
TIV
UF eferene houments
ymfony houmenttionD PFH sn this seD if the prie (eld is set to WWHHD then the vlue WW will tully e rendered to the userF hen the user sumits the vlue WWD it will e multiplied y IHH nd WWHH will ultimtely e set k on your ojetF
precision
typeX integer defultX P por some resonD if you need some preision other thn P deiml plesD you n modify this vlueF ou proly won9t need to do this unlessD for exmpleD you wnt to round to the nerest dollr @set the preision to HAF
grouping
typeX integer defultX flse he vlue set s the xumerpormtterXXqysxqih ttriute when using the r xumerpormtter lssF snherited yptions hese options inherit from the (eld typeX
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
TIW
read_only
typeX foolen defultX flse sf this option is trueD the (eld will e rendered with the disled ttriute so tht the (eld is not editleF
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.19 number Field Type
enders n input text (eld nd speilizes in hndling numer inputF his type o'ers di'erent options for the preisionD roundingD nd grouping tht you wnt to use for your numerF endered s yptions input text (eld
snherited options
(eld ymfonygomponentpormixtensiongoreypexume
precision
typeX integer defultX voleEspei( @usully round QA his spei(es how mny deimls will e llowed until the (eld rounds the sumitted vlue @vi roundingmodeAF por exmpleD if preision is set to PD sumitted vlue of PHFIPQ will e rounded toD for exmpleD PHFIP @depending on your roundingmodeAF TPH UF eferene houments
rounding_mode
typeX integer defultX sntegerovolizedtringrnsformerXXyxhhyx sf sumitted numer needs to e rounded @sed on the preision optionAD you hve severl on(gurle options for tht roundingF ih option is onstnt on the ymfonygomponentpormixtensiongorehtrnsformersntegerovolizedtringrnsformerX
sntegerovolizedtringrnsformerXXyxhhyx ounding mode to round towrds zeroF sntegerovolizedtringrnsformerXXyxhpvyy ounding mode to round towrds negtive in(nityF sntegerovolizedtringrnsformerXXyxh ounding mode to round wy from zeroF sntegerovolizedtringrnsformerXXyxhgisvsxq ounding mode to round towrds positive in(nityF sntegerovolizedtringrnsformerXXyxhrevphyx ounding mode to round towrds nerest neighor unless oth neighors re equidistntD in whih se round downF sntegerovolizedtringrnsformerXXyxhrevpiix ounding mode to round towrds the nerest neighor unless oth neighors re equidistntD in whih seD round towrds the even neighorF sntegerovolizedtringrnsformerXXyxhrevp ounding mode to round towrds nerest neighor unless oth neighors re equidistntD in whih se round upF
grouping
typeX integer defultX flse he vlue set s the xumerpormtterXXqysxqih ttriute when using the r xumerpormtter lssF snherited yptions hese options inherit from the (eld typeX
required
typeX foolen defultX true UFWF porm ypes eferene TPI
ymfony houmenttionD PFH sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.20 password Field Type
TPP
UF eferene houments
ymfony houmenttionD PFH endered s yptions snherited options input pssword (eld
lwysempty
mxlength required lel trim redonly erroruling
text ymfonygomponentpormixtensiongoreypesswo
always_empty
typeX foolen defultX true sf set to trueD the (eld will lwys render lnkD even if the orresponding (eld hs vlueF hen set to flseD the pssword (eld will e rendered with the vlue ttriute set to its true vlueF ut simplyD if for some reson you wnt to render your pssword (eld with the pssword vlue lredy entered into the oxD set this to flseF snherited yptions hese options inherit from the (eld typeX
max_length
typeX integer his option is used to dd mxlength ttriuteD whih is used y some rowsers to limit the mount of text in (eldF
required
typeX foolen defultX true
TPQ
ymfony houmenttionD PFH sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
read_only
typeX foolen defultX flse sf this option is trueD the (eld will e rendered with the disled ttriute so tht the (eld is not editleF
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.21 percent Field Type
he perent type renders n input text (eld nd speilizes in hndling perentge dtF sf your perentge dt is stored s deiml @eFgF FWSAD you n use this (eld outEofEtheEoxF sf you store your dt s numer @eFgF WSAD you should set the type option to integerF TPR UF eferene houments
ymfony houmenttionD PFH his (eld dds perentge sign 7 fter the input oxF endered s yptions input text (eld
type preision
required lel redonly erroruling
snherited options
(eld ymfonygomponentpormixtensiongoreypeeren
type
typeX string defultX frtionl his ontrols how your dt is stored on your ojetF por exmpleD perentge orresponding to SS7D might e stored s FSS or SS on your ojetF he two types hndle these two sesX
frtionl sf your dt is stored s deiml @eFgF FSSAD use this typeF he dt will e multiplied y IHH efore eing shown to the user @eFgF SSAF he sumitted dt will e divided y IHH on form sumit so tht the deiml vlue is stored @FSSAY integer sf your dt is stored s n integer @eFgF SSAD then use this optionF he rw vlue @SSA is shown to the user nd stored on your ojetF xote tht this only works for integer vluesF
precision
typeX integer defultX H fy defultD the input numers re re roundedF o llow for more deiml plesD use this optionF snherited yptions hese options inherit from the (eld typeX
TPS
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.22 radio Field Type
gretes single rdio uttonF his should lwys e used for (eld tht hs foolen vlueX if the rdio utton is seletedD the (eld will e set to trueD if the utton is not seletedD the vlue will e set to flseF he rdio type isn9t usully used diretlyF wore ommonly it9s used internlly y other types suh s hoieF sf you wnt to hve foolen (eldD use hekoxF
TPT
UF eferene houments
ymfony houmenttionD PFH endered s yptions snherited options input text (eld
vlue
required lel redonly erroruling
(eld ymfonygomponentpormixtensiongoreypedio
value
typeX mixed defultX I he vlue tht9s tully used s the vlue for the rdio uttonF his does not 'et the vlue tht9s set on your ojetF snherited yptions hese options inherit from the (eld typeX
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
TPU
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.23 repeated Field Type
his is speil (eld groupD tht retes two identil (elds whose vlues must mth @or vlidtion error is thrownAF he most ommon use is when you need the user to repet his or her pssword or emil to verify uryF endered s yptions input text (eld y defultD ut see type option
snherited options
(eld ymfonygomponentpormixtensiongoreypeepet
TPV
UF eferene houments
$builder->add('password', 'repeated', array( 'type' => 'password', 'invalid_message' => 'The password elds must match.', 'options' => array('label' => 'Password'), ));
pon suessful form sumitD the vlue entered into oth of the pssword (elds eomes the dt of the pssword keyF sn other wordsD even though two (elds re tully renderedD the end dt from the form is just the single vlue @usully stringA tht you needF he most importnt option is typeD whih n e ny (eld type nd determines the tul type of the two underlying (eldsF he options option is pssed to eh of those individul (eldsD mening E in this exmple E ny option supported y the pssword type n e pssed in this rryF
Validation
yne of the key fetures of the repeted (eld is internl vlidtion @you don9t need to do nything to set this upA tht fores the two (elds to hve mthing vlueF sf the two (elds don9t mthD n error will e shown to the userF he invlidmessge is used to ustomize the error tht will e displyed when the two (elds do not mth eh otherF pield yptions
type
typeX string defultX text he two underlying (elds will e of this (eld typeF por exmpleD pssing type of pssword will render two pssword (eldsF
options
typeX rry defultX rry@A his options rry will e pssed to eh of the two underlying (eldsF sn other wordsD these re the options tht ustomize the individul (eld typesF por exmpleD if the type option is set to psswordD this rry might ontin the options lwysempty or required E oth options tht re supported y the pssword (eld typeF
TPW
rst_name
typeX string defultX (rst his is the tul (eld nme to e used for the (rst (eldF his is mostly meninglessD howeverD s the tul dt entered into oth of the (elds will e ville under the key ssigned to the repeted (eld itself @eFgF psswordAF roweverD if you don9t speify lelD this (eld nme is used to guess the lel for youF
second_name
typeX string defultX seond he sme s (rstnmeD ut for the seond (eldF snherited options hese options inherit from the (eld typeX
invalid_message
typeX string defultX his vlue is not vlid his is the vlidtion error messge tht9s used when the dt entered is determined y internl vlidtion of (eld typeF his might hppenD for exmpleD if the user enters string into time (eld tht nnot e onverted into rel timeF por norml vlidtion messges @suh s when setting minimum length for (eldAD set the vlidtion messges with your vlidtion rules @refereneAF
invalid_message_parameters
typeX rry defultX rry@A hen setting the invlidmessge optionD you my need to inlude some vriles in the stringF his n e done y dding pleholders to tht option nd inluding the vriles in this optionX
$builder->add('some_eld', 'some_type', array( // ... 'invalid_message' => 'You entered an invalid value - it should include %num% letters', 'invalid_message_parameters' => array('%num%' => 6), ));
TQH
UF eferene houments
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.24 search Field Type
his renders n `input typea4serh4Gb (eldD whih is text ox with speil funtionlity supported y some rowsersF ed out the input serh (eld t hivesntorwvSForg endered s snherited options input serh (eld mxlength required lel trim redonly erroruling
rent type glss snherited yptions hese options inherit from the (eld typeX
text ymfonygomponentpormixtensiongoreypeerh
max_length
typeX integer his option is used to dd mxlength ttriuteD whih is used y some rowsers to limit the mount of text in (eldF
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF UFWF porm ypes eferene TQI
ymfony houmenttionD PFH his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
read_only
typeX foolen defultX flse sf this option is trueD the (eld will e rendered with the disled ttriute so tht the (eld is not editleF
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.25 text Field Type
TQP
UF eferene houments
rent type glss snherited yptions hese options inherit from the (eld typeX
(eld ymfonygomponentpormixtensiongoreypeexty
max_length
typeX integer his option is used to dd mxlength ttriuteD whih is used y some rowsers to limit the mount of text in (eldF
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
TQQ
trim
typeX foolen defultX true sf trueD the whitespe of the sumitted string vlue will e stripped vi the trim@A funtion when the dt is oundF his gurntees tht if vlue is sumitted with extr whitespeD it will e removed efore the vlue is merged k onto the underlying ojetF
read_only
typeX foolen defultX flse sf this option is trueD the (eld will e rendered with the disled ttriute so tht the (eld is not editleF
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.26 textarea Field Type
rent type glss snherited yptions hese options inherit from the (eld typeX
(eld ymfonygomponentpormixtensiongoreypeextr
TQR
UF eferene houments
max_length
typeX integer his option is used to dd mxlength ttriuteD whih is used y some rowsers to limit the mount of text in (eldF
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
read_only
typeX foolen defultX flse sf this option is trueD the (eld will e rendered with the disled ttriute so tht the (eld is not editleF
TQS
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
7.9.27 time Field Type
e (eld to pture time inputF his n e rendered s text (eldD series of text (elds @eFgF hourD minuteD seondA or series of selet (eldsF he underlying dt n e stored s hteime ojetD stringD timestmp or n rryF nderlying ht ype endered s yptions n e hteimeD stringD timestmpD or rry @see the input optionA n e vrious tgs @see elowA
form ymfonygomponentpormixtensiongoreypeime
his (eld type is highly on(gurleD ut esy to useF he most importnt options re input nd widgetF uppose tht you hve strtime (eld whose underlying time dt is hteime ojetF he following on(gures the time type for tht (eld s three di'erent hoie (eldsX
$builder->add('startTime', 'time', array( 'input' => 'datetime', 'widget' => 'choice', ));
TQT
UF eferene houments
ymfony houmenttionD PFH he input option must e hnged to mth the type of the underlying dte dtF por exmpleD if the strtime (eld9s dt were unix timestmpD you9d need to set input to timestmpX
$builder->add('startTime', 'time', array( 'input' => 'timestamp', 'widget' => 'choice', ));
he (eld lso supports n rry nd string s vlid input option vluesF pield yptions
widget
typeX string defultX hoie he si wy in whih this (eld should e renderedF gn e one of the followingX
hoieX renders two @or three if withseonds is trueA selet inputsF textX renders two or three text inputs @hourD minuteD seondAF singletextX renders single input of type textF ser9s input will e vlidted ginst the form hhXmm @or hhXmmXss if using seondsAF
input
typeX string defultX dtetime he formt of the input dt E iFeF the formt tht the dte is stored on your underlying ojetF lid vlues reX
string @eFgF IPXIUXPTA dtetime @ hteime ojetA rry @eFgF rry@9hour9 ab IPD 9minute9 ab IUD 9seond9 ab PTAA timestmp @eFgF IQHUPQPHHHA
he vlue tht omes k from the form will lso e normlized k into this formtF
with_seconds
typeX foolen defultX flse
TQU
ymfony houmenttionD PFH hether or not to inlude seonds in the inputF his will result in n dditionl input to pture seondsF
hours
typeX integer defultX I to PQ vist of hours ville to the hours (eld typeF his option is only relevnt when the widget option is set to hoieF
minutes
typeX integer defultX I to SW vist of minutes ville to the minutes (eld typeF his option is only relevnt when the widget option is set to hoieF
seconds
typeX integer defultX I to SW vist of seonds ville to the seonds (eld typeF his option is only relevnt when the widget option is set to hoieF
data_timezone
typeX string defultX system defult timezone imezone tht the input dt is stored inF his must e one of the r supported timezones
user_timezone
typeX string defultX system defult timezone imezone for how the dt should e shown to the user @nd therefore lso the dt tht the user sumitsAF his must e one of the r supported timezones
7.9.28 timezone Field Type
he timezone type is suset of the ghoieype tht llows the user to selet from ll possile timezonesF
TQV
UF eferene houments
ymfony houmenttionD PFH he vlue for eh timezone is the full timezone nmeD suh s emeriGghigo or iuropeGsstnulF nlike the hoie typeD you don9t need to speify hoies or hoielist option s the (eld type utomtilly uses lrge list of lolesF ou n speify either of these options mnullyD ut then you should just use the hoie type diretlyF endered s snherited options n e vrious tgs @see elet tgD ghekoxes or dio futtonsA
rent type glss snherited options hese options inherit from the hoie typeX
hoie ymfonygomponentpormixtensiongoreypeimezo
multiple
typeX foolen defultX flse sf trueD the user will e le to selet multiple options @s opposed to hoosing just one optionAF hepending on the vlue of the expnded optionD this will render either selet tg or hekoxes if true nd selet tg or rdio uttons if flseF he returned vlue will e n rryF
expanded
typeX foolen defultX flse sf set to trueD rdio uttons or hekoxes will e rendered @depending on the multiple vlueAF sf flseD selet element will e renderedF
TQW
preferred_choices
typeX rry defultX rry@A sf this option is spei(edD then suEset of ll of the options will e moved to the top of the selet menuF he following would move the fz option to the topD with visul seprtor etween it nd the rest of the optionsX
$builder->add('foo_choices', 'choice', array( 'choices' => array('foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz'), 'preferred_choices' => array('baz'), ));
xote tht preferred hoies re only meningful when rendering s selet element @iFeF expnded is flseAF he preferred hoies nd norml hoies re seprted visully y set of dotted lines @iFeF EEEEEEEEEEEEEEEEEEEAF his n e ustomized when rendering the (eldX
wig
TRH
UF eferene houments
// a blank (with no text) option will be added $builder->add('states', 'choice', array( 'required' => false, ));
hese options inherit from the (eld typeX
required
typeX foolen defultX true sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF
TRI
he url (eld is text (eld tht prepends the sumitted vlue with given protool @eFgF httpXGGA if the sumitted vlue doesn9t lredy hve protoolF endered s yptions snherited options input url (eld
defultprotool
mxlength required lel trim redonly erroruling
text ymfonygomponentpormixtensiongoreyperlyp
default_protocol
typeX string defultX http sf vlue is sumitted tht doesn9t egin with some protool @eFgF httpXGGD ftpXGGD etAD this protool will e prepended to the string when the dt is ound to the formF snherited yptions hese options inherit from the (eld typeX
max_length
typeX integer his option is used to dd mxlength ttriuteD whih is used y some rowsers to limit the mount of text in (eldF
required
typeX foolen defultX true TRP UF eferene houments
ymfony houmenttionD PFH sf trueD n rwvS required ttriute will e renderedF he orresponding lel will lso render with required lssF his is super(il nd independent from vlidtionF et estD if you let ymfony guess your (eld typeD then the vlue of this option will e guessed from your vlidtion informtionF
label
typeX string defultX he lel is guessed from the (eld nme ets the lel tht will e used when rendering the (eldF he lel n lso e diretly set inside the templteX
read_only
typeX foolen defultX flse sf this option is trueD the (eld will e rendered with the disled ttriute so tht the (eld is not editleF
error_bubbling
typeX foolen defultX flse sf trueD ny errors for this (eld will e pssed to the prent (eld or formF por exmpleD if set to true on norml (eldD ny errors for tht (eld will e tthed to the min formD not to the spei( (eldF e form is omposed of (eldsD eh of whih re uilt with the help of (eld type @eFgF text typeD hoie typeD etAF ymfonyP omes stndrd with lrge list of (eld types tht n e used in your pplitionF
TRQ
text textre emil integer money numer pssword perent serh url
ghoie pields
TRR
UF eferene houments
olletion repeted
ridden pields
hidden srf
fse pields
(eld form
his referene mnul overs ll the possile wig funtions ville for rendering formsF here re severl di'erent funtions villeD nd eh is responsile for rendering di'erent prt of form @eFgF lelsD errorsD widgetsD etAF
7.10.1 form_label(form.name, label, variables)
enders the lel for the given (eldF ou n optionlly pss the spei( lel you wnt to disply s the seond rgumentF
{{ form_label(form.name) }} {# The two following syntaxes are equivalent #} {{ form_label(form.name, 'Your Name', { 'attr': {'class': 'foo'} }) }} {{ form_label(form.name, null, { 'label': 'Your name', 'attr': {'class': 'foo'} }) }}
TRS
enders the rwv widget of given (eldF sf you pply this to n entire form or olletion of (eldsD eh underlying form row will e renderedF
{# render a widget, but add a "foo" class to it #} {{ form_widget(form.name, { 'attr': {'class': 'foo'} }) }}
he seond rgument to formwidget is n rry of vrilesF he most ommon vrile is ttrD whih is n rry of rwv ttriutes to pply to the rwv widgetF sn some sesD ertin types lso hve other templteErelted options tht n e pssedF hese re disussed on typeEyEtype sisF
7.10.4 form_row(form.name, variables)
enders the row of given (eldD whih is the omintion of the (eld9s lelD errors nd widgetF
{# render a eld row, but display a label with text "foo" #} {{ form_row(form.name, { 'label': 'foo' }) }}
he seond rgument to formrow is n rry of vrilesF he templtes provided in symfony only llow to override the lel s shown in the exmple oveF
7.10.5 form_rest(form, variables)
his renders ll (elds tht hve not yet een rendered for the given formF st9s good ide to lwys hve this somewhere inside your form s it9ll render hidden (elds for you nd mke ny (elds you forgot to render more ovious @sine it9ll render the (eld for youAF
{{ form_rest(form) }}
TRT
UF eferene houments
sf the form ontins t lest one (le uplod (eldD this will render the required entypea4multiprtGformEdt4 form ttriuteF st9s lwys good ide to inlude this in your form tgX
lidtes tht vlue is not lnkD de(ned s not equl to lnk string nd lso not equl to nullF o fore tht vlue is simply not equl to nullD see the xotxull onstrintF epplies to yptions glss lidtor fsi sge sf you wnted to ensure tht the (rstxme property of n euthor lss were not lnkD you ould do the followingX property or method
messge
ymfonygomponentlidtorgonstrintsxotflnk ymfonygomponentlidtorgonstrintsxotflnkli
ewv
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\NotBlank() */ protected $rstName; }
UFIIF lidtion gonstrints eferene TRU
message
typeX string defultX his vlue should not e lnk his is the messge tht will e shown if the vlue is lnkF
7.11.2 Blank
lidtes tht vlue is lnkD de(ned s equl to lnk string or equl to nullF o fore tht vlue stritly e equl to nullD see the xull onstrintF o fore tht vlue is not lnkD see xotflnkF epplies to yptions glss lidtor fsi sge sfD for some resonD you wnted to ensure tht the (rstxme property of n euthor lss were lnkD you ould do the followingX property or method
messge
ymfonygomponentlidtorgonstrintsflnk ymfonygomponentlidtorgonstrintsflnklidt
ewv
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Blank() */ protected $rstName; }
TRV
UF eferene houments
message
typeX string defultX his vlue should e lnk his is the messge tht will e shown if the vlue is not lnkF
7.11.3 NotNull
lidtes tht vlue is not stritly equl to nullF o ensure tht vlue is simply not lnk @not lnk stringAD see the xotflnk onstrintF epplies to yptions glss lidtor fsi sge sf you wnted to ensure tht the (rstxme property of n euthor lss were not stritly equl to nullD you wouldX property or method
messge
ymfonygomponentlidtorgonstrintsxotxull ymfonygomponentlidtorgonstrintsxotxulllid
ewv
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\NotNull() */ protected $rstName; }
TRW
message
typeX string defultX his vlue should not e null his is the messge tht will e shown if the vlue is nullF
7.11.4 Null
lidtes tht vlue is extly equl to nullF o fore tht property is simply lnk @lnk string or nullAD see the flnk onstrintF o ensure tht property is not nullD see xotxullF epplies to yptions glss lidtor fsi sge sfD for some resonD you wnted to ensure tht the (rstxme property of n euthor lss extly equl to nullD you ould do the followingX property or method
messge
ymfonygomponentlidtorgonstrintsxull ymfonygomponentlidtorgonstrintsxulllidtor
ewv
// src/Acme/BlogBundle/Entity/Author.php namespace Acme\BlogBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Null() */ protected $rstName; }
TSH UF eferene houments
yptions
message
typeX string defultX his vlue should e null his is the messge tht will e shown if the vlue is not nullF
7.11.5 True
lidtes tht vlue is trueF pei(llyD this heks to see if the vlue is extly trueD extly the integer ID or extly the string IF elso see plseF epplies to yptions glss lidtor fsi sge his onstrint n e pplied to properties @eFgF termseepted property on registrtion modelA or to getter methodF st9s most powerful in the ltter seD where you n ssert tht method returns true vlueF por exmpleD suppose you hve the following methodX property or method
messge
ymfonygomponentlidtorgonstrintsrue ymfonygomponentlidtorgonstrintsruelidtor
// src/Acme/BlogBundle/Entity/Author.php namespace Acme\BlogBundle\Entity; class Author { protected $token; public function isTokenValid() { return $this->token == $this->generateToken(); }
TSI
ewv
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { protected $token; /** * @Assert\True(message = "The token is invalid") */ public function isTokenValid() { return $this->token == $this->generateToken(); }
wv
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/ <class name="Acme\BlogBundle\Entity\Author"> <getter property="tokenValid"> <constraint name="True"> <option name="message">The token is invalid...</option> </constraint> </getter> </class> </constraint-mapping>
r
class Author { protected $token; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addGetterConstraint('tokenValid', new True(array( 'message' => 'The token is invalid', ))); } public function isTokenValid() { return $this->token == $this->generateToken(); }
message
typeX string defultX his vlue should e true his messge is shown if the underlying dt is not trueF
7.11.6 False
lidtes tht vlue is flseF pei(llyD this heks to see if the vlue is extly flseD extly the integer HD or extly the string HF elso see rueF epplies to yptions glss lidtor fsi sge he plse onstrint n e pplied to property or getter methodD ut is most ommonly useful in the ltter seF por exmpleD suppose tht you wnt to gurntee tht some stte UFIIF lidtion gonstrints eferene TSQ property or method
messge
ymfonygomponentlidtorgonstrintsplse ymfonygomponentlidtorgonstrintsplselidto
ymfony houmenttionD PFH property is not in dynmi invlidttes rryF pirstD you9d rete getter methodX
protected $state; protectd $invalidStates = array(); public function isStateInvalid() { return in_array($this->state, $this->invalidStates); }
sn this seD the underlying ojet is only vlid if the isttesnvlid method returns flseX
ewv
# src/BlogBundle/Resources/cong/validation.yml Acme\BlogBundle\Entity\Author getters: stateInvalid: - "False": message: You've entered an invalid state.
ennottions
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\False() */ public function isStateInvalid($message = "You've entered an invalid state.") { // ... } }
X hen using ewvD e sure to surround plse with quotes @4plse4A or else ewv will onvert this into foolen vlueF
yptions
message
typeX string defultX his vlue should e flse TSR UF eferene houments
ymfony houmenttionD PFH his messge is shown if the underlying dt is not flseF
7.11.7 Type
lidtes tht vlue is of spei( dt typeF por exmpleD if vrile should e n rryD you n use this onstrint with the rry type option to vlidte thisF epplies to yptions property or method
type messge
ymfonygomponentlidtorgonstrintsype ymfonygomponentlidtorgonstrintsypelidto
ewv
# src/BlogBundle/Resources/cong/validation.yml Acme\BlogBundle\Entity\Author: properties: age: - Type: type: integer message: The value {{ value }} is not a valid {{ type }}.
ennottions
// src/Acme/BlogBundle/Entity/Author.php namespace Acme\BlogBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Type(type="integer", message="The value {{ value }} is not a valid {{ type }}.") */ protected $age; }
TSS
type
typeX string defult option his required option is the fully quli(ed lss nme or one of the r dttypes s determined y r9s is funtionsF
rry ool llle )ot doule int integer long null numeri ojet rel resoure slr string
message
typeX string defultX his vlue should e of type {{ type }} he messge if the underlying dt is not of the given typeF
7.11.8 Email
lidtes tht vlue is vlid emil ddressF he underlying vlue is st to string efore eing vlidtedF
TST
UF eferene houments
messge hekw
ymfonygomponentlidtorgonstrintsimil ymfonygomponentlidtorgonstrintsimillidt
ewv
# src/BlogBundle/Resources/cong/validation.yml Acme\BlogBundle\Entity\Author: properties: email: - Email: message: The email "{{ value }}" is not a valid email. checkMX: true
ennottions
// src/Acme/BlogBundle/Entity/Author.php namespace Acme\BlogBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Email( * message = "The email '{{ value }}' is not a valid email.", * checkMX = true *) */ protected $email; }
yptions
message
typeX string defultX his vlue is not vlid emil ddress his messge is shown if the underlying dt is not vlid emil ddressF
TSU
checkMX
typeX foolen defultX flse sf trueD then the hekdnsrr r funtion will e used to hek the vlidity of the w reord of the host of the given emilF
7.11.9 MinLength
lidtes tht the length of string is t lest s long s the given limitF epplies to yptions property or method
ymfonygomponentlidtorgonstrintswinvength ymfonygomponentlidtorgonstrintswinvength
ewv
# src/Acme/BlogBundle/Resources/cong/validation.yml Acme\BlogBundle\Entity\Blog: properties: rstName: - MinLength: { limit: 3, message: Your name must have at least {{ limit}} characters. }
ennottions
// src/Acme/BlogBundle/Entity/Blog.php use Symfony\Component\Validator\Constraints as Assert; class Blog { /** * @Assert\MinLength( * limit=3, * message="Your name must have at least {{ limit}} characters." *) */ protected $summary; }
TSV
UF eferene houments
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <class name="Acme\BlogBundle\Entity\Blog"> <property name="summary"> <constraint name="MinLength"> <option name="limit">3</option> <option name="message">Your name must have at least {{ limit}} characters.</option> </constraint> </property> </class>
yptions
limit
typeX integer defult option his required option is the min vlueF lidtion will fil if the length of the give string is less thn this numerF
message
typeX string defultX his vlue is too shortF st should hve {{ limit }} hrters or more he messge tht will e shown if the underlying string hs length tht is shorter thn the limit optionF
charset
typeX hrset defultX pEV sf the r extension mstring is instlledD then the r funtion mstrlen will e used to lulte the length of the stringF he vlue of the hrset option is pssed s the seond rgument to tht funtionF
7.11.10 MaxLength
lidtes tht the length of string is not lrger thn the given limitF
TSW
ymfonygomponentlidtorgonstrintswxvength ymfonygomponentlidtorgonstrintswxvength
ewv
// src/Acme/BlogBundle/Entity/Blog.php use Symfony\Component\Validator\Constraints as Assert; class Blog { /** * @Assert\MaxLength(100) */ protected $summary; }
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <class name="Acme\BlogBundle\Entity\Blog"> <property name="summary"> <constraint name="MaxLength"> <value>100</value> </constraint> </property> </class>
TTH
UF eferene houments
limit
typeX integer defult option his required option is the mx vlueF lidtion will fil if the length of the give string is greter thn this numerF
message
typeX string defultX his vlue is too longF st should hve {{ limit }} hrters or less he messge tht will e shown if the underlying string hs length tht is longer thn the limit optionF
charset
typeX hrset defultX pEV sf the r extension mstring is instlledD then the r funtion mstrlen will e used to lulte the length of the stringF he vlue of the hrset option is pssed s the seond rgument to tht funtionF
7.11.11 Url
messge protools
ymfonygomponentlidtorgonstrintsrl ymfonygomponentlidtorgonstrintsrllidtor
ewv
TTI
bioUrl: - Url:
ennottions
// src/Acme/BlogBundle/Entity/Author.php namespace Acme\BlogBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Url */ protected $bioUrl; }
yptions
message
typeX string defultX his vlue is not vlid v his messge is shown if the v is invlidF
protocols
typeX rry defultX rry@9http9D 9https9A he protools tht will e onsidered to e vlidF por exmpleD if you lso needed ftpXGG type vs to e vlidD you9d rede(ne the protools rryD listing httpD httpsD nd lso ftpF
7.11.12 Regex
lidtes tht vlue mthes regulr expressionF epplies to yptions property or method
ymfony houmenttionD PFH fsi sge uppose you hve desription (eld nd you wnt to verify tht it egins with vlid word hrterF he regulr expression to test for this would e GwCGD inditing tht you9re looking for t lest one or more word hrters t the eginning of your stringX
ewv
// src/Acme/BlogBundle/Entity/Author.php namespace Acme\BlogBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Regex("/^\w+/") */ protected $description; }
elterntivelyD you n set the mth option to flse in order to ssert tht given string does not mthF sn the following exmpleD you9ll ssert tht the (rstxme (eld does not ontin ny numers nd give it ustom messgeX
ewv
# src/Acme/BlogBundle/Resources/cong/validation.yml Acme\BlogBundle\Entity\Author: properties: rstName: - Regex: pattern: "/\d/" match: false message: Your name cannot contain a number
ennottions
TTQ
use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Regex( * pattern="/\d/", * match=false, * message="Your name cannot contain a number" *) */ protected $rstName; }
yptions
pattern
typeX string defult option his required option is the regulr expression pttern tht the input will e mthed ginstF fy defultD this vlidtor will fil if the input string does not mth this regulr expression @vi the pregmth r funtionAF roweverD if mth is set to flseD then vlidtion will fil if the input string does mth this ptternF
match
typeX foolen defultX true sf true @or not setAD this vlidtor will pss if the given string mthes the given pttern regulr expressionF roweverD when this option is set to flseD the opposite will ourX vlidtion will pss only if the given string does not mth the pttern regulr expressionF
message
typeX string defultX his vlue is not vlid his is the messge tht will e shown if this vlidtor filsF
TTR
UF eferene houments
lidtes tht vlue is vlid s ddressF fy defultD this will vlidte the vlue s svRD ut numer of di'erent options exist to vlidte s svT nd mny other omintionsF epplies to yptions property or method
version messge
ymfonygomponentlidtorgonstrintssp ymfonygomponentlidtorgonstrintssplidtor
ewv
// src/Acme/BlogBundle/Entity/Author.php namespace Acme\BlogBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Ip */ protected $ipAddress; }
yptions
version
typeX string defultX R his determines extly how the ip ddress is vlidted nd n tke one of vriety of di'erent vluesX UFIIF lidtion gonstrints eferene TTS
R E lidtes for svR ddresses T E lidtes for svT ddresses ll E lidtes ll s formts
xo privte rnges
Rnopriv E lidtes for svR ut without privte s rnges Tnopriv E lidtes for svT ut without privte s rnges llnopriv E lidtes for ll s formts ut without privte s rnges
xo reserved rnges
Rnores E lidtes for svR ut without reserved s rnges Tnores E lidtes for svT ut without reserved s rnges llnores E lidtes for ll s formts ut without reserved s rnges
ynly puli rnges
Rpuli E lidtes for svR ut without privte nd reserved rnges Tpuli E lidtes for svT ut without privte nd reserved rnges llpuli E lidtes for ll s formts ut without privte nd reserved rnges
message
typeX string defultX his is not vlid s ddress his messge is shown if the string is not vlid s ddressF
7.11.14 Max
lidtes tht given numer is less thn some mximum numerF epplies to yptions property or method
glss lidtor
ymfonygomponentlidtorgonstrintswx ymfonygomponentlidtorgonstrintswxlidtor
TTT
UF eferene houments
ymfony houmenttionD PFH fsi sge o verify tht the ge (eld of lss is not greter thn SHD you might dd the followingX
ewv
# src/Acme/EventBundle/Resources/cong/validation.yml Acme\EventBundle\Entity\Participant: properties: age: - Max: { limit: 50, message: You must be 50 or under to enter. }
ennottions
// src/Acme/EventBundle/Entity/Participant.php use Symfony\Component\Validator\Constraints as Assert; class Participant { /** * @Assert\Max(limit = 50, message = "You must be 50 or under to enter.") */ protected $age; }
yptions
limit
typeX integer defult option his required option is the mx vlueF lidtion will fil if the given vlue is greter thn this mx vlueF
message
typeX string defultX his vlue should e {{ limit }} or less he messge tht will e shown if the underlying vlue is greter thn the limit optionF
invalidMessage
typeX string defultX his vlue should e vlid numer
TTU
ymfony houmenttionD PFH he messge tht will e shown if the underlying vlue is not numer @per the isnumeri r funtionAF
7.11.15 Min
lidtes tht given numer is greter thn some minimum numerF epplies to yptions property or method
ymfonygomponentlidtorgonstrintswin ymfonygomponentlidtorgonstrintswinlidtor
o verify tht the ge (eld of lss is IV or greterD you might dd the followingX
ewv
# src/Acme/EventBundle/Resources/cong/validation.yml Acme\EventBundle\Entity\Participant: properties: age: - Min: { limit: 18, message: You must be 18 or older to enter. }
ennottions
// src/Acme/EventBundle/Entity/Participant.php use Symfony\Component\Validator\Constraints as Assert; class Participant { /** * @Assert\Min(limit = "18", message = "You must be 18 or older to enter") */ protected $age; }
TTV
UF eferene houments
limit
typeX integer defult option his required option is the min vlueF lidtion will fil if the given vlue is less thn this min vlueF
message
typeX string defultX his vlue should e {{ limit }} or more he messge tht will e shown if the underlying vlue is less thn the limit optionF
invalidMessage
typeX string defultX his vlue should e vlid numer he messge tht will e shown if the underlying vlue is not numer @per the isnumeri r funtionAF
7.11.16 Date
lidtes tht vlue is vlid dteD mening either hteime ojet or string @or n ojet tht n e st into stringA tht follows vlid EwwEhh formtF epplies to yptions glss lidtor fsi sge property or method
messge
ymfonygomponentlidtorgonstrintshte ymfonygomponentlidtorgonstrintshtelidto
ewv
TTW
ennottions
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Date() */ protected $birthday; }
yptions
message
typeX string defultX his vlue is not vlid dte his messge is shown if the underlying dt is not vlid dteF
7.11.17 DateTime
lidtes tht vlue is vlid dtetimeD mening either hteime ojet or string @or n ojet tht n e st into stringA tht follows vlid EwwEhh rrXwwX formtF epplies to yptions glss lidtor fsi sge property or method
messge
ymfonygomponentlidtorgonstrintshteime ymfonygomponentlidtorgonstrintshteimel
ewv
// src/Acme/BlogBundle/Entity/Author.php namespace Acme\BlogBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\DateTime() */ protected $createdAt; }
yptions
message
typeX string defultX his vlue is not vlid dtetime his messge is shown if the underlying dt is not vlid dtetimeF
7.11.18 Time
lidtes tht vlue is vlid time string with formt rrXwwXF lidtes tht vlue is vlid timeD mening either hteime ojet or string @or n ojet tht n e st into stringA tht follows vlid rrXwwX formtF epplies to yptions glss lidtor fsi sge uppose you hve n ivent lssD with strtet (eld tht is the time of the dy when the event strtsX property or method
messge
ymfonygomponentlidtorgonstrintsime ymfonygomponentlidtorgonstrintsimelidto
ewv
startsAt: - Time: ~
ennottions
// src/Acme/EventBundle/Entity/Event.php namespace Acme\EventBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class Event { /** * @Assert\Time() */ protected $startsAt; }
yptions
message
typeX string defultX his vlue is not vlid time his messge is shown if the underlying dt is not vlid timeF
7.11.19 Choice
his onstrint is used to ensure tht the given vlue is one of given set of vlid hoiesF st n lso e used to vlidte tht eh item in n rry of items is one of those vlid hoiesF
TUP
UF eferene houments
ymfonygomponentlidtorgonstrintsghoie ymfonygomponentlidtorgonstrintsghoielid
he si ide of this onstrint is tht you supply it with n rry of vlid vlues @this n e done in severl wysA nd it vlidtes tht the vlue of the given property exists in tht rryF sf your vlid hoie list is simpleD you n pss them in diretly vi the hoies optionX
ewv
# src/Acme/BlogBundle/Resources/cong/validation.yml Acme\BlogBundle\Entity\Author: properties: gender: - Choice: choices: [male, female] message: Choose a valid gender.
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <class name="Acme\BlogBundle\EntityAuthor"> <property name="gender"> <constraint name="Choice"> <option name="choices"> <value>male</value> <value>female</value> </option> <option name="message">Choose a valid gender.</option> </constraint>
TUQ
</property> </class>
ennottions
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Choice(choices = {"male", "female"}, message = "Choose a valid gender.") */ protected $gender; }
r
// src/Acme/BlogBundle/EntityAuthor.php use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\Choice; class Author { protected $gender; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('gender', new Choice( 'choices' => array('male', 'female'), 'message' => 'Choose a valid gender', )); }
upplying the ghoies with gllk puntion ou n lso use llk funtion to speify your optionsF his is useful if you wnt to keep your hoies in some entrl lotion so thtD for exmpleD you n esily ess those hoies for vlidtion or for uilding selet form elementF
ou n pss the nme of this method to the llk option of the ghoie onstrintF
ewv
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Choice(callback = "getGenders") */ protected $gender; }
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <class name="Acme\BlogBundle\Entity\Author"> <property name="gender"> <constraint name="Choice"> <option name="callback">getGenders</option> </constraint> </property> </class>
sf the stti llk is stored in di'erent lssD for exmple tilD you n pss the lss nme nd the method s n rryF
ewv
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <class name="Acme\BlogBundle\Entity\Author"> <property name="gender"> <constraint name="Choice"> <option name="callback"> <value>Util</value> <value>getGenders</value> </option> </constraint> </property> </class>
ennottions
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Choice(callback = {"Util", "getGenders"}) */ protected $gender; }
eville yptions
choices
typeX rry defult option e required option @unless llk is spei(edA E this is the rry of options tht should e onsidered in the vlid setF he input vlue will e mthed ginst this rryF
callback
typeX string|rry|glosure his is llk method tht n e used insted of the hoies option to return the hoies rryF ee upplying the ghoies with gllk puntion for detils on its usgeF
TUT
UF eferene houments
multiple
typeX foolen defultX flse sf this option is trueD the input vlue is expeted to e n rry insted of singleD slr vlueF he onstrint will hek tht eh vlue of the input rry n e found in the rry of vlid hoiesF sf even one of the input vlues nnot e foundD the vlidtion will filF
min
typeX integer sf the multiple option is trueD then you n use the min option to fore t lest numer of vlues to e seletedF por exmpleD if min is QD ut the input rry only ontins P vlid itemsD the vlidtion will filF
max
typeX integer sf the multiple option is trueD then you n use the mx option to fore no more thn numer of vlues to e seletedF por exmpleD if mx is QD ut the input rry ontins R vlid itemsD the vlidtion will filF
message
typeX string defultX he vlue you seleted is not vlid hoie his is the messge tht you will reeive if the multiple option is set to flseD nd the underlying vlue is not in the vlid rry of hoiesF
multipleMessage
typeX string defultX yne or more of the given vlues is invlid his is the messge tht you will reeive if the multiple option is set to trueD nd one of the vlues on the underlying rry eing heked is not in the rry of vlid hoiesF
minMessage
typeX string defultX ou must selet t lest {{ limit }} hoies
TUU
ymfony houmenttionD PFH his is the vlidtion error messge tht9s displyed when the user hooses too few hoies per the min optionF
maxMessage
typeX string defultX ou must selet t most {{ limit }} hoies his is the vlidtion error messge tht9s displyed when the user hooses too mny options per the mx optionF
strict
typeX foolen defultX flse sf trueD the vlidtor will lso hek the type of the input vlueF pei(llyD this vlue is pssed to s the third rgument to the r inrry method when heking to see if vlue is in the vlid hoies rryF
7.11.20 Collection
his onstrint is used when the underlying dt is olletion @iFeF n rry or n ojet tht implements rversle nd erryeessAD ut you9d like to vlidte di'erent keys of tht olletion in di'erent wysF por exmpleD you might vlidte the emil key using the imil onstrint nd the inventory key of the olletion with the win onstrintF his onstrint n lso mke sure tht ertin olletion keys re present nd tht extr keys re not presentF epplies to yptions property or method (elds llowixtrpields extrpieldswessge llowwissingpields missingpieldswessge
ymfonygomponentlidtorgonstrintsgolletion ymfonygomponentlidtorgonstrintsgolletionl
he golletion onstrint llows you to vlidte the di'erent keys of olletion individullyF ke the following exmpleX TUV UF eferene houments
namespace Acme\BlogBundle\Entity; class Author { protected $proleData = array( 'personal_email', 'short_bio', ); public function setProleData($key, $value) { $this->proleData[$key] = $value; }
o vlidte tht the personlemil element of the pro(leht rry property is vlid emil ddress nd tht the shortio element is not lnk ut is no longer thn IHH hrters in lengthD you would do the followingX
ewv
properties: proleData: - Collection: elds: personal_email: Email short_bio: - NotBlank - MaxLength: limit: 100 message: Your short bio is too long! allowMissingelds: true
ennottions
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Collection( * elds = { * "personal_email" = @Assert\Email, * "short_bio" = { * @Assert\NotBlank(), * @Assert\MaxLength( * limit = 100,
UFIIF lidtion gonstrints eferene TUW
* message = "Your bio is too long!" * ) * } * }, * allowMissingelds = true *) */ protected $proleData = array( 'personal_email', 'short_bio', );
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <class name="Acme\BlogBundle\Entity\Author"> <property name="proleData"> <constraint name="Collection"> <option name="elds"> <value key="personal_email"> <constraint name="Email" /> </value> <value key="short_bio"> <constraint name="NotBlank" /> <constraint name="MaxLength"> <option name="limit">100</option> <option name="message">Your bio is too long!</option> </constraint> </value> </option> <option name="allowMissingFields">true</option> </constraint> </property> </class>
r
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\Collection; use Symfony\Component\Validator\Constraints\Email; use Symfony\Component\Validator\Constraints\MaxLength; class Author { private $options = array();
TVH UF eferene houments
public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('proleData', new Collection(array( 'elds' => array( 'personal_email' => arraynew Email(), 'lastName' => array(new NotBlank(), new MaxLength(100)), ), 'allowMissingFields' => true, ))); }
elds
typeX rry defult option his option is requiredD nd is n ssoitive rry de(ning ll of the keys in the olletion ndD for eh keyD extly whih vlidtor@sA should e exeuted ginst tht element of the olletionF
allowExtraFields
typeX foolen defultX flse sf this option is set to flse nd the underlying olletion ontins one or more elements tht re not inluded in the (elds optionD vlidtion error will e returnedF sf set to trueD extr (elds re okF
TVI
extraFieldsMessage
typeX foolen defultX he (elds {{ (elds }} were not expeted he messge shown if llowixtrpields is flse nd n extr (eld is detetedF
allowMissingFields
typeX foolen defultX flse sf this option is set to flse nd one or more (elds from the (elds option re not present in the underlying olletionD vlidtion error will e returnedF sf set to trueD it9s ok if some (elds in the (elds option re not present in the underlying olletionF
missingFieldsMessage
typeX foolen defultX he (elds {{ (elds }} re missing he messge shown if llowwissingpields is flse nd one or more (elds re missing from the underlying olletionF
7.11.21 UniqueEntity
lidtes tht prtiulr (eld @or (eldsA in hotrine entity re uniqueF his is ommonly usedD for exmpleD to prevent new user to register using n emil ddress tht lredy exists in the systemF epplies to yptions lss
(elds messge em
ymfonyfridgehotrinelidtorgonstrintsniquei ymfonyfridgehotrinelidtorgonstrintsniquei
uppose you hve n emeserfundle with ser entity tht hs n emil (eldF ou n use the nique onstrint to gurntee tht the emil (eld remins unique etween ll of the onstrins in your user tleX
ennottions
TVP
UF eferene houments
// Acme/UserBundle/Entity/User.php use Symfony\Component\Validator\Constraints as Assert; use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @DoctrineAssert\UniqueEntity("email") */ class Author { /** * @var string $email * * @ORM\Column(name="email", type="string", length=255, unique=true) * @Assert\Email() */ protected $email; } // ...
ewv
elds
typeX rry|string defult option his required option is the (eld @or list of (eldsA on whih this entity should e uniqueF por exmpleD you ould speify tht oth the emil nd nme (elds in the ser exmple ove should e uniqueF
message
typeX string defultX his vlue is lredy usedF he messge tht9s displyed with this onstrint filsF
TVQ
em
typeX string he nme of the entity mnger to use for mking the query to determine the uniquenessF sf left lnkD the defult entity mnger will e usedF
7.11.22 Language
lidtes tht vlue is vlid lnguge odeF epplies to yptions glss lidtor fsi sge property or method
messge
ymfonygomponentlidtorgonstrintsvnguge ymfonygomponentlidtorgonstrintsvngugeli
ewv
// src/Acme/UserBundle/Entity/User.php namespace Acme\UserBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class User { /** * @Assert\Language */ protected $preferredLanguage; }
TVR
UF eferene houments
message
typeX string defultX his vlue is not vlid lnguge his messge is shown if the string is not vlid lnguge odeF
7.11.23 Locale
lidtes tht vlue is vlid loleF he vlue for eh lole is either the two letter syTQWEI lnguge ode @eFgF frAD or the lnguge ode followed y n undersore @AD then the syQITT ountry ode @eFgF frp for prenhGprneAF epplies to yptions glss lidtor fsi sge property or method
messge
ymfonygomponentlidtorgonstrintsvole ymfonygomponentlidtorgonstrintsvolelidt
ewv
// src/Acme/UserBundle/Entity/User.php namespace Acme\UserBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class User { /** * @Assert\Locale */ protected $locale; }
UFIIF lidtion gonstrints eferene TVS
yptions
message
typeX string defultX his vlue is not vlid lole his messge is shown if the string is not vlid loleF
7.11.24 Country
lidtes tht vlue is vlid twoEletter ountry odeF epplies to yptions glss lidtor fsi sge property or method
messge
ymfonygomponentlidtorgonstrintsgountry ymfonygomponentlidtorgonstrintsgountrylid
ewv
// src/Acme/UserBundle/Entity/User.php namespace Acme\UserBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class User { /** * @Assert\Country */ protected $country; }
TVT UF eferene houments
message
typeX string defultX his vlue is not vlid ountry his messge is shown if the string is not vlid ountry odeF
7.11.25 File
e string @or ojet with totring@A methodA pth to n existing (leY e vlid ymfonygomponentrttppoundtionpilepile ojet @inluding ojets of lss ymfonygomponentrttppoundtionpileplodedpileAF
his onstrint is ommonly used in forms with the (le form typeF X sf the (le you9re vlidting is n imgeD try the smge onstrintF epplies to yptions property or method
ymfonygomponentlidtorgonstrintspile ymfonygomponentlidtorgonstrintspilelidtor
his onstrint is most ommonly used on property tht will e rendered in form s (le form typeF por exmpleD suppose you9re reting n uthor form where you n uplod io hp for the uthorF sn your formD the iopile property would e (le typeF he euthor lss might look s followsX
TVU
// src/Acme/BlogBundle/Entity/Author.php namespace Acme\BlogBundle\Entity; use Symfony\Component\HttpFoundation\File\File; class Author { protected $bioFile; public function setBioFile(File $le = null) { $this->bioFile = $le; } public function getBioFile() { return $this->bioFile; }
o gurntee tht the iopile pile ojet is vlidD nd tht it is elow ertin (le size nd vlid hpD dd the followingX
ewv
# src/Acme/BlogBundle/Resources/cong/validation.yml Acme\BlogBundle\Entity\Author properties: bioFile: - File: maxSize: 1024k mimeTypes: [application/pdf, application/x-pdf] mimeTypesMessage: Please upload a valid PDF
ennottions
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\File( * maxSize = "1024k", * mimeTypes = {"application/pdf", "application/x-pdf"}, * mimeTypesMessage = "Please upload a valid PDF" *) */
TVV UF eferene houments
protected $bioFile;
wv
<!-- src/Acme/BlogBundle/Resources/cong/validation.xml --> <class name="Acme\BlogBundle\Entity\Author"> <property name="bioFile"> <constraint name="File"> <option name="maxSize">1024k</option> <option name="mimeTypes"> <value>application/pdf</value> <value>application/x-pdf</value> </option> <option name="mimeTypesMessage">Please upload a valid PDF</option> </constraint> </property> </class>
r
// src/Acme/BlogBundle/Entity/Author.php // ... use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\File; class Author { // ... public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('bioFile', new File(array( 'maxSize' => '1024k', 'mimeTypes' => array( 'application/pdf', 'application/x-pdf', ), 'mimeTypesMessage' => 'Please upload a valid PDF', ))); }
he iopile property is vlidted to gurntee tht it is rel (leF sts size nd mime type re lso vlidted euse the pproprite options hve een spei(edF
TVW
maxSize
typeX mixed sf setD the size of the underlying (le must e elow this (le size in order to e vlidF he size of the (le n e given in one of the following formtsX
ytesX o speify the mxize in ytesD pss vlue tht is entirely numeri @eFgF RHWTAY kiloytesX o speify the mxize in kiloytesD pss numer nd su0x it with lowerse k @eFgF PHHkAY megytesX o speify the mxize in megytesD pss numer nd su0x it with pitl w @eFgF RwAF
mimeTypes
typeX rry or string sf setD the vlidtor will hek tht the mime type of the underlying (le is equl to the given mime type @if stringA or exists in the olletion of given mime types @if n rryAF
maxSizeMessage
typeX string defultX he (le is too lrge @{{ size }}AF ellowed mximum size is {{ limit }} he messge displyed if the (le is lrger thn the mxize optionF
mimeTypesMessage
typeX string defultX he mime type of the (le is invlid @{{ type }}AF ellowed mime types re {{ types }} he messge displyed if the mime type of the (le is not vlid mime type per the mimeypes optionF
notFoundMessage
typeX string defultX he (le ould not e found he messge displyed if no (le n e found t the given pthF his error is only likely if the underlying vlue is string pthD s pile ojet nnot e onstruted with n invlid (le pthF TWH UF eferene houments
notReadableMessage
typeX string defultX he (le is not redle he messge displyed if the (le existsD ut the r isredle funtion fils when pssed the pth to the (leF
uploadIniSizeErrorMessage
typeX string defultX he (le is too lrgeF ellowed mximum size is {{ limit }} he messge tht is displyed if the uploded (le is lrger thn the uplodmx(lesize rFini settingF
uploadFormSizeErrorMessage
typeX string defultX he (le is too lrge he messge tht is displyed if the uploded (le is lrger thn llowed y the rwv (le input (eldF
uploadErrorMessage
typeX string defultX he (le ould not e uploded he messge tht is displyed if the uploded (le ould not e uploded for some unknown resonD suh s the (le uplod filed or it ouldn9t e written to diskF
7.11.26 Image
he smge onstrint works extly like the pile onstrintD exept tht its mimeypes nd mimeypeswessge options re utomtilly setup to work for imge (les spei(llyF ee the pile onstrint for the ulk of the doumenttion on this onstrintF yptions his onstrint shres ll of its options with the pile onstrintF st doesD howeverD modify two of the defult option vluesX
TWI
mimeTypes
typeX rry or string defultX n rry of jpgD gif nd png imge mime types
mimeTypesMessage
typeX string defultX his (le is not vlid imge
7.11.27 Callback
he purpose of the gllk ssertion is to let you rete ompletely ustom vlidtion rules nd to ssign ny vlidtion errors to spei( (elds on your ojetF sf you9re using vlidtion with formsD this mens tht you n mke these ustom errors disply next to spei( (eldD insted of simply t the top of your formF his proess works y speifying one or more llk methodsD eh of whih will e lled during the vlidtion proessF ih of those methods n do nythingD inluding reting nd ssigning vlidtion errorsF X e llk method itself doesn9t fil or return ny vlueF snstedD s you9ll see in the exmpleD llk method hs the ility to diretly dd vlidtor violtionsF epplies to yptions glss lidtor etup lss
methods
ymfonygomponentlidtorgonstrintsgllk ymfonygomponentlidtorgonstrintsgllklid
ewv
// ... use Symfony\Component\Validator\ExecutionContext; class Author { // ... private $rstName; public function isAuthorValid(ExecutionContext $context) { // somehow you have an array of "fake names" $fakeNames = array(); // check if the name is actually a fake name if (in_array($this->getFirstName(), $fakeNames)) { $property_path = $context->getPropertyPath() . '.rstName'; $context->setPropertyPath($property_path); $context->addViolation('This name sounds totally fake!', array(), null); }
yptions
methods
typeX rry defultX rry@A defult option his is n rry of the methods tht should e exeuted during the vlidtion proessF ih method n e one of the following formtsX IF tring method nme
TWQ
ymfony houmenttionD PFH sf the nme of method is simple string @eFgF iseuthorlidAD tht method will e lled on the sme ojet tht9s eing vlidted nd the ixeutiongontext will e the only rgument @see the ove exmpleAF PF tti rry llk ih method n lso e spei(ed s stndrd rry llkX
ewv
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; /** * @Assert\Callback(methods={ * { "Acme\BlogBundle\MyStaticValidatorClass", "isAuthorValid"} * }) */ class Author { }
r
// src/Acme/BlogBundle/Entity/Author.php use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\Callback; class Author { public $name; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addConstraint(new Callback(array( 'methods' => array('isAuthorValid'), )));
TWR UF eferene houments
sn this seD the stti method iseuthorlid will e lled on the emeflogfundlewyttilidtorglss lssF st9s pssed oth the originl ojet eing vlidted @eFgF euthorA s well s the ixeutiongontextX
namespace Acme\BlogBundle; use Symfony\Component\Validator\ExecutionContext; use Acme\BlogBundle\Entity\Author; class MyStaticValidatorClass { static public function isAuthorValid(Author $author, ExecutionContext $context) { // ... } }
X sf you speify your gllk onstrint vi rD then you lso hve the option to mke your llk either r losure or nonE stti llkF st is not urrently possileD howeverD to speify servie s onstrintF o vlidte using servieD you should rete ustom vlidtion onstrint nd dd tht new onstrint to your lssF
7.11.28 All
hen pplied to n rry @or rversle ojetAD this onstrint llows you to pply olletion of onstrints to eh element of the rryF epplies to yptions glss lidtor fsi sge uppose tht you hve n rry of stringsD nd you wnt to vlidte eh entry in tht rryX property or method
onstrints
ymfonygomponentlidtorgonstrintsell ymfonygomponentlidtorgonstrintselllidtor
ewv
TWS
// src/Acme/UserBundle/Entity/User.php namespace Acme\UserBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class User { /** * @Assert\All({ * @Assert\NotBlank * @Assert\MinLength(5), * }) */ protected $favoriteColors = array(); }
xowD eh entry in the fvoritegolors rry will e vlidted to not e lnk nd to e t lest S hrters longF yptions
constraints
typeX rry defult option his required option is the rry of vlidtion onstrints tht you wnt to pply to eh element of the underlying rryF
7.11.29 UserPassword
PFIF his vlidtes tht n input vlue is equl to the urrent uthentited user9s psswordF his is useful in form where user n hnge his psswordD ut needs to enter his old pssword for seurityF
TWT
UF eferene houments
ymfony houmenttionD PFH X his should not e used vlidte login formD sine this is done utomtilly y the seurity systemF hen pplied to n rry @or rversle ojetAD this onstrint llows you to pply olletion of onstrints to eh element of the rryF epplies to yptions glss lidtor fsi sge uppose you hve sswordghnge lssD tht9s used in form where the user n hnge his pssword y entering his old pssword nd new psswordF his onstrint will vlidte tht the old pssword mthes the user9s urrent psswordX property or method
messge
ymfonygomponentlidtorgonstrintsserssword ymfonyfundleeurityfundlelidtorgonstrints
ewv
# src/UserBundle/Resources/cong/validation.yml Acme\UserBundle\Form\Model\ChangePassword: properties: oldPassword: - UserPassword: message: "Wrong value for your current password"
ennottions
// src/Acme/UserBundle/Form/Model/ChangePassword.php namespace Acme\UserBundle\Form\Model; use Symfony\Component\Validator\Constraints as Assert; class ChangePassword { /** * @Assert\UserPassword( * message = "Wrong value for your current password" *) */ protected $oldPassword; }
TWU
message
typeX messge defultX his vlue should e the user urrent pssword his is the messge tht9s displyed when the underlying string does not mth the urrent user9s psswordF
7.11.30 Valid
his onstrint is used to enle vlidtion on ojets tht re emedded s properties on n ojet eing vlidtedF his llows you to vlidte n ojet nd ll suEojets ssoited with itF epplies to yptions glss fsi sge sn the following exmpleD we rete two lsses euthor nd eddress tht oth hve onstrints on their propertiesF purthermoreD euthor stores n eddress instne in the 6ddress propertyF property or method
trverse
ymfonygomponentlidtorgonstrintsype
// src/Acme/HelloBundle/Address.php class Address { protected $street; protected $zipCode; } // src/Acme/HelloBundle/Author.php class Author { protected $rstName; protected $lastName; protected $address; }
ewv
TWV
UF eferene houments
# src/Acme/HelloBundle/Resources/cong/validation.yml Acme\HelloBundle\Address: properties: street: - NotBlank: ~ zipCode: - NotBlank: ~ - MaxLength: 5 Acme\HelloBundle\Author: properties: rstName: - NotBlank: ~ - MinLength: 4 lastName: - NotBlank: ~
wv
<!-- src/Acme/HelloBundle/Resources/cong/validation.xml --> <class name="Acme\HelloBundle\Address"> <property name="street"> <constraint name="NotBlank" /> </property> <property name="zipCode"> <constraint name="NotBlank" /> <constraint name="MaxLength">5</constraint> </property> </class> <class name="Acme\HelloBundle\Author"> <property name="rstName"> <constraint name="NotBlank" /> <constraint name="MinLength">4</constraint> </property> <property name="lastName"> <constraint name="NotBlank" /> </property> </class>
ennottions
// src/Acme/HelloBundle/Author.php class Author { /** * @Assert\NotBlank * @Assert\MinLength(4) */ protected $rstName; /** * @Assert\NotBlank */ protected $lastName; } protected $address;
// src/Acme/HelloBundle/Address.php use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\MaxLength; class Address { protected $street; protected $zipCode; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('street', new NotBlank()); $metadata->addPropertyConstraint('zipCode', new NotBlank()); $metadata->addPropertyConstraint('zipCode', new MaxLength(5)); }
UHH UF eferene houments
} // src/Acme/HelloBundle/Author.php use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\MinLength; class Author { protected $rstName; protected $lastName; protected $address; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('rstName', new NotBlank()); $metadata->addPropertyConstraint('rstName', new MinLength(4)); $metadata->addPropertyConstraint('lastName', new NotBlank()); }
ith this mppingD it is possile to suessfully vlidte n uthor with n invlid ddressF o prevent thtD dd the lid onstrint to the 6ddress propertyF
ewv
<!-- src/Acme/HelloBundle/Resources/cong/validation.xml --> <class name="Acme\HelloBundle\Author"> <property name="address"> <constraint name="Valid" /> </property> </class>
ennottions
UHI
// src/Acme/HelloBundle/Author.php use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints\Valid; class Author { protected $address; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('address', new Valid()); }
sf you vlidte n uthor with n invlid ddress nowD you n see tht the vlidtion of the eddress (elds filedF emerellofundleeuthorFddressFzipgodeX his vlue is too longF st should hve S hrters or less yptions
traverse
typeX string defultX true sf this onstrint is pplied to property tht holds n rry of ojetsD then eh ojet in tht rry will e vlidted only if this option is set to trueF he lidtor is designed to vlidte ojets ginst onstrintsF sn rel lifeD onstrint ould eX he ke must not e urnedF sn ymfonyPD onstrints re similrX hey re ssertions tht ondition is trueF
UHP
UF eferene houments
he following onstrints re ntively ville in ymfonyPX fsi gonstrints hese re the si onstrintsX use them to ssert very si things out the vlue of properties or the return vlue of methods on your ojetF
wx win
hte gonstrints
hte hteime
UHQ
ime
golletion gonstrints
pile smge
yther gonstrints
gsX
o enle ustom templte helperD dd it s regulr servie in one of your on(gurtionD tg it with templtingFhelper nd de(ne n lis ttriute @the helper will e essile vi this lis in the templtesAX
ewv
o enle wig extensionD dd it s regulr servie in one of your on(gurtionD nd tg it with twigFextensionX
ewv
services: twig.extension.your_extension_name:
UFIPF he hependeny snjetion gs UHS
o enle ustom listenerD dd it s regulr servie in one of your on(gurtionD nd tg it with kernelFeventlistenerF ou must provide the nme of the event your servie listens toD s well s the method tht will e lledX
ewv
services: kernel.listener.your_listener_name: class: Fully\Qualied\Listener\Class\Name tags: - { name: kernel.event_listener, event: xxx, method: onXxx }
wv
$container ->register('kernel.listener.your_listener_name', 'Fully\Qualied\Listener\Class\Name') ->addTag('kernel.event_listener', array('event' => 'xxx', 'method' => 'onXxx')) ;
X ou n lso speify priority s n ttriute of the kernelFeventlistener tg @muh like the method or event ttriutesAD with either positive or negtive integerF his UHT UF eferene houments
ymfony houmenttionD PFH llows you to mke sure your listener will lwys e lled efore or fter nother listener listening for the sme eventF
o enle ustom templte engineD dd it s regulr servie in one of your on(gurtionD tg it with templtingFengineX
ewv
o enle ustom routing loderD dd it s regulr servie in one of your on(gurtionD nd tg it with routingFloderX
ewv
UHU
wonolog llows you to shre its hndlers etween severl logging hnnelsF he logger servie uses the hnnel pp ut you n hnge the hnnel when injeting the logger in servieF
ewv
services: my_service: class: Fully\Qualied\Loader\Class\Name arguments: [@logger] tags: - { name: monolog.logger, channel: acme }
wv
<service id="my_service" class="Fully\Qualied\Loader\Class\Name"> <argument type="service" id="logger" /> <tag name="monolog.logger" channel="acme" /> </service>
r
$denition = new Denition('Fully\Qualied\Loader\Class\Name', array(new Reference('logger')); $denition->addTag('monolog.logger', array('channel' => 'acme')); $container->register('my_service', $denition);;
X his works only when the logger servie is onstrutor rgumentD not when it is injeted through setterF
UHV
UF eferene houments
wonolog llows you to dd proessors in the logger or in the hndlers to dd extr dt in the reordsF e proessor reeives the reord s n rgument nd must return it fter dding some extr dt in the extr ttriute of the reordF vet9s see how you n use the uiltEin sntrospetionroessor to dd the (leD the lineD the lss nd the method where the logger ws triggeredF ou n dd proessor glollyX
ewv
ewv
ewv
7.13 YAML
ewv wesite is humn friendly dt seriliztion stndrd for ll progrmming lngugesF ewv is simple lnguge tht desries dtF es rD it hs syntx for simple types like stringsD oolensD )otsD or integersF fut unlike rD it mkes di'erene etween rrys @sequenesA nd hshes @mppingsAF he ymfonyP XnmespeXymfonygomponentml gomponent knows how to prse ewv nd dump r rry to ewvF
UIH
UF eferene houments
ymfony houmenttionD PFH X iven if the ewv formt n desrie omplex nested dt strutureD this hpter only desries the minimum set of fetures needed to use ewv s on(gurtion (le formtF
try { $value = $yaml->parse(le_get_contents('/path/to/le.yaml')); } catch (\InvalidArgumentException $e) { // an error occurred during parsing echo "Unable to parse the YAML string: ".$e->getMessage(); }
X es the prser is reentrntD you n use the sme prser ojet to lod di'erent ewv stringsF hen loding ewv (leD it is sometimes etter XmethodXymfonygomponentmlmlXXprse wrpper methodX to use the
st exeutes the ewv (le s if it ws r (leD so tht you n emed r ommnds in ewv (lesY hen (le nnot e prsedD it utomtilly dds the (le nme to the error messgeD simplifying deugging when your pplition is loding severl ewv (lesF
UFIQF ewv
UII
use Symfony\Component\Yaml\Dumper; $array = array('foo' => 'bar', 'bar' => array('foo' => 'bar', 'bar' => 'baz')); $dumper = new Dumper(); $yaml = $dumper->dump($array); le_put_contents('/path/to/le.yaml', $yaml);
X here re some limittionsX the dumper is not le to dump resoures nd dumping r ojets is onsidered n lph fetureF sf you only need to dump one rryD you n use XmethodXymfonygomponentmlmlXXdump stti method shortutX the
echo $dumper->dump($array, 1); foo: bar bar: { foo: bar, bar: baz } echo $dumper->dump($array, 2); foo: bar bar: foo: bar bar: baz
UIP
UF eferene houments
trings
'A single quote '' in a single-quoted string' "A double-quoted string in YAML\n"
uoted styles re useful when string strts or ends with one or more relevnt spesF X he douleEquoted style provides wy to express ritrry stringsD y using espe sequenesF st is very useful when you need to emed n or uniode hrter in stringF hen string ontins line reksD you n use the literl styleD indited y the pipe @|AD to indite tht the string will spn severl linesF sn literlsD newlines re preservedX
\/ /| |\/| | / / | | | |__
elterntivelyD strings n e written with the folded styleD denoted y bD where eh line rek is repled y speX
> This is a very long sentence that spans several lines in the YAML but which will be rendered as a string without carriage returns.
X xotie the two spes efore eh line in the previous exmplesF hey won9t pper in the resulting r stringsF
UFIQF ewv
UIQ
# an integer 12 # an octal 014 # an hexadecimal 0xC # a oat 13.4 # an exponential number 1.2e+34 # innity .inf
xulls xulls in ewv n e expressed with null or ~F foolens foolens in ewv re expressed with true nd flseF htes ewv uses the syEVTHI stndrd to express dtesX
"symfony 1.4": PHP: 5.2 Doctrine: 1.2 "Symfony2": PHP: 5.3 Doctrine: 2.0
he following ewv is equivlent to the following r odeX
array( 'symfony 1.4' => array( 'PHP' => 5.2, 'Doctrine' => 1.2, ), 'Symfony2' => array( 'PHP' => 5.3, 'Doctrine' => 2.0, ), );
UFIQF ewv UIS
ymfony houmenttionD PFH here is one importnt thing you need to rememer when using indenttion in ewv (leX sndenttion must e done with one or more spesD ut never with tultionsF ou n nest sequenes nd mppings s you likeX
'Chapter 1': [Introduction, Event Types] 'Chapter 2': [Introduction, Helpers] "symfony 1.4": { PHP: 5.2, Doctrine: 1.2 } "Symfony2": { PHP: 5.3, Doctrine: 2.0 }
gomments gomments n e dded in ewv y pre(xing them with hsh mrk @5AX
# Comment on a line "Symfony2": { PHP: 5.3, Doctrine: 2.0 } # Comment at the end of a line
X gomments re simply ignored y the ewv prser nd do not need to e indented ording to the urrent level of nesting in olletionF
hynmi ewv (les sn ymfonyPD ewv (le n ontin r ode tht is evluted just efore the prsing oursX UIT UF eferene houments
1.0: version: <?php echo le_get_contents('1.0/VERSION')."\n" ?> 1.1: version: "<?php echo le_get_contents('1.1/VERSION') ?>"
fe reful to not mess up with the indenttionF ueep in mind the following simple tips when dding r ode to ewv (leX
he `cphp cb sttements must lwys strt the line or e emedded in vlueF sf `cphp cb sttement ends lineD you need to expliitly output new line @nAF
o run ymfonyPD your system needs to dhere to list of requirementsF ou n esily see if your system psses ll requirements y running the weGon(gFphp in your symfony distriutionF ine the gvs often uses di'erent phpFini on(gurtion (leD it9s lso good ide to hek your requirements from the ommnd line viX
php app/check.php
felow is the list of required nd optionl requirementsF
7.14.1 Required
r needs to e minimum version of r SFQFP tyx needs to e enled type needs to e enled our rFini needs to hve the dteFtimezone setting
7.14.2 Optional
ou need to hve the rEwv module instlled ou need to hve t lest version PFTFPI of lixml r tokenizer needs to e enled mstring funtions need to e enled ionv needs to e enled ys needs to e enled @only on BnixA
UFIRF equirements for running ymfonyP UIU
sntl needs to e instlled with sg RC eg QFHFIUC @or nother opode he needs to e instlledA rFini reommended settings
! shortopentgsX o' ! mgiquotesgpX o' ! registerglolsX o' ! sessionFutostrtX o'
7.14.3 Doctrine
sf you wnt to use hotrineD you will need to hve hy instlledF edditionllyD you need to hve the hy driver instlled for the dtse server you wnt to useF
gon(gurtion yptionsX
iver wondered wht on(gurtion options you hve ville to you in (les suh s ppGon(gGon(gFymlc sn this setionD ll the ville on(gurtion is roken down y the key @eFgF frmeworkA tht de(nes eh possile setion of your ymfonyP on(gurtionF ! frmework ! dotrine ! seurity ! sseti ! swiftmiler ! twig ! monolog ! wepro(ler
porms nd lidtion
! porm pield ype eferene ! lidtion gonstrints eferene ! wig emplte puntion eferene
yther eres
! he hependeny snjetion gs ! ewv UIV UF eferene houments
gon(gurtion yptionsX
iver wondered wht on(gurtion options you hve ville to you in (les suh s ppGon(gGon(gFymlc sn this setionD ll the ville on(gurtion is roken down y the key @eFgF frmeworkA tht de(nes eh possile setion of your ymfonyP on(gurtionF ! frmework ! dotrine ! seurity ! sseti ! swiftmiler ! twig ! monolog ! wepro(ler
porms nd lidtion
! porm pield ype eferene ! lidtion gonstrints eferene ! wig emplte puntion eferene
yther eres
! he hependeny snjetion gs ! ewv ! equirements for running ymfonyP
UIW
UPH
UF eferene houments
V Bundles
UPI
ymfony houmenttionD PFH he ymfony tndrd idition omes with some undlesF vern more out themX
UPQ
UPR
Symfony SE Bundles
ensioprmeworkixtrfundle ensioqenertorfundle tweurityixtrfundle hotrinepixturesfundle hotrinewigrtionsfundle hotrinewongohffundle ensioprmeworkixtrfundle ensioqenertorfundle tweurityixtrfundle hotrinepixturesfundle hotrinewigrtionsfundle hotrinewongohffundle
UPS
UPT
VF ymfony i fundles
VI
UPU
UPW
UQH
Contributing
henever you (nd ug in ymfonyPD we kindly sk you to report itF st helps us mke etter ymfonyPF X sf you think you9ve found seurity issueD plese use the speil proedure instedF fefore sumitting ugX
houleEhek the o0il doumenttion to see if you9re not misusing the frmeworkY esk for ssistne on the users milingElistD the forumD or on the 5symfony sg hnnel if you9re not sure if your issue is relly ugF
sf your prolem de(nitely looks like ugD report it using the o0il ug trker nd follow some si rulesX
se the title (eld to lerly desrie the issueY hesrie the steps needed to reprodue the ug with short ode exmples @providing unit test tht illustrtes the ug is estAY qive s muh detils s possile out your environment @yD r versionD ymfony versionD enled extensionsD FFFAY @optionlA etth pthF
UQI
thes re the est wy to provide ug (x or to propose enhnements to ymfonyPF ghek vist he purpose of the hek list is to ensure tht ontriutions my e reviewed with needless feedk loops to ensure tht your ontriutions n e inluded into ymfonyP s quikly s possileF ell pull requests should inlude the following templte in the request desriptionX
Bug x: [yes|no] Feature addition: [yes|no] Backwards compatibility break: [yes|no] Symfony2 tests pass: [yes|no] Fixes the following tickets: [comma separated list of tickets xed by the PR]
en exmple sumission ould now look s followsX
Bug x: no Feature addition: yes Backwards compatibility break: no Symfony2 tests pass: yes Fixes the following tickets: hnk you for inluding the (lled out templte in your sumission3 X ell feture ddition9s should e send to the mster rnhD while ll ug (xes should e send to the oldest still tive rnhF purthermore sumissions should s rule of thum not rek kwrds omptiilityF lese mrk ny sumissions s s in the title in se the sumission is not yet omplete @for exmple if the tests do not yet pssAF
snitil etup fefore working on ymfonyPD setup friendly environment with the following softwreX
UQP
WF gontriuting
$ git cong --global user.name "Your Name" $ git cong --global user.email you@example.com
X sf you re new to qitD we highly reommend you to red the exellent nd free roqit ookF qet the ymfonyP soure odeX
grete qitru ount nd sign inY pork the ymfonyP repository @lik on the pork uttonAY efter the hrdore forking tion hs ompletedD lone your fork lolly @this will rete symfony diretoryAX
pollow the oding stndrds @use git di' !hek to hek for triling spesAY edd unit tests to prove tht the ug is (xed or tht the new feture tully worksY ho tomi nd logilly seprte ommits @use the power of git rese to hve len nd logil historyAY rite good ommit messgesF
X e good ommit messge is omposed of summry @the (rst lineAD optionlly followed y lnk line nd more detiled desriptionF he summry should strt with the gomponent you re working on in squre rkets @hependenysnjetionD prmeworkfundleD FFFAF se ver @(xed FFFD dded FFFD FFFA to strt the summry nd don9t dd period t the endF
umitting th fefore sumitting your pthD updte your rnh @needed if it tkes you while to (nish your hngesAX
$ git checkout master $ git fetch upstream $ git merge upstream/master $ git checkout BRANCH_NAME $ git rebase master
hen doing the rese ommndD you might hve to (x merge on)itsF git sttus will show you the unmerged (lesF esolve ll the on)itsD then ontinue the reseX
UQR
WF gontriuting
ymfony houmenttionD PFH fsed on the feedk from the milingElist or vi the pull request on qitruD you might need to rework your pthF fefore reEsumitting the pthD rese with msterD don9t mergeY nd fore the push to the originX
pound seurity issue in ymfonyPc hon9t use the milingElist or the ug trkerF ell seurity issues must e sent to seurity t symfonyEprojetFom instedF imils sent to this ddress re forwrded to the ymfony oreEtem privte milingElistF por eh reportD we (rst try to on(rm the vulnerilityF hen it is on(rmedD the oreEtem works on solution following these stepsX IF end n knowledgement to the reporterY PF ork on pthY QF rite post desriing the vulnerilityD the possile exploitsD nd how to pthGupgrde 'eted pplitionsY RF epply the pth to ll mintined versions of ymfonyY SF ulish the post on the o0il ymfony logF X hile we re working on pthD plese do not revel the issue pulilyF
fefore sumitting pth for inlusionD you need to run the ymfonyP test suite to hek tht you hve not roken nythingF rnit o run the ymfonyP test suiteD instll rnit QFSFH or lter (rstX WFIF gontriuting gode UQS
$ pear channel-discover pear.phpunit.de $ pear channel-discover components.ez.no $ pear channel-discover pear.symfony-project.com $ pear install phpunit/PHPUnit
hependenies @optionlA o run the entire test suiteD inluding tests tht depend on externl dependeniesD ymfonyP needs to e le to utolod themF fy defultD they re utoloded from vendorG under the min root diretory @see utolodFphpFdistAF he test suite needs the following thirdEprty lirriesX
$ phpunit
he output should disply yuF sf notD you need to (gure out wht9s going on nd if the tests re roken euse of your modi(tionsF X un the test suite efore pplying your modi(tions to hek tht they run (ne on your on(gurtionF
UQT
WF gontriuting
ymfony houmenttionD PFH gode goverge sf you dd new fetureD you lso need to hek the ode overge y using the overgeEhtml optionX
$ phpunit --coverage-html=cov/
ghek the ode overge y opening the generted ovGindexFhtml pge in rowserF X he ode overge only works if you hve heug enled nd ll dependenies instlledF
hen ontriuting ode to ymfonyPD you must follow its oding stndrdsF o mke long story shortD here is the golden ruleX smitte the existing ymfonyP odeF wost openEsoure fundles nd lirries used y ymfonyP lso follow the sme guidelinesD nd you should tooF ememer tht the min dvntge of stndrds is tht every piee of ode looks nd feels fmilirD it9s not out this or tht eing more redleF ine piture E or some ode E is worth thousnd wordsD here9s short exmple ontining most fetures desried elowX
<?php /* * This le is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * le that was distributed with this source code. */ namespace Acme; class Foo { const SOME_CONST = 42; private $foo; /** * @param string $dummy Some argument description */
WFIF gontriuting gode UQU
public function __construct($dummy) { $this->foo = $this->transform($dummy); } /** * @param string $dummy Some argument description * @return string|null Transformed input */ private function transform($dummy) { if (true === $dummy) { return; } elseif ('string' === $dummy) { $dummy = substr($dummy, 0, 5); } } return $dummy;
truture
xever use short tgs @`cAY hon9t end lss (les with the usul cb losing tgY sndenttion is done y steps of four spes @ts re never llowedAY se the linefeed hrter @HxHeA to end linesY edd single spe fter eh omm delimiterY hon9t put spes fter n opening prenthesis nd efore losing oneY edd single spe round opertors @aaD 88D FFFAY edd single spe efore the opening prenthesis of ontrol keyword @ifD elseD forD whileD FFFAY edd lnk line efore return sttementsY hon9t dd triling spes t the end of linesY se res to indite ontrol struture ody regrdless of the numer of sttements it ontinsY ut res on their own line for lssesD methodsD nd funtions delrtionY
UQV
WF gontriuting
eprte the onditionl sttements @ifD elseD FFFA nd the opening re with single spe nd no lnk lineY helre visiility expliitly for lssD methodsD nd properties @usge of vr is prohiitedAY se lowerse r ntive typed onstntsX flseD trueD nd nullF he sme goes for rry@AY se upperse strings for onstnts with words seprted with undersoresY he(ne one lss per (leY helre lss properties efore methodsY helre puli methods (rstD then proteted ones nd (nlly privte onesF
xming gonventions
se melgseD not undersoresD for vrileD funtion nd method nmesY se undersores for optionD rgumentD prmeter nmesY se nmespes for ll lssesY se ymfony s the (rst nmespe levelY u0x interfes with snterfeY se lphnumeri hrters nd undersores for (le nmesY hon9t forget to look t the more verose gonventions doument for more sujetive nming onsidertionsF
houmenttion
edd rho loks for ll lssesD methodsD nd funtionsY he dpkge nd dsupkge nnottions re not usedF
viense
ymfony is relesed under the ws lienseD nd the liense lok hs to e present t the top of every r (leD efore the nmespeF
UQW
he goding tndrds doument desries the oding stndrds for the ymfonyP projets nd the internl nd thirdEprty undlesF his doument desries oding stndrds nd onventions used in the ore frmework to mke it more onsistent nd preditleF ou re enourged to follow them in your own odeD ut you don9t need toF wethod xmes hen n ojet hs min mny reltion with relted things @ojetsD prmetersD FFFAD the method nmes re normlizedX
get@A set@A hs@A ll@A reple@A remove@A ler@A isimpty@A dd@A register@A ount@A keys@A
he usge of these methods re only llowed when it is ler tht there is min reltionX
gookietr hs mny gookie ojetsY ervie gontiner hs mny servies nd mny prmeters @s servies is the min reltionD we use the nming onvention for this reltionAY gonsole snput hs mny rguments nd mny optionsF here is no min reltionD nd so the nming onvention does not pplyF
por mny reltions where the onvention does not pplyD the following methods must e used insted @where is the nme of the relted thingAX
URH
WF gontriuting
ymfony houmenttionD PFH win eltion get@A set@A nG hs@A ll@A reple@A remove@A ler@A isimpty@A dd@A register@A ount@A keys@A yther eltions get@A set@A reple@A hs@A gets@A sets@A remove@A ler@A isimpty@A dd@A register@A ount@A nG
X hile set nd reple re very similrD there is one notle di'ereneX set my repleD or dd new elements to the reltionF reple on the other hnd is spei(lly foridden to dd new elementsD ut most throw n exeption in these sesF
ymfonyP is relesed under the ws lienseF eording to ikipediX st is permissive lienseD mening tht it permits reuse within proprietry softwre on the ondition tht the liense is distriuted with tht softwreF he liense is lso qvEomptileD mening tht the qv permits omintion nd redistriution with softwre tht uses the ws vienseF he viense gopyright @A PHHREPHII pien otenier ermission is herey grntedD free of hrgeD to ny person otining opy of this softwre nd ssoited doumenttion (les @the oftwreAD to del in the oftwre without restritionD inluding without limittion the rights to useD opyD modifyD mergeD pulishD distriuteD sulienseD ndGor sell opies of the oftwreD nd to permit persons to whom the oftwre is furnished to do soD sujet to the following onditionsX he ove opyright notie nd this permission notie shll e inluded in ll opies or sustntil portions of the oftwreF
URI
ymfony houmenttionD PFH ri ypei s yshih e sD sry eex yp ex usxhD ii y swvsihD sxgvhsxq f xy vswsih y ri eexsi yp wigrexefsvsD psxi py e esgve yi exh xyxsxpsxqiwixF sx xy iix revv ri ery y gysqr ryvhi fi vsefvi py ex gveswD heweqi y yri vsefsvsD riri sx ex egsyx yp gyxegD y y yrisiD essxq pywD y yp y sx gyxxigsyx sr ri ypei y ri i y yri hievsxq sx ri ypeiF
houmenttion is s importnt s odeF st follows the ext sme priniplesX hD testsD ese of mintenneD extensiilityD optimiztionD nd reftoring just to nme fewF end of ourseD doumenttion hs ugsD typosD hrd to red tutorilsD nd moreF gontriuting fefore ontriutingD you need to eome fmilir with the mrkup lnguge used y the doumenttionF he ymfonyP doumenttion is hosted on qitruX
https://github.com/symfony/symfony-docs
sf you wnt to sumit pthD fork the o0il repository on qitru nd then lone your forkX
X he ymfonyP doumenttion is liensed under gretive gommons ettriutionEhre elike QFH nported vienseF
eporting n sssue he most esy ontriution you n mke is reporting issuesX typoD grmmr mistkeD ug in ode exmpleD missing explntionD nd so onF tepsX
he ymfonyP doumenttion uses retruturedext s its mrkup lnguge nd phinx for uilding the output @rwvD hpD FFFAF retruturedext retruturedext is n esyEtoEredD whtEyouEseeEisEwhtEyouEget plintext mrkup syntx nd prser systemF ou n lern more out its syntx y reding existing ymfonyP douments or y reding the retruturedext rimer on the phinx wesiteF sf you re fmilir with wrkdownD e reful s things s sometimes very similr ut di'erentX
vists strts t the eginning of line @no indenttion is llowedAY snline ode loks use douleEtiks @like thisAF
phinx phinx is uild system tht dds some nie tools to rete doumenttion from retruturedext doumentsF es suhD it dds new diretives nd interpreted text roles to stndrd re mrkupF WFPF gontriuting houmenttion URQ
Syntax Highlighting
ell ode exmples uses r s the defult highlighted lngugeF ou n hnge it with the odeElok diretiveX
Conguration Blocks
henever you show on(gurtionD you must use the on(gurtionElok diretive to show the on(gurtion in ll supported on(gurtion formts @rD ewvD nd wvA
.. conguration-block:: .. code-block:: yaml # Conguration in YAML .. code-block:: xml <!-- Conguration in XML //--> .. code-block:: php // Conguration in PHP
he previous re snippet renders s followX
ewv
# Conguration in YAML
wv
URR
WF gontriuting
// Conguration in PHP
he urrent list of supported formts re the followingX wrkup formt html xml php yml jinj htmlCjinj jinjChtml phpChtml htmlCphp ini phpEnnottions hisplyed rwv wv r ewv wig wig wig r r sxs ennottions
Testing Documentation
o test doumenttion efore ommitX
snstll phinxY un the phinx quik setupY snstll the on(gurtionElok phinx extension @see elowAY un mke html nd view the generted rwv in the uild diretoryF
URS
9.2.3 Translations
he ymfonyP doumenttion is written in inglish nd mny people re involved in the trnsltion proessF gontriuting pirstD eome fmilir with the mrkup lnguge used y the doumenttionF henD susrie to the ymfony dos milingElistD s ollortion hppens thereF pinllyD (nd the mster repository for the lnguge you wnt to ontriute forF rere is the list of the o0il mster repositoriesX
inglishX httpXGGgithuFomGsymfonyGsymfonyEdos prenhX httpsXGGgithuFomGgsorpioGsymfonyEdosEfr stlinX httpsXGGgithuFomGgrkGsymfonyEdosEit tpneseX httpsXGGgithuFomGsymfonyEjpnGsymfonyEdosEj olishX httpXGGgithuFomGmplusoGsymfonyEdosEpl omninX httpXGGgithuFomGseioGsymfonyEdosEro ussinX httpXGGgithuFomGvlnheIPQGsymfonyEdosEru pnishX httpsXGGgithuFomGgitnhoGsymfonyEdosEes
X sf you wnt to ontriute trnsltions for new lngugeD red the dedited setionF
toining the rnsltion em sf you wnt to help trnslting some douments for your lnguge or (x some ugsD onsider joining usY it9s very esy proessX
sntrodue yourself on the ymfony dos milingElistY @optionlA esk whih douments you n work onY pork the mster repository for your lnguge @lik the pork utton on the qitru pgeAY
URT WF gontriuting
rnslte some doumentsY esk for pull request @lik on the ull equest from your pge on qitruAY he tem mnger epts your modi(tions nd merges them into the mster repositoryY he doumenttion wesite is updted every other night from the mster repositoryF
edding new vnguge his setion gives some guidelines for strting the trnsltion of the ymfonyP doumenttion for new lngugeF es strting trnsltion is lot of workD tlk out your pln on the ymfony dos milingE list nd try to (nd motivted people willing to helpF hen the tem is redyD nominte tem mngerY he will e responsile for the mster repositoryF grete the repository nd opy the inglish doumentsF he tem n now strt the trnsltion proessF hen the tem is on(dent tht the repository is in onsistent nd stle stte @everything is trnsltedD or nonEtrnslted douments hve een removed from the totrees ! (les nmed indexFrst nd mpFrstFinAD the tem mnger n sk tht the repository is dded to the list of o0il mster repositories y sending n emil to pien @fien t symfonyFomAF wintenne rnsltion does not end when everything is trnsltedF he doumenttion is moving trget @new douments re ddedD ugs re (xedD prgrphs re reorgnizedD FFFAF he trnsltion tem need to losely follow the inglish repository nd pply hnges to the trnslted douments s soon s possileF X xon mintined lnguges re removed from the o0il list of repositories s osolete doumenttion is dngerousF
he ymfonyP doumenttion is liensed under gretive gommons ettriutionEhre elike QFH nported vienseF ou re freeX
ettriution " ou must ttriute the work in the mnner spei(ed y the uthor or liensor @ut not in ny wy tht suggests tht they endorse you or your use of the workAY hre elike " sf you lterD trnsformD or uild upon this workD you my distriute the resulting work only under the sme or similr liense to this oneF
ith the understnding thtX
iver " eny of the ove onditions n e wived if you get permission from the opyright holderY uli homin " here the work or ny of its elements is in the puli domin under pplile lwD tht sttus is in no wy 'eted y the lienseY yther ights " sn no wy re ny of the following rights 'eted y the lienseX
! our fir deling or fir use rightsD or other pplile opyright exeptions nd limittionsY ! he uthor9s morl rightsY ! ights other persons my hve either in the work itself or in how the work is usedD suh s puliity or privy rightsF
xotie " por ny reuse or distriutionD you must mke ler to others the liense terms of this workF he est wy to do this is with link to this we pgeF
his is humnEredle summry of the vegl gode @the full lienseAF
9.3 Community
9.3.1 IRC Meetings
he purpose of this meeting is to disuss topis in rel time with mny of the ymfonyP devsF enyone my propose topis on the symfonyEdev milingElist until PR hours efore the meetingD idelly inluding well prepred relevnt informtion vi some vF PR hours efore the meeting link to doodle will e posted inluding list of ll proposed topisF enyone n vote on the topis until the eginning of the meeting to de(ne the order in the gendF ih topi will e timeoxed to ISmins nd the meeting lsts one hourD leving enough time for t lest R topisF
URV
WF gontriuting
ymfony houmenttionD PFH X xote tht its not the expeted gol of them meeting to (nd (nl solutionsD ut more to ensure tht there is ommon understnding of the issue t hnd nd move the disussion forwrd in wys whih re hrd to hieve with less rel time ommunition toolsF weetings will hppen eh hursdy t IUXHH gi @CHIXHHA on the 5symfonyEdev hnnel on the preenode sg serverF he sg logs will lter e pulished on the tr wikiD whih will inlude short summry for eh of the topisF ikets will e reted for ny tsks or issues identi(ed during the meeting nd referened in the summryF ome simple guidelines nd pointers for prtiiptionX
st9s possile to hnge votes until the eginning of the meeting y liking on idit n entryY he doodle will e losed for voting t the eginning of the meetingY egend is de(ned y whih topis got the most votes in the doodleD or whihever ws proposed (rst in se of tieY et the eginning of the meeting one person will identify himGherself s the modertorY he modertor is essentilly responsile for ensuring the ISmin timeox nd ensuring tht tsks re lerly identi(edY sully the modertor will lso hndle writing the summry nd reting tr tikets unless someone else steps upY enyone n join nd is expliitly invited to prtiipteY sdelly one should fmilirize oneself with the proposed topi efore the meetingY hen strting on new topi the proposer is invited to strt things o' with few wordsY enyone n then omment s they see (tY hepending on how mny people prtiipte one should potentilly retrin oneself from pushing spei( rgument too hrdY ememer the sg logs will e pulished lter onD so people hve the hne to review omments lter on one moreY eople re enourged to rise their hnd to tke on tsks de(ned during the meetingF
rere is n exmple doodleF
WFQF gommunity
URW
sn order to follow wht is hppening in the ommunity you might (nd helpful these dditionl resouresX
vist of open pull requests vist of reent ommits vist of open ugs nd enhnements vist of open soure undles godeX
! fugs | ! thes | ! eurity | ! ests | ! goding tndrds | ! gode gonventions | ! viense
houmenttionX
! yverview | ! pormt | ! rnsltions | ! viense
gommunityX
! sg weetings | ! yther esoures
godeX
! fugs | ! thes | ! eurity | ! ests | ! goding tndrds | ! gode gonventions | USH WF gontriuting
houmenttionX
! yverview | ! pormt | ! rnsltions | ! viense
gommunityX
! sg weetings | ! yther esoures
WFQF gommunity
USI
USP
WF gontriuting
Symbols
gon(gurtionD SII
B
D IVI rnitD IVP D IVW D VS D VR D TV D TV D US D ITW D IUI D IUR D IVI D IUI D IUQ grwlerD IUU D IVS vlidtorD IVU D IWH D IVW D IWH D IVV D SPR
A
fundle ixtension gon(gurtionD RQV snheritneD RQV yverridingD RQV fundles fest rtiesD RQQ ixtensionD RRH xming gonventionsD RQQ
C
gheD PTH gheEgontrol rederD PTS gheEgontrol hederD PTV gonditionl qetD PUI gon(gurtionD PUQ isD PUQ itg hederD PTW ixpires hederD PTV qtewyD PTI rD PTR r ixpirtionD PTU snvlidtionD PUU vstEwodi(ed hederD PUH roxyD PTI everse roxyD PTI fe methodsD PTT ymfonyP everse roxyD PTP wigD IPR ypes ofD PTP USQ
ymfony houmenttionD PFH lidtionD PTW rnishD SHR ryD PUP gvs hotrine ywD ITV gon(gurtion eutoloderD SII gheD PUQ gonventionD RRV heug modeD RHR hotrine hfevD STV emntiD RQV ewvD UIH gon(gurtion eferene essetiD STQ hotrine ywD STR prmeworkD SSU wonologD SUT wiftmilerD SUR wigD SUR ero(lerD SUV gontrollerD VU RHR pgesD WT eessing serviesD WT es erviesD QRQ fse ontroller lssD WQ gommon sksD WQ gontroller rgumentsD WH porwrdingD WR wnging errorsD WT ediretingD WR endering templtesD WS equest ojetD WW equestEontrollerEresponse lifeyleD VU esponse ojetD WW outes nd ontrollersD VW imple exmpleD VV tring nming formtD IIS he sessionD WU gonvention gon(gurtionD RRV
D
heuggingD SPQ hependeny snjetion gontinerD PWQ hependeny snjetionD ixtensionD RRH hotrineD IRQ edding mpping metdtD IRS hfevD QUT hfev on(gurtionD STV pormsD PIS qenerting entities from existing dtseD QUQ yw gon(gurtion efereneD STR yw gonsole gommndsD ITV
E
imilsD RRW qmilD RSI invironmentsD RHI ghe diretoryD RHU gon(gurtion (lesD RHP greting new environmentD RHS ixeuting di'erent environmentsD RHR ixternl rmetersD RHV isD PUQ ivent uernelD QIU kernelFontrollerD QIV kernelFexeptionD QPH kernelFrequestD QIV kernelFresponseD QIW kernelFviewD QIW ivent hisptherD QPHD SPWD SQI greting nd hispthing n iventD QPR ivent ulssesD QPP ivent susriersD QPU iventsD QPI vistenersD QPP xming onventionsD QPI topping event )owD QPV
F
pinderD SIQ pormsD IWW fsi templte renderingD PHP fuiltEin pield ypesD PHU grete form in ontrollerD PHI
ymfony houmenttionD PFH grete simple formD IWW greting form lssesD PIR gp rotetionD PPR gustomizing (eldsD PIV hotrineD PIS imedded formsD PIT pield type guessingD PHWD PIH pield type optionsD PHW pields irthdyD SUW hekoxD SVI hoieD SVQD THH olletionD SVV ountryD SVV srfD SWI dteD SWP dtetimeD SWS emilD SWV (eldD THU (leD THS formD THW hiddenD THW integerD THW lngugeD TII loleD TIR moneyD TIU numerD TPH psswordD TPP perentD TPR rdioD TPT repetedD TPV serhD TQI textD TQP textreD TQR timeD TQT timezoneD TQV urlD TRI qlol hemingD PPI rndling form sumissionD PHQ endering eh (eld y hndD PIP endering in emplteD PII emplte prgment snheritneD PPI emplte frgment nmingD PPH hemingD PIV wig form funtion refereneD TRS ypes efereneD SUW lidtionD PHR lidtion qroupsD PHT
H
r QHRD PUI equestEresponse prdigmD RH r heders gheEgontrolD PTSD PTV itgD PTW ixpiresD PTV vstEwodi(edD PUH ryD PUP
I
snstlltionD TQ snternlsD QIR gontroller esolverD QIT snternl equestsD QIU uernelD QIS equest rndlingD QIT
J
vyoutD SHU
M
erformne USS
ymfony houmenttionD PFH eutoloderD QIQ footstrp (lesD QIQ fyte ode heD QIP r empltesD SHT rnit D IVP ro(lerD QPV sing the pro(ler servieD QPW isulizingD QPWD QQH ro(ling ht golletorD SQR ixtension on(gurtionD PWW importsD PWV eferening serviesD QHI ht is serviecD PWR ht iscD PWR essionD WU htse torgeD RQH single emplte yverriding exeption templtesD IQW yverriding templtesD IQV single ession R plsh messgesD WU equest lotD SHV edd request formt nd mime typeD SQP tylesheets equirementsD UIU snluding stylesheetsD IQS outingD IHH ymfonyP gomponentsD RV formt prmeterD IIQ ymfonyP pundmentlsD QW esolute vsD IPH equests nd responsesD RQ edvned exmpleD IIQ T ellow G in route prmeterD QRT empltingD IPI fsisD IHH gontrollersD IIS imedding tionD IQI greting routesD IHP imedding gesD SHW heuggingD IIW pile votionsD IPV qenerting vsD IIW pormtsD IRI qenerting vs in templteD IPH relpersD IPWD SIH snludeD SHW smporting routing resouresD IIT wethod requirementD III snluding other templtesD IQH leholdersD IHR snluding stylesheets nd tvsriptsD IQS equirementsD IHV snheritneD IPR heme requirementD QRR vyoutD SHU nder the hoodD IHP vinking to ssetsD IQS vinking to pgesD IQQ S xming gonventionsD IPV eurity yutput espingD IRH eess gontrol vists @egvsAD RUH lotD SHV edvned egv oneptsD RUR gs nd relpersD IPW gon(gurtion efereneD SUH he templting servieD IQU gustom euthentition roviderD RWQ hreeElevel inheritne ptternD IQW rget rediret pthD SHQ ht is templtecD IPP eurityD otersD RTU estsD QIPD RSU ervie gontinerD PWQ hotrineD RSW edvned on(gurtionD QHV r euthentitionD RST gon(guring serviesD PWS ro(lingD RSV UST
ymfony houmenttionD PFH rnsltionsD PUV fsi trnsltionD PVH gon(gurtionD PUW greting trnsltion resouresD PVR pllk nd defult loleD PVU sn templtesD PWI wessge tloguesD PVQ wessge dominsD PVU wessge pleholdersD PVI lurliztionD PVW rnsltion resoure lotionsD PVQ ser9s loleD PVU wig gheD IPR gon(gurtion efereneD SUR sntrodutionD IPP
V
lidtion gonstrint trgetsD IWQ gustom onstrintsD QWW qetter onstrintsD IWR roperty onstrintsD IWQ rnish on(gurtionD SHR snvlidtionD SHS
W
ewvD UIH
USU