"(My) Best Pratices in Symfony" è una parte delle slides utilizzate durante un Train to Symfony2 organizzato in una web agency nel Giugno 2014.
Non è un elenco di best practices in senso stretto, sono semplicemente spunti dai quali partire per affrontare alcune problematiche pratiche.
Scopri su http://traintosymfony.com cos'è Train to Symfony, e quanto possa essere utile alla tua azienda.
I test unitari sono sempre più utilizzati per verificare la correttezza del codice che scriviamo.
Ci si trova però a volte di fronte a codice scritto in maniera poco "disaccoppiata". Questo può impedirci di sostituire a runtime dei Dependent-on Object con dei Mock Object o degli Stub. Nel talk descriverò un plugin scritto per symfony (ma utilizzabile anche in altri ambiti) che permette di sostituire delle classi a runtime ridefinendole e configurandole all'interno dei test, creando un ambiente che isola il codice da verificare.
Il talk prevederà degli esempi pratici di utilizzo dello strumento descritto.
Algoritmi e Programmazione Avanzata - Esercizi propedeuticiSergio Porcu
Argomenti trattati:
- inserimento di un elemento in un vettore
- visualizzazione di un numero binario di n bit
- inserzione in lista ordinata
- fusione di array
- simulazione del gioco della vita
I test unitari sono sempre più utilizzati per verificare la correttezza del codice che scriviamo.
Ci si trova però a volte di fronte a codice scritto in maniera poco "disaccoppiata". Questo può impedirci di sostituire a runtime dei Dependent-on Object con dei Mock Object o degli Stub. Nel talk descriverò un plugin scritto per symfony (ma utilizzabile anche in altri ambiti) che permette di sostituire delle classi a runtime ridefinendole e configurandole all'interno dei test, creando un ambiente che isola il codice da verificare.
Il talk prevederà degli esempi pratici di utilizzo dello strumento descritto.
Algoritmi e Programmazione Avanzata - Esercizi propedeuticiSergio Porcu
Argomenti trattati:
- inserimento di un elemento in un vettore
- visualizzazione di un numero binario di n bit
- inserzione in lista ordinata
- fusione di array
- simulazione del gioco della vita
This document provides an introduction and overview of Symfony, including its origins, features, architecture, and basic usage. Key points covered include Symfony's MVC structure, routing, forms, validation, ORM/database access, caching, plugins, and use of the command line interface. The presentation aims to explain Symfony's core concepts and capabilities in under 15 minutes.
Symony2 A Next Generation PHP FrameworkRyan Weaver
A mixture of architecture and hands-on examples, this presentation takes you through the killer features of Symfony2, how it's so decoupled, and how you can get started developing in it.
As an added bonus, a number of new standalone PHP libraries and tools are mentioned at the end.
This document discusses PHP, Symfony frameworks, and the software development lifecycle. It provides background on Pierre Joye and his work with PHP and Microsoft. It also briefly discusses features of PHP like closures, intl, phar, and enchant. Additionally, it notes statistics on PHP popularity and compares it to other languages. Finally, it discusses Symfony framework features like focus on business needs and enforcing clean code.
This document provides an introduction and overview of Symfony, including its origins, features, architecture, and basic usage. Key points covered include Symfony's MVC structure, routing, ORM/database access, caching, plugins, and use of the command line interface. The presentation outlines Symfony's core components and how they work together to build database-driven web applications.
The document discusses internationalization (i18n) and localization (l10n) features in the symfony framework. It covers setting the user's culture, outputting localized data, storing localized text in the database, and translating the user interface. Key aspects include determining the culture, using i18n helpers to format output for the user's culture, creating localized database schemas, and translating templates using dictionary files.
Fare con Zend Framework 2 ciò che facevo con ZF1Steve Maraspin
Introduzione a Zend Framework 2 per chi proviene da Zend Framework 1, tenuta allo Zend Framework Day di Milano del 01/02/2013. Introduzione alle nuove caratteristiche e pattern architetturali di ZF2
Zend Framework 2 non è l'evoluzione di ZF, ma un progetto nuovo: il codice è stato riscritto e poche sono le parti in comune con la versione precedente. Lo sviluppatore abituato a ZF1 non ha vita facile, ed è fondato il timore di dover imparare tutto da capo. In questo talk vediamo come cambiare le vecchie abitudini di sviluppatori ZF1, per sfruttare al meglio le potenzialità del nuovo strumento. Attraverso esempi concreti, in cui vedremo all'opera i nuovi pattern e le best practice, mostriamo come - partendo con il piede giusto - il passaggio a ZF2 possa essere meno traumatico del previsto. Il talk è orientato soprattutto a chi già conosce ZF1, ma gli argomenti affrontati possono essere utili anche a chi si avvicina a ZF per la prima volta.
jQuery è un framework javascript che permette di semplificare la scrittura di codice javascript, facilitando l'iterazione con gli elementi della pagina (controlli, stili, eventi, animazioni, ...), e permettendo di aumentare la user experience delle applicazioni, riducendone al tempo stesso la complessità di scrittura. Vista la sua diffusione e potenza, è stato anche incluso nei project templete di Visual Studio. In questa sessione vedremo cos'è jQuery, e scopriremo le potenzialità e funzionalità che offre, verificando se il motto "write less do more" sia vero o meno.
Come portare il profiler di symfony2 in drupal8Luca Lusso
Molti progetti PHP open source hanno adottato Symfony2 come base per la loro prossima versione, tra questi c'è anche il CMS Drupal (http://drupal.org). In questo talk vedremo come scrivere un modulo per Drupal8 in modo da sfruttare il più possibile il suo nuovo motore Symfony2, dall'integrazione con il service container alla gestione degli eventi, dal routing a Twig. Verrà usato come esempio il modulo webprofiler (http://drupal.org/project/webprofiler) per dimostrare come un bundle per Symfony2 possa essere trasformato in un modulo per Drupal8 e integrato facilmente nel sistema.
Topic: Symfony
Language: italian (english version soon)
First of three presentations shown during the first edition of the Train to Symfony
Verona 13/14 April 2013
http://traintosymfony.com
http://twitter.com/TrainToSymfony
Emanuele Gaspari
https://twitter.com/inmarelibero
Levate l'ancora! Rotte senza problemi con ZF2Diego Drigani
Introduzione al routing di Zend Framework 2, tenuta allo Zend Framework Day del 01/02/2013 a Milano.
Avere URL pulite e ben strutturate è molto importante, sia da un punto di vista SEO, che di organizzazione delle proprie API. In Zend Framework 2 è il router ad occuparsi di gestire le richieste http, di delegare l'esecuzione delle stesse all'opportuno frammento di codice sorgente, e quindi di estrarne gli eventuali parametri. Questo talk introduce le potenti funzionalità del nuovo sistema di routing di ZF2. Grazie a esempi reali (con gestione di richiestte http, ma anche CLI), sarete in grado di utilizzare il nuovo router di ZF2 in tutta la sua flessibilità.
Non Conventional Android Programming (Italiano)Davide Cerbo
Android è il nuovo sistema operativo open source per dispositivi mobili e realizzato da Google che si è posta la missione di rendere l’internet mobile accessibile a tutti tramite dispositi a basso costo.
Durante questo intervento mostrerò come sia possibile sviluppare per questo sistema operativo (e non solo) senza l’utilizzo di Java e come sia possibile utilizzare una versione light di Spring Framework nelle applicazioni mobili.
Il Symfony CMF è maturo e ci permette di creare le basi per un content manager integrandolo direttamente in applicazioni Symfony nuove o già esistenti.
This document provides an introduction and overview of Symfony, including its origins, features, architecture, and basic usage. Key points covered include Symfony's MVC structure, routing, forms, validation, ORM/database access, caching, plugins, and use of the command line interface. The presentation aims to explain Symfony's core concepts and capabilities in under 15 minutes.
Symony2 A Next Generation PHP FrameworkRyan Weaver
A mixture of architecture and hands-on examples, this presentation takes you through the killer features of Symfony2, how it's so decoupled, and how you can get started developing in it.
As an added bonus, a number of new standalone PHP libraries and tools are mentioned at the end.
This document discusses PHP, Symfony frameworks, and the software development lifecycle. It provides background on Pierre Joye and his work with PHP and Microsoft. It also briefly discusses features of PHP like closures, intl, phar, and enchant. Additionally, it notes statistics on PHP popularity and compares it to other languages. Finally, it discusses Symfony framework features like focus on business needs and enforcing clean code.
This document provides an introduction and overview of Symfony, including its origins, features, architecture, and basic usage. Key points covered include Symfony's MVC structure, routing, ORM/database access, caching, plugins, and use of the command line interface. The presentation outlines Symfony's core components and how they work together to build database-driven web applications.
The document discusses internationalization (i18n) and localization (l10n) features in the symfony framework. It covers setting the user's culture, outputting localized data, storing localized text in the database, and translating the user interface. Key aspects include determining the culture, using i18n helpers to format output for the user's culture, creating localized database schemas, and translating templates using dictionary files.
Fare con Zend Framework 2 ciò che facevo con ZF1Steve Maraspin
Introduzione a Zend Framework 2 per chi proviene da Zend Framework 1, tenuta allo Zend Framework Day di Milano del 01/02/2013. Introduzione alle nuove caratteristiche e pattern architetturali di ZF2
Zend Framework 2 non è l'evoluzione di ZF, ma un progetto nuovo: il codice è stato riscritto e poche sono le parti in comune con la versione precedente. Lo sviluppatore abituato a ZF1 non ha vita facile, ed è fondato il timore di dover imparare tutto da capo. In questo talk vediamo come cambiare le vecchie abitudini di sviluppatori ZF1, per sfruttare al meglio le potenzialità del nuovo strumento. Attraverso esempi concreti, in cui vedremo all'opera i nuovi pattern e le best practice, mostriamo come - partendo con il piede giusto - il passaggio a ZF2 possa essere meno traumatico del previsto. Il talk è orientato soprattutto a chi già conosce ZF1, ma gli argomenti affrontati possono essere utili anche a chi si avvicina a ZF per la prima volta.
jQuery è un framework javascript che permette di semplificare la scrittura di codice javascript, facilitando l'iterazione con gli elementi della pagina (controlli, stili, eventi, animazioni, ...), e permettendo di aumentare la user experience delle applicazioni, riducendone al tempo stesso la complessità di scrittura. Vista la sua diffusione e potenza, è stato anche incluso nei project templete di Visual Studio. In questa sessione vedremo cos'è jQuery, e scopriremo le potenzialità e funzionalità che offre, verificando se il motto "write less do more" sia vero o meno.
Come portare il profiler di symfony2 in drupal8Luca Lusso
Molti progetti PHP open source hanno adottato Symfony2 come base per la loro prossima versione, tra questi c'è anche il CMS Drupal (http://drupal.org). In questo talk vedremo come scrivere un modulo per Drupal8 in modo da sfruttare il più possibile il suo nuovo motore Symfony2, dall'integrazione con il service container alla gestione degli eventi, dal routing a Twig. Verrà usato come esempio il modulo webprofiler (http://drupal.org/project/webprofiler) per dimostrare come un bundle per Symfony2 possa essere trasformato in un modulo per Drupal8 e integrato facilmente nel sistema.
Topic: Symfony
Language: italian (english version soon)
First of three presentations shown during the first edition of the Train to Symfony
Verona 13/14 April 2013
http://traintosymfony.com
http://twitter.com/TrainToSymfony
Emanuele Gaspari
https://twitter.com/inmarelibero
Levate l'ancora! Rotte senza problemi con ZF2Diego Drigani
Introduzione al routing di Zend Framework 2, tenuta allo Zend Framework Day del 01/02/2013 a Milano.
Avere URL pulite e ben strutturate è molto importante, sia da un punto di vista SEO, che di organizzazione delle proprie API. In Zend Framework 2 è il router ad occuparsi di gestire le richieste http, di delegare l'esecuzione delle stesse all'opportuno frammento di codice sorgente, e quindi di estrarne gli eventuali parametri. Questo talk introduce le potenti funzionalità del nuovo sistema di routing di ZF2. Grazie a esempi reali (con gestione di richiestte http, ma anche CLI), sarete in grado di utilizzare il nuovo router di ZF2 in tutta la sua flessibilità.
Non Conventional Android Programming (Italiano)Davide Cerbo
Android è il nuovo sistema operativo open source per dispositivi mobili e realizzato da Google che si è posta la missione di rendere l’internet mobile accessibile a tutti tramite dispositi a basso costo.
Durante questo intervento mostrerò come sia possibile sviluppare per questo sistema operativo (e non solo) senza l’utilizzo di Java e come sia possibile utilizzare una versione light di Spring Framework nelle applicazioni mobili.
Il Symfony CMF è maturo e ci permette di creare le basi per un content manager integrandolo direttamente in applicazioni Symfony nuove o già esistenti.
How create a single page apps using html5 and javascript Stefano Marchisio
Create a html5/javascript apps with mvc/ajax using knockout.js/mvvm. Javascript to IQueryable is a framework that allows you to write a simple query in javascript client side and then execute it server side with EntityFramework or a linq provider that implement IQueryable. On the server is used "Dynamic Expressions and Queries in LINQ by Microsoft" to compose dynamically your query. In this way you can create a grid with filter, paging and sort functions. There is also support for: mvc3 unobtrusive jquery validation and jquery mobile/phonegap. - http://Javascriptiqueryable.codeplex.com - http://www.youtube.com/watch?v=qjwyKwsXHKs - http://www.linqitalia.com/articoli/entity-framework/sfruttare-javascript-eseguire-query-linq-server-tramite-dynamic-iqueryable.aspx
Topic: Symfony
Language: italian (english version soon)
First of three presentations shown during the first edition of the Train to Symfony
Verona 13/14 April 2013
http://traintosymfony.com
http://twitter.com/TrainToSymfony
Emanuele Gaspari
https://twitter.com/inmarelibero
5. Train to Symfony
5http://traintosymfony.comIl codice nel posto giusto
Dove scrivo il codice che risolve questo problema?
Quanti controller posso creare?
È normale creare tanti servizi?
Ho codice che si ripete in alcuni controller, è normale?
Come chiamo i templates TWIG?
Il progetto del collega è strutturato diversamente dal mio, come mai?
7. Train to Symfony
7http://traintosymfony.comIl codice nel posto giusto
Symfony propone già delle convenzioni:
●
struttura delle cartelle di un progetto
●
struttura delle cartelle di un bundle
●
configurazione dei bundles
●
routing
●
composer
●
[...]
10. Train to Symfony
10http://traintosymfony.comIl codice nel posto giusto
controller
primo punto in cui verrebbe da mettere codice
forse non è il posto giusto:
●
se mi servirà in altri punti dell'applicazione
●
se posso delegare della logica in un servizio (es.
mandare un'email)
11. Train to Symfony
11http://traintosymfony.comIl codice nel posto giusto
/**
* @Route(“/{category_id}/{product_id}”)
*/
public function showAction($category_id, $product_id)
{
$em = $this->getDoctrine()->getManager();
$category = $em->getRepository('FooBarBundle:Category')->find($category_id);
if (!$category) { throw $this->createNotFoundException('Unable to find Category.'); }
$product = $em->getRepository('FooBarBundle:Product')->find($product_id);
if (!$product) { throw $this->createNotFoundException('Unable to Product.'); }
if (!$product->isInCategory($category)) {
throw new HTTPException(500, “Product does not belong to Category {$category}”);
}
[...]
}
/**
* @Route(“/{category_id}/{product_id}”)
*/
public function showAction($category_id, $product_id)
{
$em = $this->getDoctrine()->getManager();
$category = $em->getRepository('FooBarBundle:Category')->find($category_id);
if (!$category) { throw $this->createNotFoundException('Unable to find Category.'); }
$product = $em->getRepository('FooBarBundle:Product')->find($product_id);
if (!$product) { throw $this->createNotFoundException('Unable to Product.'); }
if (!$product->isInCategory($category)) {
throw new HTTPException(500, “Product does not belong to Category {$category}”);
}
[...]
}
Il controller lancia eccezioni
12. Train to Symfony
12http://traintosymfony.comIl codice nel posto giusto
/**
* @Route(“/{category_id}/{product_id}”)
*/
public function showAction($category_id, $product_id)
{
// throws exceptions
$this->container->get('url_checker')->checkProductUrl($product_id, $category_id);
[...]
}
/**
* @Route(“/{category_id}/{product_id}”)
*/
public function showAction($category_id, $product_id)
{
// throws exceptions
$this->container->get('url_checker')->checkProductUrl($product_id, $category_id);
[...]
}
Cerco di delegare più logica possibile ai servizi
14. Train to Symfony
14http://traintosymfony.comIl codice nel posto giusto
entity
logica che opera su un singolo oggetto
funzioni che operano su entity collegate
funzioni che formattano uno o più campi
class Product {
public function getFullPrice() {
}
public function getSpecialPrice() {
}
}
class Product {
public function getFullPrice() {
}
public function getSpecialPrice() {
}
}
16. Train to Symfony
16http://traintosymfony.comIl codice nel posto giusto
class ContactType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('email', 'email', array(
'label' => 'Email',
'attr' => array('placeholder' => 'Il tuo indirizzo email'),
'constraints' => array(
new Email(array('message' => 'Inserisci un indirizzo email valido.'))
)
))
->add('message', 'textarea', array(
'label' => 'Messaggio',
'constraints' => array(
new NotBlank(array('message' => 'Inserisci un messaggio.')),
)
));
}
public function getName() {
return 'foo_barbundle_contact';
}
}
class ContactType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('email', 'email', array(
'label' => 'Email',
'attr' => array('placeholder' => 'Il tuo indirizzo email'),
'constraints' => array(
new Email(array('message' => 'Inserisci un indirizzo email valido.'))
)
))
->add('message', 'textarea', array(
'label' => 'Messaggio',
'constraints' => array(
new NotBlank(array('message' => 'Inserisci un messaggio.')),
)
));
}
public function getName() {
return 'foo_barbundle_contact';
}
}
# src/Foo/BarBundle/Form/ContactType.php
17. Train to Symfony
17http://traintosymfony.comIl codice nel posto giusto
listener
catturare eventi lanciati da Symfony, da bundles
di terze parti (FOSUserBundle), o custom
sviluppare un'architettura orientata ad eventi
difficoltà nel (ri)trovare il codice
18. Train to Symfony
18http://traintosymfony.comIl codice nel posto giusto
http://symfony.com/it/doc/current/book/internals.html#evento-kernel-response
class MyResponseListener
{
public function onKernelResponse(FilterResponseEvent $event)
{
$response = $event->getResponse();
[..]
}
}
class MyResponseListener
{
public function onKernelResponse(FilterResponseEvent $event)
{
$response = $event->getResponse();
[..]
}
}
# src/Foo/BarBundle/Listener/MyResponseListener.php
19. Train to Symfony
19http://traintosymfony.comIl codice nel posto giusto
repository
logica per estrarre informazioni dal database
non eseguire operazioni su dati già disponibili
all'interno dispongo solamente dell'entity manager
20. Train to Symfony
20http://traintosymfony.comIl codice nel posto giusto
NO
SI
$em->getRepository('FooBarBundle:Product')->findSpecialOffers();
$em->getRepository('FooBarBundle:Product')->search(array(
'q' => $q,
'special_offer' => true,
'return_qb' => true
))
$em->getRepository('FooBarBundle:Product')->findSpecialOffers();
$em->getRepository('FooBarBundle:Product')->search(array(
'q' => $q,
'special_offer' => true,
'return_qb' => true
))
$em->getRepository('FooBarBundle:Product')->isInCategory($product, $category);$em->getRepository('FooBarBundle:Product')->isInCategory($product, $category);
21. Train to Symfony
21http://traintosymfony.comIl codice nel posto giusto
template
logica estremamente limitata (if)
se un template mostra contenuto molto diverso in base a
della logica, valutare se creare diversi templates (es.
risultati di una ricerca, form contatti simili)
22. Train to Symfony
22http://traintosymfony.comIl codice nel posto giusto
servizi
accesso al container e agli altri servizi
spesso fanno da “ponte” tra controller, custom repository
e altri servizi
acquistare molta familiarità con i servizi
creare tutti quelli necessari
nome e id del servizio molto importanti
23. Train to Symfony
23http://traintosymfony.comIl codice nel posto giusto
/**
* @Route(“/catalog/{productPath}”, requirements={“productPath” = “.+”})
*/
public function showAction($productPath)
{
$catalogService = $this->container->get('catalog.service');
/*
* check if $productPath is a valid url
* throws exception
*/
$product = $catalogService->getProductFromPath($productPath);
return array(
'product' => $product
);
}
/**
* @Route(“/catalog/{productPath}”, requirements={“productPath” = “.+”})
*/
public function showAction($productPath)
{
$catalogService = $this->container->get('catalog.service');
/*
* check if $productPath is a valid url
* throws exception
*/
$product = $catalogService->getProductFromPath($productPath);
return array(
'product' => $product
);
}
# src/Foo/BarBundle/Controller/ProductController.php
example.com/catalog/category1/subcategory1/product1example.com/catalog/category1/subcategory1/product1
25. Train to Symfony
25http://traintosymfony.comIl codice nel posto giusto
use [...]
class CatalogService
{
public function __construct($em, $router) {
[...]
}
public function getProductFromPath($productPath)
{
// divide $productPath in tokens
// controlla che l'ultimo token sia lo slug di un prodotto, altrimenti lancia un'eccezione
// controlla che gli altri token siano slug di categorie, altrimenti lancia un'eccezione
// controlla che le categorie siano corrette, altrimenti lancia un'eccezione
return $product;
}
}
use [...]
class CatalogService
{
public function __construct($em, $router) {
[...]
}
public function getProductFromPath($productPath)
{
// divide $productPath in tokens
// controlla che l'ultimo token sia lo slug di un prodotto, altrimenti lancia un'eccezione
// controlla che gli altri token siano slug di categorie, altrimenti lancia un'eccezione
// controlla che le categorie siano corrette, altrimenti lancia un'eccezione
return $product;
}
}
# src/Foo/BarBundle/Service/CatalogService.php
27. Train to Symfony
27http://traintosymfony.comIl codice nel posto giusto
Devo (sempre) considerare che:
qualcun altro metterà mano al nostro codice
anch'io riprenderò in mano il mio codice
se adotto delle soluzioni standard, il mio codice
è più comprensibile
29. Train to Symfony
29http://traintosymfony.comOrganizzazione dei bundles
Quali bundles creo?
SiteBundle (FrontendBundle)
UserBundle (AdminBundle, BackendBundle)
Creo un altro bundle:
per una funzionalità particolare
se devo estenderne uno dei vendor
se mette a disposizione una funzionalità trasversale
(es. RedirectBundle in SymfonyBricks)
31. Train to Symfony
31http://traintosymfony.comOrganizzazione dei bundles
/Controller
nessun limite sul numero di controller
meglio molti controller che pochi ma molto lunghi
attenzione ai nomi dei controller, si riflettono in Resources/views
33. Train to Symfony
33http://traintosymfony.comOrganizzazione dei bundles
class BricksSiteExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new LoaderYamlFileLoader($container, new
FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}
}
class BricksSiteExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new LoaderYamlFileLoader($container, new
FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}
}
# src/Bricks/SiteBundle/DependencyInjection/BricksSiteExtension.php
*Extension.php si occupa di caricare i files di configurazione (servizi)
34. Train to Symfony
34http://traintosymfony.comOrganizzazione dei bundles
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('bricks_site');
// Here you should define the parameters that are allowed to
// configure your bundle. See the documentation linked above for
// more information on that topic.
return $treeBuilder;
}
}
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('bricks_site');
// Here you should define the parameters that are allowed to
// configure your bundle. See the documentation linked above for
// more information on that topic.
return $treeBuilder;
}
}
# src/Bricks/SiteBundle/DependencyInjection/Configuration.php
Configuration.php carica i parametri nel container
43. Train to Symfony
43http://traintosymfony.comDesign di controllers
Buone pratiche nei controller:
●
meno logica possibile
●
evitare ripetizione di codice
●
delegare il più possibile a servizi e repositories
●
valutare se una pagina = una action
(es. submit di un form)
●
lanciare eccezioni
45. Train to Symfony
45http://traintosymfony.comDesign di controllers
Al posto di:
use FooBarBundleEntityProduct;
/**
* @Route("/product/{id}")
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$product = $em->getRepository('FooBarBundle:Product')->find($id);
if (!$product) {
throw new NotFoundHttpException(“Unable to find entity”);
}
$price = $product->getPrice();
}
use FooBarBundleEntityProduct;
/**
* @Route("/product/{id}")
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$product = $em->getRepository('FooBarBundle:Product')->find($id);
if (!$product) {
throw new NotFoundHttpException(“Unable to find entity”);
}
$price = $product->getPrice();
}
# src/Foo/BarBundle/Controller/DefaultController.php
46. Train to Symfony
46http://traintosymfony.comDesign di controllers
use FooBarBundleEntityProduct;
/**
* @Route("/product/{id}")
* @ParamConverter("product", class="FooBarBundle:Product")
*/
public function showAction(Product $product)
{
$price = $product->getPrice();
[...]
}
use FooBarBundleEntityProduct;
/**
* @Route("/product/{id}")
* @ParamConverter("product", class="FooBarBundle:Product")
*/
public function showAction(Product $product)
{
$price = $product->getPrice();
[...]
}
# src/Foo/BarBundle/Controller/DefaultController.php
utilizzo @ParamConverter:
48. Train to Symfony
48http://traintosymfony.comFiles di configurazione custom
È bene tenere in ordine i file di configurazione in app/config
●
creare un file per ogni bundle da configurare
●
inserire parametri nel container tramite
files di configurazione custom
50. Train to Symfony
50http://traintosymfony.comFiles di configurazione custom
In un file custom di configurazione definisco:
●
parametri per un bundle, che voglio tenere
in un file separato (bundle_*)
●
parametri per il container
(chiave “parameters”)
●
parametri disponibili nei templates TWIG
(chiave “twig.globals”)
51. Train to Symfony
51http://traintosymfony.comFiles di configurazione custom
Per le configurazioni che cambiano in base alla macchina
è consigliato tenere una versione .dist
●
condivisione repository git
●
ambiente locale/remoto
●
opensource: informazioni sensibili
●
es: parameters.yml e parameters.yml.dist
53. Train to Symfony
53http://traintosymfony.comDal service container a TWIG
Come configuro variabili perché siano disponibili in TWIG?
Con la chiave twig.globals una variabile è accessibile in tutti i templates
54. Train to Symfony
54http://traintosymfony.comDal service container a TWIG
parameters:
# array of available interface translations
interface_translation_locales:
en:
code: en
flag: gb.png
it:
code: it
flag: it.png
es:
code: es
flag: es.png
twig:
globals:
# parameter accessible from twig templates
interface_translation_locales: "%interface_translation_locales%"
parameters:
# array of available interface translations
interface_translation_locales:
en:
code: en
flag: gb.png
it:
code: it
flag: it.png
es:
code: es
flag: es.png
twig:
globals:
# parameter accessible from twig templates
interface_translation_locales: "%interface_translation_locales%"
# SymfonyBricks/app/config/locales.yml
56. Train to Symfony
56http://traintosymfony.comDal service container a TWIG
services:
# estensione twig per il catalogo
catalog.twig.extension:
class: FooBarBundleExtensionCatalogExtension
arguments: [@catalog.service]
tags:
- { name: twig.extension }
services:
# estensione twig per il catalogo
catalog.twig.extension:
class: FooBarBundleExtensionCatalogExtension
arguments: [@catalog.service]
tags:
- { name: twig.extension }
# src/Foo/BarBundle/Resources/config/services.yml
1) definisco un'estensione TWIG custom
57. Train to Symfony
57http://traintosymfony.comDal service container a TWIG
class CatalogExtension extends Twig_Extension
{
public function __construct($catalogService) {
$this->catalogService = $catalogService;
}
public function getFunctions() {
return array(
'getCatalogService' => new Twig_Function_Method($this, 'getCatalogService')
);
}
public function getCatalogService() {
return $this->catalogService;
}
}
class CatalogExtension extends Twig_Extension
{
public function __construct($catalogService) {
$this->catalogService = $catalogService;
}
public function getFunctions() {
return array(
'getCatalogService' => new Twig_Function_Method($this, 'getCatalogService')
);
}
public function getCatalogService() {
return $this->catalogService;
}
}
# src/Foo/BarBundle/Extension/CatalogExtension.php
2) implemento l'estensione TWIG CatalogExtension
58. Train to Symfony
58http://traintosymfony.comDal service container a TWIG
{% set catalogService = getCatalogService() %}
{% for category in rootCategory.children %}
<a href="{{ catalogService.generatePath(category) }}">
{{ category.name }}
</a>
{% endfor %}
{% set catalogService = getCatalogService() %}
{% for category in rootCategory.children %}
<a href="{{ catalogService.generatePath(category) }}">
{{ category.name }}
</a>
{% endfor %}
3) lo utilizzo nel template, senza che il servizio sia passato da un controller
62. Train to Symfony
62http://traintosymfony.comEnvironments
AppKernel.php carica la configurazione dell'environment
class AppKernel extends Kernel
{
public function registerBundles()
{
[...]
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
}
}
class AppKernel extends Kernel
{
public function registerBundles()
{
[...]
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
}
}
# app/AppKernel.php
63. Train to Symfony
63http://traintosymfony.comEnvironments
Creare un ambiente aggiuntivo è semplice:
●
creo web/previewfeatures.php
●
inizializzo l'environment “preview_features” tramite
●
creo app/config/dev_preview_features.yml
$kernel = new AppKernel('preview_features', false);$kernel = new AppKernel('preview_features', false);