Sei sulla pagina 1di 83

SYMFONY

CursoSymfony Unizar.MiguelMartn2012.

INDICE
Da1:TEORA
PRCTICA MVC+FundamentosdeSymfony +Routing (bsico) InstalacindeWAMP2.2+Symfony CONTROLLER+Routing (avanzado) EjerciciosCONTROLLERyROUTING TEMPLATING(TWIG) EjerciciosTEMPLATING Formularios EjerciciosFormularios Doctrine Crearaplicacinparagestionartareas

Da2:TEORA
PRCTICA

Da3:TEORA
PRCTICA

Da4:TEORA
PRCTICA

Da5:TEORA
PRCTICA

BOLAEXTRA:Seguridad(autenticacinyautorizacin)
2

Da1:IntroduccinaSymfony yMVC
Modelovistacontrolador(MVC):conceptoyejemplo FundamentosdeSymfony MecanismoHTTP:leerRequest,generarResponse LecturadeRequest/GeneracindeResponse enSymfony Controlador:paraqu sirve? AlternativasaSymfony InstalacindeSymfony Consejosdedesarrollo(+instalacindesoftware) Introduccinalworkflow deSymfony Creacindelprimerproyecto Entornos

IntroduccinaModeloVistaControlador(MVC)
[WIKIPEDIAfor Modelo_Vista_Controlador: http://es.wikipedia.org/wiki/Modelo_Vista_Controlador ]

Modelo:Estaeslarepresentacinespecfica delainformacinconlacualelsistemaopera. Enresumen,elmodeloselimitaalorelativo delavista ysucontrolador facilitandolas presentacionesvisualescomplejas.Elsistema tambinpuedeoperarconmsdatosno relativosalapresentacin,haciendouso integradodeotraslgicasdenegocioyde datosafinesconelsistemamodelado. Vista:Estepresentaelmodeloenunformato adecuadoparainteractuar,usualmentela interfazdeusuario. Controlador:Esterespondeaeventos, usualmenteaccionesdelusuario,einvoca peticionesalmodeloy,probablemente,ala vista.

CursoSymfony Unizar.MiguelMartn2012.

IntroduccinaModeloVistaControlador(MVC)
AplicacinenPHPbsico:
ConexinaBD Recuperacindedatos Muestradatos
<?php //index.php $link =mysql_connect('localhost','myuser','mypassword'); mysql_select_db('blog_db',$link); $result =mysql_query('SELECTid,title FROMpost',$link); ?> <html> <head> <title>List of Posts</title> </head> <body> <h1>List of Posts</h1> <ul> <?php while ($row =mysql_fetch_assoc($result)):?> <li> <ahref="/show.php?id=<?php echo$row['id']?>"> <?php echo $row['title']?> </a> </li> <?php endwhile;?> </ul> </body> </html> <?php mysql_close($link);?>

MezclaPHP+HTML(lgicay presentacin) Rpidadeescribir Singestindeerrores Difcilreutilizacindelcdigo Difcildemantener Noseaisla delSGBD(ysi cambiamosaPostgre enunfuturo?)

IntroduccinaMVC(II)
Separacin:
<?php //index.php $link =mysql_connect('localhost','myuser','mypassword'); mysql_select_db('blog_db',$link); $result =mysql_query('SELECTid,title FROMpost',$link);

Lgica(controlador)

$posts =array(); while ($row =mysql_fetch_assoc($result)){ $posts[]=$row; } mysql_close($link); //include the HTMLpresentation code require 'templates/list.php'; <html> <head> <title>List of Posts</title> </head> <body> <h1>List of Posts</h1> <ul> <?php foreach ($posts as $post):?> <li> <ahref="/read?id=<?php echo$post['id']?>"> <?php echo $post['title']?> </a> </li> <?php endforeach;?> </ul> </body> </html> 6

Presentacin

IntroduccinaMVC(III)
Qu pasasiqueremosreutilizarel cdigodeconexinalaBD? YsicambiamoselsistemaGestorde laBD?
<?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('SELECTid,title FROMpost',$link); $posts =array(); while ($row =mysql_fetch_assoc($result)){ $posts[]=$row; } close_database_connection($link); return $posts; }

Solucin:MODELO
Accesoadatos

<?php //index.php

Ahoraindex.php esmuysimple:
recogerlosdatosdelmodelo,realizarla lgicadeseadaconellos(controlador)y pasrselosalacapadepresentacin(vista).

require_once 'model.php'; $posts =get_all_posts(); require 'templates/list.php';

IntroduccinaMVC(IV)
Qu pasasiqueremosreutilizar lavista? Creamosunnuevofichero: layout.php ynuestrotemplate (templates/list.php)se simplifica. Laideaesalmacenarporunlado losvaloresdelasvariables (list.php)yporotro, mostrarlos(layout.php)
<! templates/layout.php > <html> <head> <title><?php echo $title ?></title> </head> <body> <?php echo $content ?> </body> </html>

<?php //templates/list.php $title ='List of Posts'?>

<?php ob_start()?> <h1>List of Posts</h1> ob_start() iniciala"captura"delbufferde <ul> <?php foreach ($posts as $post):?> salidayob_end_flush() terminala <li> capturadelbufferdesalida.Deestemodo <ahref="/read?id=<?php echo$post['id']?>"> podemoshacerunechodetodoesebuffer. <?php echo $post['title']?> </a> </li> <?php endforeach;?> </ul> <?php $content =ob_get_clean()?> <?php include 'layout.php'?>

IntroduccinaMVC(V)
Vamosavercmocrearamosunavista nueva,queenvezdemostrarellistadode posts,muestreunoenconcreto.
//Aadimosestafuncinamodel.php function get_post_by_id($id){ $link =open_database_connection(); $id =mysql_real_escape_string($id); $query ='SELECTdate,title,bodyFROMpostWHEREid ='.$id; $result =mysql_query($query); $row =mysql_fetch_assoc($result); close_database_connection($link); return $row; } <?php //show.php require_once 'model.php'; $post =get_post_by_id($_GET['id']); require 'templates/show.php'; <?php //templates/show.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'?>

Introducimoslanuevafuncinal modelo(get_post_by_id en model.php)

Creamoselnuevocontrolador (show.php)

Creamoslavista (templates/show.php)

IntroduccinaMVC(VI)
Seintroduceunnuevoproblema:tenemosVARIOSCONTROLADORES(index.php yshow.php).
<?php //index.php require_once 'model.php'; $posts =get_all_posts(); require 'templates/list.php'; <?php //show.php require_once 'model.php'; $post =get_post_by_id($_GET['id']); require 'templates/show.php';

Encadacontroladorincluimoselmodelo(model.php),peroysituviramosqueincluirunnuevoficheroadicionalomodificarun comportamientogeneral? TendramosqueeditarTODOSloscontroladores

Solucin:Controladornicoqueejecutatodaslaspeticiones: SinFRONTCONTROLLER /index.php =>Listadodeposts delblog(ejecutaindex.php) /show.php =>Unpostconcreto(ejecutashow.php) ConFRONTCONTROLLER(index.php) /index.php =>Listadodeposts delblog(ejecutaindex.php) /index.php/show =>Unpostconcreto(ejecutaindex.php)

10

IntroduccinaMVC(VII)
<?php //index.php (seconvierteenelcontroladorprincipal) //cargamoselmodelo require_once 'model.php'; //cargamoselficherodondesedefinenlasfuncionesdelosanteriorescontroladores... require_once 'controllers.php'; //ejecutamosunafuncinuotraenfuncinalarutainvocada... $uri =$_SERVER['REQUEST_URI']; if ($uri =='/index.php'){//sehainvocadoaindex.php >debemoslistartodoslospost list_action(); }elseif ($uri =='/index.php/show'&&isset($_GET['id'])){ //sehainvocadoa/index.php/show>debemosmostrarelpostidentificadopor$_GET[id] show_action($_GET['id']); }else { header('Status:404Not Found'); echo '<html><body><h1>Page Not Found</h1></body></html>'; } //controllers.php (listado detodas las posibles rutas >acciones alas que invocar) 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'; }

11

IntroduccinaMVC(VIII)
index.php :controlalasrutasyqu funcin(decontrollers.php)ejecutarencadacaso controllers.php:contienelasaccionesdecadacontrolador(list_action()yshow_action model.php:contienelasfuncionesdeaccesoadatos(BD) PHPconMVC layout.php:contienelaplantillageneraldelavista:generalasalidaapartirdeunaestructura
HTMLestticoylosvaloresdealgunasvariablesquesonasignadosen:

templates/list.php:davaloralasvariablesquelayout.php mostrar ($title y$conten templates/blog.php:davaloralasvariablesquelayout.php mostrar

PHPinicial

index.php:hacetodo

12

FundamentosSYMFONY
Desarrollarmsrpido:
*mejororganizacin *funcionalidadesmscomunes

Construiraplicaciones:
*msrobustas *msflexibles *msseguras

CursoSymfony Unizar.MiguelMartn2012.

13

FUNDAMENTOSSYMFONY(II)
Resumen:misindecualquieraplicacinweb =Interpretarpeticinydevolverrespuesta. Suelehabermuchasfuncionalidadescomunes entretodaslasapps web:consultasalabasededatos,
renderizadoyreutilizacindeplantillas,envodecorreos,validacindeentradasdeusuario,controldelaseguridadweb.

Symfony proveeunsetdeherramientas quefacilitanestaslaborescomunes. Symfony seorganizaenlibrerasindependientes(Components).Puedenserutilizadascon independenciadesiseusaelframework completoono. Algunasdelasmsimportantes:


HttpFoundation:ContienelasclasesRequest yResponse (+manejosesiones,fileuploads) Routing:Mapeoderutasafunciones(/contact ejecutarcontactAction()) Form:Unframework flexibleparacrearymanejarformularios Validator:Sistemaparacrearreglasyusarlasparavalidardatosenviadosporelusuario Templating:renderizadodeplantillas(+herenciasyotros) Security:manejodelaseguridaddelaaplicacin Translation:paratraduccindecadenasdetexto

Symfony facilitaelusodeestaslibrerasdeformaconjuntaeintegraotrasexternas(porejemplo Doctrine,quesirveparaaislarlasconsultasalaBDdelSGBDusado.)

CursoSymfony Unizar.MiguelMartn2012.

14

Mecanismo bsicoHTTP

PHPcreavariablessuperglobales conainformacindelapeticin(request)
<?php $uri =$_SERVER['REQUEST_URI']; $foo =$_GET['foo']; header('Contenttype:text/html'); echo 'TheURIrequestedis:'.$uri;echo 'Thevalueofthe "foo"parameteris:'.$foo; ?>

Trasinterpretarelcdigo,devuelvelarespuesta
HTTP/1.1200OK Date:Sat,03Apr201102:14:33GMTServer:Apache/2.2.17(Unix) ContentType:text/html TheURIrequestedis:/testing?foo=symfony Thevalueofthe "foo"parameteris:symfony

15

SYMFONY
claseRequest

Clasecuyosobjetosalmacenaninformacindelapeticin (Request)
Proveemtodos(comoisSecure()oisXmlHttpRequest())querealizanalgunastareas engorrosasdetenerquehacerlasenPHP.
http://symfony.com/doc/current/components/http_foundation.html#accessingrequestdata

<?php use Symfony\Component\HttpFoundation\Request; $request =Request::createFromGlobals(); //laURLsolicitada (p.ej./about)SINPARAMETROS $request>getPathInfo(); //Acceder alas variablesGETyPOST $request>query>get('foo'); $request>request>get('bar','valorpor defecto si barnoexiste'); //Acceder alas variablesdel SERVER $request>server>get('HTTP_HOST'); //Acceso alainstancia deun UploadedFile identificado por foo $request>files>get('foo'); //Acceso alas cookies... $request>cookies>get('PHPSESSID'); //Acceso ainformacin delas cabeceras del Request,ya enminsculas ynormalizadas $request>headers>get('host'); $request>headers>get('content_type'); $request>getMethod();//GET,POST,PUT,DELETE,HEAD $request>getLanguages();//arraydelenguajes que acepta el cliente

16

SYMFONY
claseResponse

Clasecuyosobjetossirvenparagenerarlarespuestaalcliente.
http://symfony.com/doc/current/components/http_foundation.html#response

<?php use Symfony\Component\HttpFoundation\Response; // construccinamano delaResponse $response =new Response(); $response>setContent('<html><body><h1>Hello world!</h1></body></html>'); $response>setStatusCode(200); $response>headers>set('ContentType','text/html'); $response>setCharset('ISO88591');//pordefecto,asumeUTF8 //envodecabecerasHTTP+contenido $response>send();

//sepuedehacerconmenospasos return new Response(Hola); ?>

Yatenemosclarocmoprocesarlapeticinydevolverlarespuesta.Lapartejugosa consisteenescribirelcdigoqueinterpretalapeticinycrealarespuesta.

Qu msofreceSymfony?
Loveremospronto
17

SYMFONYFront controller
PHPTradicional EnPHPcadaficherorecogelapeticin,realiza lalgicacorrespondienteydevuelveuna respuesta:
index.php blog.php contact.php

Symfony Front controller:manejaTODASlaspeticiones quellegan.


/index.php /index.php/blog /index.php/contact

PROBLEMA:PocaflexibilidadenlasURLs (reescribirtodoslosenlaces)ohacer chapuzas


//index.php asROUTER $request =Request::createFromGlobals(); $path =$request>getPathInfo(); //the URIpath being requested if (in_array($path,array('','/')){ $response =new Response(HOME!'); }elseif ($path =='/contact'){ $response =new Response('Contact!'); }else { $response =new Response(Not found.',404); } $response>send();

ejecutaindex.php ejecutaindex.php ejecutaindex.php

Estetipodesolucinseimplementaenla mayoradelosCMSs (WP,etc)

18

SYMFONYFront controller (II)

1. Recibirpeticindelcliente(GET/contact) 2. Interpretarruta(decidirqu funcinejecutarenfuncindelainformacindelapeticinyde laconfiguracinderutascreada)ypasrselaalcontrolador(aka dondevaelcdigo)


contact: pattern:/contact defaults:{_controller:BundleEjemplo:Main:contact } class MainController { public function contactAction(){ return new Response('<h1>Hi!</h1>'); } }

3. Devolverrespuestaalcliente
CursoSymfony Unizar.MiguelMartn2012. 19

SYMFONYAlternativas

COMPARATIVA http://www.phpframeworks.com/

CursoSymfony Unizar.MiguelMartn2012.

20

InstalacindeSymfony
DescargarSymfony StandardEdition:enZIP! http://symfony.com/download
www/< your web root directory Symfony/< the unpacked archive app/ cache/ config/ logs/ Resources/ bin/ src/ Acme/ DemoBundle/ Controller/ Resources/ ... vendor/ symfony/ doctrine/ ... web/ app.php ...

Extraerelcontenidodel.zipenelDocumentRoot del servidorweb.Laestructuraes:

Configuracindelentorno: http://localhost/Symfony/web/config.php

21

InstalacindeSymfony enWAMP2.2(conPHP5.3.8y Apache2.2.1)


http://www.leccionespracticas.com/php/instalaciondesymfony2enwampconphp53 extensionintlyaceleradoracpresuelto/
1. Descargareinstalar>WAMPServer2.2 enc:\wamp2.2\ LaversinqueinstalamoscontienePHP5.3.8yApache2.2.21 2.DescargarSymfony 2.0(EdicinStandard) [DESCARGARLAVERSION2.0ENZIP!!]ydescomprimirlosarchivos enc:\wamp2.2\www\Symfony 2.1.Arrancarwamp server ejecutandoC:\wamp2.2\wampmanager.exe 2.2.Abrirelnavegadoreirahttp://localhost/Symfony/web/config.php 2.3.LomsprobableesquenosrecomiendeinstalarAPC yintl.Seguiremos,paraello,lospasos2y3. 3.Activarlasextensionesphp_intl: 3.1.Copiarlosicu*.dll deC:\wamp2.2\bin\php\php5.3.8aC:\wamp2.2\bin\apache\Apache2.2.21\bin (sinohacemosestepaso,Symfony NOdetectar elphp_intl yseguir diciendoqueloinstalemos) 3.2.Activarlaextensinphp_intl:WampManager >PHP>Extensions >php_intl 3.3.ReiniciarWAMP:WampServer >Restart all services 4.InstalaraceleradorPHPAPC (SIEXISTEELFICHEROphp_apc.dll OMITIRESTEPUNTO!) 4.1.Descargarhttp://downloads.php.net/pierre/php_apc3.1.55.3vc9x86.zip 4.2.Descomprimirphp_apc.dll enC:\wamp2.2\bin\php\php5.3.8\ext 4.3.Activarphp_apc enWampManager >PHP>Extensions >php_apc 4.4.ReiniciarWAMP:WampServer >Restart all services Enestepunto,alirahttp://localhost/Symfony/web/config.php deberamosverlasiguientepantalla,queindicaquepodemosempezara configurar Symfony porqueelentornoyaest preparado.

22

InstalacindeSymfony enWAMP2.2(conPHP5.3.8y Apache2.2.1)


http://localhost/Symfony/web/config.php

23

ConfiguracindeSymfony:seguirlospasos
Vamosadejareluser root delaBDsinpwd,algoqueNUNCAdeberahacersefueradeuna demo

24

Aadirbinariodephp alavariablePATH
vamos a aadir la carpeta de los binarios de php a la variable PATHde Windows.
c:\wamp2.2\bin\php\php5.3.8\php.exe),

Para mayor comodidad

(y poder invocar el comando php en lugar de

Para ello, en W7:


click botn de inicio, click derecho sobre Equipo>propiedades>Configuracin avanzadadelsistema>variablesdeentorno,recuadroVariablesdel sistema. Localizar la variable Path y pulsar Editar. Al final del todo, aadir el path a la carpeta de binarios de php, dentro de la carpeta donde instalamos WAMP:

; c:\wamp2.2\bin\php\php5.3.8

25

Probando:Hello world enSymfony


http://localhost/Symfony/web/app_dev.php/demo/hello/Miguel

Responsabilidaddelprogramador=
Escribirelcdigoquemapealapeticindelcliente (/demo/hello/Miguel)alrecursoasociadoconella (lapginaquemuestraHello Miguel! enHTML)

26

PrimerprogramaenSymfony:ROUTING
http://localhost/Symfony/web/app_dev.php/demo/hello/Miguel
app/config/routing.yml archivodeconfiguracinconreglas app/config/routing_dev.yml archivodeconfiguracinconreglasdelentornodedesarrollo(app_**dev**.php) enelcontrolador
*MssobrearchivosYAML(.yml)enhttp://www.yaml.org/

Nombrelgicodelcontrolador:referenciaelmtodoindexAction de Acme\DemoBundle\Controller\WelcomeController

_welcome: pattern:/ defaults:{_controller:AcmeDemoBundle:Welcome:index } _demo: resource:"@AcmeDemoBundle/Controller/DemoController.php" type:annotation prefix:/demo //src/Acme/DemoBundle/Controller/WelcomeController.php namespace Acme\DemoBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class WelcomeController extends Controller { public function indexAction() { //sevaarenderizareltemplate AcmeDemoBundle:Welcome:index.html.twig return $this>render('AcmeDemoBundle:Welcome:index.html.twig'); } } TWIG(motordetemplates pordefecto).Msenhttp://twig.sensiolabs.org/ HacereferenciaalarchivoResources/views/Welcome/index.html.twig dentrodesrc/Acme/DemoBundle 27

PrimerprogramaenSymfony:CONTROLLER
http://localhost/Symfony/web/app_dev.php/demo/hello/Miguel
app/config/routing.yml archivodeconfiguracinconreglas app/config/routing_dev.yml archivodeconfiguracinconreglasdelentornodedesarrollo(app_**dev**.php) enelcontrolador
*MssobrearchivosYAML(.yml)enhttp://www.yaml.org/

_welcome: pattern:/ defaults:{_controller:AcmeDemoBundle:Welcome:index } _demo: resource:"@AcmeDemoBundle/Controller/DemoController.php" type:annotation prefix:/demo //src/Acme/DemoBundle/Controller/DemoController.php


use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class DemoController extends Controller { /** *@Route("/hello/{name}",name="_demo_hello") *@Template() */ public function helloAction($name) { return array('name'=>$name); } //... } 28

EjerciciosSYMFONY

E1.Modificar el ejemplo para que enlugar deponer HelloX! ponga Hola X!

29

EjerciciosSYMFONY

S1.Modificar el ejemplo para que enlugar deponer HelloX! ponga Hola X!

Observarenelfrontcontroller (app/config/routing_dev.yml)qu controlador seest ejecutandoparaesaURL: _demo: resource:"@AcmeDemoBundle/Controller/DemoController.php" type:annotation prefix:/demo Abrirsrc/Acme/DemoBundle/Controller/DemoController.php y observar el cdigo.Aqui sehace laLGICA(recuerda:el controlador debe generar laRESPUESTA)yvemos las rutas como notas precedidas por @Route ({name}es un placeholder) /** *@Route("/hello/{name}",name="_demo_hello") *@Template() */ publicfunctionhelloAction($name) { returnarray('name'=>$name); }
IndicaquelasURLs seindicarncomo anotacionesenelficheroDemoController. Todaslasrutasquecomiencencon/demolas resolver elcontroladorDemoController.php

Enelejemploanterior,elcontroladorllamabaa
$this>render('AcmeDemoBundle:Welcome:index.html.twig');

SinembargoenestecasosolosedevuelveunArrayde parmetros.Existeunaanotacin(@Template())que indicaqueserenderice eltemplate,pasandocada variabledelarrayaltemplate.Elnombredeltemplate utilizadosederivadelnombredelcontrolador(hello).Asi queenestecaso,serenderiza


src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig VERTODOSLOSMODIFICADORESPORANOTACIONESEN CONTROLADORESen http://symfony.com/doc/current/bundles/SensioFrameworkExtra Bundle/index.html#annotationsforcontrollers

Abrirsrc/Acme/DemoBundle/Resources/views/Demo/hello.html.twig ymodificarlaPLANTILLA: {%extends "AcmeDemoBundle::layout.html.twig"%} {%block title &iexcl;Hola "~name %} {%block content %} <h1>&iexcl;Hola {{name }}!</h1> {%endblock %} {%setcode =code(_self)%} 30

EjerciciosSYMFONY

E2.Modificar el ejemplo para que enlugar deponer Hola x! ponga Hola X! para /demo/hello/x y/demo/hello/X

31

EjerciciosSYMFONY

S2.Modificar el ejemplo para que enlugar deponer Hola x! ponga Hola X! para /demo/hello/xy/demo/hello/X

Observarenelfrontcontroller (app/config/routing_dev.yml)qu controlador seest ejecutandoparaesaURL: _demo: resource:"@AcmeDemoBundle/Controller/DemoController.php" type:annotation prefix:/demo Abrirsrc/Acme/DemoBundle/Controller/DemoController.php y observar el cdigo.Aqui sehace laLGICA(recuerda:el controlador debe generar laRESPUESTA)yvemos las rutas como notas precedidas por @Route yque {name}es un placeholder /** *@Route("/hello/{name}",name="_demo_hello") *@Template() */ publicfunctionhelloAction($name) { returnarray('name'=>strtoupper($name)); }
Enestecaso,podremosrealizarlamodificacinobienen elControlador(ypasarlavariableyaenmaysculasala Vista): strtoupper($name)

OpodramosmodificardirectamentelaVista,para mostrarenmaysculascualquiervariablename quenos lleguedeeseuotroControlador: Hola{{name|upper }}

Eltemplate src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig {%extends "AcmeDemoBundle::layout.html.twig"%} {%block title &iexcl;Hola "~name %} {%block content %} <h1>&iexcl;Hola {{name|upper }}!</h1> {%endblock %} {%setcode =code(_self)%} 32

EjerciciosSYMFONY

E3.Modificar el ejemplo para que alinvocar /demo/hello/NOSE PRODUZCAninguna excepcin

Ademsdemostrarlaexcepcin,vemosqueenla parteinferiorhayunanuevabarradeherramientas (WEBDEBUGTOOLBAR).Estosucedeenelentorno dedesarrollo(development environment)


33

EjerciciosSYMFONY

S31.Modificar el ejemplo para que alinvocar /demo/hello/NOSE PRODUZCAninguna excepcin

Observarenelfrontcontroller (app/config/routing_dev.yml)qu controlador seest ejecutandoparaesaURL: _demo: resource:"@AcmeDemoBundle/Controller/DemoController.php" type:annotation prefix:/demo Modificarsrc/Acme/DemoBundle/Controller/DemoController.php Para aadir lanueva ruta: /** *@Route("/hello/}",name="_demo_hello") *@Template() */ publicfunctionnonameAction($name) { returnarray('name'=>strtoupper($name)); }
Definimosunanuevaruta(/hello/)yhacemosquese invoquelafuncinnonameAction cuandosellameaesta URL.

Comoeltemplate vaasociadoelnombredelaaccin, debemoscrearunnoname.html.twig

Copiamostemplate src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig a src/Acme/DemoBundle/Resources/views/Demo/noname.html.twig yrealizamoslasmodificaciones pertinentes {%extends "AcmeDemoBundle::layout.html.twig"%} {%block title &iexcl;Hola DESCONOCIDO!"%} {%block content %} <h1>&iexcl;Hola.Noteconozco.</h1> {%endblock %} {%setcode =code(_self)%} 34

EjerciciosSYMFONY

S32.Modificar el ejemplo para que alinvocar /demo/hello/NOSE PRODUZCAninguna excepcin

Observarenelfrontcontroller (app/config/routing_dev.yml)qu controlador seest ejecutandoparaesaURL: _demo: resource:"@AcmeDemoBundle/Controller/DemoController.php" type:annotation prefix:/demo Modificarsrc/Acme/DemoBundle/Controller/DemoController.php Para aadir lanueva ruta: /** *@Route("/hello/}",name="_demo_hello") *@Template(AcmeDemoBundle:Demo:hello.html.twig) */ publicfunctionhelloAction() { $name =ANONIMO; returnarray('name'=>$name); }
Definimosunanuevaruta/hello/yhacemosquese renderice eltemplate hello.html.twig (@Template(AcmeDemoBundle:Demo:hello.html.twig)) metindolenosotroselvalorde$name deformamanual.

Msinformacinsobrelanota@Template en http://symfony.com/doc/current/bundles/SensioFramew orkExtraBundle/annotations/view.html

Dejamostalcualsrc/Acme/DemoBundle/Resources/views/Demo/hello.html.twig

35

DESARROLLO:

CONSEJOS(parasermsfeliz)

Emplea un buen IDE. Yo uso NOTEPAD++ http://notepad-plus-plus.org/ Cuidadoconlostabuladoresenlosficherosderutas(handeserespacios!). EnNOTEPAD++seevitaasi:


Settings >Preference >Edit Components (tab)>Tab Setting (group)>Replace byspace Inversion 5.6.8(and above): Settings >Preferences...>Language Menu/Tab Settings >Tab Settings (group)>Replace byspace

DEBUG: Adems del debugger de Symfony


Utiliza Firebug y la consola de errores de firefox para hacer debug de tus apps web: https://addons.mozilla.org/es-es/firefox/addon/firebug/ Puedes usar UrlParams (o HttpFox) para observar la informacin de GET/POST de los Requests
UrlParams (noparaFF11)https://addons.mozilla.org/enUS/firefox/addon/urlparams/?id=1290 HttpFox (s paraFF11)https://addons.mozilla.org/enUS/firefox/addon/httpfox/

OPTIMIZACIN:
Puedes usar HttpWatch para Firefox para visualizar y optimizar la carga de tus recursos (comprimiendo CSS, JS, optimizando imgenes, creando CSS Sprites, etc) http://www.httpwatch.com/

La mejor ayuda, la API de Symfony2: todas las funciones, al detalle http://api.symfony.com/2.0/index.html


36

E5:Creacindeunnuevoproyecto
Welcometothe Symfony2bundlegenerator ... Use/insteadof\ forthe namespacedelimitertoavoidanyproblem. Bundlenamespace[curso/e5Bundle]: Inyourcode,abundleisoftenreferencedbyitsname.Itcanbethe concatenationofallnamespacepartsbutit'sreallyuptoyoutocome upwithauniquename(agoodpracticeistostartwiththe vendorname). Basedonthe namespace,wesuggestcursoe5Bundle. Bundlename[cursoe5Bundle]: Thebundlecanbegeneratedanywhere.Thesuggesteddefaultdirectoryuses the standardconventions. Targetdirectory[W:\WEB\wamp2.2\www\Symfony/src]: Determinethe formattouseforthe generatedconfiguration. Configurationformat(yml,xml,php,orannotation)[yml]: Tohelpyougettingstartedfaster,the commandcangeneratesome codesnippetsforyou. Doyouwanttogeneratethe wholedirectorystructure[no]? Summarybeforegeneration

cd c:\wamp2.2\www\Symfony

C:\wamp2.2\bin\php\php5.3.8\php.exe app/console generate:bundle namespace=curso/e5Bundle format=yml

//Aadeautomticamenteaapp/AppKernel.php public function registerBundles() { $bundles =array( //... new Acme\HelloBundle\AcmeHelloBundle(), ); //... return $bundles;

Youaregoingtogeneratea"curso\e5Bundle\cursoe5Bundle"bundle in"W:\WEB\wamp2.2\www\Symfony/src/"usingthe "yml"format. Doyouconfirmgeneration[yes]? Bundlegeneration Generatingthe bundlecode:OK Checkingthatthe bundleisautoloaded:OK ConfirmautomaticupdateofyourKernel[yes]? Enablingthe bundleinsidethe Kernel:OK Confirmautomaticupdateofthe Routing[yes]? Importingthe bundleroutingresource:OK

//Aadeautomticamentelainformacinderutas //comohaceruninclude delficheroenelque //delegamoslagestinderutas: //cursoe5Bundle/Resources/config/routing.yml cursoe5Bundle: resource: "@cursoe5Bundle/Resources/config/routing.yml" prefix:/

Youcannowstartusingthe generatedcode!

37

PrimerejercicioenSymfony

Antesdeleernoselmanualdecualquiercacharro,siempreprobamosausarlounpoco.Estecasono vaasermenos.RecuerdaloquecontamossobrelasclasesREQUESTyRESPONSEdeSymfony yel ejemplodelHello Worldqueacabamosdever. URLdelapginadebienvenidadebeser:http://localhost/Symfony/web/app_dev.php/curso Lapginadebienvenidadebemostrareltexto:Bienvenidoalcurso ytenercomo<title>Cursode Symfony</title>


38

E51:Pginadebienvenida
E51S1:Lasolucinmssimple:IncluirResponse enelcontroladorydevolverdirectamentelaRespuesta(sin templates nivariables)

#this is app/config/routing.yml cursoe5Bundle: resource:"@cursoe5Bundle/Resources/config/routing.yml" prefix:/curso #this is src/curso/e5Bundle/Resources/config/routing.yml cursoe5Bundle_homepage: pattern:/ defaults:{_controller:cursoe5Bundle:Default:index } <?php //this is src\Curso\e5Bundle\Controller\DefaultController.php namespace curso\e5Bundle\Controller; useSymfony\Bundle\FrameworkBundle\Controller\Controller; useSymfony\Component\HttpFoundation\Response; class DefaultController extends Controller { public function indexAction(){ return new Response('<html><head><title>CursodeSymfony</title></head> <body>Bienvenidoalcurso</body></html>'); } }

39

E51:Pginadebienvenida
E51S2:Contemplates yvariables:reutilizacinyflexibilidad(facilidaddemodificacin).Losficherosderutasse mantienenigual.SemodificaelDefaultController yeltemplate arenderizar(index.html.twig)
#this is app/config/routing.yml cursoe5Bundle: resource:"@cursoe5Bundle/Resources/config/routing.yml" prefix:/curso

#this is src/curso/e5Bundle/Resources/config/routing.yml cursoe5Bundle_homepage: pattern:/ defaults:{_controller:cursoe5Bundle:Default:index }

<?php //this is src\Curso\e5Bundle\Controller\DefaultController.php namespace curso\e5Bundle\Controller; useSymfony\Bundle\FrameworkBundle\Controller\Controller; useSymfony\Component\HttpFoundation\Response; class DefaultController extends Controller NOMBRES DE LAS PLANTILLAS { <nombreBundle>:<nombreController>:<nombrePlantilla> public function indexAction(){ $titulo=CursodeSymfony"; $msg ="Bienvenidoalcurso"; return $this>render('cursoe5Bundle:Default:index.html.twig',array('titulo'=>titulo,'mensaje'=>$msg )); } }

<! customized bysrc\curso\e5Bundle\Resources\views\Default\index.html.twig > <html> <head> <title>{{titulo}}</title> </head> <body> {{mensaje}} </body> </html>

40

Entornos
Symfony ofrecedistintosENTORNOS.Laejecucindelcdigoesidntica, perosepermitendiferentesconfiguraciones.
Porejemplo,enentornodedesarrollo(dev)seloggean warnings yerrores,mientrasqueenentornodeproduccin(prod)seloggean nicamenteerrores. Tambinexistendiferenciasdecacheo(enentornodeproduccinsecacheayenentornodedesarrolloloscambiossevanreflejando)

http://www.symfony.com/doc/current/book/internals.html#configuration http://www.symfony.com/doc/current/cookbook/configuration/environments.html http://www.symfony.com/doc/master/reference/configuration/web_profiler.html Elentornosevecondicionadoporelcontroladorqueusamos:app_dev.php eselcontrolador principaldelentornodev,mientrasqueapp.php eselcontroladorprincipaldelentornoprod.


Ojo!EnalgunasversionesdeSymfony esnecesarioeliminarelmododebug (habilitadopordefecto)enelentornode produccin.Paraello,editarweb/app.php ycambiar $kernel=new AppKernel('prod',true); por $kernel=new AppKernel('prod',true); Ojo!SinodevuelvesHTMLbienformado,noverseldebugger delentornodev.

Enproduccindeberamosactivarmod_rewrite [1] yhacerqueel DocumentRoot apuntasedirectamentealdirectorioweb/ paratenerURLs msamigables:http://localhost/demo/hello/Fabien

[1]http://httpd.apache.org/docs/current/mod/mod_rewrite.html

41

Yaconocemoslobsico

ROUTING Controlderutas
Motivacin Ficherosderouting (fich principaleinclusindeficherosexternos) Rutasbsicasconplaceholders Rutasbsicasconplaceholders (defaults) Rutasbsicasconplaceholders (defaults)yrequerimientos Rutasavanzadas Parmetrosespeciales(_controller,_format,_locale) Visualizacinydebugging derutas GeneracindeURLs

43

ROUTING:motivacin
Cadadasehacemsimportanteconstruiraplicacionesweb conrutasSEF(searchenginefriendly),que: seanfcilmentelegibles(yrecordables), contenganlaspalabrasclaveparalasquequeremosposicionarnos mantenganciertajerarquizacin,etc. seanflexibles(puedacambiarlasconmuchafacilidad,sinrecorrertodoslosarchivosquelasenlazan)[1] gestindeerrores(404)yverificacindeparmetrosderutas(seguridad!) sitiosmultiidioma

S: www.mitienda.com/vestidos/rojos/vestidorojo1 (detallevestidorojo1) www.mitienda.com/vestidos/rojos (listadodevestidosrojos) www.mitienda.com/vestidos (listadodevestidos) www.mitienda.com/ (listadodeproductos)

No: www.mitienda.com/moduleprods/index.php?product_id=1238s81KZZ&show=detail&foo=bar&sessid=9182757ka1

[1]Ojo!Sicambiaslasrutasyquieresmantenertuposicionamiento, debesasegurartedehacerunredirect (301o302)


44

ROUTING:controlderutas
Comoyaadelantamoselda1,Symfony ofreceunmecanismodecontrolderutasmediante (1)Ficherogeneralderutas:puedetenerdefinidaslasrutasdirectamenteoincluirotrosficherosderutas
#Symfony/app/config/routing.yml proyecto1Bundle: resource:@AcmeHelloBundle/Resources/config/routing.yml"
#src/Acme/HelloBundle/Resources/config/routing.yml acme_hello: pattern:/hello/{name} defaults:{_controller:AcmeHelloBundle:Hello:index }

cursoe5Bundle: resource:"@cursoe5Bundle/Resources/config/routing.yml" prefix:/proyecto2


#esteparmetrohacequeatodaslasrutasdelficheroanteriorselesanteponga/proyecto2

[opcional](2)Ficheroderutasparaelproyectoqueestamosdesarrollando.
#Symfony/src/curso/e5Bundle/Resources/config/routing.yml cursoe5Bundle_homepage: pattern:/ defaults:{_controller:cursoe5Bundle:Default:index} cursoe5Bundle_flashmessage: pattern:/flashmessage defaults:{_controller:cursoe5Bundle:Default:flashmessage}

45

ROUTING:placeholders
Veamos,conmsdetalle,unficheroderutas.Lasreglassevanmatcheando enordendedefinicin,porloqueel ordens queimporta.
#Symfony/src/curso/e5Bundle/Resources/config/routing.yml cursoe5Bundle_blog: pattern:/blog/{slug} defaults:{_controller:cursoe5Bundle:Default:index }

pattern:DefineunpatrnquesecotejacontralaURLdelRequest.Enestecaso,elpatrndefinidoparacursoe5Bundle_bloghar matchconrutasdeltipo /blog/*Porejemplo,sielRequest sehacea/blog/post1elvalordelavariableslug tomar elvalor post1(yestavariableestar disponibleenelController). _controller:IndicaaSymfony qu controladordeberaejecutarcuandolaURLsolicitadaseajustealpatrndefinido.Sellamaal controladorporsunombrelgico(sereferenciaaunaclaseymtodoespecficos).
//cursoe5Bundle:Default:index >src/curso/e5Bundle/Controller/DefaultController.php (mtodoindexAction) class DefaultController{ public function indexAction($slug){ //disponibleelvalordelavariable(aka placeholder)slug. ... return new Response(...); } }

46

ROUTING:ejercicioR0
Generarlaconfiguracinnecesariaparaque:
URL ejercicioR0/Miguel/Martin/18 muestre TellamasMiguelMartin ytienes18aos

1.Qu sucedealinvocarejercicioR0/Miguel/Martin/? 2.Qu sucedealinvocarejercicioR0/Miguel/Martin/CACA? 3.Culeselcharset pordefectodeSymfony?(usaHttpFox)

47

ROUTING:ejercicioR0

48

ROUTING:placeholders defaults
DeseamosquelaaplicacinrespondaavariasURLs (losplaceholders debentenerunvalorpor defecto).Procedemosameterlosenlalneadefaults yasignarlesunvalorpordefecto. NtesequesecreanvariasrutasposiblesconUNsolopattern.

#routing.yml cursoe5Bundle_ejercicioR1: pattern:/ejercicioR1/{nombre}/{apellido}/{edad} defaults:{_controller:cursoe5Bundle:Default:ejercicioC1,nombre:MINOMBRE,apellido:MIAPELLIDO,edad:X}

//DefaultController.php public function ejercicioR1Action($nombre,$apellido,$edad) { return new Response('<html><body>Tellamas'.$nombre.''.$apellido.'ytienes'.$edad.'a&ntilde;os'); }

49

ROUTING:ejercicioR1
GenerarlaconfiguracinnecesariaparaquelassiguientesURLs secomportencomoseenuncia
URL URL URL URL ejercicioR1/Miguel/Martin/18 ejercicioR1/Miguel/Martin ejercicioR1/Miguel ejercicioR1/ muestre muestre muestre muestre TellamasMiguelMartin ytienes18aos TellamasMiguelMartin ytienesXaos TellamasMiguelAPELLIDOytienesXaos TellamasNOMBREAPELLIDOytienesXaos

Conunanicaaccin definidaenelcontrolador

1.Qu sucedealinvocarlasiguienteURL? ejercicioR1/Miguel/Martin/TE_PONGO_LETRAS_DONDE_ESPERABAS_NUMERO

2.Qu sucedealinvocaracualquieradelassiguientesURLs? ejercicioR1/ (Terminadoenbarra) ejercicioR1/Miguel/Martin/ (Terminadoenbarra) ejercicioR1/Miguel/(Terminadoenbarra)

50

ROUTING:Requirements sobreplaceholders
Sinuestrocontroladornocontrola()queelparmetro$edadseanumrico,podemosencontrarsituaciones problemticas.Pero,paraqu pasaralcontroladoralgoquenonosinteresa?Mejordetectarlo antes Symfony nospermiteasegurarnos,desdeelficheroderutas,dequeelpatrnsolodebehacermatch siformadopor unoomsdgitos(\d+). Losrequirements sonexpresionesregulares.Setrata,portanto,deunmecanismo bastantepotente: idioma:en|fr|es|de
#routing.yml cursoe5Bundle_ejercicioR1: pattern:/ejercicioR1/{nombre}/{apellido}/{edad} defaults:{_controller:cursoe5Bundle:Default:ejercicioC1,nombre:MINOMBRE,apellido:MIAPELLIDO,edad:X} requirements: edad:\d+

//DefaultController.php public function ejercicioR1Action($nombre,$apellido,$edad) { return new Response('<html><body>Tellamas'.$nombre.''.$apellido.'ytienes'.$edad.'a&ntilde;os'); }

Qu sucedesiesperamosquelarutaseainvocadaporPOST,conciertainformacin,y nosllegaporGET?
51

ROUTING:Requirements demtodo
Sinuestrocontroladornocontrola()cmoseharealizadoelRequest,podemosencontrar situacionesproblemticas.Pero,paraqu pasaralcontroladoralgoquenonosinteresa?Mejor detectarloantes Symfony nospermiteasegurarnos,desdeelficheroderutas,dequeelpatrnsolodebehacermatch si elRequest seharealizadoporelmtodo deseado(GET,HEAD,POST,PUT,DELETE). Sinoseindicamtodoalguno,larutadefinidahar matchparacualquiermtodo!
#routing.yml cursoe5Bundle_ejercicioR1: pattern:/ejercicioR1/{nombre}/{apellido}/{edad} defaults:{_controller:cursoe5Bundle:Default:ejercicioC1,nombre:MINOMBRE,apellido:MIAPELLIDO,edad:X} requirements: edad:\d+ _method:GET

//DefaultController.php public function ejercicioR1Action($nombre,$apellido,$edad) { return new Response('<html><body>Tellamas'.$nombre.''.$apellido.'ytienes'.$edad.'a&ntilde;os'); }

52

ROUTING:Rutasavanzadasyparmetros
especiales
article_show: pattern:/articles/{culture}/{year}/{title}.{_format} defaults:{_controller:AcmeDemoBundle:Article:show,_format:html } requirements: culture:en|fr _format:html|rss year:\d+
Qu quiere decir esto? Esta ruta solo se matchear si: * la url empieza por /articles y contiene al menos los parmetros culture,year y title * El parmetro culture tiene valor igual a en o fr * El parmetro year est formado por ms de un dgito * El parmetro _format es opcional. De existir, su valor debe ser html o rss. Su valor (si se omite) es html

Vemos, adems, algo nuevo y muy til: el parmetro _format Podemos usar este valor para indicar el ContentType de la respuesta y devolver distintos resultados (por ejemplo, renderizar con distintos templates) para distintos valores del parmetro _format. En este sentido, por ejemplo, una peticin con _format=json se traducira en una respuesta de tipo Content Type application/json 53

ROUTING:parmetrosespeciales
Parmetros especiales (empiezan por _): _method: _controller: _format: _locale: _scheme: Determina el mtodo de la peticin (POST, GET,) Determina qu controlador se ejecutar cuando la ruta haga match Utilizado para determinar el formato de la peticin Utilizado para determinar los valores de locale de la sesin Si se settea con https fuerza a que se use siempre HTTPS (al generar las rutas tambin se generarn con https, y si hacemos un request http, automticamente se redireccionar a https)
Como el valor de locale se almacena en la sesin del usuario, puede resultar tentador utilizar la misma URL para mostrar un mismo recurso en distintos idiomas, en funcin del valor almacenado en el locale del cliente. Por ejemplo, www.misitio.com/contact podra mostrar el contenido el ingls para un usuario y francs en otro. Esto supone una violacin de principio bsico de la Web: un mismo recurso debe devolver el mismo recurso con independencia del usuario. Adems, qu idioma debera ser indexado por los crawlers de buscadores? Es ms conveniente incluir el valor de locale en la URL. Al utilizar el parmetro especial _locale, cuando el usuario visite la URI /de/contact, el valor de locale ser automticamente setteado a de en la sesin del usuario ($session>setLocale('fr');) A partir de ese momento se puede usar el valor de locale para crear rutas a otras pginas traducidas en la

aplicacin.

contact: pattern:/{_locale}/contact defaults:{_controller:AcmeDemoBundle:Contact:index,_locale:en} requirements: _locale:en|fr|de 54

Parapoderhacerlosejerciciosde Routing quevienenacontinuacin, necesitamossaberunpocosobreel controlador Pasamosapgina64

ROUTING:ejercicioR2
(0) Borrar la cach del navegador, informacin de sesiones, etc (firefox: SHIFT+CTRL+SUPR). Al visitar /ejercicioR2 se debe mostrar el valor de sesin locale actual Alvisitar/en/ejercicioR2 sedebemostrarelvalordelasesinlocale yCAMBIARelmismoa en Alvisitar/de/ejercicioR2 sedebemostrarelvalordelasesinlocale yCAMBIARelmismoa de Alvisitar/fr/ejercicioR2 sedebemostrarelvalordelasesinlocale yCAMBIARelmismoa fr Alvisitar/es/ejercicioR2 sedebemostrarelvalordelasesinlocale yCAMBIARelmismoa es
(PISTA:RECUERDAlasSESIONES(explicadasenelcaptuloControlador)y PISTA2:$this>getRequest()>getSession()>getLocale())

Msavanzado:intentamostrarlabanderaasociadaallocale actual

OJO con estas cosas!


http://es.wikipedia.org/wiki/Uniform_Resource_Identifier

Lectura interesante:
http://damnhandy.com/2007/11/19/urivsurlwhatsthedifference/

56

ROUTING:visualizacin&debugging

Comando para mostrar informacin sobre una ruta (nombreruta) o todas, en ausencia de parmetro

php app/console router:debug [nombreruta]

57

ROUTING:generacindeURLs (desdeelcontrolador)
En realidad, el sistema de rutas es un mapeado bidireccional: - De URL a controlador+parmetros [match] //enelcontrolador... $params =$router>match('/blog/myblogpost'); //array('slug'=>'myblogpost','_controller'=>'AcmeBlogBundle:Blog:show')

De controlador+parmetros a URL [generate] RUTA RELATIVA (por defecto!) //enelcontrolador...(class XXXextends Controller) $uri =$this>get('router')>generate('blog_show',array('slug'=>'myblogpost')); ///blog/myblogpost
Tambin funciona desde Javascript utilizando FOSJsRoutingBundle: https://github.com/FriendsOfSymfony/FOSJsRoutingBundle var url = Routing.generate('blog_show', { "slug": 'my-blog-post});

RUTA ABSOLUTA (tercer parmetro con valor = true) //enelcontrolador...(class XXXextends Controller) $uri =$this>get('router')>generate('blog_show',array('slug'=>'myblogpost'),true); //http://www.misitio.com/blog/myblogpost //elHOSTconelquegeneraURLs absolutasesaqulalquesehareferenciadoenelRequest (lo tomade//laserver information dePHP) //Parascriptsdesdelneadecomandoshayquesettearlo explcitamente: //$request>headers>set(HOST,www.misitio.com);

58

ROUTING:generate ydefaults +EJ


Existe un comportamiento curioso. Por ejemplo, para el /hello/{nombre}, habamos definido en routing.yml cursoe5Bundle_helloworld: pattern:/hello/{nombre} defaults: La informacin completa de la ruta es:
[cursoe5Bundle_helloworld]=>Symfony\Component\Routing\Route Object ( [pattern:Symfony\Component\Routing\Route:private]=>/curso/hello/{nombre} [defaults:Symfony\Component\Routing\Route:private]=>Array ( [_controller]=>curso\e5Bundle\Controller\DefaultController::helloAction [nombre]=>SINNOMBRE ) [requirements:Symfony\Component\Routing\Route:private]=>Array ( ) [options:Symfony\Component\Routing\Route:private]=>Array ( [compiler_class]=>Symfony\Component\Routing\RouteCompiler ) [compiled:Symfony\Component\Routing\Route:private]=> )

{_controller:cursoe5Bundle:Default:hello,nombre:SINNOMBRE}

Si generamos una ruta hacia ese sitio con valor en el parmetro distinto al valor por defecto $router>generate(cursoe5Bundle_helloworld,array(nombre =>Miguel)); //produce:/curso/hello/Miguel Sin embargo, si generamos con los valores por defecto, tendremos $router>generate(cursoe5Bundle_helloworld,array(nombre =>SINNOMBRE)); //produce:/curso/hello

59

ROUTING:ejercicioR3
CLASE ROUTER: http://api.symfony.com/2.0/Symfony/Component/Routing/Router.html CLASE ROUTE: http://api.symfony.com/2.0/Symfony/Component/Routing/Route.html CLASE ROUTE COLLECTION: http://api.symfony.com/2.0/Symfony/Component/Routing/RouteCollection.html

En /ejercicioR3 generaremos links a algunas de las pginas creadas. En lugar de hacerlo como en el caso anterior (generbamos el link completo en el controlador) nos limitaremos a crear un array con valores de links del tipo: $links=array(/enlace0,/enlace1); Utiliza la plantilla siguiente (que debes guardar como Resources/views/Default/ejercicioR3.html.twig)
<!DOCTYPEhtml PUBLIC"//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"dir="ltr"lang="enUS"xmlns:fb="http://www.facebook.com/2008/fbml" xmlns:addthis="http://www.addthis.com/help/apispec"> <head> <title>CursoSymfony</title> </head> <body> {%if links%} {%for linkinlinks%} <li><ahref="{{link|e }}">{{link|e }}</a></li> {%endfor %} {%else %} Nolinks,noparty! {%endif %} </body> </html>

Utiliza esta lnea para devolver Response renderizando con plantilla return $this>render('cursoe5Bundle:Default:ejercicioR3.html.twig',array('links'=>$rutas));

60

ROUTING:ejercicioR4 (desdeelcontrolador)
(2) Mejorar el cdigo para que se muestren los nombres de los links en lugar de los valores a los que apuntan Renderizar con la siguiente plantilla ejercicioR3.html.twig: <!DOCTYPEhtml PUBLIC"//W3C//DTDXHTML1.0Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"dir="ltr"lang="enUS" xmlns:fb="http://www.facebook.com/2008/fbml"xmlns:addthis="http://www.addthis.com/help/api spec"> <head> <title>CursoSymfony</title> </head> <body> {%if links%} {%for key,value inlinks%} <li><ahref="{{value|e }}">{{key|e }}</a></li> {%endfor %} {%else %} Nolinks,noparty! {%endif %} </body> </html>

61

ROUTING:ejercicioR5
CLASEROUTER:http://api.symfony.com/2.0/Symfony/Component/Routing/Router.html CLASEROUTE:http://api.symfony.com/2.0/Symfony/Component/Routing/Route.html CLASEROUTECOLLECTION:http://api.symfony.com/2.0/Symfony/Component/Routing/RouteCollection.html

(3) Mejorar el cdigo para que se generen los nombres, urls y valores por defecto de forma automtica a partir del catlogo de rutas definidas en nuestro proyecto. nicamente tener en cuenta aqullas rutas que comiencen con /curso. Renderizar con la siguiente plantilla ejercicioR5.html.twig: <!DOCTYPEhtml PUBLIC"//W3C//DTDXHTML1.0Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"dir="ltr"lang="enUS" xmlns:fb="http://www.facebook.com/2008/fbml"xmlns:addthis="http://www.addthis.com/help/api spec"> <head> <title>CursoSymfony</title> </head> <body> {%if links%} {%for key,value inlinks%} <li><ahref="{{value|e }}">{{key|e }}</a></li> {%endfor %} {%else %} Nolinks,noparty! {%endif %} {%if outputis defined %} <pre>{{output|raw }}</pre> {%endif %} </body> </html>

62

ROUTING:GeneracindeURLs con querystring


$router>generate(blog,array(page =>2,cat =>Symfony)); //blog/2?category=Symfony

63

CONTROLLER (CONTROLADOR)
TEORA:
Definicinymecanismo Controladorbsico Parmetros BaseController yejemplos Renderizadodeplantillas(invocacinavista) Otrosservicios Mensajesflash Manejodeerrores Manejodesesiones ObjetoResponse

64

CONTROLADOR
Controlador =funcinquetomainformacindelapeticinHTTPyconstruyeuna respuesta(XML,HTML,imagen,error404,etc).Contienelalgicaquelaaplicacin necesitapararenderizar elcontenidodeunapgina:lecturadelapeticin,cargar informacindelaBD,enviarunemailogestionarsesionesdeusuario.
use Symfony\Component\HttpFoundation\Response; public function helloAction() { return new Response('Helloworld!'); }

Ejemplos: ControladorA:preparaResponse conelcontenidodelahomepage. ControladorB:leeunparmetro(id)delRequest,consultaalaBDelusername asociadoaesaIDygenerala Response.Sinoexisteusername asociadoaeseid,produceunaRespuestacon404(noencontrado). ControladorC:leelainformacindeloscamposdelformulariodelRequest, almacenalosresultadosenlaBD, mandaunemailalwebmasteryproduceunaResponse mostrndolealclienteelmensajeMuchasgraciaspor rellenarelformulario.
65

CONTROLADOR:Mecanismo
REQUEST

FRONTCONTROLLER
(app.php oapp_dev.php)

ElRouterleeinformacinsobrela peticin(pej URI),encuentrala rutaasociadaadichainformaciny leeelparmetro_controller asociadoadicharuta.

Ejecucindel

CONTROLADOR
asociadoaesaruta

MODELO

TEMPLATING
creacinde Respuesta. 66

Normalmente,uncontroladoresunmtodosimpledentrodeunobjetocontrolador.Tambinselesconoceporacciones. //src/Acme/HelloBundle/Controller/HelloController.php namespace Acme\HelloBundle\Controller; use Symfony\Component\HttpFoundation\Response; class HelloController { Secomienzadeclarandoelnamespace (PHP5.3)eimportandolaclase Response. Elnombredelaclasesedefinecomoelnombredelaclasedelcontrolador seguidodelapalabraController.Deestaformasepermitequesean referenciadosporlaprimeraparte(Hello)delnombreenlaconfiguracin derutas. CadaaccindelaclasedelcontroladorsenombraconelsufijoAction yse referenciaenelficherodeconfiguracinderutasporelnombredela accin(index). Elparmetro$name seconocecomoplaceholder (msdetallesencaptulo derouting). return new Response('<html><body>Hello '.$name.'! </body></html>'); } } Porltimo,segeneralarespuesta.

CONTROLADORBsico

public function indexAction($name) {

#app/config/routing.yml hello: pattern:/hello/{name} defaults:{_controller:AcmeHelloBundle:Hello:index } URL:/hello/ryan ejecutarlaaccinHelloController::indexAction()ypasarelvalorryan comoparmetro$name

67

CONTROLADOR:Parmetros
<?php //src/Acme/HelloBundle/Controller/HelloController.php namespace Acme\HelloBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class HelloController extends Controller { public function indexAction($first_name,$last_name,$color) { //... } }
Elordendelosargumentosen elcontroladorNOIMPORTA. Loques importaesquetodos losparmetrosdefinidosenel controladorestnpresentesen elficheroderutas* Notodoslosargumentosdela rutadebenestarenel controlador**

#app/config/routing.yml hello: pattern:/hello/{first_name}/{last_name} defaults:{_controller:AcmeHelloBundle:Hello:index,color:green } URL:/hello/miguel/martin Sehaceelmatching delarutaylasvariablesdeplaceholder sejuntanalosdefaults paracrearunarraydeparmetrosdisponibleenelcontrolador.

68

CONTROLADOR:ObjetoResponse
Lo nico obligatorio para un controlador es devolver un objeto Response.
http://api.symfony.com/2.0/Symfony/Component/HttpFoundation/Response.html //createasimpleResponsewitha200statuscode(the default) $response =new Response('Hello'.$name,200); //createaJSONresponsewitha200statuscode $response =new Response(json_encode(array('name'=>$name))); $response>headers>set('ContentType','application/json');

Existe el objeto HeaderBag con varios mtodos que permiten leer y modificar las cabeceras del Response.
http://api.symfony.com/2.0/Symfony/Component/HttpFoundation/HeaderBag.html

69

CONTROLADOR:Parmetros
Se puede disponer del objeto Request completo. Especialmente til para formularios. Existen multitud de mtodos definidos para el objeto Request:
http://api.symfony.com/2.0/Symfony/Component/HttpFoundation/Request.html

use Symfony\Component\HttpFoundation\Request; public function updateAction(Request$request) { $form =$this>createForm(...); $form>bindRequest($request); //... }

$request =$this>getRequest(); $request>isXmlHttpRequest();//is it an Ajaxrequest? $request>getPreferredLanguage(array('en','fr')); $request>query>get('page');//get a$_GETparameter $request>request>get('page');//get a$_POSTparameter

70

CONTROLADOR:Class BaseController
Symfony viene con una clase llamada Controller que incluye facilidades para desarrollar las tareas ms comunes de los controladores y facilitar el acceso a los recursos necesarios: http://api.symfony.com/2.0/Symfony/Bundle/FrameworkBundle/Controller/Controller.html Haciendo un extend de la clase Controller, podemos utilizar diversos mtodos.

//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>'); } }

71

CONTROLADOR:Class BaseController
Veamos algunas de las tareas habituales de un controlador, apoyadas por funciones de la clase Controller.
//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() { //REDIRECTING: //generateUrl crealaURLparaunarutadefinida. //elmtodoredirect realizaunaredireccin302(temporal). //parared.301,indicarloenelsegundoparmetro:$this>redirect($this>generateUrl('homepage'),301); //LarutaindicadaalafuncingenerateUrl DEBECOINCIDIRINTEGRAMENTECONLODECLARADOENFICHDERUTAS! return $this>redirect($this>generateUrl('cursoe5Bundle_homepage '));
cursoe5Bundle_homepage: pattern:/ defaults:{_controller:cursoe5Bundle:Default:index }

//FORWARDING: //Tambinsepuededelegarelcontrolenotrocontrolador,enlugarderedireccionarlaURLdelcliente. //Elmtodoforward devuelveunobjetoResponse,resultadodeejecutarelcontroladorespecfo. $response =$this>forward('AcmeHelloBundle:Hello:fancy',array( 'name'=>$name, //AcmeHelloBundle/Controller/HelloController 'color'=>'green' )); public function fancyAction($name,$color){ //modificar$responsealgustoodevolverlodirectamente... return $response; } }
//...create and return aResponseobject }

72

CONTROLADOR:Class BaseController

73

CONTROLADOR:Renderizadode plantillas(generarVISTA)
Otra de las tareas comunes es generar la salida de nuestra aplicacin (normalmente, formato HTML). El mtodo renderView() devuelve el contenido de haber renderizado una plantilla (template). Con este contenido, se puede devolver la respuesta.
$content =$this>renderView('AcmeHelloBundle:Hello:index.html.twig',array('name'=>$name)); //llamadaarenderizadode:Resources/views/Hello/index.html.twig return new Response($content);

Escrito de forma ms compacta: return $this>render('AcmeHelloBundle:Hello:index.html.twig',array('name'=>$name));

Internamente: $templating =$this>get('templating'); $content =$templating>render('AcmeHelloBundle:Hello:index.html.twig',array('name'=>$name));

74

Ejercicios
En/inforequest mostrarlainformacindel Request (Consejo:usaprint_r($VAR,1) y<pre>)

En/redirect redirigira http://www.google.es

CONTROLADOR:Otrosservicios
En ocasiones es interesante acceder a servicios de otras clases utilizando el mtodo get. Para listar todas los existentes, ejecutar: php app/console container:debug

Algunosdelosquesuelenutilizarsemsamenudo:

$request =$this>getRequest(); $templating =$this>get('templating'); $router=$this>get('router'); $mailer =$this>get('mailer');

76

CONTROLADOR:Manejodeerroresy pginas404
Cuando el recurso solicitado no se encuentra disponible, se debe generar la respuesta HTTP404. Al hacer extends de la clase Controller, procedemos asi:
public function indexAction() { $product =//retrievethe objectfromdatabase if (!$product){ throw $this>createNotFoundException('Theproductdoesnotexist'); } return $this>render(...); }

Del mismo modo, se pueden lanzar excepciones 500:


throw new \Exception(Algohaidomal...!');

Y se pueden personalizar las pginas de error:


http://symfony.com/doc/current/cookbook/controller/error_pages.html

77

Ejercicio:generarException
En/division obtenerdosnmerosaleatorios(numeradorentre0y10, denominadorentre0y2) Realizarladivisinentreellos Contemplarlaposibilidaddequeeldenominadorseaceroygenerar excepcinentalcaso. AYUDA:http://php.net/manual/es/function.rand.php

CONTROLADOR:Manejodesesiones
Symfony proporciona un objeto de sesiones para almacenar informacin del usuario entre peticiones. $session =$this>getRequest()>getSession(); //storeanattributeforreuseduringalateruserrequest $session>set('foo','bar'); //inanothercontrollerforanotherrequest $foo =$session>get('foo'); //setthe userlocale $session>setLocale('fr');

79

CONTROLADOR:EJERCICIO Manejodesesiones
En/cuantasveces Deberesidiruncontadorquenosindiquecuntasvecesnoshemosconectadoadicha pgina.

80

CONTROLADOR:Manejodecookies
//paralageneracindeCookies... useSymfony\Component\HttpFoundation\Cookie; useSymfony\Component\BrowserKit\Request;

/*Generaunacookiellamada'COOKIE_MIGUEL'*/ public function generaCookieAction(){ $mi_cuki =new Cookie('COOKIE_MIGUEL',$value ="valor",$expire=0,$path ='/',$domain =null,$secure =false,$httpOnly =true); //opc1:renderizarsintemplates $response=new Response('<html><head><title>GeneroCookie</title></head><body>Enmi respuestavalacookie...</body></html>'); $response>headers>setCookie($mi_cuki); return $response;

//opc2:renderizarcontemplates //$response=new Response(); //$response>headers>setCookie(new Cookie(cookie_name,cookie_value)); //return $this>render(template_path,array(..template_parameters),$response); }

81

CONTROLADOR:Manejodecookies II
/*Leelacookiellamada'COOKIE_MIGUEL'siexiste,omuestratodaslascookies public function leeCookieAction(){ $request =$this>get('request'); $cookies =$request>cookies; if ($cookies>has('COOKIE_MIGUEL')){ return new Response("Encontrada'COOKIE_MIGUEL':<pre>".print_r($cookies >get('COOKIE_MIGUEL'),1)."</pre>"); } return new Response("<pre>".print_r($cookies,1)."</pre>"); } */

82

CONTROLADOR:Mensajesflash
Tambin puedes almacenar pequeos mensajes en la sesin del usuario. Estos mensajes estarn disponibles nicamente en la siguiente peticin. Esto es til al procesar formularios. En este ejemplo se procesa el formulario, se muestra este mensaje flash y se realiza la redireccin. Para que este mensaje aparezca en la pantalla del usuario, deber estar contemplado en la plantilla.

{%if app.session.hasFlash('notice')%} public function updateAction() { $form =$this>createForm(...); $form>bindRequest($this>getRequest()); if ($form>isValid()){ //dosomesortofprocessing <div class="flashnotice"> {{ app.session.flash('notice')}} </div> {%endif %}

$this>get('session')>setFlash('notice','Yourchangesweresaved!'); return $this>redirect($this>generateUrl(...)); } return $this>render(...); }

83

Potrebbero piacerti anche