(my) best practices in symfony

64
Train to Symfony 1 http://traintosymfony.com TRAIN TO SYMFONY (My) Best Practices in Symfony the frameworkshop http://traintosymfony.com @TrainToSymfony BUSINESS CLASS

Upload: inmarelibero

Post on 19-Jun-2015

779 views

Category:

Engineering


0 download

DESCRIPTION

"(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.

TRANSCRIPT

Page 1: (My) Best Practices in Symfony

Train to Symfony 1http://traintosymfony.com

TRAINTO SYMFONY

(My) Best Practices in Symfony

the frameworkshop

http://traintosymfony.com @TrainToSymfony

BUSINESS CLASS

Page 2: (My) Best Practices in Symfony

Train to Symfony 2http://traintosymfony.com

(MY) BEST PRACTICESIN SYMFONY

Page 3: (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”

Page 4: (My) Best Practices in Symfony

Train to Symfony 4http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY

Il codice nel posto giusto

Page 5: (My) Best Practices in Symfony

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?

Page 6: (My) Best Practices in Symfony

Train to Symfony 6http://traintosymfony.comIl codice nel posto giusto

È utile conoscere ed adottare convenzioniper poi sapere dove trovare e scrivere codice

Page 7: (My) Best Practices in Symfony

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● [...]

Page 8: (My) Best Practices in Symfony

Train to Symfony 8http://traintosymfony.comIl codice nel posto giusto

Ok, ma dove scrivo effettivamente il mio codice?

Page 9: (My) Best Practices in Symfony

Train to Symfony 9http://traintosymfony.comIl codice nel posto giusto

controller

service

listener

repository

form builder

entity

template

Page 10: (My) Best Practices in Symfony

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)

Page 11: (My) Best Practices in Symfony

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

Page 12: (My) Best Practices in Symfony

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

Page 13: (My) Best Practices in Symfony

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

Page 14: (My) Best Practices in Symfony

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() {}

}

Page 15: (My) Best Practices in Symfony

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

Page 16: (My) Best Practices in Symfony

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

Page 17: (My) Best Practices in Symfony

Train to Symfony 17http://traintosymfony.comIl codice nel posto giusto

listener

catturare eventi lanciati da Symfony, da bundlesdi terze parti (FOSUserBundle), o custom

sviluppare un'architettura orientata ad eventi

difficoltà nel (ri)trovare il codice

Page 18: (My) Best Practices in Symfony

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

Page 19: (My) Best Practices in Symfony

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

Page 20: (My) Best Practices in Symfony

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);

Page 21: (My) Best Practices in Symfony

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)

Page 22: (My) Best Practices in Symfony

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 repositorye altri servizi

acquistare molta familiarità con i servizi

creare tutti quelli necessari

nome e id del servizio molto importanti

Page 23: (My) Best Practices in Symfony

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

Page 24: (My) Best Practices in Symfony

Train to Symfony 24http://traintosymfony.comIl codice nel posto giusto

services:

# catalog service catalog.service: class: Foo\BarBundle\Service\CatalogService arguments: [@doctrine.orm.entity_manager, @router]

services:

# catalog service catalog.service: class: Foo\BarBundle\Service\CatalogService arguments: [@doctrine.orm.entity_manager, @router]

# src/Foo/BarBundle/Resources/config/services.yml

<service id="catalog.service" class="Foo\BarBundle\Service\CatalogService"><argument type="service" id="doctrine.orm.entity_manager" /><argument type="service" id="router" />

</service>

<service id="catalog.service" class="Foo\BarBundle\Service\CatalogService"><argument type="service" id="doctrine.orm.entity_manager" /><argument type="service" id="router" />

</service>

# src/Foo/BarBundle/Resources/config/services.xml

Page 25: (My) Best Practices in Symfony

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

Page 26: (My) Best Practices in Symfony

Train to Symfony 26http://traintosymfony.comIl codice nel posto giusto

Quali sono le convenzioni che definiamo noi?

Page 27: (My) Best Practices in Symfony

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

Page 28: (My) Best Practices in Symfony

Train to Symfony 28http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY

Organizzazione dei bundles

Page 29: (My) Best Practices in Symfony

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)

Page 30: (My) Best Practices in Symfony

Train to Symfony 30http://traintosymfony.comOrganizzazione dei bundles

Organizzazione internadi un bundle

Page 31: (My) Best Practices in Symfony

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

Page 32: (My) Best Practices in Symfony

Train to Symfony 32http://traintosymfony.comOrganizzazione dei bundles

/DependencyInjection

configura il bundle

classi chiamate al bootstrap del bundle

Page 33: (My) Best Practices in Symfony

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 Loader\YamlFileLoader($container, newFileLocator(__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 Loader\YamlFileLoader($container, newFileLocator(__DIR__.'/../Resources/config'));

$loader->load('services.yml'); }}

# src/Bricks/SiteBundle/DependencyInjection/BricksSiteExtension.php

*Extension.php si occupa di caricare i files di configurazione (servizi)

Page 34: (My) Best Practices in Symfony

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

Page 35: (My) Best Practices in Symfony

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

Page 36: (My) Best Practices in Symfony

Train to Symfony 36http://traintosymfony.comOrganizzazione dei bundles

/Extension (/TWIG)

contiene le estensioni custom di TWIG

filtri e funzioni TWIG

Page 37: (My) Best Practices in Symfony

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

Page 38: (My) Best Practices in Symfony

Train to Symfony 38http://traintosymfony.comOrganizzazione dei bundles

/Listener

contiene i miei custom Listener

scegliere una convenzione per i nomi

Page 39: (My) Best Practices in Symfony

Train to Symfony 39http://traintosymfony.comOrganizzazione dei bundles

/Resources

configurazione del bundle (config/services.xml)

templates

assets (sì js e css, no immagini)

Page 40: (My) Best Practices in Symfony

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

Page 41: (My) Best Practices in Symfony

Train to Symfony 41http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY

Design di controllers

Page 42: (My) Best Practices in Symfony

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?

Page 43: (My) Best Practices in Symfony

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

Page 44: (My) Best Practices in Symfony

Train to Symfony 44http://traintosymfony.comDesign di controllers

Utilizzo di @ParamConverter

http://symfony.com/it/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html

Page 45: (My) Best Practices in Symfony

Train to Symfony 45http://traintosymfony.comDesign di controllers

Al posto di:

use Foo\BarBundle\Entity\Product;

/** * @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 Foo\BarBundle\Entity\Product;

/** * @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

Page 46: (My) Best Practices in Symfony

Train to Symfony 46http://traintosymfony.comDesign di controllers

use Foo\BarBundle\Entity\Product;

/** * @Route("/product/{id}") * @ParamConverter("product", class="FooBarBundle:Product") */public function showAction(Product $product){

$price = $product->getPrice();

[...]}

use Foo\BarBundle\Entity\Product;

/** * @Route("/product/{id}") * @ParamConverter("product", class="FooBarBundle:Product") */public function showAction(Product $product){

$price = $product->getPrice();

[...]}

# src/Foo/BarBundle/Controller/DefaultController.php

utilizzo @ParamConverter:

Page 47: (My) Best Practices in Symfony

Train to Symfony 47http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY

Files di configurazione custom

Page 48: (My) Best Practices in Symfony

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 tramitefiles di configurazione custom

Page 49: (My) Best Practices in Symfony

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

Page 50: (My) Best Practices in Symfony

Train to Symfony 50http://traintosymfony.comFiles di configurazione custom

In un file custom di configurazione definisco:

● parametri per un bundle, che voglio tenerein un file separato (bundle_*)

● parametri per il container(chiave “parameters”)

● parametri disponibili nei templates TWIG(chiave “twig.globals”)

Page 51: (My) Best Practices in Symfony

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

Page 52: (My) Best Practices in Symfony

Train to Symfony 52http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY

Dal service container a TWIG

Page 53: (My) Best Practices in Symfony

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

Page 54: (My) Best Practices in Symfony

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

Page 55: (My) Best Practices in Symfony

Train to Symfony 55http://traintosymfony.comDal service container a TWIG

Posso rendere disponibile anche un servizio(da usare con discrezione)

Page 56: (My) Best Practices in Symfony

Train to Symfony 56http://traintosymfony.comDal service container a TWIG

services:

# estensione twig per il catalogo catalog.twig.extension: class: Foo\BarBundle\Extension\CatalogExtension arguments: [@catalog.service] tags: - { name: twig.extension }

services:

# estensione twig per il catalogo catalog.twig.extension: class: Foo\BarBundle\Extension\CatalogExtension arguments: [@catalog.service] tags: - { name: twig.extension }

# src/Foo/BarBundle/Resources/config/services.yml

1) definisco un'estensione TWIG custom

Page 57: (My) Best Practices in Symfony

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

Page 58: (My) Best Practices in Symfony

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

Page 59: (My) Best Practices in Symfony

Train to Symfony 59http://traintosymfony.com(MY) BEST PRACTICES IN SYMFONY

Environments

Page 60: (My) Best Practices in Symfony

Train to Symfony 60http://traintosymfony.comEnvironments

prod, dev e test sono i 3 ambienti predefiniti

● app.php● app_dev.php

Page 61: (My) Best Practices in Symfony

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

Page 62: (My) Best Practices in Symfony

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

Page 63: (My) Best Practices in Symfony

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);

Page 64: (My) Best Practices in Symfony

Train to Symfony 64http://traintosymfony.com

the frameworkshop

http://traintosymfony.com @TrainToSymfony

(My) Best Practices in Symfony

TRAINTO SYMFONY

BUSINESS CLASS