SlideShare une entreprise Scribd logo
1  sur  64
Télécharger pour lire hors ligne
Train to Symfony
1http://traintosymfony.com
TRAIN
TO SYMFONY
(My) Best Practices in Symfony
the frameworkshop
http://traintosymfony.com @TrainToSymfony
BUSINESS CLASS
Train to Symfony
2http://traintosymfony.com
(MY) BEST PRACTICES
IN SYMFONY
Train to Symfony
3http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY
Conoscere le best practices di Symfony
non per sapere “come si fa”
ma per capire “a cosa mi serve”
Train to Symfony
4http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY
Il codice nel posto giusto
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?
Train to Symfony
6http://traintosymfony.comIl codice nel posto giusto
È utile conoscere ed adottare convenzioni
per poi sapere dove trovare e scrivere codice
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
●
[...]
Train to Symfony
8http://traintosymfony.comIl codice nel posto giusto
Ok, ma dove scrivo effettivamente il mio codice?
Train to Symfony
9http://traintosymfony.comIl codice nel posto giusto
controller
service
listener
repository
form builder
entity
template
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)
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
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
Train to Symfony
13http://traintosymfony.comIl codice nel posto giusto
Nel controller cerco di fare meno operazioni possibili
Delego più logica possibile ad altri componenti
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() {
}
}
Train to Symfony
15http://traintosymfony.comIl codice nel posto giusto
form builder
definizione di un form specificandone i campi
scelta dei campi da gestire in base a della logica
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
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
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
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
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);
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)
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
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
Train to Symfony
24http://traintosymfony.comIl codice nel posto giusto
services:
# catalog service
catalog.service:
class: FooBarBundleServiceCatalogService
arguments: [@doctrine.orm.entity_manager, @router]
services:
# catalog service
catalog.service:
class: FooBarBundleServiceCatalogService
arguments: [@doctrine.orm.entity_manager, @router]
# src/Foo/BarBundle/Resources/config/services.yml
<service id="catalog.service" class="FooBarBundleServiceCatalogService">
<argument type="service" id="doctrine.orm.entity_manager" />
<argument type="service" id="router" />
</service>
<service id="catalog.service" class="FooBarBundleServiceCatalogService">
<argument type="service" id="doctrine.orm.entity_manager" />
<argument type="service" id="router" />
</service>
# src/Foo/BarBundle/Resources/config/services.xml
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
Train to Symfony
26http://traintosymfony.comIl codice nel posto giusto
Quali sono le convenzioni che definiamo noi?
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
Train to Symfony
28http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY
Organizzazione dei bundles
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)
Train to Symfony
30http://traintosymfony.comOrganizzazione dei bundles
Organizzazione interna
di un bundle
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
Train to Symfony
32http://traintosymfony.comOrganizzazione dei bundles
/DependencyInjection
configura il bundle
classi chiamate al bootstrap del bundle
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)
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
Train to Symfony
35http://traintosymfony.comOrganizzazione dei bundles
/Entity
meglio (?) definire tutte le entities in un solo posto
solitamente nel frontend (problema generazione CRUD)
problema inglese/italiano
Train to Symfony
36http://traintosymfony.comOrganizzazione dei bundles
/Extension (/TWIG)
contiene le estensioni custom di TWIG
filtri e funzioni TWIG
Train to Symfony
37http://traintosymfony.comOrganizzazione dei bundles
/Form
usare i FormType anche per form semplici
validazione possibile nel FormType
usare i FormType anche come servizi
Train to Symfony
38http://traintosymfony.comOrganizzazione dei bundles
/Listener
contiene i miei custom Listener
scegliere una convenzione per i nomi
Train to Symfony
39http://traintosymfony.comOrganizzazione dei bundles
/Resources
configurazione del bundle (config/services.xml)
templates
assets (sì js e css, no immagini)
Train to Symfony
40http://traintosymfony.comOrganizzazione dei bundles
/Service
contiene tutti i servizi creati
nient'altro che semplici classi PHP con un namespace
aspetto più critico di un servizio: il nome e l'id
Train to Symfony
41http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY
Design di controllers
Train to Symfony
42http://traintosymfony.comDesign di controllers
Funzionalità del sito
Sintassi degli url
Caricamento delle routes in routing.yml
Quanti controller creo? Come raggruppo le actions?
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
Train to Symfony
44http://traintosymfony.comDesign di controllers
Utilizzo di @ParamConverter
http://symfony.com/it/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
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
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:
Train to Symfony
47http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY
Files di configurazione custom
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
Train to Symfony
49http://traintosymfony.comFiles di configurazione custom
La direttiva imports include un qualsiasi file yml:
imports:
- { resource: parameters.yml }
- { resource: security.yml }
# bundles config
- { resource: bundle_assetic.yml }
- { resource: bundle_fos_user.yml }
- { resource: bundle_hwi_oauth.yml }
- { resource: bundle_stof_doctrine_extensions.yml }
- { resource: bundle_vich_uploads.yml }
# project config
- { resource: conf_custom_templates.yml }
- { resource: conf_email_addresses.yml }
- { resource: conf_locales.yml }
- { resource: conf_special_product_categories.yml }
imports:
- { resource: parameters.yml }
- { resource: security.yml }
# bundles config
- { resource: bundle_assetic.yml }
- { resource: bundle_fos_user.yml }
- { resource: bundle_hwi_oauth.yml }
- { resource: bundle_stof_doctrine_extensions.yml }
- { resource: bundle_vich_uploads.yml }
# project config
- { resource: conf_custom_templates.yml }
- { resource: conf_email_addresses.yml }
- { resource: conf_locales.yml }
- { resource: conf_special_product_categories.yml }
# app/config/config.yml
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”)
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
Train to Symfony
52http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY
Dal service container a TWIG
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
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
Train to Symfony
55http://traintosymfony.comDal service container a TWIG
Posso rendere disponibile anche un servizio
(da usare con discrezione)
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
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
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
Train to Symfony
59http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY
Environments
Train to Symfony
60http://traintosymfony.comEnvironments
prod, dev e test sono i 3 ambienti predefiniti
●
app.php
●
app_dev.php
Train to Symfony
61http://traintosymfony.comEnvironments
Il front controller definisce l'ambiente corrente:
$kernel = new AppKernel('prod', false);$kernel = new AppKernel('prod', false);
# web/app.php
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
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);
Train to Symfony
64http://traintosymfony.com
the frameworkshop
http://traintosymfony.com @TrainToSymfony
(My) Best Practices in Symfony
TRAIN
TO SYMFONYBUSINESS CLASS

Contenu connexe

En vedette (7)

symfonyイントロダクション
symfonyイントロダクションsymfonyイントロダクション
symfonyイントロダクション
 
勉強会のすすめ
勉強会のすすめ勉強会のすすめ
勉強会のすすめ
 
jQueryチュートリアル
jQueryチュートリアルjQueryチュートリアル
jQueryチュートリアル
 
Symony2 A Next Generation PHP Framework
Symony2 A Next Generation PHP FrameworkSymony2 A Next Generation PHP Framework
Symony2 A Next Generation PHP Framework
 
Php symfony and software lifecycle
Php symfony and software lifecyclePhp symfony and software lifecycle
Php symfony and software lifecycle
 
symfonyイントロダクション
symfonyイントロダクションsymfonyイントロダクション
symfonyイントロダクション
 
symfony : I18n And L10n
symfony : I18n And L10nsymfony : I18n And L10n
symfony : I18n And L10n
 

Similaire à (My) Best Practices in Symfony

JAMP DAY 2010 - ROMA (3)
JAMP DAY 2010 - ROMA (3)JAMP DAY 2010 - ROMA (3)
JAMP DAY 2010 - ROMA (3)
jampslide
 
Dominare il codice legacy
Dominare il codice legacyDominare il codice legacy
Dominare il codice legacy
Tommaso Torti
 

Similaire à (My) Best Practices in Symfony (20)

Primo Incontro Con Scala
Primo Incontro Con ScalaPrimo Incontro Con Scala
Primo Incontro Con Scala
 
Fare con Zend Framework 2 ciò che facevo con ZF1
Fare con Zend Framework 2 ciò che facevo con ZF1Fare con Zend Framework 2 ciò che facevo con ZF1
Fare con Zend Framework 2 ciò che facevo con ZF1
 
Write less do more...with jQuery
Write less do more...with jQueryWrite less do more...with jQuery
Write less do more...with jQuery
 
Come portare il profiler di symfony2 in drupal8
Come portare il profiler di symfony2 in drupal8Come portare il profiler di symfony2 in drupal8
Come portare il profiler di symfony2 in drupal8
 
Routing (2/3) | Train to Symfony
Routing (2/3) | Train to SymfonyRouting (2/3) | Train to Symfony
Routing (2/3) | Train to Symfony
 
JAMP DAY 2010 - ROMA (3)
JAMP DAY 2010 - ROMA (3)JAMP DAY 2010 - ROMA (3)
JAMP DAY 2010 - ROMA (3)
 
Levate l'ancora! Rotte senza problemi con ZF2
Levate l'ancora! Rotte senza problemi con ZF2Levate l'ancora! Rotte senza problemi con ZF2
Levate l'ancora! Rotte senza problemi con ZF2
 
Non Conventional Android Programming (Italiano)
Non Conventional Android Programming (Italiano)Non Conventional Android Programming (Italiano)
Non Conventional Android Programming (Italiano)
 
Drupal diventa un CMF e WordPress che fa? Slide WordCamp Milano 2019
Drupal diventa un CMF e WordPress che fa? Slide WordCamp Milano 2019Drupal diventa un CMF e WordPress che fa? Slide WordCamp Milano 2019
Drupal diventa un CMF e WordPress che fa? Slide WordCamp Milano 2019
 
Dominare il codice legacy
Dominare il codice legacyDominare il codice legacy
Dominare il codice legacy
 
Php mysql3
Php mysql3Php mysql3
Php mysql3
 
PHP Template Engine (introduzione)
PHP Template Engine (introduzione)PHP Template Engine (introduzione)
PHP Template Engine (introduzione)
 
Sinfonia in Domino RE - Integrazione Symphony e Lotus Notes 8.x
Sinfonia in Domino RE - Integrazione Symphony e Lotus Notes 8.xSinfonia in Domino RE - Integrazione Symphony e Lotus Notes 8.x
Sinfonia in Domino RE - Integrazione Symphony e Lotus Notes 8.x
 
introduzione a symfony 2
introduzione a symfony 2 introduzione a symfony 2
introduzione a symfony 2
 
Un CMS in 25min con Symfony CMF
Un CMS in 25min con Symfony CMFUn CMS in 25min con Symfony CMF
Un CMS in 25min con Symfony CMF
 
Perl Template Toolkit
Perl Template ToolkitPerl Template Toolkit
Perl Template Toolkit
 
How create a single page apps using html5 and javascript
How create a single page apps using html5 and javascript How create a single page apps using html5 and javascript
How create a single page apps using html5 and javascript
 
Symfony (1/3) | Train to Symfony
Symfony (1/3) | Train to SymfonySymfony (1/3) | Train to Symfony
Symfony (1/3) | Train to Symfony
 
Javascript - 7 | WebMaster & WebDesigner
Javascript - 7 | WebMaster & WebDesignerJavascript - 7 | WebMaster & WebDesigner
Javascript - 7 | WebMaster & WebDesigner
 
Hexagonal architecture ita
Hexagonal architecture itaHexagonal architecture ita
Hexagonal architecture ita
 

Dernier

Dernier (9)

GIORNATA TECNICA 18/04 | DE LEO Antonio
GIORNATA TECNICA 18/04  | DE LEO AntonioGIORNATA TECNICA 18/04  | DE LEO Antonio
GIORNATA TECNICA 18/04 | DE LEO Antonio
 
GIORNATA TECNICA DA AQP 18/04 | MOTTA Simone
GIORNATA TECNICA DA AQP 18/04 | MOTTA SimoneGIORNATA TECNICA DA AQP 18/04 | MOTTA Simone
GIORNATA TECNICA DA AQP 18/04 | MOTTA Simone
 
GIORNATA TECNICA 18/04 | DE ROSA Roberto
GIORNATA TECNICA 18/04 | DE ROSA RobertoGIORNATA TECNICA 18/04 | DE ROSA Roberto
GIORNATA TECNICA 18/04 | DE ROSA Roberto
 
GIORNATA TECNICA DA AQP 18/04 | ZONNO Serena
GIORNATA TECNICA DA AQP 18/04 | ZONNO SerenaGIORNATA TECNICA DA AQP 18/04 | ZONNO Serena
GIORNATA TECNICA DA AQP 18/04 | ZONNO Serena
 
Descrizione della struttura architettonica Eretteo.pptx
Descrizione della struttura architettonica Eretteo.pptxDescrizione della struttura architettonica Eretteo.pptx
Descrizione della struttura architettonica Eretteo.pptx
 
Presentzione Matematica similitudini circonferenze e omotetie.pptx
Presentzione  Matematica similitudini circonferenze e omotetie.pptxPresentzione  Matematica similitudini circonferenze e omotetie.pptx
Presentzione Matematica similitudini circonferenze e omotetie.pptx
 
GIORNATA TECNICA 18/04 | LITTERIO Raffaele
GIORNATA TECNICA 18/04 | LITTERIO RaffaeleGIORNATA TECNICA 18/04 | LITTERIO Raffaele
GIORNATA TECNICA 18/04 | LITTERIO Raffaele
 
GIORNATA TECNICA 18/04 | BENANTI Alessandro
GIORNATA TECNICA 18/04 | BENANTI AlessandroGIORNATA TECNICA 18/04 | BENANTI Alessandro
GIORNATA TECNICA 18/04 | BENANTI Alessandro
 
GIORNATA TECNICA 18/04 | SPIZZIRRI Massimo
GIORNATA TECNICA 18/04 | SPIZZIRRI MassimoGIORNATA TECNICA 18/04 | SPIZZIRRI Massimo
GIORNATA TECNICA 18/04 | SPIZZIRRI Massimo
 

(My) Best Practices in Symfony

  • 1. Train to Symfony 1http://traintosymfony.com TRAIN TO SYMFONY (My) Best Practices in Symfony the frameworkshop http://traintosymfony.com @TrainToSymfony BUSINESS CLASS
  • 3. Train to Symfony 3http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY Conoscere le best practices di Symfony non per sapere “come si fa” ma per capire “a cosa mi serve”
  • 4. Train to Symfony 4http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY Il codice nel posto giusto
  • 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?
  • 6. Train to Symfony 6http://traintosymfony.comIl codice nel posto giusto È utile conoscere ed adottare convenzioni per poi sapere dove trovare e scrivere codice
  • 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 ● [...]
  • 8. Train to Symfony 8http://traintosymfony.comIl codice nel posto giusto Ok, ma dove scrivo effettivamente il mio codice?
  • 9. Train to Symfony 9http://traintosymfony.comIl codice nel posto giusto controller service listener repository form builder entity template
  • 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
  • 13. Train to Symfony 13http://traintosymfony.comIl codice nel posto giusto Nel controller cerco di fare meno operazioni possibili Delego più logica possibile ad altri componenti
  • 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() { } }
  • 15. Train to Symfony 15http://traintosymfony.comIl codice nel posto giusto form builder definizione di un form specificandone i campi scelta dei campi da gestire in base a della logica
  • 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
  • 24. Train to Symfony 24http://traintosymfony.comIl codice nel posto giusto services: # catalog service catalog.service: class: FooBarBundleServiceCatalogService arguments: [@doctrine.orm.entity_manager, @router] services: # catalog service catalog.service: class: FooBarBundleServiceCatalogService arguments: [@doctrine.orm.entity_manager, @router] # src/Foo/BarBundle/Resources/config/services.yml <service id="catalog.service" class="FooBarBundleServiceCatalogService"> <argument type="service" id="doctrine.orm.entity_manager" /> <argument type="service" id="router" /> </service> <service id="catalog.service" class="FooBarBundleServiceCatalogService"> <argument type="service" id="doctrine.orm.entity_manager" /> <argument type="service" id="router" /> </service> # src/Foo/BarBundle/Resources/config/services.xml
  • 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
  • 26. Train to Symfony 26http://traintosymfony.comIl codice nel posto giusto Quali sono le convenzioni che definiamo noi?
  • 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
  • 28. Train to Symfony 28http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY Organizzazione dei bundles
  • 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)
  • 30. Train to Symfony 30http://traintosymfony.comOrganizzazione dei bundles Organizzazione interna di un bundle
  • 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
  • 32. Train to Symfony 32http://traintosymfony.comOrganizzazione dei bundles /DependencyInjection configura il bundle classi chiamate al bootstrap del bundle
  • 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
  • 35. Train to Symfony 35http://traintosymfony.comOrganizzazione dei bundles /Entity meglio (?) definire tutte le entities in un solo posto solitamente nel frontend (problema generazione CRUD) problema inglese/italiano
  • 36. Train to Symfony 36http://traintosymfony.comOrganizzazione dei bundles /Extension (/TWIG) contiene le estensioni custom di TWIG filtri e funzioni TWIG
  • 37. Train to Symfony 37http://traintosymfony.comOrganizzazione dei bundles /Form usare i FormType anche per form semplici validazione possibile nel FormType usare i FormType anche come servizi
  • 38. Train to Symfony 38http://traintosymfony.comOrganizzazione dei bundles /Listener contiene i miei custom Listener scegliere una convenzione per i nomi
  • 39. Train to Symfony 39http://traintosymfony.comOrganizzazione dei bundles /Resources configurazione del bundle (config/services.xml) templates assets (sì js e css, no immagini)
  • 40. Train to Symfony 40http://traintosymfony.comOrganizzazione dei bundles /Service contiene tutti i servizi creati nient'altro che semplici classi PHP con un namespace aspetto più critico di un servizio: il nome e l'id
  • 41. Train to Symfony 41http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY Design di controllers
  • 42. Train to Symfony 42http://traintosymfony.comDesign di controllers Funzionalità del sito Sintassi degli url Caricamento delle routes in routing.yml Quanti controller creo? Come raggruppo le actions?
  • 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
  • 44. Train to Symfony 44http://traintosymfony.comDesign di controllers Utilizzo di @ParamConverter http://symfony.com/it/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
  • 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:
  • 47. Train to Symfony 47http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY Files di configurazione custom
  • 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
  • 49. Train to Symfony 49http://traintosymfony.comFiles di configurazione custom La direttiva imports include un qualsiasi file yml: imports: - { resource: parameters.yml } - { resource: security.yml } # bundles config - { resource: bundle_assetic.yml } - { resource: bundle_fos_user.yml } - { resource: bundle_hwi_oauth.yml } - { resource: bundle_stof_doctrine_extensions.yml } - { resource: bundle_vich_uploads.yml } # project config - { resource: conf_custom_templates.yml } - { resource: conf_email_addresses.yml } - { resource: conf_locales.yml } - { resource: conf_special_product_categories.yml } imports: - { resource: parameters.yml } - { resource: security.yml } # bundles config - { resource: bundle_assetic.yml } - { resource: bundle_fos_user.yml } - { resource: bundle_hwi_oauth.yml } - { resource: bundle_stof_doctrine_extensions.yml } - { resource: bundle_vich_uploads.yml } # project config - { resource: conf_custom_templates.yml } - { resource: conf_email_addresses.yml } - { resource: conf_locales.yml } - { resource: conf_special_product_categories.yml } # app/config/config.yml
  • 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
  • 52. Train to Symfony 52http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY Dal service container a TWIG
  • 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
  • 55. Train to Symfony 55http://traintosymfony.comDal service container a TWIG Posso rendere disponibile anche un servizio (da usare con discrezione)
  • 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
  • 59. Train to Symfony 59http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY Environments
  • 60. Train to Symfony 60http://traintosymfony.comEnvironments prod, dev e test sono i 3 ambienti predefiniti ● app.php ● app_dev.php
  • 61. Train to Symfony 61http://traintosymfony.comEnvironments Il front controller definisce l'ambiente corrente: $kernel = new AppKernel('prod', false);$kernel = new AppKernel('prod', false); # web/app.php
  • 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);
  • 64. Train to Symfony 64http://traintosymfony.com the frameworkshop http://traintosymfony.com @TrainToSymfony (My) Best Practices in Symfony TRAIN TO SYMFONYBUSINESS CLASS