diff --git a/best_practices/configuration.rst b/best_practices/configuration.rst index 4cc8c6dd..beddf36b 100644 --- a/best_practices/configuration.rst +++ b/best_practices/configuration.rst @@ -42,6 +42,8 @@ con il comportamento dell'applicazione. In altre parole, l'applicazione non si d sapere dov'è posizionata la base dati o come vi accede. L'unica cosa che gli importa sapere è che la base dati sia configurata correttamente. +.. _best-practices-canonical-parameters: + Parametri canonici ------------------ diff --git a/best_practices/controllers.rst b/best_practices/controllers.rst index df3094dd..35299da7 100644 --- a/best_practices/controllers.rst +++ b/best_practices/controllers.rst @@ -13,7 +13,7 @@ iniziare a rifattorizzare il codice del controllore e spostarlo in un servizio. .. best-practice:: - Estendere il controller dalla classe base fornita da FrameworkBundle + Estendere il controllore dalla classe base fornita da FrameworkBundle e usare le annotazioni per configurare rotte, cache e sicurezza, quando possibile. L'accoppiamento dei controllore al framework sottostante consente di sfruttare tutte @@ -30,13 +30,13 @@ Non sarà necessario esplorare decine di file di formati diversi (YAML, XML, PHP): tutta la configurazione è lì dove serve e in un solo formato. Complessivamente, quindi, si dovrebbe disaccoppiare totalmente la logica di business -dal framework e nello stesso tempo accoppiare totalmente al framework controller e rotte, +dal framework e nello stesso tempo accoppiare totalmente al framework controllori e rotte, in modo da ottenere il massimo da Symfony. Configurazione delle rotte -------------------------- -Per caricare tutte le rotte definite nelle annotazioni dei controller del bundle +Per caricare tutte le rotte definite nelle annotazioni dei controllori del bundle `AppBundle` aggiungete la seguente configurazione al file principale delle rotte: .. code-block:: yaml @@ -46,8 +46,8 @@ Per caricare tutte le rotte definite nelle annotazioni dei controller del bundle resource: "@AppBundle/Controller/" type: annotation -Questa configurazione caricherà le annotazioni da ogni controller presente sia nella -directory ``src/AppBundle/Controller/`` che nelle sue sottocartelle. Se +Questa configurazione caricherà le annotazioni da ogni controllore presente sia nella +cartella ``src/AppBundle/Controller/`` sia nelle sue sottocartelle. Se l'applicazione definisce molti controllori, è perfettamente lecito organizzare il tutto in sottocartelle. @@ -76,25 +76,20 @@ Configurazione dei template Non usare l'annotazione ``@Template()`` per configurare il template usato dal controllore. -Anche se l'annotazione ``@Template()`` risulta molto utile essa nasconde qualche trabocchetto. Per -questo motivo, si raccomanda di non usarla. +Anche se l'annotazione ``@Template()`` risulta molto utile, essa nasconde qualche trucco. +Ritenendo che il gioco non valga la candela, si raccomanda di non +usarla. -La maggior parte delle volte ``@Template`` è usato senza parametri il che rende più difficile -sapere quale template viene renderizzato. Il suo utilizzo inoltre rende meno ovvio -ai principianti che un controller deve sempre ritornare un oggetto Response (a meno che non si usi -un view layer). - -Infine l'annotazione ``@Template`` usa la classe ``TemplateListener`` per ascoltare -l'evento ``kernel.view`` del framework. L'ascoltatore ha un impatto non trascurabile -sulle prestazioni dell'applicazione. Nell'esempio dell'applicazione blog il rendering -dell'homepage impiega 5 millisecondi usando il metodo ``$this->render()``, mentre ben -26 millisecondi usando l'annotazione ``@Template``. +La maggior parte delle volte ``@Template`` è usato senza parametri, il che rende più difficile +sapere quale template viene reso. Il suo utilizzo inoltre rende meno ovvio +ai principianti che un controllore deve sempre restituire un oggetto Response (a meno che non si usi +il livello della vista). Come dovrebbe essere il controllore ----------------------------------- -Considerando tutto, ecco un esempio di come dovrebbe essere il controller -per l'homepage della nostra applicazione: +Considerando tutto, ecco un esempio di come dovrebbe essere il controllore +per l'homepage di un'applicazione: .. code-block:: php @@ -130,7 +125,7 @@ per effettuare la ricerca dell'entity in modo automatico e passarla come paramet .. best-practice:: - Usare il ParamConverter per caricare automaticamente le entità di Doctrine + Usare ParamConverter per caricare automaticamente le entità di Doctrine, nei casi più semplici. Per esempio: @@ -153,7 +148,7 @@ Per esempio: )); } -Solitamente ci si aspetterebbe un argomento ``$id`` nel metodo ``showAction``. Invece, +Solitamente ci si aspetterebbe un parametro ``$id`` nel metodo ``showAction``. Invece, creando un nuovo parametro (``$post``) e specificando il tipo di classe ``Post`` (che è un'entità Doctrine), ParamConverter cercherà automaticamente un oggetto la cui proprietà ``$id`` corrisponde al valore ``{id}``. Nel @@ -204,8 +199,8 @@ perché è abbastanza flessibile: // ... } -Possiamo infine dire che la scorciatoia di ParamConverter è buona nelle situazioni semplici. -Nonostante ciò non si dovrebbe mai dimenticare che la ricerca diretta di entity è un'operazione +Si può infine dire che la scorciatoia di ParamConverter è buona nelle situazioni semplici. +Nonostante ciò, non si dovrebbe mai dimenticare che la ricerca diretta di entity è un'operazione molto facile. Eseguire codice prima e dopo diff --git a/best_practices/creating-the-project.rst b/best_practices/creating-the-project.rst index 573d0656..3c5d1879 100644 --- a/best_practices/creating-the-project.rst +++ b/best_practices/creating-the-project.rst @@ -8,35 +8,15 @@ In passato, i progetti Symfony erano creati con `Composer`_, il gestore di dipen per applicazioni PHP. Tuttavia, la raccomandazione attuale è di usare **l'installatore di Symfony**, che deve essere installato prima della creazione del primo progetto. -Sistemi Linux e Mac OS X -~~~~~~~~~~~~~~~~~~~~~~~~ - -Aprire una console dei comandi ed eseguire i seguenti comandi: - -.. code-block:: bash - - $ curl -LsS http://symfony.com/installer > symfony.phar - $ sudo mv symfony.phar /usr/local/bin/symfony - $ chmod a+x /usr/local/bin/symfony - -Ora si può eseguire l'installatore di Symfony come comando globale di sistema, di nome -``symfony``. - -Sistemi Windows -~~~~~~~~~~~~~~~ - -Aprire una console dei comandi ed eseguire i seguenti comandi: - -.. code-block:: bash - - c:\> php -r "readfile('http://symfony.com/installer');" > symfony.phar +.. best-practice:: -Quindi spostare il file ``symfony.phar`` appena scaricato nella cartella dei progetti -ed eseguirlo, come segue: + Usare l'installatore di Symfony per creare nuovi progetti basati su Symfony. -.. code-block:: bash +Leggere il :doc:`capitolo dell'installazione ` del libro di Symfony per +sapere come installare e usare l'installatore di Symfony. - c:\> php symfony.phar +.. _linux-and-mac-os-x-systems: +.. _windows-systems: Creare un'applicazione Blog --------------------------- diff --git a/best_practices/forms.rst b/best_practices/forms.rst index ff0fdf3b..0323f698 100644 --- a/best_practices/forms.rst +++ b/best_practices/forms.rst @@ -12,16 +12,16 @@ Creazione dei form Definire i form come classi PHP. -Il componente `Form` consente di creare form direttamente dal controller. +Il componente `Form` consente di creare form direttamente dal controllore. A meno che non si voglia riusare il form da qualche altra parte, quest'abitudine -non è del tutto sbagliata. Nonostante ciò, per form più complessi da poter riutilizzare in altri controller +non è del tutto sbagliata. Nonostante ciò, per form più complessi da poter riutilizzare in altri controllori si raccomanda di definire ogni form nella propria classe PHP:: namespace AppBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; - use Symfony\Component\OptionsResolver\OptionsResolverInterface; + use Symfony\Component\OptionsResolver\OptionsResolver; class PostType extends AbstractType { @@ -36,7 +36,7 @@ si raccomanda di definire ogni form nella propria classe PHP:: ; } - public function setDefaultOptions(OptionsResolverInterface $resolver) + public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'data_class' => 'AppBundle\Entity\Post' @@ -207,3 +207,21 @@ In secondo luogo si raccomand di usare ``$form->isSubmitted()`` nel costrutto `` per rendere il codice più chiaro. Tecnicamente non è necessario, dato che ``isValid()`` esegue prima ``isSubmitted()``. Senza questo, tuttavia, il flusso risulterebbe un po' strano e il form sembrerebbe *sempre* processato, anche per le richieste GET. + +TIpi di campo personalizzati +---------------------------- + +.. best-practice:: + + Aggiungere il prefisso ``app_`` ai campi personalizzati, per evitare collisioni. + +I tipi di campo personalizzati ereditano dalla classe ``AbstractType``, che definisce il metodo +``getName()`` per configurare il nome del tipo. Tali nomi devono essere univoci +nell'applicazione. + +Se un tipo personalizzato usa lo stesso nome di uno dei tipi di Symfony, +lo sovrascriverà. Lo stesso accade quando il tipo personalizzato corrisponde +a un qualsiasi tipo definito da bundle di terze parti installati nell'applicazione. + +Aggiungere il prefisso ``app_`` ai campi personalizzati, per evitare collisioni +che potrebbero portare a errori. diff --git a/best_practices/templates.rst b/best_practices/templates.rst index 3c9a2473..4664c3df 100644 --- a/best_practices/templates.rst +++ b/best_practices/templates.rst @@ -33,8 +33,8 @@ Solitamente gli sviluppatori Symfony mettevano i template dell'applicazione nell ``Resources/views/`` di ciascun bundle. Per riferirsi ad essi usavano il nome logico (p.e. ``AcmeDemoBundle:Default:index.html.twig``). -Anche se per i bundle a terzi quest'abitudine è corretta, è molto più conveniente, invece, -inserire i template dell'applicazione nella directory ``app/Resources/views/``. +Anche se per i bundle di terzi questa abitudine è corretta, è molto più conveniente, invece, +inserire i template dell'applicazione nella cartella ``app/Resources/views/``. Innanzitutto questo semplifica drasticamente il nome logico dei template: ================================================= ================================== @@ -51,12 +51,16 @@ Un altro vantaggio è che centralizzare i template semplifica il lavoro dei grafici. Essi non dovranno cercare più i template in tante cartelle sparpagliate fra i bundle. +.. best-practice:: + + Usare la notazione_serpente in minuscolo per nomi di cartelle e template. + Estensioni Twig --------------- .. best-practice:: - Definire le estensioni di Twig nella directory ``AppBundle/Twig``, configurandole + Definire le estensioni di Twig nella cartella ``AppBundle/Twig``, configurandole nel file ``app/config/services.yml``. All'applicazione serve un filtro Twig personalizzato `m2html` in modo da poter diff --git a/best_practices/tests.rst b/best_practices/tests.rst index 4ec8f211..e6b9be8c 100644 --- a/best_practices/tests.rst +++ b/best_practices/tests.rst @@ -11,8 +11,8 @@ Test unitari I test unitari sono usati per testare la "logica di business"; essa è totalmente indipendente dal framework motivo per cui Symfony non include al suo interno -nessun tool per i test unitari. Tuttavia, gli strumenti più conosciuti sono -[PhpUnit](https://phpunit.de/) e [PhpSpec](http://www.phpspec.net/). +nessuno strumento per i test unitari. Tuttavia, gli strumenti più conosciuti +sono `PhpUnit`_ e `PhpSpec`_. Test funzionali --------------- @@ -30,25 +30,35 @@ Un semplice esempio di un test funzionale: .. code-block:: php - /** @dataProvider provideUrls */ - public function testPageIsSuccessful($url) - { - $client = self::createClient(); - $client->request('GET', $url); + // src/AppBundle/Tests/ApplicationAvailabilityFunctionalTest.php + namespace AppBundle\Tests; - $this->assertTrue($client->getResponse()->isSuccessful()); - } + use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; - public function provideUrls() + class ApplicationAvailabilityFunctionalTest extends WebTestCase { - return array( - array('/'), - array('/posts'), - array('/post/fixture-post-1'), - array('/blog/category/fixture-category'), - array('/archives'), - // ... - ); + /** + * @dataProvider urlProvider + */ + public function testPageIsSuccessful($url) + { + $client = self::createClient(); + $client->request('GET', $url); + + $this->assertTrue($client->getResponse()->isSuccessful()); + } + + public function urlProvider() + { + return array( + array('/'), + array('/posts'), + array('/post/fixture-post-1'), + array('/blog/category/fixture-category'), + array('/archives'), + // ... + ); + } } Questo codice controlla che tutti gli URL vengano caricati correttamente, cioè diff --git a/book/controller.rst b/book/controller.rst index 8ee4f298..7f0f99bc 100644 --- a/book/controller.rst +++ b/book/controller.rst @@ -92,8 +92,8 @@ di un oggetto controllore. I controllori sono anche chiamati *azioni*. .. code-block:: php - // src/Acme/HelloBundle/Controller/HelloController.php - namespace Acme\HelloBundle\Controller; + // src/AppBundle/Controller/HelloController.php + namespace AppBundle\Controller; use Symfony\Component\HttpFoundation\Response; @@ -429,35 +429,47 @@ base di ``Controller``. Un ottimo modo per vedere le funzionalità del nucleo in Rinvio ~~~~~~ -Se si vuole rinviare l'utente a un'altra pagina, usare il -metodo -:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::redirect`:: +Se si vuole rinviare l'utente a un'altra pagina, usare il metodo ``redirectToRoute``:: public function indexAction() { - return $this->redirect($this->generateUrl('homepage')); + return $this->redirectToRoute('homepage'); + + // redirectToRoute è equivalente all'uso combinato di redirect() E generateUrl(): + // return $this->redirect($this->generateUrl('homepage'), 301); } -Il metodo ``generateUrl()`` è solo una funzione di supporto che genera l'URL -per una determinata rotta. Per maggiori informazioni, vedere il capitolo -:doc:`Rotte `. +.. versionadded:: 2.6 + Il metodo ``redirectToRoute()`` è stato aggiunto in Symfony 2.6. In precedenza (e anche ora), si + potevano usare ``redirect()`` e ``generateUrl()`` insieme (vedere esempio precedente). + +Oppure, se si vuole rinviare all'esterno, basta usare ``redirect()`` e passare l'URL:: + + public function indexAction() + { + return $this->redirect('http://symfony.com/doc'); + } Per impostazione predefinita, il metodo ``redirect()`` esegue un rinvio 302 (temporaneo). Per eseguire un rinvio 301 (permanente), modificare il secondo parametro:: public function indexAction() { - return $this->redirect($this->generateUrl('homepage'), 301); + return $this->redirectToRoute('homepage', array(), 301); } .. tip:: - Il metodo ``redirect()`` è semplicemente una scorciatoia che crea un oggetto ``Response`` - specializzato nel rinviare l'utente. È equivalente a:: + Il metodo ``redirect()`` è semplicemente una scorciatoia che crea un oggetto + ``Response`` specializzato nel rinviare l'utente. È + equivalente a:: use Symfony\Component\HttpFoundation\RedirectResponse; - return new RedirectResponse($this->generateUrl('homepage')); + public function indexAction() + { + return new RedirectResponse($this->generateUrl('homepage')); + } .. index:: single: Controllore; Rendere i template @@ -471,14 +483,16 @@ Se si serve dell'HTML, si vorrà rendere un template. Il metodo ``render()`` rende un template **e** ne inserisce il contenuto in un oggetto ``Response``:: - // rende app/Resources/views/Hello/index.html.twig - return $this->render('Hello/index.html.twig', array('name' => $name)); + // rende app/Resources/views/hello/index.html.twig + return $this->render('hello/index.html.twig', array('name' => $name)); Si possono anche mettere template in sottocartelle. Meglio però evitare di creare strutture inutilmente profonde:: - // rende app/Resources/views/Hello/Greetings/index.html.twig - return $this->render('Hello/Greetings/index.html.twig', array('name' => $name)); + // rende app/Resources/views/hello/greetings/index.html.twig + return $this->render('hello/greetings/index.html.twig', array( + 'name' => $name + )); Il motore di template di Symfony è spiegato in gran deettaglio nel capitolo :doc:`Template `. @@ -518,7 +532,10 @@ Ci sono innumerevoli altri servizi disponibili. Per elencarli tutti, utilizzare .. code-block:: bash - $ php app/console container:debug + $ php app/console debug:container + +.. versionadded:: 2.6 + Prima di Symfony 2.6, questo comando si chiamava ``container:debug``. Per maggiori informazioni, vedere il capitolo :doc:`/book/service_container`. @@ -625,7 +642,9 @@ Per esempio, immaginiamo che si stia elaborando un form inviato:: 'Le modifiche sono state salvate!' ); - return $this->redirect($this->generateUrl(...)); + // $this->addFlash è equivalente a $this->get('session')->getFlashBag()->add + + return $this->redirectToRoute(...); } return $this->render(...); @@ -654,7 +673,7 @@ il messaggio ``notice``:
$message
" ?> - + Per come sono stati progettati, i messaggi flash sono destinati a vivere esattamente per una richiesta (hanno la "durata di un flash"). Sono progettati per essere utilizzati con un rinvio, esattamente come @@ -680,9 +699,6 @@ e il contenuto che viene inviato al client:: $response = new Response(json_encode(array('name' => $name))); $response->headers->set('Content-Type', 'application/json'); -.. versionadded:: 2.4 - Il supporto per le costanti dei codici di stato HTTP è stato aggiunto in Symfony 2.4. - La proprietà ``headers`` è un oggetto :class:`Symfony\\Component\\HttpFoundation\\HeaderBag` con alcuni utili metodi per leggere e modificare gli header ``Response``. I nomi degli header sono normalizzati in modo che diff --git a/book/doctrine.rst b/book/doctrine.rst index 45c8d4e0..0e6bb0fa 100644 --- a/book/doctrine.rst +++ b/book/doctrine.rst @@ -32,8 +32,8 @@ Il modo più facile per capire come funziona Doctrine è quello di vederlo in az In questa sezione, configureremo una base dati, creeremo un oggetto ``Product``, lo persisteremo nella base dati e lo recupereremo da esso. -Configurazione dela base dati -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Configurazione della base dati +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Prima di iniziare, occorre configurare le informazioni sulla connessione alla base dati. Per convenzione, questa informazione solitamente è configurata in un @@ -77,8 +77,10 @@ file ``app/config/parameters.yml``: + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/doctrine + http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd"> + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/doctrine + http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd"> persist($product)``. Ricordiamo che questo metodo dice semplicemente a Doctrine di gestire o "osservare" l'oggetto ``$product``. @@ -773,6 +781,8 @@ La sintassi DQL è incredibilmente potente e consente di fare join tra entità successivamente), raggruppare, ecc. Per maggiori informazioni, vedere la documentazione ufficiale di Doctrine `Doctrine Query Language`_. +.. _book-doctrine-custom-repository-classes: + Classi repository personalizzate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -864,7 +874,7 @@ Si può usare il metodo appena creato proprio come i metodi predefiniti del repo $em = $this->getDoctrine()->getManager(); $products = $em->getRepository('AppBundle:Product') - ->findAllOrderedByName(); + ->findAllOrderedByName(); .. note:: @@ -884,7 +894,9 @@ Doctrine stesso a creare la classe. .. code-block:: bash - $ php app/console doctrine:generate:entity --entity="AcmeStoreBundle:Category" --fields="name:string(255)" + $ php app/console doctrine:generate:entity \ + --entity="AppBundle:Category" \ + --fields="name:string(255)" Questo task genera l'entità ``Category``, con un campo ``id``, un campo ``name`` e le relative funzioni getter e setter. @@ -929,7 +941,8 @@ Per correlare le entità ``Category`` e ``Product``, iniziamo creando una propri products: targetEntity: Product mappedBy: category - # non dimenticare di inizializzare la collection nel metodo __construct() dell'entità + # non dimenticare di inizializzare la collection nel metodo __construct() + # dell'entità .. code-block:: xml @@ -1151,7 +1164,7 @@ categoria non viene richiesta (processo noto come "lazy load"). Si può anche cercare nella direzione opposta:: - public function showProductAction($id) + public function showProductsAction($id) { $category = $this->getDoctrine() ->getRepository('AppBundle:Category') diff --git a/book/forms.rst b/book/forms.rst index 9bac84ba..2fb11c15 100644 --- a/book/forms.rst +++ b/book/forms.rst @@ -96,7 +96,7 @@ all'interno di un controllore:: ->add('save', 'submit', array('label' => 'Crea post')) ->getForm(); - return $this->render('Default/new.html.twig', array( + return $this->render('default/new.html.twig', array( 'form' => $form->createView(), )); } @@ -144,14 +144,14 @@ aiutanti per i form: .. code-block:: html+jinja - {# app/Resources/views/Default/new.html.twig #} + {# app/Resources/views/default/new.html.twig #} {{ form_start(form) }} {{ form_widget(form) }} {{ form_end(form) }} .. code-block:: html+php - + start($form) ?> widget($form) ?> end($form) ?> @@ -175,7 +175,7 @@ Questo è tutto! Bastano tre righe per rendere completamente il form: Rende tutti i campi, inclusi l'elemento stesso, un'etichetta ed eventuali messaggi di errori; -``form_end()`` +``form_end(form)`` Rende il tag finale del form e ogni campo che non sia ancora stato reso, nel caso in cui i campi siano stati resti singolarmante a mano. È utile per rendere campi nascosci e sfruttare la @@ -442,12 +442,12 @@ rispettivi errori visualizzati nel form. .. code-block:: html+jinja - {# app/Resources/views/Default/new.html.twig #} + {# app/Resources/views/default/new.html.twig #} {{ form(form, {'attr': {'novalidate': 'novalidate'}}) }} .. code-block:: html+php - + form($form, array( 'attr' => array('novalidate' => 'novalidate'), )) ?> @@ -561,6 +561,32 @@ Si può anche definire l'intera logica con una Closure:: )); } +L'uso dell'opzione ``validation_groups`` sovrascrive il gruppo di validazione predefinito +in uso. Se si vogliono validare anche i vincoli predefiniti +dell'entità, si deve cambiare l'opzione in questo modo:: + + use Acme\AcmeBundle\Entity\Client; + use Symfony\Component\Form\FormInterface; + use Symfony\Component\OptionsResolver\OptionsResolverInterface; + + // ... + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'validation_groups' => function(FormInterface $form) { + $data = $form->getData(); + if (Client::TYPE_PERSON == $data->getType()) { + return array('Default', 'person'); + } + + return array('Default', 'company'); + }, + )); + } + +Si possono trovare maggiori informazioni su come funzionino i gruppi di validazione e i vincoli +predefiniti nella sezione del libro relativa ai :ref:`gruppi di validazione `. + .. index:: single: Form; Gruppi di validazione basati sul bottone cliccato @@ -758,7 +784,7 @@ di codice. Naturalmente, solitamente si ha bisogno di molta più flessibilità: .. code-block:: html+jinja - {# app/Resources/views/Default/new.html.twig #} + {# app/Resources/views/default/new.html.twig #} {{ form_start(form) }} {{ form_errors(form) }} @@ -768,7 +794,7 @@ di codice. Naturalmente, solitamente si ha bisogno di molta più flessibilità: .. code-block:: html+php - + start($form) ?> errors($form) ?> @@ -1440,19 +1466,19 @@ rende il form: .. code-block:: html+jinja - {# app/Resources/views/Default/new.html.twig #} - {% form_theme form 'Form/fields.html.twig' %} + {# app/Resources/views/default/new.html.twig #} + {% form_theme form 'form/fields.html.twig' %} - {% form_theme form 'Form/fields.html.twig' 'Form/fields2.html.twig' %} + {% form_theme form 'form/fields.html.twig' 'Form/fields2.html.twig' %} {# ... rendere il form #} .. code-block:: html+php - - setTheme($form, array('Form')) ?> + + setTheme($form, array('form')) ?> - setTheme($form, array('Form', 'Form2')) ?> + setTheme($form, array('form', 'form2')) ?> @@ -1578,9 +1604,8 @@ della configurazione dell'applicazione: # app/config/config.yml twig: - form: - resources: - - 'Form/fields.html.twig' + form_themes: + - 'form/fields.html.twig' # ... .. code-block:: xml @@ -1594,9 +1619,7 @@ della configurazione dell'applicazione: http://symfony.com/schema/dic/twig http://symfony.com/schema/dic/twig/twig-1.0.xsd"> - - Form/fields.html.twig - + form/fields.html.twig @@ -1605,10 +1628,8 @@ della configurazione dell'applicazione: // app/config/config.php $container->loadFromExtension('twig', array( - 'form' => array( - 'resources' => array( - 'Form/fields.html.twig', - ), + 'form_themes' => array( + 'form/fields.html.twig', ), // ... )); @@ -1755,6 +1776,8 @@ Il token CSRF può essere personalizzato specificatamente per ciascun form. Per // ... } +.. _form-disable-csrf: + Per disabilitare la protezione CSRF, impostare l'opzione ``csrf_protection`` a ``false``. Si può anche personalizzarei a livello globale nel progetto. Per ulteriori informazioni, vedere la sezione diff --git a/book/from_flat_php_to_symfony2.rst b/book/from_flat_php_to_symfony2.rst index 6351ac82..6e9671f7 100644 --- a/book/from_flat_php_to_symfony2.rst +++ b/book/from_flat_php_to_symfony2.rst @@ -367,7 +367,7 @@ sicurezza, caricamento della configurazione, rotte. In questa applicazione, require_once 'controllers.php'; // dirotta internamente la richiesta - $uri = $_SERVER['REQUEST_URI']; + $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); if ('/index.php' == $uri) { list_action(); } elseif ('/index.php/show' == $uri && isset($_GET['id'])) { @@ -447,7 +447,7 @@ in una cartella ``vendor/``: .. code-block:: bash - $ php composer.phar install + $ composer install Oltre a scaricare le dipendenza, Composer genera un file ``vendor/autoload.php``, che si occupa di auto-caricare tutti i file del framework Symfony, nonché dei @@ -547,8 +547,8 @@ risolvono questi problemi. Invece di risolvere nuovamente problemi comuni, si può lasciare a Symfony il compito di occuparsene. Ecco la stessa applicazione di esempio, ora costruita in Symfony:: - // src/Acme/BlogBundle/Controller/BlogController.php - namespace Acme\BlogBundle\Controller; + // src/AppBundle/Controller/BlogController.php + namespace AppBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; @@ -603,7 +603,7 @@ semplice: getTitle() ?> - + Il layout è quasi identico: @@ -646,7 +646,7 @@ Una configurazione delle rotte fornisce tali informazioni in un formato leggibil Ora che Symfony gestisce tutti i compiti più comuni, il front controller è semplicissimo. E siccome fa così poco, non si avrà mai bisogno di modificarlo una -volta creato (e se si usa una distribuzione di Symfony, non servirà nemmeno +volta creato (e se si usa una `distribuzione di Symfony`_, non servirà nemmeno crearlo!):: // web/app.php @@ -681,8 +681,8 @@ da PHP puro a Symfony ci abbia migliorato la vita: a nuovi sviluppatori di essere produttivi nel progetto in modo più rapido. * Il 100% del codice che si scrive è per la *propria* applicazione. **Non occorre - sviluppare o mantenere utilità a basso livello**, come :ref:`autoloading`, - :doc:`routing` o rendere i :doc:`controllori`. + sviluppare o mantenere utilità a basso livello**, come :ref:`autoload `, + :doc:`rotte ` o rendere i :doc:`controllori `. * Symfony dà **accesso a strumenti open source**, come Doctrine e i componenti Templating, Security, Form, Validation e Translation (solo per nominarne @@ -710,7 +710,7 @@ Prendiamo per esempio il template della lista, scritto in Twig: .. code-block:: html+jinja - {# app/Resources/views/Blog/list.html.twig #} + {# app/Resources/views/blog/list.html.twig #} {% extends "layout.html.twig" %} {% block title %}Lista dei post{% endblock %} @@ -761,3 +761,4 @@ Imparare di più con le ricette .. _`Twig`: http://twig.sensiolabs.org .. _`Varnish`: https://www.varnish-cache.org/ .. _`PHPUnit`: http://www.phpunit.de +.. _`distribuzione di Symfony`: https://github.com/symfony/symfony-standard diff --git a/book/http_cache.rst b/book/http_cache.rst index f313a74b..85ee4204 100644 --- a/book/http_cache.rst +++ b/book/http_cache.rst @@ -155,14 +155,23 @@ il kernel della cache:: $kernel->loadClassCache(); // inserisce AppKernel all'interno di AppCache $kernel = new AppCache($kernel); + $request = Request::createFromGlobals(); + $response = $kernel->handle($request); $response->send(); + $kernel->terminate($request, $response); Il kernel della cache agirà immediatamente da reverse proxy, mettendo in cache le risposte dell'applicazione e restituendole al client. +.. caution:: + + Se si usa l'opzione :ref:`framework.http_method_override ` + per leggere il metodo HTTP da un parametro ``_method``, vedere il collegamento precedente + per un trucco da applicare. + .. tip:: Il kernel della cache ha uno speciale metodo ``getLog()``, che restituisce una @@ -383,6 +392,8 @@ in cache dati, eccetera). Questo ha due conseguenze molto ragionevoli: post di un blog). Metterli in cache impedirebbe ad alcune richieste di arrivare all'applicazione o di modificarla. +.. _http-cache-defaults: + Regole e valori predefiniti della cache ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -572,18 +583,24 @@ l'applicazione restituirebbe. Un ``ETag`` è come un'impronta digitale ed è usa confrontare rapidamente se due diverse versioni di una risorsa siano equivalenti. Come le impronte digitali, ogni ``ETag`` deve essere univoco tra tutte le rappresentazioni della stessa risorsa. -Vediamo una semplice implementazione, che genera l'ETag come un md5 del contenuto:: +Ecco una semplice implementazione, che genera l'ETag come un md5 del contenuto:: + + // src/AppBundle/Controller/DefaultController.php + namespace AppBundle\Controller; use Symfony\Component\HttpFoundation\Request; - public function indexAction(Request $request) + class DefaultController extends Controller { - $response = $this->render('MyBundle:Main:index.html.twig'); - $response->setETag(md5($response->getContent())); - $response->setPublic(); // assicurarsi che la risposta sia pubblica - $response->isNotModified($request); + public function homepageAction(Request $request) + { + $response = $this->render('static/homepage.html.twig'); + $response->setETag(md5($response->getContent())); + $response->setPublic(); // assicurarsi che la risposta sia pubblica + $response->isNotModified($request); - return $response; + return $response; + } } Il metodo :method:`Symfony\\Component\\HttpFoundation\\Response::isNotModified` @@ -630,28 +647,36 @@ Per esempio, si può usare la data di ultimo aggiornamento per tutti gli oggetti necessari per calcolare la rappresentazione della risorsa come valore dell'header ``Last-Modified``:: + // src/AppBundle/Controller/ArticleController.php + namespace AppBundle\Controller; + + // ... use Symfony\Component\HttpFoundation\Request; + use AppBundle\Entity\Article; - public function showAction($articleSlug, Request $request) + class ArticleController extends Controller { - // ... + public function showAction(Article $article, Request $request) + { + $author = $article->getAuthor(); - $articleDate = new \DateTime($article->getUpdatedAt()); - $authorDate = new \DateTime($author->getUpdatedAt()); + $articleDate = new \DateTime($article->getUpdatedAt()); + $authorDate = new \DateTime($author->getUpdatedAt()); - $date = $authorDate > $articleDate ? $authorDate : $articleDate; + $date = $authorDate > $articleDate ? $authorDate : $articleDate; - $response->setLastModified($date); - // imposta la risposta come pubblica. Altrimenti, è privata come valore predefinito. - $response->setPublic(); + $response->setLastModified($date); + // imposta la risposta come pubblica. Altrimenti, è privata come valore predefinito. + $response->setPublic(); - if ($response->isNotModified($request)) { - return $response; - } + if ($response->isNotModified($request)) { + return $response; + } - // ... fare qualcosa per popolare la risposta con il contenuto completo + // ... fare qualcosa per popolare la risposta con il contenuto completo - return $response; + return $response; + } } Il metodo method:`Symfony\\Component\\HttpFoundation\\Response::isNotModified` @@ -680,40 +705,46 @@ In altre parole, meno un'applicazione fa per restituire una risposta 304, meglio è. Il metodo ``Response::isNotModified()`` fa esattamente questo, esponendo uno schema semplice ed efficiente:: + // src/AppBundle/Controller/ArticleController.php + namespace AppBundle\Controller; + + // ... use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; - public function showAction($articleSlug, Request $request) + class ArticleController extends Controller { - // Prende l'informazione minima per calcolare - // l'ETag o o il valore di Last-Modified - // (in base alla Request, i dati sono recuperati da una - // base dati o da una memoria chiave-valore, per esempio) - $article = ...; - - // crea una Response con un ETag e/o un header Last-Modified - $response = new Response(); - $response->setETag($article->computeETag()); - $response->setLastModified($article->getPublishedAt()); - - // imposta la risposta come pubblica. Altrimenti, è privata come valore predefinito. - $response->setPublic(); - - // Verifica che la Response non sia modificata per la Request data - if ($response->isNotModified($request)) { - // restituisce subito la Response 304 - return $response; - } + public function showAction($articleSlug, Request $request) + { + // Prende l'informazione minima per calcolare + // l'ETag o o il valore di Last-Modified + // (in base alla Request, i dati sono recuperati da una + // base dati o da una memoria chiave-valore, per esempio) + $article = ...; + + // crea una Response con un ETag e/o un header Last-Modified + $response = new Response(); + $response->setETag($article->computeETag()); + $response->setLastModified($article->getPublishedAt()); + + // imposta la risposta come pubblica. Altrimenti, è privata come valore predefinito. + $response->setPublic(); + + // Verifica che la Response non sia modificata per la Request data + if ($response->isNotModified($request)) { + // restituisce subito la Response 304 + return $response; + } - // qui fare qualcosa, come recuperare altri dati - $comments = ...; + // qui fare qualcosa, come recuperare altri dati + $comments = ...; - // o rendere un template con la $response già iniziata - return $this->render( - 'MyBundle:MyController:article.html.twig', - array('article' => $article, 'comments' => $comments), - $response - ); + // o rendere un template con la $response già iniziata + return $this->render('article/show.html.twig', array( + 'article' => $article, + 'comments' => $comments + ), $response); + } } Quando la ``Response`` non è stata modificata, ``isNotModified()`` imposta automaticamente @@ -796,8 +827,8 @@ utili:: // Forza la risposta a restituire un 304 senza contenuti $response->setNotModified(); -Inoltre, la maggior parte degli header HTTP relativi alla cache può essere impostata -tramite il singolo metodo ``setCache()``:: +Inoltre, la maggior parte degli header HTTP relativi alla cache può essere impostata tramite il singolo +metodo :method:`Symfony\\Component\\HttpFoundation\\Response::setCache`:: // Imposta le opzioni della cache in una sola chiamata $response->setCache(array( @@ -863,10 +894,10 @@ metodo HTTP ``PURGE``:: // app/AppCache.php - // ... use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; + // ... class AppCache extends HttpCache { @@ -877,7 +908,10 @@ metodo HTTP ``PURGE``:: } if ('127.0.0.1' !== $request->getClientIp()) { - return new Response('Invalid HTTP method', Response::HTTP_BAD_REQUEST); + return new Response( + 'Invalid HTTP method', + Response::HTTP_BAD_REQUEST + ); } $response = new Response(); @@ -987,8 +1021,10 @@ Per usare ESI, assicurarsi prima di tutto di abilitarlo nella configurazione del + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony + http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> @@ -1010,13 +1046,19 @@ indipendentemente dal resto della pagina. .. code-block:: php - public function indexAction() + // src/AppBundle/Controller/DefaultController.php + + // ... + class DefaultController extends Controller { - $response = $this->render('MyBundle:MyController:index.html.twig'); - // imposta il tempo massimo condiviso, il che rende la risposta pubblica - $response->setSharedMaxAge(600); + public function aboutAction() + { + $response = $this->render('static/about.html.twig'); + // imposta il tempo massimo condiviso, il che rende la risposta pubblica + $response->setSharedMaxAge(600); - return $response; + return $response; + } } In questo esempio, abbiamo dato alla cache della pagina intera un tempo di vita di dieci @@ -1031,21 +1073,36 @@ Symfony usa l'aiutante ``render`` per configurare i tag ESI: .. code-block:: jinja + {# app/Resources/views/static/about.html.twig #} + {# si può fare riferimento a un controllore #} - {{ render_esi(controller('...:news', { 'maxPerPage': 5 })) }} + {{ render_esi(controller('AppBundle:News:latest', { 'maxPerPage': 5 })) }} {# ... o a un URL #} {{ render_esi(url('latest_news', { 'maxPerPage': 5 })) }} .. code-block:: html+php + + + // si può fare riferimento a un controllore + use Symfony\Component\HttpKernel\Controller\ControllerReference; render( - new \Symfony\Component\HttpKernel\Controller\ControllerReference('...:news', array('maxPerPage' => 5)), - array('strategy' => 'esi')) - ?> + new ControllerReference( + 'AppBundle:News:latest', + array('maxPerPage' => 5) + ), + array('strategy' => 'esi') + ) ?> + // ... o a un URL + use Symfony\Component\Routing\Generator\UrlGeneratorInterface; render( - $view['router']->generate('latest_news', array('maxPerPage' => 5), true), + $view['router']->generate( + 'latest_news', + array('maxPerPage' => 5), + UrlGeneratorInterface::ABSOLUTE_URL + ), array('strategy' => 'esi'), ) ?> @@ -1082,11 +1139,19 @@ dalla pagina principale. .. code-block:: php - public function newsAction($maxPerPage) + // src/AppBundle/Controller/NewsController.php + namespace AppBundle\Controller; + + // ... + class NewsController extends Controller { - // ... + public function latestAction($maxPerPage) + { + // ... + $response->setSharedMaxAge(60); - $response->setSharedMaxAge(60); + return $response; + } } Con ESI, la cache dell'intera pagina sarà valida per 600 secondi, mentre il @@ -1115,8 +1180,10 @@ che va abilitato nella configurazione: + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony + http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> @@ -1149,7 +1216,7 @@ accessi al minimo. direttiva ``max-age`` e metterà in cache l'intera pagina. E questo non è quello che vogliamo. -L'aiutante ``render`` supporta due utili opzioni: +L'aiutante ``render_esi`` supporta due utili opzioni: ``alt`` usato come attributo ``alt`` nel tag ESI, che consente di specificare diff --git a/book/http_fundamentals.rst b/book/http_fundamentals.rst index b5be18f5..b53f0c7d 100644 --- a/book/http_fundamentals.rst +++ b/book/http_fundamentals.rst @@ -287,9 +287,6 @@ orientata agli oggetti per costruire la risposta che occorre restituire al clien // stampa gli header HTTP seguiti dal contenuto $response->send(); -.. versionadded:: 2.4 - Il supporto per le costanti dei codici di stato HTTP è stato aggiunto in Symfony 2.4. - Se Symfony offrisse solo questo, si avrebbe già a disposizione un kit di strumenti per accedere facilmente alle informazioni di richiesta e un'interfaccia orientata agli oggetti per creare la risposta. Anche imparando le molte potenti caratteristiche di Symfony, @@ -376,7 +373,7 @@ possono peggiorare rapidamente:: if (in_array($path, array('', '/'))) { $response = new Response('Benvenuto nella homepage.'); - } elseif ($path == '/contact') { + } elseif ('/contact' === $path) { $response = new Response('Contattaci'); } else { $response = new Response('Pagina non trovata.', Response::HTTP_NOT_FOUND); @@ -462,8 +459,8 @@ iniziamo aggiungendo una voce per ``/contact`` nel file di configurazione delle return $collection; Quando qualcuno vista la pagina ``/contact``, questa rotta viene corrisposta e il controllore -specificato è eseguito. Come si imparerà nel :doc:`capitolo delle rotte`, -la stringa ``AcmeDemoBundle:Main:contact`` è una sintassi breve che punta a uno specifico +specificato è eseguito. Come si imparerà nel :doc:`capitolo delle rotte `, +la stringa ``AppBundle:Main:contact`` è una sintassi breve che punta a uno specifico metodo PHP ``contactAction`` in una classe chiamata ``MainController``:: // src/AppBundle/Controller/MainController.php @@ -481,7 +478,7 @@ metodo PHP ``contactAction`` in una classe chiamata ``MainController``:: In questo semplice esempio, il controllore semplicemente crea un oggetto :class:`Symfony\\Component\\HttpFoundation\\Response` con il codice HTML -"

Contattaci!

". Nel :doc:`capitolo sul controllore`, +``

Contattaci!

``. Nel :doc:`capitolo sul controllore `, si imparerà come un controllore possa rendere dei template, consentendo al codice di "presentazione" (cioè a qualsiasi cosa che scrive effettivamente HTML) di vivere in un file template separato. Questo consente al controllore di preoccuparsi solo delle cose @@ -518,30 +515,32 @@ possono essere usate in *qualsiasi* progetto PHP. Queste librerie, chiamate *componenti di Symfony*, contengono qualcosa di utile per quasi ogni situazione, comunque sia sviluppato il proprio progetto. Solo per nominarne alcuni: -* :doc:`HttpFoundation ` - Contiene le - classi ``Request`` e ``Response``, insieme ad altre classi per gestire sessioni - e caricamenti di file; +:doc:`HttpFoundation ` + Contiene le classi ``Request`` e ``Response``, insieme ad altre classi + per gestire sessioni e caricamenti di file; -* :doc:`Routing ` - Sistema di rotte potente e veloce, che - consente di mappare uno specifico URI (p.e. ``/contact``) ad alcune informazioni - su come tale richiesta andrebbe gestita (p.e. eseguendo il metodo - ``contactAction()``); +:doc:`Routing ` + Sistema di rotte potente e veloce, che + consente di mappare uno specifico URI (p.e. ``/contact``) ad alcune informazioni + su come tale richiesta andrebbe gestita (p.e. eseguendo il metodo ``contactAction()``); -* :doc:`Form ` - Un framework completo e flessibile per creare form e gestire invii di - dati; +:doc:`Form ` + Un framework completo e flessibile per creare form e gestire invii di + dati; -* `Validator`_ Un sistema per creare regole sui dati e quindi validarli, sia che i dati - inviati dall'utente seguano o meno tali regole; +`Validator`_ + Un sistema per creare regole sui dati e quindi validarli, sia che i dati + inviati dall'utente seguano o meno tali regole; -* :doc:`Templating ` Un insieme di strumenti per rendere template, gestire l'ereditarietà dei - template (p.e. un template è decorato con un layout) ed eseguire altri compiti - comuni sui template; +:doc:`Templating ` + Un insieme di strumenti per rendere template, gestire l'ereditarietà dei template (p.e. + un template è decorato con un layout) ed eseguire altri compiti comuni sui template; -* :doc:`Security ` - Una potente libreria per gestire tutti i tipi di sicurezza all'interno - di un'applicazione; +:doc:`Security ` + Una potente libreria per gestire tutti i tipi di sicurezza all'interno di un'applicazione; -* :doc:`Translation ` - Un framework - per tradurre stringhe nella propria applicazione. +:doc:`Translation ` + Un framework per tradurre stringhe nella propria applicazione. Tutti questi componenti sono disaccoppiati e possono essere usati in *qualsiasi* progetto PHP, indipendentemente dall'uso del framework Symfony. Ogni parte di essi è stata diff --git a/book/index.rst b/book/index.rst index 0e7abfe5..7b881731 100644 --- a/book/index.rst +++ b/book/index.rst @@ -22,6 +22,5 @@ Libro service_container performance internals - stable_api .. include:: /book/map.rst.inc diff --git a/book/installation.rst b/book/installation.rst index b725c273..eec9eb46 100644 --- a/book/installation.rst +++ b/book/installation.rst @@ -6,14 +6,13 @@ Installare e configurare Symfony Lo scopo di questo capitolo è mettere in grado di avere un'applicazione funzionante basata su Symfony. Per semplificare il processo di creazione di nuove -applicaizoni, Symfony fornisce un installatore, che va installato una sola volta, -alla creazione della prima applicazione. +applicazioni, Symfony fornisce un installatore. Installare l'installatore di Symfony ------------------------------------ -L'utilizzo dell'installatore di Symfony è l'unico modo raccomandato di creare nuove -applicaizoni Symfony. Questo installatore è un'applicazione PHP, che va installata +L'utilizzo dell'**installatore di Symfony** è l'unico modo raccomandato di creare nuove +applicazioni Symfony. Questo installatore è un'applicazione PHP, che va installata solo una volta e che può quindi creare tutte le applicazioni Symfony. .. note:: @@ -33,12 +32,10 @@ Aprire un terminale ed eseguire i seguenti tre comandi: .. code-block:: bash - $ curl -LsS http://symfony.com/installer > symfony.phar - $ sudo mv symfony.phar /usr/local/bin/symfony - $ chmod a+x /usr/local/bin/symfony + $ sudo curl -LsS http://symfony.com/installer -o /usr/local/bin/symfony + $ sudo chmod a+x /usr/local/bin/symfony -Questo creerà nel sistema un comando globale ``symfony``, che sarà usato -per creare nuove applicazioni Symfony. +Questo creerà nel sistema un comando globale ``symfony``. Sistemi Windows ~~~~~~~~~~~~~~~ @@ -47,15 +44,15 @@ Aprire la console dei comandi ed eseguire il seguente comando: .. code-block:: bash - c:\> php -r "readfile('http://symfony.com/installer');" > symfony.phar + c:\> php -r "readfile('http://symfony.com/installer');" > symfony Quindi, spostare il file ``symfony.phar`` nella cartella dei progetti ed eseguirlo, come segue: .. code-block:: bash - c:\> move symfony.phar c:\progetti - c:\progetti\> php symfony.phar + c:\> move symfony c:\progetti + c:\progetti\> php symfony Creare l'applicazione Symfony ----------------------------- @@ -90,13 +87,30 @@ Basare un progetto su una specifica versione di Symfony Se un progetto deve essere basato su una specifica versione di Symfony, passare il numero di versione come secondo parametro del comando ``new``: +.. code-block:: bash + + # usa la versione più recente di un ramo di Symfony + $ symfony new progetto 2.3 + $ symfony new progetto 2.5 + $ symfony new progetto 2.6 + + # usa una specifica versione di Symfony + $ symfony new progetto 2.3.26 + $ symfony new progetto 2.6.5 + + # usa la versione LTS (Long Term Support) più recente + $ symfony new progetto lts + +Se si vuole basare un progetto sull'ultima :ref:`versione LTS di Symfony `, +passare ``lts`` come secondo parametro del comando ``new``: + .. code-block:: bash # Linux, Mac OS X - $ symfony new progetto 2.3.23 + $ symfony new progetto lts # Windows - c:\projects\> php symfony.phar new progetto 2.3.23 + c:\projects\> php symfony new progetto lts Leggere il :doc:`processo di rilascio di Symfony ` per comprendere meglio il motivo per cui esistono varie versioni di Symfony e quale @@ -288,6 +302,18 @@ tutte insieme: A seconda della complessità del progetto, questo processo di aggiornamento può impiegare anche vari minuti per essere completato. +.. tip:: + + Symfony fornisce un comando per verificare se le dipendenze di un progetto + contengano vulnerabilità note: + + .. code-block:: bash + + $ php app/console security:check + + Una buona pratica di sicurezza consiste nell'eseguire regolarmente questo comando, per poter + aggiornare o sostituire delle dipendenze compromesse, il prima possibile. + .. _installing-a-symfony2-distribution: Installare una distribuzione di Symfony @@ -315,7 +341,7 @@ Uso di un controllo dei sorgenti -------------------------------- Se si usa un sistema di controllo di versione, come `Git`_, si può tranquillamente eseguire il commit -do tutto il codice del progetto. Questo perché le applicaizoni Symfony contengono già un file +do tutto il codice del progetto. Questo perché le applicazioni Symfony contengono già un file ``.gitignore``, preparato appositamente per Symfony. Per istruzioni specifiche su come impostare al meglio un progetto per essere memorizzato diff --git a/book/internals.rst b/book/internals.rst index 5f310db2..b934bcc6 100644 --- a/book/internals.rst +++ b/book/internals.rst @@ -208,26 +208,22 @@ Il tipo è passato a tutti gli eventi e gli ascoltatori possono agire di consegu Eventi ~~~~~~ -.. versionadded:: 2.4 - Il metodo ``isMasterRequest()`` è stato introdotto in Symfony 2.4. - In precedenza veniva usato il metodo ``getRequestType()``. - Ogni evento lanciato dal kernel è una sotto-classe di :class:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent`. Questo vuol dire che ogni evento ha accesso alle stesse informazioni di base: -* :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getRequestType` - restituisce - il *tipo* della richiesta (``HttpKernelInterface::MASTER_REQUEST`` - o ``HttpKernelInterface::SUB_REQUEST``); +:method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getRequestType` + Restituisce il *tipo* della richiesta (``HttpKernelInterface::MASTER_REQUEST`` o + ``HttpKernelInterface::SUB_REQUEST``). -* :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::isMasterRequest` - - verifica se è una richiesta principale; +:method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::isMasterRequest` + Verifica se è una richiesta principale. -* :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getKernel` - restituisce - il kernel che gestisce la richiesta; +:method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getKernel` + Restituisce il kernel che gestisce la richiesta. -* :method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getRequest` - restituisce - la ``Request`` attualmente in gestione. +:method:`Symfony\\Component\\HttpKernel\\Event\\KernelEvent::getRequest` + Restituisce la ``Request`` attualmente in gestione. ``isMasterRequest()`` ..................... diff --git a/book/map.rst.inc b/book/map.rst.inc index 573c8027..0a1b3381 100644 --- a/book/map.rst.inc +++ b/book/map.rst.inc @@ -16,4 +16,3 @@ * :doc:`/book/service_container` * :doc:`/book/performance` * :doc:`/book/internals` -* :doc:`/book/stable_api` diff --git a/book/page_creation.rst b/book/page_creation.rst index b9becb4f..6f1972f0 100644 --- a/book/page_creation.rst +++ b/book/page_creation.rst @@ -112,9 +112,9 @@ questo capitolo), eseguire il seguente comando e seguire le istruzioni su scherm .. code-block:: bash - $ php app/console generate:bundle --namespace=Acme/HelloBundle --format=yml + $ php app/console generate:bundle --namespace=Acme/DemoBundle --format=yml -Dietro le quinte, viene creata una cartella per il bundle in ``src/Acme/HelloBundle``. +Dietro le quinte, viene creata una cartella per il bundle in ``src/Acme/DemoBundle``. Inoltre viene aggiunta automaticamente una riga al file ``app/AppKernel.php``, in modo che il bundle sia registrato nel kernel:: @@ -141,7 +141,7 @@ Symfony si trova in ``app/config/routing.yml``. Come ogni configurazione in Symf si può anche scegliere di usare XML o PHP per configurare le rotte. Se si guarda il file principale delle rotte, si vedrà che Symfony ha già aggiunto -una voce, quando è stato generato ``AcmeHelloBundle``: +una voce, quando è stato generato ``AcmeDemoBundle``: .. configuration-block:: @@ -181,9 +181,10 @@ una voce, quando è stato generato ``AcmeHelloBundle``: Questa voce è molto basica: dice a Symfony di caricare la configurazione delle rotte dal file ``Resources/config/routing.yml`` (``routing.xml`` o ``routing.php`` -rispettivamente negli esempi di codice XML e PHP), che si trova dentro ``AcmeDemoBundle``. -Questo vuol dire che si mette la configurazione delle rotte direttamente in ``app/config/routing.yml`` -o si organizzano le proprie rotte attraverso la propria applicazione, e le si importano da qui. +rispettivamente negli esempi di codice XML e PHP), che si trova dentro +AcmeDemoBundle. Questo vuol dire che si mette la configurazione delle rotte direttamente in +``app/config/routing.yml`` o si organizzano le proprie rotte attraverso la propria applicazione +e le si importano da qui. .. note:: @@ -248,14 +249,14 @@ Passo 2: creare il controllore ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Quando un URL come ``/hello/Ryan`` viene gestita dall'applicazione, la rotta ``hello`` -viene corrisposta e il controllore ``AcmeHelloBundle:Hello:index`` eseguito dal +viene corrisposta e il controllore ``AcmeDemoBundle:Hello:index`` eseguito dal framework. Il secondo passo del processo di creazione della pagina è quello di creare tale controllore. Il controllore ha il nome *logico* ``AcmeDemoBundle:Random:index`` ed è mappato sul metodo ``indexAction`` di una classe PHP chiamata -``Acme\DemoBundle\Controller\RandomController``. Iniziamo creando questo file dentro il nostro -``AcmeDemoBundle``:: +``Acme\DemoBundle\Controller\RandomController``. Iniziamo creando questo file dentro +il nostro AcmeDemoBundle:: // src/Acme/DemoBundle/Controller/RandomController.php namespace Acme\DemoBundle\Controller; @@ -378,7 +379,7 @@ predefinita, Symfony supporta due diversi linguaggi di template: i classici template PHP e i template, concisi ma potenti, `Twig`_. Non ci si allarmi, si è liberi di scegliere tra i due, o anche tutti e due nello stesso progetto. -Il controllore rende il template ``AcmeHelloBundle:Hello:index.html.twig``, +Il controllore rende il template ``AcmeDemoBundle:Hello:index.html.twig``, che usa la seguente convenzioni dei nomi: **NomeBundle**:**NomeControllore**:**NomeTemplate** @@ -543,7 +544,7 @@ classe kernel, ``AppKernel``, per inizializzare l'applicazione. http://localhost/app.php/random/10 Il front controller, ``app.php``, viene eseguito e l'URL "interno" - ``/hello/Ryan`` è dirottato internamente, usando la configurazione delle rotte. + ``/random/10`` è dirottato internamente, usando la configurazione delle rotte. Usando ``mod_rewrite`` di Apache, si può forzare l'esecuzione del file ``app.php`` senza bisogno di specificarlo nell'URL: @@ -707,8 +708,9 @@ chiamato ``AcmeTestBundle.php``:: .. tip:: - Il nome ``AcmeTestBundle`` segue le :ref:`convenzioni sui nomi dei bundle`. - Si potrebbe anche scegliere di accorciare il nome del bundle semplicemente a ``TestBundle``, + Il nome AcmeTestBundle segue le + :ref:`convenzioni sui nomi dei bundle`. Si + potrebbe anche scegliere di accorciare il nome del bundle semplicemente a TestBundle, chiamando la classe ``TestBundle`` (e chiamando il file ``TestBundle.php``). Questa classe vuota è l'unico pezzo necessario a creare un nuovo bundle. Sebbene solitamente @@ -730,8 +732,7 @@ Ora che il bundle è stato creato, va abilitato tramite la classe ``AppKernel``: return $bundles; } -Sebbene non faccia ancora nulla, ``AcmeTestBundle`` è ora pronto per -essere usato. +Sebbene non faccia ancora nulla, AcmeTestBundle è ora pronto per essere usato. Symfony fornisce anche un'interfaccia a linea di comando per generare uno scheletro di base per un bundle: @@ -767,7 +768,7 @@ mantenere il codice coerente tra tutti i bundle di Symfony. Si dia un'occhiata a (tale cartella non è indispensabile); ``Resources/config/`` - ospita la configurazione, compresa la configurazione delle rotte (p.e. ``routing.yml``); + contiene la configurazione, compresa la configurazione delle rotte (p.e. ``routing.yml``); ``Resources/views/`` contiene i template, organizzati per nome di controllore (p.e. ``Hello/index.html.twig``); @@ -938,7 +939,7 @@ ogni richiesta nell'ambiente ``dev`` (per facilitare gli sviluppatori), ma salva in cache nell'ambiente ``prod``. Tutti gli ambienti stanno insieme nella stessa macchina e sono eseguiti nella stessa applicazione. -Un progetto Symfony2 generalmente inizia con tre ambienti (``dev``, ``test`` +Un progetto Symfony generalmente inizia con tre ambienti (``dev``, ``test`` e ``prod``), ma creare nuovi ambienti è facile. Si può vedere la propria applicazione in ambienti diversi, semplicemente cambiando il front controller nel browser. Per vedere l'applicazione in ambiente ``dev``, accedere all'applicazione diff --git a/book/performance.rst b/book/performance.rst index 5a633f7f..f20483c4 100644 --- a/book/performance.rst +++ b/book/performance.rst @@ -18,7 +18,8 @@ Usare una cache bytecode (p.e. APC) Una delle cose migliori (e più facili) che si possono fare per migliorare le prestazioni è quella di usare una cache bytecode. L'idea di una cache bytecode è di rimuove l'esigenza di dover ricompilare ogni volta il codice sorgente PHP. Ci sono numerose -`cache bytecode`_ disponibili, alcune delle quali open source. La più usata +`cache bytecode`_ disponibili, alcune delle quali open source. Dalla versione 5.5, +PHP include `OPcache`_. Per versioni precedenti, la cache più usata è probabilmente `APC`_. Usare una cache bytecode non ha alcun effetto negativo, e Symfony è stato progettato @@ -128,8 +129,7 @@ Si noti che ci sono due svantaggi nell'uso di un file di avvio: * durante il debug, occorre inserire i breakpoint nel file di avvio. Se si usa Symfony Standard Edition, il file di avvio è ricostruito automaticamente -dopo l'aggiornamento delle librerie dei venditori, tramite il comando -``php composer.phar install``. +dopo l'aggiornamento delle librerie dei venditori, tramite il comando ``composer install``. File di avvio e cache bytecode ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -140,6 +140,7 @@ questa caratteristica è disabilitata nella cache bytecode (p.e. con ``apc.stat= non c'è più ragione di usare un file di avvio. .. _`cache bytecode`: http://en.wikipedia.org/wiki/List_of_PHP_accelerators +.. _`OPcache`: http://php.net/manual/it/book.opcache.php .. _`APC`: http://php.net/manual/it/book.apc.php .. _`autoloader.php`: https://github.com/symfony/symfony-standard/blob/master/app/autoload.php .. _`file di avvio`: https://github.com/sensio/SensioDistributionBundle/blob/master/Composer/ScriptHandler.php diff --git a/book/propel.rst b/book/propel.rst index 70e800c1..b8b3e6a1 100644 --- a/book/propel.rst +++ b/book/propel.rst @@ -15,15 +15,6 @@ Un semplice esempio: un prodotto In questa sezione, configureremo la nostra base dati, creeremo un oggetto ``Product``, lo persisteremo nella base dati e lo recuperemo nuovamente. -.. sidebar:: Codice insieme all'esempio - - Se si vuole seguire il codice di questo capitolo, creare un - ``AcmeStoreBundle``, tramite: - - .. code-block:: bash - - $ php app/console generate:bundle --namespace=Acme/StoreBundle - Configurare la base dati ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -42,12 +33,6 @@ file ``app/config/parameters.yml``: database_password: password database_charset: UTF8 -.. note:: - - La definizione della configurazione tramite ``parameters.ini`` è solo una convenzione. - I parametri definiti in tale file sono riferiti dal file di configurazione principale - durante le impostazioni iniziali di Propel: - I parametri definiti in ``parameters.yml`` possono essere inclusi nel file di configurazione (``config.yml``): @@ -60,6 +45,12 @@ configurazione (``config.yml``): password: "%database_password%" dsn: "%database_driver%:host=%database_host%;dbname=%database_name%;charset=%database_charset%" +.. note:: + + La definizione della configurazione tramite ``parameters.yml`` è una + :ref:`best practice di Symfony `, + ma si può usare qualsiasi metodo si ritenga appropriato. + Ora che Propel ha informazioni sulla base dati, si può fare in modo che crei la base dati al posto nostro: @@ -86,14 +77,15 @@ generate da Propel contengono della logica di business. Si supponga di costruire un'applicazione in cui occorre mostrare dei prodotti. Innanzitutto, creare un file ``schema.xml`` nella cartella ``Resources/config`` del -proprio ``AcmeStoreBundle``: +proprio AppBundle: .. code-block:: xml + @@ -129,7 +121,7 @@ Dopo aver creato ``schema.xml``, generare il modello, eseguendo: $ php app/console propel:model:build Questo comando genera ogni classe del modello, per sviluppare rapidamente -un'applicazione, nella cartella ``Model/`` di ``AcmeStoreBundle``. +un'applicazione, nella cartella ``Model/`` di AppBundle. Creare schema e tabelle della base dati ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -149,33 +141,40 @@ schema creato in precedenza. .. tip:: - Si possono eseguire gli ultimi tre comandi in uno, usando il seguente: - ``php app/console propel:build --insert-sql``. + Si possono eseguire gli ultimi tre comandi in uno, usando il seguente + comando: + + .. code-block:: bash + + $ php app/console propel:build --insert-sql Persistere oggetti nella base dati ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Ora che si ha un oggetto ``Product`` e una tabella ``product`` corrispondente, si è pronti per persistere nella base dati. Da dentro un controllore, è molto -facile. Aggiungere il seguente metodo a ``DefaultController`` del +facile. Aggiungere il seguente metodo a ``ProductController`` del bundle:: - // src/Acme/StoreBundle/Controller/DefaultController.php + // src/AppBundle/Controller/ProductController.php // ... - use Acme\StoreBundle\Model\Product; + use AppBundle\Model\Product; use Symfony\Component\HttpFoundation\Response; - public function createAction() + class ProductController extends Controller { - $product = new Product(); - $product->setName('Un nome'); - $product->setPrice(19.99); - $product->setDescription('Lorem ipsum dolor'); + public function createAction() + { + $product = new Product(); + $product->setName('Un nome'); + $product->setPrice(19.99); + $product->setDescription('Lorem ipsum dolor'); - $product->save(); + $product->save(); - return new Response('Creato prodotto con id '.$product->getId()); + return new Response('Creato prodotto con id '.$product->getId()); + } } In questo pezzo di codice, è stato istanziato e usato un oggetto ``$product``. @@ -194,21 +193,27 @@ Recuperare oggetti dalla base dati è anche più semplice. Per esempio, si suppo di aver configurato una rotta per mostrare uno specifico ``Product``, in base al valore del suo ``id``:: + // src/AppBundle/Controller/ProductController.php + // ... - use Acme\StoreBundle\Model\ProductQuery; + use AppBundle\Model\ProductQuery; - public function showAction($id) + class ProductController extends Controller { - $product = ProductQuery::create() - ->findPk($id); + // ... - if (!$product) { - throw $this->createNotFoundException( - 'Nessun prodotto trovato con id '.$id - ); - } + public function showAction($id) + { + $product = ProductQuery::create()->findPk($id); + + if (!$product) { + throw $this->createNotFoundException( + 'Nessun prodotto trovato con id '.$id + ); + } - // ... fare qualcosa, come passare l'oggetto $product a un template + // ... fare qualcosa, come passare l'oggetto $product a un template + } } Aggiornare un oggetto @@ -217,24 +222,30 @@ Aggiornare un oggetto Una volta recuperato un oggetto con Propel, aggiornarlo è facile. Si supponga di avere una rotta che mappi l'id di un prodotto all'azione di aggiornamento di un controllore:: + // src/AppBundle/Controller/ProductController.php + // ... - use Acme\StoreBundle\Model\ProductQuery; + use AppBundle\Model\ProductQuery; - public function updateAction($id) + class ProductController extends Controller { - $product = ProductQuery::create() - ->findPk($id); + // ... - if (!$product) { - throw $this->createNotFoundException( - 'Nessun prodotto trovato con id '.$id - ); - } + public function updateAction($id) + { + $product = ProductQuery::create()->findPk($id); - $product->setName('Nuovo nome del prodotto!'); - $product->save(); + if (!$product) { + throw $this->createNotFoundException( + 'Nessun prodotto trovato con id '.$id + ); + } - return $this->redirect($this->generateUrl('homepage')); + $product->setName('Nuovo nome del prodotto!'); + $product->save(); + + return $this->redirect($this->generateUrl('homepage')); + } } L'aggiornamento di un oggetto si esegue in tre passi: @@ -257,16 +268,22 @@ Cercare gli oggetti Propel fornisce delle classi ``Query``, per eseguire query, semplici o complesse, senza sforzo:: - \Acme\StoreBundle\Model\ProductQuery::create()->findPk($id); + use AppBundle\Model\ProductQuery; + // ... + + ProductQuery::create()->findPk($id); - \Acme\StoreBundle\Model\ProductQuery::create() + ProductQuery::create() ->filterByName('Pippo') ->findOne(); Si immagini di voler cercare prodotti che costino più di 19.99, ordinati dal più economico al più costoso. Da dentro un controllore, fare come segue:: - $products = \Acme\StoreBundle\Model\ProductQuery::create() + use AppBundle\Model\ProductQuery; + // ... + + $products = ProductQuery::create() ->filterByPrice(array('min' => 19.99)) ->orderByPrice() ->find(); @@ -279,20 +296,26 @@ astrazione. Se si vogliono riutilizzare delle query, si possono aggiungere i propri metodi alla classe ``ProductQuery``:: - // src/Acme/StoreBundle/Model/ProductQuery.php + // src/AppBundle/Model/ProductQuery.php + + // ... class ProductQuery extends BaseProductQuery { public function filterByExpensivePrice() { - return $this - ->filterByPrice(array('min' => 1000)); + return $this->filterByPrice(array( + 'min' => 1000, + )); } } Ma si noti che Propel genera diversi metodi per noi e un semplice ``findAllOrderedByName()`` può essere scritto senza sforzi:: - \Acme\StoreBundle\Model\ProductQuery::create() + use AppBundle\Model\ProductQuery; + // ... + + ProductQuery::create() ->orderByName() ->find(); @@ -310,7 +333,7 @@ Si inizi aggiungendo la definizione di ``category`` al file ``schema.xml``:
@@ -382,12 +405,14 @@ Salvare oggetti correlati Vediamo ora un po' di codice in azione. Immaginiamo di essere dentro un controllore:: + // src/AppBundle/Controller/ProductController.php + // ... - use Acme\StoreBundle\Model\Category; - use Acme\StoreBundle\Model\Product; + use AppBundle\Model\Category; + use AppBundle\Model\Product; use Symfony\Component\HttpFoundation\Response; - class DefaultController extends Controller + class ProductController extends Controller { public function createProductAction() { @@ -418,21 +443,25 @@ Recuperare oggetti correlati ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Quando serve recuperare oggetti correlati, il flusso di lavoro assomiglia del tutto al -precedente. Prima, recuperare un oggetto ``$product`` e quindi accedere alla ``Category`` -relativa:: +precedente. Prima, recuperare un oggetto ``$product`` e quindi accedere alla ``Category`` relativa:: + + // src/AppBundle/Controller/ProductController.php // ... - use Acme\StoreBundle\Model\ProductQuery; + use AppBundle\Model\ProductQuery; - public function showAction($id) + class ProductController extends Controller { - $product = ProductQuery::create() - ->joinWithCategory() - ->findPk($id); + public function showAction($id) + { + $product = ProductQuery::create() + ->joinWithCategory() + ->findPk($id); - $categoryName = $product->getCategory()->getName(); + $categoryName = $product->getCategory()->getName(); - // ... + // ... + } } Si noti che, nell'esempio qui sopra, è stata eseguita una sola query. @@ -448,13 +477,13 @@ Callback del ciclo di vita A volte, occorre eseguire un'azione appena prima (o appena dopo) che l'oggetto sia inserito, aggiornato o cancellato. Questi tipi di azioni sono noti come "callback del -ciclo di vita" oppure come "hook", perché sono metodi callback che occorre eseguire +ciclo di vita" oppure come "agganci", perché sono metodi callback che occorre eseguire durante i diversi stadi del ciclo di vita di un oggetto (p.e. quando l'oggetto viene inserito, aggiornato, cancellato, eccetera). -Per aggiungere un hook, basta aggiungere un nuovo metodo alla classe:: +Per aggiungere un aggancio, basta aggiungere un nuovo metodo alla classe:: - // src/Acme/StoreBundle/Model/Product.php + // src/AppBundle/Model/Product.php // ... class Product extends BaseProduct @@ -465,7 +494,7 @@ Per aggiungere un hook, basta aggiungere un nuovo metodo alla classe:: } } -Propel fornisce i seguenti hook: +Propel fornisce i seguenti agganci: ``preInsert()`` codice eseguito prima dell'inserimento di un nuovo oggetto diff --git a/book/security.rst b/book/security.rst index 84100794..5ad30d65 100644 --- a/book/security.rst +++ b/book/security.rst @@ -21,7 +21,8 @@ sezioni: 3) Recuperare l'oggetto corrispondente all'utente corrente Successivamente ci saranno un certo numero di piccole (ma interessanti) sezioni, -come :ref:`logout ` e :ref:`codifica delle password `. +come :ref:`logout ` e +:ref:`codifica delle password `. .. _book-security-firewalls: @@ -180,7 +181,7 @@ Per attivarlo, aggiungere la voce ``http_basic`` nel firewall: ), )); -Facile! Per fare una prova, si deve richiedere che un utente sia loggato per poter vedere +Facile! Per fare una prova, si deve richiedere che un utente sia connesso per poter vedere una pagina. Per rendere le cose interessanti, creare una nuova pagina su ``/admin``. Per esempio, se si usano le annotazioni, creare qualcosa come questo:: @@ -202,7 +203,7 @@ esempio, se si usano le annotazioni, creare qualcosa come questo:: } Quindi, aggiungere a ``security.yml`` una voce ``access_control`` che richieda all'utente -di essere loggato per poter accedere a tale URL: +di essere connesso per poter accedere a tale URL: .. configuration-block:: @@ -492,7 +493,7 @@ parte, se ne vorranno codificare le password. Il miglior algoritmo da usare è 'encoders' => array( 'Symfony\Component\Security\Core\User\User' => array( - 'algorithm' => 'plaintext', + 'algorithm' => 'bcrypt', 'cost' => 12, ) ), @@ -666,11 +667,11 @@ Aggiungere codice per negare l'accesso Ci sono **due** modi per negare accesso a qualcosa: -1) :ref:`access_control in security.yml ` +#. :ref:`access_control in security.yml ` consente di proteggere schemi di URL (p.e. ``/admin/*``). È facile, ma meno flessibile; -2) :ref:`nel codice, tramite il servizio security.context `. +#. :ref:`nel codice, tramite il servizio security.context `. .. _security-authorization-access-control: @@ -737,7 +738,7 @@ corrispondente all'espressione regolare ``^/admin`` richieda ``ROLE_ADMIN``: )); Questo va benissimo per proteggere intere sezioni, ma si potrebbero anche voler -to :ref:`proteggere singoli controllori `. +:ref:`proteggere singoli controllori `. Si possono definire quanti schemi di URL si vuole, ciascuno con un'espressione regolare. @@ -813,20 +814,26 @@ Si può negare accesso da dentro un controllore:: public function helloAction($name) { - if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) { - throw $this->createAccessDeniedException(); - } + // Il secondo parametro si usa per specificare l'oggetto su cui si testa il ruolo + $this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Non si può accedere a questa pagina!'); + + // Vecchio modo : + // if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) { + // throw $this->createAccessDeniedException('Non si può accedere a questa pagina!'); + // } // ... } +.. versionadded:: 2.6 + Il metodo ``denyAccessUnlessGranted()`` è stato introdotto in Symfony 2.6. In precedenza (ma anche + ora), si poteva verificare l'accesso direttamente e sollevare ``AccessDeniedException``, come + mostrato nell'esempio preedente). + .. versionadded:: 2.6 Il servizio ``security.authorization_checker`` è stato introdotto in Symfony 2.6. Prima di Symfony 2.6, si doveva usare il metodo ``isGranted()`` del servizio ``security.context``. -.. versionadded:: 2.5 - Il metodo ``createAccessDeniedException`` è stato introdotto in Symfony 2.5. - Il metodo :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::createAccessDeniedException` crea uno speciale oggetto :class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException`, che alla fine lancia una risposta HTTP 403 in Symfony. @@ -877,8 +884,7 @@ la funzione aiutante predefinita: Se si usa questa funzione *non* essendo dietro a un firewall, sarà lanciata un'ecceezione. È quindi sempre una buona idea avere almeno un firewall -principale, che copra tutti gli URL (come mostrato in -questo capitolo). +principale, che copra tutti gli URL (come mostrato in questo capitolo). .. caution:: @@ -900,12 +906,13 @@ venga usata, solo ad alcuni utenti. Per maggiori informazioni, vedere :doc:`/cookbook/security/securing_services`. -Verificare se un utente sia loggato (IS_AUTHENTICATED_FULLY) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Verificare se un utente sia connesso (IS_AUTHENTICATED_FULLY) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Finora, i controlli sugli accessi sono stati basati su ruoli, stringhe che iniziano con ``ROLE_`` e assegnate agli utenti. Se invece si vuole *solo* verificare se un -utente sia loggato (senza curarsi dei ruoli), si può usare ``IS_AUTHENTICATED_FULLY``:: +utente sia connesso (senza curarsi dei ruoli), si può usare +``IS_AUTHENTICATED_FULLY``:: // ... @@ -923,16 +930,16 @@ utente sia loggato (senza curarsi dei ruoli), si può usare ``IS_AUTHENTICATED_F Si può usare questo metodo anche in ``access_control``. ``IS_AUTHENTICATED_FULLY`` non è un ruolo, ma si comporta come tale ed è assegnato a ciascun -utente che sia sia loggato. In effetti, ci sono tre attributi +utente che sia sia connesso. In effetti, ci sono tre attributi speciali di questo tipo: -* ``IS_AUTHENTICATED_REMEMBERED``: Assegnato a *tutti* gli utenti loggati, anche se - sono stati loggati tramite un cookie "ricordami". Anche se non si usa +* ``IS_AUTHENTICATED_REMEMBERED``: Assegnato a *tutti* gli utenti connessi, anche se + si sono connessi tramite un cookie "ricordami". Anche se non si usa la :doc:`funzionalità "ricordami" `, - lo si può usare per verificare se l'utente sia loggato. + lo si può usare per verificare se l'utente sia connesso. * ``IS_AUTHENTICATED_FULLY``: Simile a ``IS_AUTHENTICATED_REMEMBERED``, - ma più forte. Gli utenti loggati tramite un cookie "ricordami" + ma più forte. Gli utenti connessi tramite un cookie "ricordami" avranno ``IS_AUTHENTICATED_REMEMBERED``, ma non ``IS_AUTHENTICATED_FULLY``. * ``IS_AUTHENTICATED_ANONYMOUSLY``: Assegnato a *tutti* gli utenti (anche quelli anonimi). @@ -1028,8 +1035,8 @@ se il proprio oggetto utente ha un metodo ``getFirstName()``, lo si può usare:: return new Response('Ciao '.$user->getFirstName()); } -Verificare sempre se l'utente è loggato -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Verificare sempre se l'utente è connesso +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ È importante verificare prima se l'utente sia autenticato. Se non lo è, ``$user`` sarà ``null`` oppure la stringa ``anon.``. Come? Esatto, @@ -1037,16 +1044,16 @@ c'è una stranezza. Se non si è leggati, l'utente è tecnicamente la stringa ``anon.``, anche se la scorciatoia ``getUser()`` del controllore la converte in ``null`` per convenienza. -Il punto è questo: verificare sempre se l'utente sia loggato, prima di usare +Il punto è questo: verificare sempre se l'utente sia connesso, prima di usare l'oggetto ``User`` e usare il metodo ``isGranted`` (o :ref:`access_control `) per farlo:: - // Usare questo per vedere se l'utente sia loggato + // Usare questo per vedere se l'utente sia connesso if (!$this->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')) { throw new AccessDeniedException(); } - // Non verificare mai l'oggetto User per verdere se l'utente sia loggato + // Non verificare mai l'oggetto User per verdere se l'utente sia connesso if ($this->getUser()) { } @@ -1314,6 +1321,34 @@ Symfony non creerà alcun cookie): .. _book-security-checking-vulnerabilities: +Verificare vulnerabilità note nelle dipendenze +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.5 + Il comando ``security:check`` è stato introdotto in Symfony 2.5. Questo comando è + incluso in ``SensioDistributionBundle``, bundle che va registrato nell'applicazione + per consentire l'utilizzo del comando stesso. + +Quando si hanno molte dipendenze in progetti Symfony, alcune potrebbero +contenere delle vulnerabilità. Per questo motivo, Symfony include un comando chiamato +``security:check``, che verifica il file ``composer.lock`` e trova eventuali +vulnerabilità nelle dipendenze installate: + +.. code-block:: bash + + $ php app/console security:check + +Una buona pratica di sicurezza consiste nell'eseguire regolarmente questo comando, per poter +aggiornare o sostituire dipendenze compromesse il prima possibile. Internamente, +questo comando usa la `base dati degli avvisi di sicurezza`_ pubblicato dall'organizzazione +FriendsOfPHP. + +.. tip:: + + Il comando ``security:check`` esce con un codice diverso da zero, se alcune + dipendenze sono afflitte da problemi noti di sicurezza. + Quindi, si può facilmente integrare in un processo di build. + Considerazioni finali --------------------- @@ -1335,10 +1370,11 @@ Saperne di più con il ricettario * :doc:`Forzare HTTP/HTTPS ` * :doc:`Impersonare un utente ` -* :doc:`Blacklist di utenti per indirizzo IP ` +* :doc:`/cookbook/security/voters_data_permission` * :doc:`Access Control List (ACL) ` * :doc:`/cookbook/security/remember_me` * :doc:`/cookbook/security/multiple_user_providers` .. _`strumento online`: https://www.dailycred.com/blog/12/bcrypt-calculator .. _`documentazione di frameworkextrabundle`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html +.. _`base dati degli avvisi di sicurezza`: https://github.com/FriendsOfPHP/security-advisories diff --git a/book/service_container.rst b/book/service_container.rst index 157400d8..b7e939d3 100644 --- a/book/service_container.rst +++ b/book/service_container.rst @@ -381,10 +381,9 @@ dell'applicazione. La direttiva ``imports`` consente all'applicazione di includere risorse di configurazione per il contenitore di servizi da qualsiasi altro posto (in genere da bundle). La locazione ``resource``, per i file, è il percorso assoluto al file -risorse. La speciale sintassi ``@AcmeHello`` risolve il percorso della cartella del -bundle ``AcmeHelloBundle``. Questo aiuta a specificare il percorso alla risorsa -senza preoccuparsi in seguito, se si sposta ``AcmeHelloBundle`` in una cartella -diversa. +risorse. La speciale sintassi ``@AcmeHelloBundle`` risolve il percorso della cartella del +bundle AcmeHelloBundle. Questo aiuta a specificare il percorso alla risorsa +senza preoccuparsi in seguito, se si sposta AcmeHelloBundle in una cartella diversa. .. index:: single: Contenitore di servizi; Configurazione delle estensioni @@ -480,7 +479,7 @@ non contiene nessuna magia e non esegue nessuna azione su cui non si abbia il controllo. Naturalmente è possibile fare molto di più della semplice "attivazione" dell'estensione -del contenitore dei servizi di ``FrameworkBundle``. Ogni estensione consente facilmente +del contenitore dei servizi di FrameworkBundle. Ogni estensione consente facilmente di personalizzare il bundle, senza preoccuparsi di come i servizi interni siano definiti. @@ -569,7 +568,7 @@ il contenitore dei servizi fornisce una soluzione molto migliore: services: my_mailer: # ... - + newsletter_manager: class: Acme\HelloBundle\Newsletter\NewsletterManager arguments: ["@my_mailer"] @@ -762,7 +761,7 @@ Iniettare la dipendenza con il metodo setter, necessita solo di un cambio di sin services: my_mailer: # ... - + newsletter_manager: class: Acme\HelloBundle\Newsletter\NewsletterManager calls: @@ -797,7 +796,7 @@ Iniettare la dipendenza con il metodo setter, necessita solo di un cambio di sin use Symfony\Component\DependencyInjection\Reference; $container->setDefinition('my_mailer', ...); - + $container->setDefinition('newsletter_manager', new Definition( 'Acme\HelloBundle\Newsletter\NewsletterManager' ))->addMethodCall('setMailer', array( @@ -938,7 +937,7 @@ esiste e in caso contrario non farà nulla: - + @@ -953,7 +952,7 @@ esiste e in caso contrario non farà nulla: use Symfony\Component\DependencyInjection\ContainerInterface; $container->setDefinition('my_mailer', ...); - + $container->setDefinition('newsletter_manager', new Definition( 'Acme\HelloBundle\Newsletter\NewsletterManager', array( diff --git a/book/stable_api.rst b/book/stable_api.rst deleted file mode 100644 index 29369427..00000000 --- a/book/stable_api.rst +++ /dev/null @@ -1,55 +0,0 @@ -.. index:: - single: API stabile - -.. _the-symfony2-stable-api: - -L'API stabile di Symfony -======================== - -L'API stabile di Symfony è un sottoinsieme di tutti i metodi pubblici di Symfony -(componenti e bundle del nucleo) che condividono le seguenti proprietà: - -* Lo spazio dei nomi e il nome della classe non cambieranno; -* Il nome del metodo non cambierà; -* La firma del metodo (i tipi dei parametri e del valore restituito) non cambierà; -* La semantica di quello che fa il metodo non cambierà; - -Tuttavia potrebbe cambiare l'implementazione. L'unico caso valido per una modifica -dell'API stabile è la soluzone di una questione di sicurezza. - -L'API stabile è basata su una lista, con il tag `@api`. Quindi, -tutto ciò che non possiede esplicitamente il tag non fa parte dell'API stabile. - -.. seealso:: - - Si può consultare la documentazione dell'API di Symfony su `api.symfony.com`_. - -.. tip:: - - Si può approfondire l'API stabile in :doc:`/contributing/code/bc`. - -.. tip:: - - Ogni bundle di terze parti dovrebbe a sua volta pubblicare la sua API stabile. - -A partire da Symfony 2.0, i seguenti componenti hanno un tag API pubblico: - -* BrowserKit -* ClassLoader -* Console -* CssSelector -* DependencyInjection -* DomCrawler -* EventDispatcher -* Filesystem -* Finder -* HttpFoundation -* HttpKernel -* Process -* Routing -* Templating -* Translation -* Validator -* Yaml - -.. _`api.symfony.com`: http://api.symfony.com diff --git a/book/templating.rst b/book/templating.rst index a37f059d..3d38e753 100644 --- a/book/templating.rst +++ b/book/templating.rst @@ -263,7 +263,7 @@ Un template figlio potrebbe assomigliare a questo: .. code-block:: html+jinja - {# app/Resources/views/Blog/index.html.twig #} + {# app/Resources/views/blog/index.html.twig #} {% extends 'base.html.twig' %} {% block title %}I post fighi del mio blog{% endblock %} @@ -277,7 +277,7 @@ Un template figlio potrebbe assomigliare a questo: .. code-block:: html+php - + extend('base.html.php') ?> set('title', 'I post fighi del mio blog') ?> @@ -336,7 +336,7 @@ in un template padre è sempre usato come valore predefinito. Si possono usare tanti livelli di ereditarietà quanti se ne desiderano. Nella prossima sezione, sarà spiegato un modello comune a tre livelli di ereditarietà, insieme al modo -in cui i template sono organizzati in un progetto Symfony2. +in cui i template sono organizzati in un progetto Symfony. Quando si lavora con l'ereditarietà dei template, ci sono alcuni concetti da tenere a mente: @@ -394,8 +394,8 @@ La maggior parte dei template usati si trovano nella cartella ``app/Resources/vi Il percorso che si userà sarà relativo a tale cartella. Per esempio, per rendere o estendere ``app/Resources/views/base.html.twig``, si userà il percorso ``base.html.twig`` e per rendere o estendere -``app/Resources/views/Blog/index.html.twig``, si userà il percorso -``Blog/index.html.twig`` path. +``app/Resources/views/blog/index.html.twig``, si userà il percorso +``blog/index.html.twig`` path. .. _template-referencing-in-bundle: @@ -410,8 +410,8 @@ specifico: template per una determinata pagina. Le tre parti della stringa, ognuna separata da due-punti (``:``), hanno il seguente significato: - * ``AcmeBlogBundle``: (*bundle*) il template è dentro - ``AcmeBlogBundle`` (p.e. ``src/Acme/BlogBundle``); + * ``AcmeBlogBundle``: (*bundle*) il template è dentro AcmeBlogBundle + (p.e. ``src/Acme/BlogBundle``); * ``Blog``: (*cartella*) indica che il template è nella sottocartella ``Blog`` di ``Resources/views``; @@ -419,18 +419,18 @@ specifico: * ``index.html.twig``: (*nome di file*) il nome del file è ``index.html.twig``. - Ipotizzando che ``AcmeBlogBundle`` sia dentro ``src/Acme/BlogBundle``, il percorso + Ipotizzando che AcmeBlogBundle sia dentro ``src/Acme/BlogBundle``, il percorso finale del layout sarebbe ``src/Acme/BlogBundle/Resources/views/Blog/index.html.twig``. * ``AcmeBlogBundle::layout.html.twig``: Questa sintassi si riferisce a un template di base - specifico di ``AcmeBlogBundle``. Poiché la parte centrale, "cartella", manca, + specifico di AcmeBlogBundle. Poiché la parte centrale, "cartella", manca, (p.e. ``Blog``), il template si trova in - ``Resources/views/layout.html.twig``dentro ``AcmeBlogBundle``. + ``Resources/views/layout.html.twig`` dentro AcmeBlogBundle. Ci sono due simboli di "due punti" al centro della stringa, quando manca la parte della sottocartella del controllore. Nella sezione :ref:`overriding-bundle-templates` si potrà trovare come ogni template -dentro ``AcmeBlogBundle``, per esempio, possa essere sovrascritto mettendo un +dentro AcmeBlogBundle, per esempio, possa essere sovrascritto mettendo un template con lo stesso nome nella cartella ``app/Resources/AcmeBlogBundle/views/``. Questo dà la possibilità di sovrascrivere template di qualsiasi bundle. @@ -446,18 +446,18 @@ Ogni nome di template ha due estensioni, che specificano *formato* e *motore* del template stesso. ======================== ======= ====== -Nome file Formato Motore +Nome del file Formato Motore ======================== ======= ====== -``Blog/index.html.twig`` HTML Twig -``Blog/index.html.php`` HTML PHP -``Blog/index.css.twig`` CSS Twig +``blog/index.html.twig`` HTML Twig +``blog/index.html.php`` HTML PHP +``blog/index.css.twig`` CSS Twig ======================== ======= ====== Per impostazione predefinita, ogni template Symfony può essere scritto in Twig o in PHP, e l'ultima parte dell'estensione (p.e. ``.twig`` o ``.php``) specifica quale di questi due *motori* va usata. La prima parte dell'estensione, (p.e. ``.html``, ``.css``, ecc.) è il formato finale che il template -genererà. Diversamente dal motore, che determina il modo in cui Symfony2 analizza il +genererà. Diversamente dal motore, che determina il modo in cui Symfony analizza il template, si tratta di una tattica organizzativa usata nel caso in cui alcune risorse debbano essere rese come HTML (``index.html.twig``), XML (``index.xml.twig``) o in altri formati. Per maggiori informazioni, leggere la sezione @@ -481,7 +481,7 @@ sezione, si potranno conoscere un gran numero di strumenti disponibili per aiutare a compiere i compiti più comuni sui template, come includere altri template, collegare pagine e inserire immagini. -Symfony2 dispone di molti tag di Twig specializzati e di molte funzioni, che facilitano +Symfony dispone di molti tag di Twig specializzati e di molte funzioni, che facilitano il lavoro del progettista di template. In PHP, il sistema di template fornisce un sistema estensibile di *aiutanti*, che fornisce utili caratteristiche nel contesto dei template. @@ -513,7 +513,7 @@ template. Primo, creare il template che occorrerà riusare. .. code-block:: html+jinja - {# app/Resources/views/Article/articleDetails.html.twig #} + {# app/Resources/views/article/article_details.html.twig #}

{{ article.title }}

@@ -523,7 +523,7 @@ template. Primo, creare il template che occorrerà riusare. .. code-block:: html+php - +

getTitle() ?>

@@ -537,20 +537,20 @@ Includere questo template da un altro template è semplice: .. code-block:: html+jinja - {# app/Resources/views/Article/list.html.twig #} + {# app/Resources/views/article/list.html.twig #} {% extends 'layout.html.twig' %} {% block body %}

Articoli recenti

{% for article in articles %} - {{ include('Article/articleDetails.html.twig', { 'article': article }) }} + {{ include('article/article_details.html.twig', { 'article': article }) }} {% endfor %} {% endblock %} .. code-block:: html+php - + extend('layout.html.php') ?> start('body') ?> @@ -558,7 +558,7 @@ Includere questo template da un altro template è semplice: render( - 'Article/articleDetails.html.php', + 'Article/article_details.html.php', array('article' => $article) ) ?> @@ -608,7 +608,7 @@ articoli recenti:: $articles = ...; return $this->render( - 'AcmeArticleBundle:Article:recentList.html.twig', + 'article/recent_list.html.twig', array('articles' => $articles) ); } @@ -684,7 +684,7 @@ Contenuto asincrono con hinclude.js Si possono inserire controllori in modo asincrono, con la libreria hinclude.js_. Poiché il contenuto incluso proviene da un'altra pagina (o da un altro controllore), -Symfony2 usa l'aiutante standard ``render`` per configurare i tag ``hinclude``: +Symfony usa l'aiutante standard ``render`` per configurare i tag ``hinclude``: .. configuration-block:: @@ -942,7 +942,7 @@ articoli: .. code-block:: html+jinja - {# app/Resources/views/Article/recentList.html.twig #} + {# app/Resources/views/article/recent_list.html.twig #} {% for article in articles %} {{ article.title }} @@ -951,7 +951,7 @@ articoli: .. code-block:: html+php - + getRequestFormat(); - return $this->render('Blog/index.'.$format.'.twig'); + return $this->render('article/index.'.$format.'.twig'); } Il metodo ``getRequestFormat`` dell'oggetto ``Request`` ha come valore predefinito ``html``, ma può restituire qualsiasi altro formato, in base al formato richiesto dall'utente. Il formato di richiesta è spesso gestito dalle rotte, quando una rotta è -configurata in modo che ``/contact`` imposti il formato di richiesta a ``html``, -mentre ``/contact.xml`` lo imposti a ``xml``. Per maggiori informazioni, vedere +configurata in modo che ``/contact`` imposti il formato di richiesta a ``html``, mentre +``/contact.xml`` lo imposti a ``xml``. Per maggiori informazioni, vedere :ref:`Esempi avanzati nel capitolo delle rotte `. Per creare collegamenti che includano il formato, usare la chiave ``_format`` @@ -1602,7 +1602,7 @@ controllore, i loro utilizzo non è obbligatorio. L'oggetto ``Response`` restitu un controllore può essere creato con o senza l'uso di un template:: // crea un oggetto Response il cui contenuto è il template reso - $response = $this->render('Article/index.html.twig'); + $response = $this->render('article/index.html.twig'); // crea un oggetto Response il cui contenuto è semplice testo $response = new Response('contenuto della risposta'); diff --git a/book/testing.rst b/book/testing.rst index b382875b..afba8d19 100644 --- a/book/testing.rst +++ b/book/testing.rst @@ -36,7 +36,8 @@ Chi fosse curioso di conoscere le opzioni di PHPUnit, può dare uno sguardo al f .. tip:: - Si può generare la copertura del codice, con l'opzione ``--coverage-html``. + Si può generare la copertura del codice, con le opzioni ``--coverage-*``, vedere + le informazioni di aiuto mostrate usando ``--help``. .. index:: single: Test; Test unitari @@ -44,15 +45,16 @@ Chi fosse curioso di conoscere le opzioni di PHPUnit, può dare uno sguardo al f Test unitari ------------ -Un test unitario è solitamente un test di una specifica classe PHP. Se si vuole -testare il comportamento generale della propria applicazione, vedere la sezione dei `Test funzionali`_. +Un test unitario è solitamente un test di una specifica classe PHP, chiamata *unità*. Se si +vuole testare il comportamento generale della propria applicazione, vedere la sezione dei +`Test funzionali`_. La scrittura di test unitari in Symfony non è diversa dalla scrittura standard di test unitari in PHPUnit. Si supponga, per esempio, di avere una classe *incredibilmente* semplice, chiamata ``Calculator``, nella cartella ``Utility/`` del bundle:: - // src/Acme/DemoBundle/Utility/Calculator.php - namespace Acme\DemoBundle\Utility; + // src/AppBundle/Util/Calculator.php + namespace AppBundle\Util; class Calculator { @@ -62,13 +64,13 @@ chiamata ``Calculator``, nella cartella ``Utility/`` del bundle:: } } -Per testarla, creare un file ``CalculatorTest`` nella cartella ``Tests/Utility`` del +Per testarla, creare un file ``CalculatorTest`` nella cartella ``Tests/Util`` del bundle:: - // src/Acme/DemoBundle/Tests/Utility/CalculatorTest.php - namespace Acme\DemoBundle\Tests\Utility; + // src/AppBundle/Tests/Util/CalculatorTest.php + namespace AppBundle\Tests\Util; - use Acme\DemoBundle\Utility\Calculator; + use AppBundle\Util\Calculator; class CalculatorTest extends \PHPUnit_Framework_TestCase { @@ -86,7 +88,8 @@ bundle:: Per convenzione, si raccomanda di replicare la struttura di cartella di un bundle nella sua sotto-cartella ``Tests/``. Quindi, se si testa una classe nella - cartella ``Utility/`` del bundle, mettere il test nella cartella ``Tests/Utility/``. + cartella ``Util/`` del bundle, mettere il test nella cartella + ``Tests/Util/``. Proprio come per l'applicazione reale, l'autoloading è abilitato automaticamente tramite il file ``bootstrap.php.cache`` (come configurato in modo predefinito nel file @@ -96,14 +99,17 @@ Anche eseguire i test per un dato file o una data cartella è molto facile: .. code-block:: bash - # eseguire tutti i test nella cartella Utility - $ phpunit -c app src/Acme/DemoBundle/Tests/Utility/ + # eseguire tutti i test dell'applicazione + $ phpunit -c app # eseguire i test per la classe Calculator - $ phpunit -c app src/Acme/DemoBundle/Tests/Utility/CalculatorTest.php + $ phpunit -c app src/AppBundle/Tests/Util + + # eseguire i test per la classe Calculator + $ phpunit -c app src/AppBundle/Tests/Util/CalculatorTest.php # eseguire tutti i test per l'intero bundle - $ phpunit -c app src/Acme/DemoBundle/ + $ phpunit -c app src/AppBundle/ .. index:: single: Test; Test funzionali @@ -126,28 +132,27 @@ Un primo test funzionale I test funzionali sono semplici file PHP, che tipicamente risiedono nella cartella ``Tests/Controller`` del bundle. Se si vogliono testare le pagine gestite dalla classe -``DemoController``, si inizi creando un file ``DemoControllerTest.php``, che estende +``PostController``, si inizi creando un file ``PostControllerTest.php``, che estende una classe speciale ``WebTestCase``. -Per esempio, l'edizione standard di Symfony fornisce un semplice test funzionale per il -suo ``DemoController`` (`DemoControllerTest`_), fatto in questo modo:: +Per esempio, un test può essere fatto in questo modo:: - // src/Acme/DemoBundle/Tests/Controller/DemoControllerTest.php - namespace Acme\DemoBundle\Tests\Controller; + // src/AppBundle/Tests/Controller/PostControllerTest.php + namespace AppBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; - class DemoControllerTest extends WebTestCase + class PostControllerTest extends WebTestCase { - public function testIndex() + public function testShowPost() { $client = static::createClient(); - $crawler = $client->request('GET', '/demo/hello/Fabien'); + $crawler = $client->request('GET', '/post/hello-world'); $this->assertGreaterThan( 0, - $crawler->filter('html:contains("Hello Fabien")')->count() + $crawler->filter('html:contains("Hello World")')->count() ); } } @@ -162,8 +167,8 @@ suo ``DemoController`` (`DemoControllerTest`_), fatto in questo modo:: .. code-block:: xml + - @@ -173,11 +178,12 @@ suo ``DemoController`` (`DemoControllerTest`_), fatto in questo modo:: Il metodo ``createClient()`` restituisce un client, che è come un browser da usare per visitare un sito:: - $crawler = $client->request('GET', '/demo/hello/Fabien'); + $crawler = $client->request('GET', '/post/hello-world'); -Il metodo ``request()`` (vedere :ref:`di più sul metodo della richiesta`) restituisce un oggetto :class:`Symfony\\Component\\DomCrawler\\Crawler`, -che può essere usato per selezionare elementi nella risposta, per cliccare su -collegamenti e per inviare form. +Il metodo ``request()`` (vedere +:ref:`di più sul metodo della richiesta`) +restituisce un oggetto :class:`Symfony\\Component\\DomCrawler\\Crawler`, che può +essere usato per selezionare elementi nella risposta, per cliccare su collegamenti e per inviare form. .. tip:: @@ -185,11 +191,13 @@ collegamenti e per inviare form. o HTML. Per altri tipi di contenuto, richiamare ``$client->getResponse()->getContent()``. Cliccare su un collegamento, seleziondolo prima con il Crawler, usando o un'espressione XPath -o un selettore CSS, quindi usando il Client per cliccarlo. Per esempio, il codice seguente -trova tutti i collegamenti con il testo ``Greet``, quindi sceglie il secondo e infine -lo clicca:: +o un selettore CSS, quindi usando il Client per cliccarlo. Per esempio:: - $link = $crawler->filter('a:contains("Greet")')->eq(1)->link(); + $link = $crawler + ->filter('a:contains("Greet")') // trova i collegamenti con testo "Greet" + ->eq(1) // seleziona il secondo collegamento della lista + ->link() // e lo clicca + ; $crawler = $client->click($link); @@ -216,50 +224,17 @@ per testare che faccia effettivamente quello che ci si aspetta. Usare il Crawler per fare asserzioni sul DOM:: // Asserisce che la risposta corrisponda a un dato selettore CSS. - $this->assertTrue($crawler->filter('h1')->count() > 0); + $this->assertGreaterThan(0, $crawler->filter('h1')->count()); Oppure, testare direttamente il contenuto della risposta, se si vuole solo asserire che il contenuto debba contenere del testo o se la risposta non è un documento XML/HTML:: - $this->assertRegExp( - '/Hello Fabien/', + $this->assertContains( + 'Hello World', $client->getResponse()->getContent() ); -.. _book-testing-request-method-sidebar: - -.. sidebar:: Di più sul metodo ``request()``: - - La firma completa del metodo ``request()`` è:: - - request( - $method, - $uri, - array $parameters = array(), - array $files = array(), - array $server = array(), - $content = null, - $changeHistory = true - ) - - L'array ``server`` contiene i valori grezzi che ci si aspetta di trovare normalmente - nell'array superglobale `$_SERVER`_ di PHP. Per esempio, per impostare gli header HTTP ``Content-Type``, - ``Referer`` e ``X-Requested-With``, passare i seguenti (ricordare il - prefisso ``HTTP_`` per gli header non standard):: - - $client->request( - 'GET', - '/demo/hello/Fabien', - array(), - array(), - array( - 'CONTENT_TYPE' => 'application/json', - 'HTTP_REFERER' => '/foo/bar', - 'HTTP_X-Requested-With' => 'XMLHttpRequest', - ) - ); - .. index:: single: Test; Asserzioni @@ -290,8 +265,10 @@ XML/HTML:: ) ); + // Asserire che la risposta contenga una stringa + $this->assertContains('foo', $client->getResponse()->getContent()); // Asserire che la risposta corrisponda a un'espressione regolare. - $this->assertRegExp('/pippo/', $client->getResponse()->getContent()); + $this->assertRegExp('/pippo(pluto)?/', $client->getResponse()->getContent()); // Asserire che il codice di stato della risposta sia 2xx $this->assertTrue($client->getResponse()->isSuccessful()); @@ -299,7 +276,7 @@ XML/HTML:: $this->assertTrue($client->getResponse()->isNotFound()); // Asserire uno specifico codice di stato 200 $this->assertEquals( - Response::HTTP_OK, + 200, // o Symfony\Component\HttpFoundation\Response::HTTP_OK $client->getResponse()->getStatusCode() ); @@ -333,6 +310,39 @@ restituisce un'istanza di ``Crawler``. generasse URL usando le rotte di Symfony, non si accorgerebbe di eventuali modifiche agli URL dell'applicazione, che potrebbero aver impatto sugli utenti finali. +.. _book-testing-request-method-sidebar: + +.. sidebar:: Di più sul metodo ``request()``: + + La firma completa del metodo ``request()`` è:: + + request( + $method, + $uri, + array $parameters = array(), + array $files = array(), + array $server = array(), + $content = null, + $changeHistory = true + ) + + L'array ``server`` contiene i valori grezzi che ci si aspetta di trovare normalmente + nell'array superglobale `$_SERVER`_ di PHP. Per esempio, per impostare gli header HTTP ``Content-Type``, + ``Referer`` e ``X-Requested-With``, passare i seguenti (ricordare il + prefisso ``HTTP_`` per gli header non standard):: + + $client->request( + 'GET', + '/post/hello-world', + array(), + array(), + array( + 'CONTENT_TYPE' => 'application/json', + 'HTTP_REFERER' => '/foo/bar', + 'HTTP_X-Requested-With' => 'XMLHttpRequest', + ) + ); + Usare il crawler per cercare elementi del DOM nella risposta. Questi elementi possono poi essere usati per cliccare su collegamenti e inviare form:: @@ -422,16 +432,16 @@ Accesso agli oggetti interni Se si usa il client per testare la propria applicazione, si potrebbe voler accedere agli oggetti interni del client:: - $history = $client->getHistory(); + $history = $client->getHistory(); $cookieJar = $client->getCookieJar(); I possono anche ottenere gli oggetti relativi all'ultima richiesta:: // l'istanza della richiesta HttpKernel - $request = $client->getRequest(); + $request = $client->getRequest(); // l'istanza della richiesta BrowserKit - $request = $client->getInternalRequest(); + $request = $client->getInternalRequest(); // l'istanza della richiesta HttpKernel $response = $client->getResponse(); @@ -439,13 +449,13 @@ I possono anche ottenere gli oggetti relativi all'ultima richiesta:: // l'istanza della richiesta BrowserKit $response = $client->getInternalResponse(); - $crawler = $client->getCrawler(); + $crawler = $client->getCrawler(); Se le richieste non sono isolate, si può accedere agli oggetti ``Container`` e ``Kernel``:: $container = $client->getContainer(); - $kernel = $client->getKernel(); + $kernel = $client->getKernel(); Accesso al contenitore ~~~~~~~~~~~~~~~~~~~~~~ @@ -459,7 +469,10 @@ di dipendenze:: Attenzione, perché ciò non funziona se si isola il client o se si usa un livello HTTP. Per un elenco di servizi disponibili nell'applicazione, usare -il comando ``container:debug``. +il comando ``debug:container``. + +.. versionadded:: 2.6 + Prima di ymfony 2.6, questo comando si chiamava ``container:debug``. .. tip:: @@ -532,31 +545,28 @@ trovarne l'ultimo e quindi selezionare il suo genitore:: Ci sono molti altri metodi a disposizione: -+------------------------+----------------------------------------------------+ -| Metodo | Descrizione | -+========================+====================================================+ -| ``filter('h1.title')`` | Nodi corrispondenti al selettore CSS | -+------------------------+----------------------------------------------------+ -| ``filterXpath('h1')`` | Nodi corrispondenti all'espressione XPath | -+------------------------+----------------------------------------------------+ -| ``eq(1)`` | Nodi per l'indice specificato | -+------------------------+----------------------------------------------------+ -| ``first()`` | Primo nodo | -+------------------------+----------------------------------------------------+ -| ``last()`` | Ultimo nodo | -+------------------------+----------------------------------------------------+ -| ``siblings()`` | Fratelli | -+------------------------+----------------------------------------------------+ -| ``nextAll()`` | Tutti i fratelli successivi | -+------------------------+----------------------------------------------------+ -| ``previousAll()`` | Tutti i fratelli precedenti | -+------------------------+----------------------------------------------------+ -| ``parents()`` | Genitori | -+------------------------+----------------------------------------------------+ -| ``children()`` | Figli | -+------------------------+----------------------------------------------------+ -| ``reduce($lambda)`` | Nodi per cui la funzione non restituisce false | -+------------------------+----------------------------------------------------+ +``filter('h1.title')`` + Nodi corrispondenti al selettore CSS +``filterXpath('h1')`` + Nodi corrispondenti all'espressione XPath +``eq(1)`` + Nodi per l'indice specificato +``first()`` + Primo nodo +``last()`` + Ultimo nodo +``siblings()`` + Fratelli +``nextAll()`` + Tutti i fratelli successivi +``previousAll()`` + Tutti i fratelli precedenti +``parents()`` + Genitori +``children()`` + Figli +``reduce($lambda)`` + Nodi per cui la funzione non restituisce false Si può iterativamente restringere la selezione del nodo, concatenando le chiamate ai metodi, perché ogni metodo restituisce una nuova istanza di Crawler per i nodi corrispondenti:: @@ -568,7 +578,8 @@ metodi, perché ogni metodo restituisce una nuova istanza di Crawler per i nodi return false; } }) - ->first(); + ->first() + ; .. tip:: @@ -621,7 +632,8 @@ passargli un oggetto ``Link``:: Form ~~~~ -Come per i collegamenti, si possono selezionare i form col metodo ``selectButton()``:: +Come per i collegamenti, si possono selezionare i form col metodo +``selectButton()``, come i link:: $buttonCrawlerNode = $crawler->selectButton('submit'); @@ -635,9 +647,7 @@ Il metodo ``selectButton()`` può selezionare i tag ``button`` e i tag ``input`` "submit". Ha diverse euristiche per trovarli: * Il valore dell'attributo ``value``; - * Il valore dell'attributo ``id`` o ``alt`` per le immagini; - * Il valore dell'attributo ``id`` o ``name`` per i tag ``button``. Quando si ha un nodo che rappresenta un bottone, richiamare il metodo ``form()`` per @@ -735,8 +745,10 @@ in ambiente ``test``. Lo si può vedere sotto l'opzione di configurazione + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/swiftmailer + http://symfony.com/schema/dic/swiftmailer/swiftmailer-1.0.xsd"> @@ -798,9 +810,10 @@ macchina locale. Inserire il file ``phpunit.xml.dist`` nel repository e ignorare il file ``phpunit.xml``. -Per impostazione predefinita, solo i test memorizzati nei bundle "standard" sono eseguiti +Per impostazione predefinita, solo i test memorizzati nelle cartelle "standard" sono eseguiti dal comando ``phpunit`` (per "standard" si intendono i test nelle cartelle -``src/*/Bundle/Tests`` o ``src/*/Bundle/*Bundle/Tests``). +``src/*/Bundle/Tests``, ``src/*/Bundle/*Bundle/Tests`` o ``src/*Bundle/Tests``), come configurato +nel file ``app/phpunit.xml.dist``: .. code-block:: xml @@ -811,6 +824,7 @@ dal comando ``phpunit`` (per "standard" si intendono i test nelle cartelle ../src/*/*Bundle/Tests ../src/*/Bundle/*Bundle/Tests + ../src/*Bundle/Tests @@ -857,6 +871,7 @@ sezione ````: Saperne di più -------------- +* Il :doc:`capitolo sui test nelle best practice ` * :doc:`/components/dom_crawler` * :doc:`/components/css_selector` * :doc:`/cookbook/testing/http_authentication` @@ -864,6 +879,5 @@ Saperne di più * :doc:`/cookbook/testing/profiling` * :doc:`/cookbook/testing/bootstrap` -.. _`DemoControllerTest`: https://github.com/symfony/symfony-standard/blob/master/src/Acme/DemoBundle/Tests/Controller/DemoControllerTest.php .. _`$_SERVER`: http://php.net/manual/it/reserved.variables.server.php .. _documentazione: http://phpunit.de/manual/current/en/ diff --git a/book/translation.rst b/book/translation.rst index 39d6954d..a3e8cdc2 100644 --- a/book/translation.rst +++ b/book/translation.rst @@ -59,7 +59,7 @@ abilitare ``translator`` nella configurazione: # app/config/config.yml framework: - translator: { fallback: en } + translator: { fallbacks: [en] } .. code-block:: xml @@ -68,11 +68,15 @@ abilitare ``translator`` nella configurazione: + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony + http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + + en + @@ -80,10 +84,10 @@ abilitare ``translator`` nella configurazione: // app/config/config.php $container->loadFromExtension('framework', array( - 'translator' => array('fallback' => 'en'), + 'translator' => array('fallbacks' => array('en')), )); -Vedere :ref:`book-translation-fallback` per dettagli sulla voce ``fallback`` +Vedere :ref:`book-translation-fallback` per dettagli sulla voce ``fallbacks`` e su cosa faccia Symfony quando non trova una traduzione. Il locale usato nelle traduzioni è quello memorizzato nella richiesta. Tipicamente, @@ -332,7 +336,7 @@ Symfony cerca i file dei messaggi (ad esempio le traduzioni) in due sedi: * la cartella ``app/Resources/translations``; -* la cartella ``app/Resources//translations``; +* la cartella ``app/Resources//translations``; * la cartella ``Resources/translations/`` del bundle. @@ -363,7 +367,8 @@ fornisce i seguenti caricatori: * ``yml``: file YAML. La scelta di quali caricatori utilizzare è interamente a carico dello sviluppatore ed è una questione -di gusti. +di gusti. L'opzione raccomandata è il formato ``xliff``. +Per altre opzioni, vedere :ref:`component-translator-message-catalogs`. .. note:: @@ -428,11 +433,11 @@ tramite l'oggetto ``request``:: .. tip:: - Leggere :doc:`/cookbook/session/locale_sticky_session` per imparare come memorizzare - il locale in sessione. + Leggere :doc:`/cookbook/session/locale_sticky_session` per + approfondimenti sull'argomento. .. index:: - single: Traduzioni; Fallback e locale predefinito + single: Traduzioni; Rimandare al locale predefinito Vedere la sezione seguente, :ref:`book-translation-locale-url`, per impostare il locale tramite rotte. @@ -460,7 +465,7 @@ supportato dal sistema delle rotte utilizzando il parametro speciale ``_locale`` # app/config/routing.yml contact: path: /{_locale}/contact - defaults: { _controller: AcmeDemoBundle:Contact:index } + defaults: { _controller: AppBundle:Contact:index } requirements: _locale: en|fr|de @@ -474,7 +479,7 @@ supportato dal sistema delle rotte utilizzando il parametro speciale ``_locale`` http://symfony.com/schema/routing/routing-1.0.xsd"> - AcmeDemoBundle:Contact:index + AppBundle:Contact:index en|fr|de @@ -489,7 +494,7 @@ supportato dal sistema delle rotte utilizzando il parametro speciale ``_locale`` $collection->add('contact', new Route( '/{_locale}/contact', array( - '_controller' => 'AcmeDemoBundle:Contact:index', + '_controller' => 'AppBundle:Contact:index', ), array( '_locale' => 'en|fr|de', @@ -508,6 +513,11 @@ come locale per la richiesta corrente. È ora possibile utilizzare il locale dell'utente per creare rotte ad altre pagine tradotte nell'applicazione. +.. tip:: + + Leggere :doc:`/cookbook/routing/service_container_parameters` per imparare come + evitare di inserire manualmente il requisito ``_locale`` in ogni rotta. + Impostare un locale predefinito ------------------------------- @@ -530,8 +540,10 @@ il framework: + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony + http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> @@ -555,8 +567,8 @@ il :ref:`dominio ` ``validators``. Per iniziare, supponiamo di aver creato un oggetto PHP, necessario da qualche parte in un'applicazione:: - // src/Acme/BlogBundle/Entity/Author.php - namespace Acme\BlogBundle\Entity; + // src/AppBundle/Entity/Author.php + namespace AppBundle\Entity; class Author { @@ -569,17 +581,9 @@ non sia vuota, aggiungere il seguente: .. configuration-block:: - .. code-block:: yaml - - # src/Acme/BlogBundle/Resources/config/validation.yml - Acme\BlogBundle\Entity\Author: - properties: - name: - - NotBlank: { message: "author.name.not_blank" } - .. code-block:: php-annotations - // src/Acme/BlogBundle/Entity/Author.php + // src/AppBundle/Entity/Author.php use Symfony\Component\Validator\Constraints as Assert; class Author @@ -590,15 +594,24 @@ non sia vuota, aggiungere il seguente: public $name; } + .. code-block:: yaml + + # src/AppBundle/Resources/config/validation.yml + AppBundle\Entity\Author: + properties: + name: + - NotBlank: { message: "author.name.not_blank" } + .. code-block:: xml - + + xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping + http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> - + @@ -609,7 +622,7 @@ non sia vuota, aggiungere il seguente: .. code-block:: php - // src/Acme/BlogBundle/Entity/Author.php + // src/AppBundle/Entity/Author.php // ... use Symfony\Component\Validator\Mapping\ClassMetadata; diff --git a/book/validation.rst b/book/validation.rst index 65a91d07..16ed80d8 100644 --- a/book/validation.rst +++ b/book/validation.rst @@ -42,17 +42,9 @@ seguente: .. configuration-block:: - .. code-block:: yaml - - # src/Acme/BlogBundle/Resources/config/validation.yml - Acme\BlogBundle\Entity\Author: - properties: - name: - - NotBlank: ~ - .. code-block:: php-annotations - // src/Acme/BlogBundle/Entity/Author.php + // src/AppBundle/Entity/Author.php // ... use Symfony\Component\Validator\Constraints as Assert; @@ -65,15 +57,23 @@ seguente: public $name; } + .. code-block:: yaml + + # src/AppBundle/Resources/config/validation.yml + AppBundle\Entity\Author: + properties: + name: + - NotBlank: ~ + .. code-block:: xml - + - + @@ -82,7 +82,7 @@ seguente: .. code-block:: php - // src/Acme/BlogBundle/Entity/Author.php + // src/AppBundle/Entity/Author.php // ... use Symfony\Component\Validator\Mapping\ClassMetadata; @@ -119,11 +119,13 @@ Prendiamo questo semplice esempio dall'interno di un controllore:: // ... use Symfony\Component\HttpFoundation\Response; - use Acme\BlogBundle\Entity\Author; + use AppBundle\Entity\Author; - public function indexAction() + // ... + public function authorAction() { $autore = new Author(); + // ... fare qualcosa con l'oggetto $autore $validator = $this->get('validator'); @@ -148,7 +150,7 @@ errore: .. code-block:: text - Acme\BlogBundle\Author.name: + AppBundle\Author.name: This value should not be blank Se si inserisce un valore per la proprietà ``$name``, apparirà il messaggio di @@ -161,12 +163,10 @@ successo. si userà indirettamente la validazione, durante la gestione di dati inviati tramite form. Per maggiori informazioni, vedere :ref:`book-validation-forms`. -Si può anche passare un insieme di errori in un template. - -.. code-block:: php +Si può anche passare un insieme di errori in un template:: if (count($errors) > 0) { - return $this->render('AcmeBlogBundle:Author:validate.html.twig', array( + return $this->render('author/validation.html.twig', array( 'errors' => $errors, )); } @@ -177,7 +177,7 @@ Dentro al template, si può stampare la lista di errori, come necessario: .. code-block:: html+jinja - {# src/Acme/BlogBundle/Resources/views/Author/validate.html.twig #} + {# app/Resources/views/author/validation.html.twig #}

L'autore ha i seguenti errori

    {% for error in errors %} @@ -187,12 +187,12 @@ Dentro al template, si può stampare la lista di errori, come necessario: .. code-block:: html+php - +

    L'autore ha i seguenti errori

    • getMessage() ?>
    • - +
    .. note:: @@ -217,10 +217,11 @@ che possono essere facilmente mostrati con il proprio form. Il tipico flusso del di un form assomiglia al seguente, all'interno di un controllore:: // ... - use Acme\BlogBundle\Entity\Author; - use Acme\BlogBundle\Form\AuthorType; + use AppBundle\Entity\Author; + use AppBundle\Form\AuthorType; use Symfony\Component\HttpFoundation\Request; + // ... public function updateAction(Request $request) { $author = new Author(); @@ -234,7 +235,7 @@ di un form assomiglia al seguente, all'interno di un controllore:: return $this->redirect($this->generateUrl(...)); } - return $this->render('BlogBundle:Author:form.html.twig', array( + return $this->render('author/form.html.twig', array( 'form' => $form->createView(), )); } @@ -243,7 +244,7 @@ di un form assomiglia al seguente, all'interno di un controllore:: Questo esempio usa una classe ``AuthorType``, non mostrata qui. -Per maggiori informazioni, vedere il capitolo sui :doc:`Form`. +Per maggiori informazioni, vedere il capitolo sui :doc:`form `. .. index:: pair: Validazione; Configurazione @@ -272,7 +273,7 @@ abilitare esplicitamente le annotazioni, se le si usano per specificare i vincol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:framework="http://symfony.com/schema/dic/symfony" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd - http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> + http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> @@ -332,17 +333,11 @@ abbia un'altra proprietà, ``gender``, che possa valere solo "M" oppure .. configuration-block:: - .. code-block:: yaml - - # src/Acme/BlogBundle/Resources/config/validation.yml - Acme\BlogBundle\Entity\Author: - properties: - gender: - - Choice: { choices: [M, F], message: Scegliere un genere valido. } - .. code-block:: php-annotations - // src/Acme/BlogBundle/Entity/Author.php + // src/AppBundle/Entity/Author.php + + // ... use Symfony\Component\Validator\Constraints as Assert; class Author @@ -354,17 +349,28 @@ abbia un'altra proprietà, ``gender``, che possa valere solo "M" oppure * ) */ public $gender; + + // ... } + .. code-block:: yaml + + # src/AppBundle/Resources/config/validation.yml + AppBundle\Entity\Author: + properties: + gender: + - Choice: { choices: [M, F], message: Scegliere un genere valido. } + # ... + .. code-block:: xml - + - + + + .. code-block:: php - // src/Acme/BlogBundle/Entity/Author.php + // src/AppBundle/Entity/Author.php // ... use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints\Choice; + use Symfony\Component\Validator\Constraints as Assert; class Author { public $gender; + // ... + public static function loadValidatorMetadata(ClassMetadata $metadata) { - $metadata->addPropertyConstraint('gender', new Choice(array( + // ... + + $metadata->addPropertyConstraint('gender', new Assert\Choice(array( 'choices' => array('M', 'F'), 'message' => 'Scegliere un genere valido.', ))); @@ -407,17 +419,9 @@ essere specificata in tal modo. .. configuration-block:: - .. code-block:: yaml - - # src/Acme/BlogBundle/Resources/config/validation.yml - Acme\BlogBundle\Entity\Author: - properties: - gender: - - Choice: [M, F] - .. code-block:: php-annotations - // src/Acme/BlogBundle/Entity/Author.php + // src/AppBundle/Entity/Author.php // ... use Symfony\Component\Validator\Constraints as Assert; @@ -428,33 +432,46 @@ essere specificata in tal modo. * @Assert\Choice({"M", "F"}) */ protected $gender; + + // ... } + .. code-block:: yaml + + # src/AppBundle/Resources/config/validation.yml + AppBundle\Entity\Author: + properties: + gender: + - Choice: [M, F] + # ... + .. code-block:: xml - + - + M F + + .. code-block:: php - // src/Acme/BlogBundle/Entity/Author.php + // src/AppBundle/Entity/Author.php // ... use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints\Choice; + use Symfony\Component\Validator\Constraints as Assert; class Author { @@ -462,9 +479,11 @@ essere specificata in tal modo. public static function loadValidatorMetadata(ClassMetadata $metadata) { + // ... + $metadata->addPropertyConstraint( 'gender', - new Choice(array('M', 'F')) + new Assert\Choice(array('M', 'F')) ); } } @@ -502,26 +521,16 @@ facile, ma il secondo consente di specificare regole di validazione più comples Proprietà ~~~~~~~~~ -La validazione delle proprietà di una classe è la tecnica di base. Symfony2 +La validazione delle proprietà di una classe è la tecnica di base. Symfony consente di validare proprietà private, protette o pubbliche. L'elenco seguente mostra come configurare la proprietà ``$firstName`` di una classe ``Author``, per avere almeno 3 caratteri. .. configuration-block:: - .. code-block:: yaml - - # src/Acme/BlogBundle/Resources/config/validation.yml - Acme\BlogBundle\Entity\Author: - properties: - firstName: - - NotBlank: ~ - - Length: - min: 3 - .. code-block:: php-annotations - // Acme/BlogBundle/Entity/Author.php + // AppBundle/Entity/Author.php // ... use Symfony\Component\Validator\Constraints as Assert; @@ -530,20 +539,30 @@ avere almeno 3 caratteri. { /** * @Assert\NotBlank() - * @Assert\Length(min = "3") + * @Assert\Length(min=3) */ private $firstName; } + .. code-block:: yaml + + # src/AppBundle/Resources/config/validation.yml + AppBundle\Entity\Author: + properties: + firstName: + - NotBlank: ~ + - Length: + min: 3 + .. code-block:: xml - + - + @@ -555,12 +574,11 @@ avere almeno 3 caratteri. .. code-block:: php - // src/Acme/BlogBundle/Entity/Author.php + // src/AppBundle/Entity/Author.php // ... use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints\NotBlank; - use Symfony\Component\Validator\Constraints\Length; + use Symfony\Component\Validator\Constraints as Assert; class Author { @@ -568,10 +586,11 @@ avere almeno 3 caratteri. public static function loadValidatorMetadata(ClassMetadata $metadata) { - $metadata->addPropertyConstraint('firstName', new NotBlank()); + $metadata->addPropertyConstraint('firstName', new Assert\NotBlank()); $metadata->addPropertyConstraint( 'firstName', - new Length(array("min" => 3))); + new Assert\Length(array("min" => 3)) + ); } } @@ -597,17 +616,9 @@ restituire ``true``: .. configuration-block:: - .. code-block:: yaml - - # src/Acme/BlogBundle/Resources/config/validation.yml - Acme\BlogBundle\Entity\Author: - getters: - passwordLegal: - - "True": { message: "La password non può essere uguale al nome" } - .. code-block:: php-annotations - // src/Acme/BlogBundle/Entity/Author.php + // src/AppBundle/Entity/Author.php // ... use Symfony\Component\Validator\Constraints as Assert; @@ -619,19 +630,27 @@ restituire ``true``: */ public function isPasswordLegal() { - // return true or false + // ... restituire true o false } } + .. code-block:: yaml + + # src/AppBundle/Resources/config/validation.yml + AppBundle\Entity\Author: + getters: + passwordLegal: + - "True": { message: "The password cannot match your first name" } + .. code-block:: xml - + - + @@ -642,17 +661,17 @@ restituire ``true``: .. code-block:: php - // src/Acme/BlogBundle/Entity/Author.php + // src/AppBundle/Entity/Author.php // ... use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints\True; + use Symfony\Component\Validator\Constraints as Assert; class Author { public static function loadValidatorMetadata(ClassMetadata $metadata) { - $metadata->addGetterConstraint('passwordLegal', new True(array( + $metadata->addGetterConstraint('passwordLegal', new Assert\True(array( 'message' => 'La password non può essere uguale al nome', ))); } @@ -662,7 +681,7 @@ Creare ora il metodo ``isPasswordLegal()`` e includervi la logica necessaria:: public function isPasswordLegal() { - return $this->firstName != $this->password; + return $this->firstName !== $this->password; } .. note:: @@ -700,24 +719,10 @@ si registra che quando aggiorna successivamente le sue informazioni: .. configuration-block:: - .. code-block:: yaml - - # src/Acme/BlogBundle/Resources/config/validation.yml - Acme\BlogBundle\Entity\User: - properties: - email: - - Email: { groups: [registration] } - password: - - NotBlank: { groups: [registration] } - - Length: { min: 7, groups: [registration] } - city: - - Length: - min: 2 - .. code-block:: php-annotations - // src/Acme/BlogBundle/Entity/User.php - namespace Acme\BlogBundle\Entity; + // src/AppBundle/Entity/User.php + namespace AppBundle\Entity; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Validator\Constraints as Assert; @@ -736,20 +741,37 @@ si registra che quando aggiorna successivamente le sue informazioni: private $password; /** - * @Assert\Length(min = "2") + * @Assert\Length(min=2) */ private $city; } + .. code-block:: yaml + + # src/AppBundle/Resources/config/validation.yml + AppBundle\Entity\User: + properties: + email: + - Email: { groups: [registration] } + password: + - NotBlank: { groups: [registration] } + - Length: { min: 7, groups: [registration] } + city: + - Length: + min: 2 + .. code-block:: xml - + + xsi:schemaLocation=" + http://symfony.com/schema/dic/constraint-mapping + http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd + "> - + + + @@ -780,33 +804,31 @@ si registra che quando aggiorna successivamente le sue informazioni: .. code-block:: php - // src/Acme/BlogBundle/Entity/User.php - namespace Acme\BlogBundle\Entity; + // src/AppBundle/Entity/User.php + namespace AppBundle\Entity; use Symfony\Component\Validator\Mapping\ClassMetadata; - use Symfony\Component\Validator\Constraints\Email; - use Symfony\Component\Validator\Constraints\NotBlank; - use Symfony\Component\Validator\Constraints\Length; + use Symfony\Component\Validator\Constraints as Assert; class User { public static function loadValidatorMetadata(ClassMetadata $metadata) { - $metadata->addPropertyConstraint('email', new Email(array( + $metadata->addPropertyConstraint('email', new Assert\Email(array( 'groups' => array('registration'), ))); - $metadata->addPropertyConstraint('password', new NotBlank(array( + $metadata->addPropertyConstraint('password', new Assert\NotBlank(array( 'groups' => array('registration'), ))); - $metadata->addPropertyConstraint('password', new Length(array( - 'min' => 7, - 'groups' => array('registration') + $metadata->addPropertyConstraint('password', new Assert\Length(array( + 'min' => 7, + 'groups' => array('registration'), ))); - $metadata->addPropertyConstraint( - 'city', - Length(array("min" => 3))); + $metadata->addPropertyConstraint('city', new Assert\Length(array( + "min" => 3, + ))); } } @@ -858,28 +880,10 @@ nome utente e password siano diversi, solo se le altre validazioni passano .. configuration-block:: - .. code-block:: yaml - - # src/Acme/BlogBundle/Resources/config/validation.yml - Acme\BlogBundle\Entity\User: - group_sequence: - - User - - Strict - getters: - passwordLegal: - - "True": - message: "La password deve essere diversa dal nome utente" - groups: [Strict] - properties: - username: - - NotBlank: ~ - password: - - NotBlank: ~ - .. code-block:: php-annotations - // src/Acme/BlogBundle/Entity/User.php - namespace Acme\BlogBundle\Entity; + // src/AppBundle/Entity/User.php + namespace AppBundle\Entity; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Validator\Constraints as Assert; @@ -908,21 +912,41 @@ nome utente e password siano diversi, solo se le altre validazioni passano } } + .. code-block:: yaml + + # src/AppBundle/Resources/config/validation.yml + AppBundle\Entity\User: + group_sequence: + - User + - Strict + getters: + passwordLegal: + - "True": + message: "La password deve essere diversa dal nome utente" + groups: [Strict] + properties: + username: + - NotBlank: ~ + password: + - NotBlank: ~ + .. code-block:: xml - + - + + + + User Strict @@ -940,8 +965,8 @@ nome utente e password siano diversi, solo se le altre validazioni passano .. code-block:: php - // src/Acme/BlogBundle/Entity/User.php - namespace Acme\BlogBundle\Entity; + // src/AppBundle/Entity/User.php + namespace AppBundle\Entity; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints as Assert; @@ -950,22 +975,13 @@ nome utente e password siano diversi, solo se le altre validazioni passano { public static function loadValidatorMetadata(ClassMetadata $metadata) { - $metadata->addPropertyConstraint( - 'username', - new Assert\NotBlank() - ); - $metadata->addPropertyConstraint( - 'password', - new Assert\NotBlank() - ); + $metadata->addPropertyConstraint('username', new Assert\NotBlank()); + $metadata->addPropertyConstraint('password', new Assert\NotBlank()); - $metadata->addGetterConstraint( - 'passwordLegal', - new Assert\True(array( - 'message' => 'La password deve essere diversa dal nome utente', - 'groups' => array('Strict'), - )) - ); + $metadata->addGetterConstraint('passwordLegal', new Assert\True(array( + 'message' => 'La password deve essere diversa dal nome utente', + 'groups' => array('Strict'), + ))); $metadata->setGroupSequence(array('User', 'Strict')); } @@ -1000,29 +1016,15 @@ l'entità e aggiungere un nuovo gruppo di vincoli, chiamato ``Premium``: .. configuration-block:: - .. code-block:: yaml - - # src/Acme/DemoBundle/Resources/config/validation.yml - Acme\DemoBundle\Entity\User: - properties: - name: - - NotBlank: ~ - creditCard: - - CardScheme: - schemes: [VISA] - groups: [Premium] - .. code-block:: php-annotations - // src/Acme/DemoBundle/Entity/User.php - namespace Acme\DemoBundle\Entity; + // src/AppBundle/Entity/User.php + namespace AppBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class User { - // ... - /** * @Assert\NotBlank() */ @@ -1035,17 +1037,31 @@ l'entità e aggiungere un nuovo gruppo di vincoli, chiamato ``Premium``: * ) */ private $creditCard; + + // ... } + .. code-block:: yaml + + # src/AppBundle/Resources/config/validation.yml + AppBundle\Entity\User: + properties: + name: + - NotBlank: ~ + creditCard: + - CardScheme: + schemes: [VISA] + groups: [Premium] + .. code-block:: xml - + - + @@ -1060,13 +1076,15 @@ l'entità e aggiungere un nuovo gruppo di vincoli, chiamato ``Premium``: + + .. code-block:: php - // src/Acme/DemoBundle/Entity/User.php - namespace Acme\DemoBundle\Entity; + // src/AppBundle/Entity/User.php + namespace AppBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Mapping\ClassMetadata; @@ -1094,8 +1112,8 @@ aggiungere :method:`Symfony\\Component\\Validator\\GroupSequenceProviderInterface::getGroupSequence`, che deve restituire un array di gruppi da usare:: - // src/Acme/DemoBundle/Entity/User.php - namespace Acme\DemoBundle\Entity; + // src/AppBundle/Entity/User.php + namespace AppBundle\Entity; // ... use Symfony\Component\Validator\GroupSequenceProviderInterface; @@ -1121,16 +1139,10 @@ fornisce una sequenza di gruppi da validare: .. configuration-block:: - .. code-block:: yaml - - # src/Acme/DemoBundle/Resources/config/validation.yml - Acme\DemoBundle\Entity\User: - group_sequence_provider: ~ - .. code-block:: php-annotations - // src/Acme/DemoBundle/Entity/User.php - namespace Acme\DemoBundle\Entity; + // src/AppBundle/Entity/User.php + namespace AppBundle\Entity; // ... @@ -1142,16 +1154,22 @@ fornisce una sequenza di gruppi da validare: // ... } + .. code-block:: yaml + + # src/AppBundle/Resources/config/validation.yml + AppBundle\Entity\User: + group_sequence_provider: true + .. code-block:: xml - + - + http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> + + @@ -1159,8 +1177,8 @@ fornisce una sequenza di gruppi da validare: .. code-block:: php - // src/Acme/DemoBundle/Entity/User.php - namespace Acme\DemoBundle\Entity; + // src/AppBundle/Entity/User.php + namespace AppBundle\Entity; // ... use Symfony\Component\Validator\Mapping\ClassMetadata; @@ -1186,14 +1204,15 @@ validare solo un semplice valore, come verificare che una stringa sia un indiriz email valido. Lo si può fare molto facilmente. Da dentro a un controllore, assomiglia a questo:: - use Symfony\Component\Validator\Constraints\Email; // ... + use Symfony\Component\Validator\Constraints as Assert; + // ... public function addEmailAction($email) { - $emailConstraint = new Email(); + $emailConstraint = new Assert\Email(); // tutte le opzioni sui vincoli possono essere impostate in questo modo - $emailConstraint->message = 'Invalid email address'; + $emailConstraint->message = 'Indirizzo email non valido'; // usa il validatore per validare il valore // Se si usa la nuova API di validazione 2.5 (è probabile) @@ -1210,13 +1229,13 @@ assomiglia a questo:: ); */ - if (count($errorList) == 0) { + if (0 === count($errorList)) { // è un indirizzo email valido, fare qualcosa } else { // *non* è un indirizzo email valido $errorMessage = $errorList[0]->getMessage(); - // fare qualcosa con l'errore + // ... fare qualcosa con l'errore } // ... diff --git a/components/class_loader/class_loader.rst b/components/class_loader/class_loader.rst index 98106a10..e7100939 100644 --- a/components/class_loader/class_loader.rst +++ b/components/class_loader/class_loader.rst @@ -36,7 +36,7 @@ La registrazione dell'autoloader :class:`Symfony\\Component\\ClassLoader\\ClassL .. note:: - In un'applicazione Symfony2, l'autoloader è registrato automaticamente (vedere + In un'applicazione Symfony, l'autoloader è registrato automaticamente (vedere ``app/autoload.php``). Usare i metodi :method:`Symfony\\Component\\ClassLoader\\ClassLoader::addPrefix` o diff --git a/components/class_loader/introduction.rst b/components/class_loader/introduction.rst index fa279776..69c33737 100644 --- a/components/class_loader/introduction.rst +++ b/components/class_loader/introduction.rst @@ -12,7 +12,7 @@ Uso Ogni volta che si usa una classe non ancora richiesta o inclusa, PHP utilizza il `meccanismo di auto-caricamento`_ per delegare il caricamento di un file che definisca -la classe. Symfony2 fornisce due autoloader, capaci di caricare classi: +la classe. Symfony fornisce due autoloader, capaci di caricare classi: * :doc:`/components/class_loader/class_loader`: carica classi che seguono lo standard dei nomi `PSR-0`; diff --git a/components/console/helpers/dialoghelper.rst b/components/console/helpers/dialoghelper.rst index 075b07e7..97171f3d 100644 --- a/components/console/helpers/dialoghelper.rst +++ b/components/console/helpers/dialoghelper.rst @@ -103,7 +103,7 @@ Validare la risposta -------------------- Si può anche validare la risposta. Per esempio, nell'ultimo esempio è stato -chiesto il nome di un bundle. Seguendo le convenzioni di Symfony2, il nome dovrebbe +chiesto il nome di un bundle. Seguendo le convenzioni di Symfony, il nome dovrebbe avere il suffisso ``Bundle``. Lo si può validare, usando il metodo :method:`Symfony\\Component\\Console\\Helper\\DialogHelper::askAndValidate`:: diff --git a/components/console/helpers/questionhelper.rst b/components/console/helpers/questionhelper.rst index 200c3524..a35b3801 100644 --- a/components/console/helpers/questionhelper.rst +++ b/components/console/helpers/questionhelper.rst @@ -57,7 +57,7 @@ se si vuole sapere il nome di un bundle, si può aggiungere a un comando:: $bundle = $helper->ask($input, $output, $question); -All'utente sarà chiesto "Si prega di inserire il nome del bundle". L'utente può insrire +All'utente sarà chiesto "Si prega di inserire il nome del bundle". L'utente può inserire un nome, che sarà restituito dal metodo :method:`Symfony\\Component\\Console\\Helper\\QuestionHelper::ask`. Se la risposta sarà vuota, sarà restituito il valore predefinito (``AcmeDemoBundle``, in questo caso). @@ -168,7 +168,7 @@ Validare la risposta -------------------- Si può anche validare la risposta. Per esempio, nell'ultimo esempio è stato -chiesto il nome di un bundle. Seguendo le convenzioni di Symfony2, il nome dovrebbe +chiesto il nome di un bundle. Seguendo le convenzioni di Symfony, il nome dovrebbe avere il suffisso ``Bundle``. Lo si può validare, usando il metodo :method:`Symfony\\Component\\Console\\Question\\Question::setValidator`:: diff --git a/components/console/introduction.rst b/components/console/introduction.rst index 24fcb0a8..77b326ac 100755 --- a/components/console/introduction.rst +++ b/components/console/introduction.rst @@ -20,22 +20,13 @@ Il componente può essere installato in due modi: * Installandolo :doc:`tramite Composer ` (``symfony/console`` su `Packagist`_); * Utilizzando il repository Git ufficiale (https://github.com/symfony/Console). -.. note:: - - Windows non supporta i colori ANSI in modo predefinito, quindi il componente Console individua e - disabilita i colori quando Windows non dà supporto. Tuttavia, se Windows non è - configurato con un driver ANSI e i propri comandi di console invocano altri scipt che - emetttono sequenze di colori ANSI, saranno mostrati come sequenze di caratteri grezzi. - - Per abilitare il supporto ai colori ANSI su Windows, si può installare `ANSICON`_. - Creazione di comandi di base ---------------------------- Per creare un comando che porga il saluto dal terminale, creare il file ``SalutaCommand.php``, contenente il seguente codice:: - namespace Acme\DemoBundle\Command; + namespace Acme\Console\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -85,21 +76,23 @@ Occorre anche creare il file da eseguire in linea di comando, che crea una ``Application`` e vi aggiunge comandi:: #!/usr/bin/env php - add(new GreetCommand); + $application->add(new SalutaCommand()); $application->run(); È possibile provare il programma nel modo seguente .. code-block:: bash - app/console demo:saluta Fabien + $ php application.php demo:saluta Fabien Il comando scriverà, nel terminale, quello che segue: @@ -111,7 +104,7 @@ Il comando scriverà, nel terminale, quello che segue: .. code-block:: bash - app/console demo:saluta Fabien --urla + $ php application.php demo:saluta Fabien --urla Il cui risultato sarà:: @@ -122,6 +115,14 @@ Il cui risultato sarà:: Colorare l'output ~~~~~~~~~~~~~~~~~ +.. note:: + + Windows non supporta i colori ANSI in modo predefinito, quindi il componente Console individua e + disabilita i colori quando Windows non dà supporto. Tuttavia, se Windows non è + configurato con un driver ANSI e i propri comandi di console invocano altri scipt che + emetttono sequenze di colori ANSI, saranno mostrati come sequenze di caratteri grezzi. + Per abilitare il supporto ai colori ANSI su Windows, si può installare `ConEmu`_ o `ANSICON`_. + È possibile inserire il testo da stampare, all'interno di speciali tag per colorare l'output. Ad esempio:: @@ -145,7 +146,7 @@ Si può definire un proprio stile, usando la classe // ... $style = new OutputFormatterStyle('red', 'yellow', array('bold', 'blink')); $output->getFormatter()->setStyle('fire', $style); - $output->writeln('foo'); + $output->writeln('pippo'); I colori di sfondo e di testo disponibili sono: ``black``, ``red``, ``green``, ``yellow``, ``blue``, ``magenta``, ``cyan`` e ``white``. @@ -201,13 +202,6 @@ di verbosità. Per esempio:: $output->writeln(...); } -.. versionadded:: 2.4 - I metodi :method:`Symfony\\Component\\Console\\Output\\Output::isQuiet`, - :method:`Symfony\\Component\\Console\\Output\\Output::isVerbose`, - :method:`Symfony\\Component\\Console\\Output\\Output::isVeryVerbose` e - :method:`Symfony\\Component\\Console\\Output\\Output::isDebug` - sono stati introdotti in Symfony 2.4 - Ci sono anche metodi più semantici da usare, per testare ciascun livello di verbosità:: @@ -258,7 +252,7 @@ comando e rendere il parametro ``nome`` obbligatorio, si dovrà scrivere:: 'cognome', InputArgument::OPTIONAL, 'Il tuo cognome?' - ) + ); A questo punto si può accedere al parametro ``cognome`` dal codice:: @@ -291,7 +285,7 @@ In questo modo, si possono specificare più nomi: $ php application.php demo:saluta Fabien Ryan Bernhard -Si può accedere al parametro ``nmoi`` come un array:: +Si può accedere al parametro ``nomi`` come un array:: if ($nomi = $input->getArgument('nomi')) { $testo .= ' '.implode(', ', $nomi); @@ -329,9 +323,11 @@ trattino come in ``-u``). Le opzioni sono *sempre* opzionali e possono accettare .. tip:: - È anche possibile fare in modo che un'opzione possa *opzionalmente* accettare un valore (ad esempio - si potrebbe avere ``--urla`` o ``--urla=forte``). Le opzioni possono anche essere configurate per - accettare array di valori. + Nulla impedisce la creazione di un comando con un'opzione che accetti in modo facoltativo + un valore. Tuttavia, non c'è modo di distinguere quando l'opzione sia stata usata senza + un valore (``comando --urla``) o quando non sia stata usata affatto + (``comando``). In entrambi i casi, il valore recuperato per l'opzione + sarebbe ``null``. Ad esempio, per specificare il numero di volte in cui il messaggio di saluto sarà stampato, si può aggiungere la seguente opzione:: @@ -362,11 +358,11 @@ l'impostazione ``--ripetizioni``: $ php application.php demo:saluta Fabien $ php application.php demo:saluta Fabien --ripetizioni=5 -Nel primo esempio, il saluto verrà stampata una sola volta, visto che ``ripetizioni`` è vuoto e +Nel primo esempio, il saluto verrà stampato una sola volta, visto che ``ripetizioni`` è vuoto e il suo valore predefinito è ``1`` (l'ultimo parametro di ``addOption``). Nel secondo esempio, il saluto verrà stampato 5 volte. -Ricordiamo che le opzioni non devono essere specificate in un ordina predefinito. Perciò, entrambi i +Ricordiamo che le opzioni non devono essere specificate in un ordine predefinito. Perciò, entrambi i seguenti esempi funzioneranno correttamente: .. code-block:: bash @@ -409,12 +405,13 @@ in grado di aiutare con diversi compiti: * :doc:`/components/console/helpers/formatterhelper`: personalizza i colori dei testi * :doc:`/components/console/helpers/progresshelper`: mostra una barra di progressione * :doc:`/components/console/helpers/tablehelper`: mostra dati in una tabella -* :doc:`/components/console/helpers/dialoghelper`: (deprecato) pone domande interattive all'utente + +.. _component-console-testing-commands: Testare i comandi ----------------- -Symfony2 mette a disposizione diversi strumenti a supporto del test dei comandi. Il più utile +Symfony mette a disposizione diversi strumenti a supporto del test dei comandi. Il più utile di questi è la classe :class:`Symfony\\Component\\Console\\Tester\\CommandTester`. Questa utilizza particolari classi per la gestione dell'input/output che semplificano lo svolgimento di test senza una reale interazione da terminale:: @@ -463,9 +460,11 @@ array al metodo $comando = $application->find('demo:saluta'); $testDelComando = new CommandTester($command); - $testDelComando->execute( - array('command' => $comando->getName(), 'name' => 'Fabien') - ); + $testDelComando->execute(array( + 'command' => $comando->getName(), + 'name' => 'Fabien', + '--ripetizioni' => 5, + )); $this->assertRegExp('/Fabien/', $testDelComando->getDisplay()); } @@ -532,6 +531,8 @@ Saperne di più * :doc:`/components/console/single_command_tool` * :doc:`/components/console/changing_default_command` * :doc:`/components/console/events` +* :doc:`/components/console/console_arguments` .. _Packagist: https://packagist.org/packages/symfony/console +.. _ConEmu: https://code.google.com/p/conemu-maximus5/ .. _ANSICON: https://github.com/adoxa/ansicon/releases diff --git a/components/debug/class_loader.rst b/components/debug/class_loader.rst index ac80d283..9e8b860f 100644 --- a/components/debug/class_loader.rst +++ b/components/debug/class_loader.rst @@ -5,10 +5,6 @@ Debug di ClassLoader ==================== -.. versionadded:: 2.4 - ``DebugClassLoader`` del componente Debug è stato introdotto in Symfony 2.4. - In precedenza, si trovava nel componente ClassLoader. - :class:`Symfony\\Component\\Debug\\DebugClassLoader` tenta di lanciare eccezioni più utili, quando gli autoloader registrati non trovano una classe. Tutti gli autoloader che implementano un metodo ``findFile()`` vengono sostituiti @@ -17,6 +13,6 @@ da un ``DebugClassLoader``. L'uso di ``DebugClassLoader`` è facile, basta richiamare il metodo statico :method:`Symfony\\Component\\Debug\\DebugClassLoader::enable`:: - use Symfony\Component\ClassLoader\DebugClassLoader; + use Symfony\Component\Debug\DebugClassLoader; DebugClassLoader::enable(); diff --git a/components/dependency_injection/compilation.rst b/components/dependency_injection/compilation.rst index 4c1e22f0..698fb0fa 100644 --- a/components/dependency_injection/compilation.rst +++ b/components/dependency_injection/compilation.rst @@ -207,7 +207,7 @@ La versione XML della configurazione sarà dunque simile a questa: .. note:: - Nel framework completo Symfony2 c'è una classe base ``Extension``, che + Nel framework completo Symfony c'è una classe base ``Extension``, che implementa questi metodi e un metodo scorciatoia per processare la configurazione. Vedere :doc:`/cookbook/bundles/extension` per maggiori dettagli. @@ -298,7 +298,7 @@ implementando :class:`Symfony\\Component\\DependencyInjection\\Extension\\Prepen } Per maggiori dettagli, si veda :doc:`/cookbook/bundles/prepend_extension`, che è specifica -del framework Symfony2, ma contiene più informazioni su questa caratteristica. +del framework Symfony, ma contiene più informazioni su questa caratteristica. Creare un passo di compilatore ------------------------------ @@ -406,7 +406,7 @@ facile l'esportazione del contenitore compilato:: file_put_contents($file, $dumper->dump()); } -``ProjectServiceContiner`` è il nome predefinito dato alla classe del contenitore +``ProjectServiceContainer`` è il nome predefinito dato alla classe del contenitore esportata: lo si può cambiare tramite l'opzione ``class``, al momento dell'esportazione:: diff --git a/components/dependency_injection/factories.rst b/components/dependency_injection/factories.rst index 9e9d731d..2dbdc18e 100644 --- a/components/dependency_injection/factories.rst +++ b/components/dependency_injection/factories.rst @@ -4,6 +4,11 @@ Usare un factory per creare servizi =================================== +.. versionadded:: 2.6 + Il metodo :method:`Symfony\\Component\\DependencyInjection\\Definition::setFactory` + è stato introdotto in Symfony 2.6. Fare riferimento alle versioni precedenti per + la sintassi per i factory prima di 2.6. + Il contenitore di servizi di Symfony fornisce un modo potente per controllare la creazione di oggetti, consentendo di specificare parametri da passare al costruttore, così come chiamate a metodi e impostazioni di parametri. A volte, tuttavia, non fornisce @@ -15,9 +20,9 @@ l'oggetto. Si supponga di avere un factory che configura e restituisce un nuovo oggetto ``NewsletterManager``:: - class NewsletterFactory + class NewsletterManagerFactory { - public function get() + public static function createNewsletterManager() { $newsletterManager = new NewsletterManager(); @@ -28,8 +33,8 @@ Si supponga di avere un factory che configura e restituisce un nuovo oggetto } Per rendere l'oggetto ``NewsletterManager`` disponibile come servizio, si può configurare -il contenitore di servizi per usare la classe factory -``NewsletterFactory``: +il contenitore di servizi per usare il metodo factory +``NewsletterFactory::createNewsletterManager()``: .. configuration-block:: @@ -37,9 +42,8 @@ il contenitore di servizi per usare la classe factory services: newsletter_manager: - class: NewsletterManager - factory_class: NewsletterManagerFactory - factory_method: createNewsletterManager + class: NewsletterManager + factory: [NewsletterManagerFactory, createNewsletterManager] .. code-block:: xml @@ -49,11 +53,9 @@ il contenitore di servizi per usare la classe factory xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + + + @@ -63,28 +65,25 @@ il contenitore di servizi per usare la classe factory // ... $definition = new Definition('NewsletterManager'); - $definition->setFactoryClass('NewsletterManagerFactory'); - $definition->setFactoryMethod('createNewsletterManager'); + $definition->setFactory(array('NewsletterManagerFactory', 'createNewsletterManager')); $container->setDefinition('newsletter_manager', $definition); -Quando si specificare la classe da usare come factory (tramite ``factory_class``), -il metodo sarà richiamato staticamente. Se il factory stesso va istanziato e il +Ora il metodo sarà richiamato staticamente. Se il factory stesso va istanziato e il metodo dell'oggetto risultante richiamato, configurare il factory stesso come servizio: -In questo caso, il metodo (p.e. ``createNewsletterManager``) va cambiato per non -essere staico: +In questo caso, il metodo (p.e. ``get``) va cambiato per non +essere statico: .. configuration-block:: .. code-block:: yaml services: - newsletter_manager_factory: - class: NewsletterManagerFactory + newsletter_manager.factory: + class: NewsletterManagerFactory newsletter_manager: - class: NewsletterManager - factory_service: newsletter_manager_factory - factory_method: createNewsletterManager + class: NewsletterManager + factory: ["@newsletter_manager.factory", createNewsletterManager] .. code-block:: xml @@ -94,36 +93,28 @@ essere staico: xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + - + + + .. code-block:: php + use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Definition; - $container->setDefinition('newsletter_manager_factory', new Definition( - 'NewsletterManager' - )); - $container->setDefinition('newsletter_manager', new Definition( - 'NewsletterManagerFactory' - ))->setFactoryService( - 'newsletter_manager_factory' - )->setFactoryMethod( - 'createNewsletterManager' - ); - -.. note:: + // ... + $container->register('newsletter_manager.factory', 'NewsletterManagerFactory'); - Il servizio factory è specificato dal suo nome id e non da un riferimento al servizio - stesso. Non occorre quindi usare la sintassi con la chiocchiola nelle configurazioni - YAML. + $newsletterManager = new Definition(); + $newsletterManager->setFactory(array( + new Reference('newsletter_manager.factory'), + 'createNewsletterManager' + )); + $container->setDefinition('newsletter_manager', $newsletterManager); Passare parametri al metodo del factory --------------------------------------- @@ -137,12 +128,12 @@ dell'esempio precedente accetti un servizio ``templating`` come parametro: .. code-block:: yaml services: - newsletter_manager_factory: - class: NewsletterManagerFactory + newsletter_manager.factory: + class: NewsletterManagerFactory + newsletter_manager: - class: NewsletterManager - factory_service: newsletter_manager_factory - factory_method: createNewsletterManager + class: NewsletterManager + factory: ["@newsletter_manager.factory", createNewsletterManager] arguments: - "@templating" @@ -154,32 +145,29 @@ dell'esempio precedente accetti un servizio ``templating`` come parametro: xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + - - - + + + .. code-block:: php + use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Definition; // ... - $container->setDefinition('newsletter_manager_factory', new Definition( - 'NewsletterManagerFactory' - )); - $container->setDefinition('newsletter_manager', new Definition( + $container->register('newsletter_manager.factory', 'NewsletterManagerFactory'); + + $newsletterManager = new Definition( 'NewsletterManager', array(new Reference('templating')) - ))->setFactoryService( - 'newsletter_manager_factory' - )->setFactoryMethod( - 'createNewsletterManager' ); + $newsletterManager->setFactory(array( + new Reference('newsletter_manager.factory'), + 'createNewsletterManager' + )); + $container->setDefinition('newsletter_manager', $newsletterManager); diff --git a/components/dependency_injection/parentservices.rst b/components/dependency_injection/parentservices.rst index 38036bec..31d5135c 100644 --- a/components/dependency_injection/parentservices.rst +++ b/components/dependency_injection/parentservices.rst @@ -176,7 +176,7 @@ e:: // ... } -In modo simile, il contenitore di servizi di Symfony2 supporta anche l'estensione di +In modo simile, il contenitore di servizi di Symfony supporta anche l'estensione di servizi nella configurazione, in modo da poter ridurre le ripetizioni, specificando un genitore per un servizio. diff --git a/components/event_dispatcher/introduction.rst b/components/event_dispatcher/introduction.rst index 302e924d..a2303407 100644 --- a/components/event_dispatcher/introduction.rst +++ b/components/event_dispatcher/introduction.rst @@ -6,7 +6,7 @@ Il componente EventDispatcher ============================= Il componente EventDispatcher fornisce strumenti che consentono ai componenti di un'applicazione - di comunicare tra di loro, distrubuendo eventi e ascoltandoli. + di comunicare tra di loro, distribuendo eventi e ascoltandoli. Introduzione @@ -24,20 +24,20 @@ o dopo che un metodo sia eseguito, senza interferire con altri plugin. Questo pr si risolve facilmente con l'ereditarietà singola, mentre l'ereditarietà multipla (dove sia possibile con PHP) ha i suoi difetti. -Il componente Event Dispatcher di Symfony2 implementa il pattern `Mediator`_ in modo +Il componente Event Dispatcher di Symfony implementa il pattern `Mediator`_ in modo semplice ed efficace, per rendere possibile tutto questo e per rendere un progetto veramente estensibile. Si prenda un semplice esempio da :doc:`/components/http_kernel/introduction`. Una volta creato un oggetto ``Response``, può essere utile consentirne la modifica ad altri elementi del sistema (p.e. aggiungere header di cache) prima del suo utilizzo effettivo. -Per poterlo fare, il kernel di Symfony2 lancia un evento, +Per poterlo fare, il kernel di Symfony lancia un evento, ``kernel.response``. Ecco come funziona: * Un *ascoltatore* (oggetto PHP) dice a un oggetto *distributore* centrale che vuole ascoltare l'evento ``kernel.response``; -* A un certo punto, il kernel di Symfony2 dice all'oggetto *distributore* di distribuire +* A un certo punto, il kernel di Symfony dice all'oggetto *distributore* di distribuire l'evento ``kernel.response``, passando un oggetto ``Event``, che ha accesso all'oggetto ``Response``; diff --git a/components/expression_language/introduction.rst b/components/expression_language/introduction.rst index 27283ecf..7fc0a92f 100644 --- a/components/expression_language/introduction.rst +++ b/components/expression_language/introduction.rst @@ -24,7 +24,7 @@ In che modo il linguaggio delle espressioni può essere utile? ------------------------------------------------------------- Lo scopo del componente è consentire agli utenti di usare espressioni all'interno -della configurazione, per logiche più complesse. Per esempio, il framework Symfony2 +della configurazione, per logiche più complesse. Per esempio, il framework Symfony usa espressioni nella sicurezza, per le regole di validazione e per la corrispondenza di rotte. Oltre a usare il componente nel framework, il componente ExpressionLanguage diff --git a/components/form/introduction.rst b/components/form/introduction.rst index d408f714..495597b3 100644 --- a/components/form/introduction.rst +++ b/components/form/introduction.rst @@ -30,7 +30,7 @@ Configurazione Se si lavora con il framework Symfony, il componente Form è già configurato. In questo caso, passare a :ref:`component-form-intro-create-simple-form`. -In Symfony2, i form sono rappresentati da oggetti e tali oggetti sono costruiti +In Symfony, i form sono rappresentati da oggetti e tali oggetti sono costruiti usando un *factory di form*. Costruire un factory di form è semplice:: use Symfony\Component\Form\Forms; @@ -74,9 +74,15 @@ Per processare i dati di un form, occorre richiamare il metodo :method:`Symfony\ $form->handleRequest(); -Dietro le quinte, viene usato un oggetto a :class:`Symfony\\Component\\Form\\NativeRequestHandler` -per leggere i dati dalle variabili globali di PHP (cioè da ``$_POST`` o da -``$_GET``), a seconda del metodo HTTP configurato nel form (POST è quello predefinito). +Dietro le quinte, viene usato un oggetto :class:`Symfony\\Component\\Form\\NativeRequestHandler` +per leggere i dati dalle opportune variabili di PHP (``$_POST`` o +``$_GET``), in base al metodo HTTP configurato nel form (quello predefinito è POST). + +.. seealso:: + + Se occorre maggiore controllo su come esattamente il form viene inviato o su quali + dati vi siano passati, si può usare :method:`Symfony\\Component\\Form\\FormInterface::submit`. + Per saperne di più, vedere :ref:`il ricettario `. .. sidebar:: Integrazione con il componente HttpFoundation @@ -154,7 +160,7 @@ errori e label). Se si usa `Twig`_ come motore di template, il componente Form offre una ricca integrazione. Per usare tale integrazione, occorre ``TwigBridge``, che integra -Twig con vari componenti di Symfony2. Usando Composer, si può +Twig con vari componenti di Symfony. Usando Composer, si può installare la versione 2.3 più recente. aggiungendo la seguente riga al file ``composer.json``: @@ -320,13 +326,13 @@ L'integrazione con il componente Validation sarà simile a questa:: // ci sono traduzioni predefinite per i messaggi di errore principali $translator->addResource( 'xlf', - $vendorFormDir . '/Resources/translations/validators.en.xlf', + $vendorFormDir.'/Resources/translations/validators.en.xlf', 'en', 'validators' ); $translator->addResource( 'xlf', - $vendorValidatorDir . '/Resources/translations/validators.en.xlf', + $vendorValidatorDir.'/Resources/translations/validators.en.xlf', 'en', 'validators' ); @@ -369,7 +375,7 @@ Creazione di un semplice form .. tip:: - Se si usa il framework Symfony2, il factory di form è disponibile + Se si usa il framework Symfony, il factory di form è disponibile automaticamente come servizio, chiamato ``form.factory``. Inoltre, la classe controller base ha un metodo :method:`Symfony\\Bundle\\FrameworkBundle\\Controller::createFormBuilder`, che è una scorciatoia per recuperare il factory di form e richiamare ``createBuilder`` @@ -489,6 +495,43 @@ non è ancora molto flessibile. Di solito, si vuole rendere ogni campo del form singolarmente, in modo da poterne controllare l'aspetto. Si vedrà come farlo nella sezione ":ref:`form-rendering-template`". +Cambiare metodo e azione del form +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.3 + La possibilità di configurare metodo e azione del form è stata introdotta in + Symfony 2.3. + +Ogni form viene normalmente inviato allo stesso URI in cui è stato reso, con una +richiesta HTTP POST. Si può modificare tale comportamento, usando le opzioni :ref:`form-option-action` +e :ref:`form-option-method` (l'opzione ``method`` è usata anche +da ``handleRequest()``, per determinare se il form sia stato inviato): + +.. configuration-block:: + + .. code-block:: php-standalone + + $formBuilder = $formFactory->createBuilder('form', null, array( + 'action' => '/search', + 'method' => 'GET', + )); + + // ... + + .. code-block:: php-symfony + + // ... + + public function searchAction() + { + $formBuilder = $this->createFormBuilder('form', null, array( + 'action' => '/search', + 'method' => 'GET', + )); + + // ... + } + .. _component-form-intro-handling-submission: Gestione dell'invio di form @@ -617,6 +660,51 @@ e gli eventuali errori mostrati accanto ai rispettivi campi. Per un elenco di tutti i vincoli disponibili, vedere :doc:`/reference/constraints`. +Accedere agli errori +~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.5 + Prima di Symfony 2.5, ``getErrors()`` restituiva un array di oggetti ``FormError``. + Il valore restituito è stato cambiato in un ``FormErrorIterator`` in Symfony + 2.5. + +.. versionadded:: 2.5 + I parametri ``$deep`` e ``$flatten`` sono stati introdotti in Symfony 2.5. + +Si può usare il metodo :method:`Symfony\\Component\\Form\\FormInterface::getErrors` +per accedere alla lista degli errori. Ogni elemento è un oggetto +:class:`Symfony\\Component\\Form\\FormError`:: + + $form = ...; + + // ... + + // un array di oggetti FormError, ma solo di errori allegati a questo + // livello del form (p.e. "errori globali") + $errori = $form->getErrors(); + + // un array di oggetti FormError, ma solo di errori allegati al campo + // "nome" + $errori = $form['nome']->getErrors(); + + // un'istanza di FormErrorIterator in una struttura appiattita + // usare getOrigin() per determinare il form che ha causato l'errore + $errors = $form->getErrors(true); + + // un'istanza di FormErrorIterator che rappresenta tutti gli errori dell'intero form + $errori = $form->getErrors(true, false); + +.. tip:: + + Nelle versioni precedenti di Symfony, ``getErrors()`` restituiva un array. Per usare gli + errori nello stesso modo in Symfony 2.5 o successivi, si deve passarli alla funzione + :phpfunction:`iterator_to_array` di PHP:: + + $erroriComeArray = iterator_to_array($form->getErrors()); + + Questo può essere utile, per esempio, se si vuole usare una funzione ``array_`` di PHP + sugli errori del form. + .. _Packagist: https://packagist.org/packages/symfony/form .. _Twig: http://twig.sensiolabs.org .. _`configurazione di Twig`: http://twig.sensiolabs.org/doc/intro.html diff --git a/components/http_foundation/introduction.rst b/components/http_foundation/introduction.rst index 20fa47eb..ec2ae6d0 100644 --- a/components/http_foundation/introduction.rst +++ b/components/http_foundation/introduction.rst @@ -13,7 +13,7 @@ In PHP, la richiesta è rappresentata da alcune variabili globali (``$_GET``, ``$_POST``, ``$_FILE``, ``$_COOKIE``, ``$_SESSION``...) e la risposta è generata da alcune funzioni (``echo``, ``header``, ``setcookie``, ...). -Il componente HttpFoundation di Symfony2 sostituisce queste variabili globali e queste +Il componente HttpFoundation di Symfony sostituisce queste variabili globali e queste funzioni di PHP con un livello orientato agli oggetti. Installazione @@ -173,7 +173,7 @@ richiesta, grazie alla proprietà pubblica ``attributes``, che è anche un'istan :class:`Symfony\\Component\\HttpFoundation\\ParameterBag`. La si usa soprattutto per allegare informazioni che appartengono alla richiesta e a cui si deve accedere in diversi punti dell'applicazione. Per informazioni su come viene -usata nel framework Symfony2, vedere +usata nel framework Symfony, vedere :ref:`il libro `. Infine, si può accedere ai dati grezzi inviati nel corpo della richiesta usando diff --git a/components/http_foundation/session_configuration.rst b/components/http_foundation/session_configuration.rst index 43eb8ad0..57ef5970 100644 --- a/components/http_foundation/session_configuration.rst +++ b/components/http_foundation/session_configuration.rst @@ -32,10 +32,10 @@ dei metodi ``setOptions()`` di ciascuna classe. Per esempio, quello fornito dall'estensione Memcached si può trovare in `php.net/memcached.setoption`_. Sebbene i gestori di salvataggio nativi possano essere attivati direttamente, usando -``ini_set('session.save_handler', $nome);``, Symfony2 fornisce un modo conveniente +``ini_set('session.save_handler', $nome);``, Symfony fornisce un modo conveniente per attivarrli nello stesso modo dei gestori personalizzati. -Symfony2 fornisce driver per i gestori nativi, come per esempio: +Symfony fornisce driver per i gestori nativi, come per esempio: * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeFileSessionHandler` @@ -58,7 +58,7 @@ Esempio di utilzzo:: I gestori di salvataggio nativi forniscono una soluzione rapida alla memorizzazione di sessioni, tuttavia in sistemi complessi, in cui occorre maggior controllo, i gestori di salvataggio personalizzati possono - fornire più libertà e flessibilità. Symfony2 fornisce varie implementazioni, + fornire più libertà e flessibilità. Symfony fornisce varie implementazioni, personalizzabili a piacimento. Gestori di salvataggio personalizzati @@ -68,7 +68,7 @@ I gestori personalizzati sono quelli che sostituiscono completamente i gestori d nativi di PHP, fornendo sei funzioni di callback, richiamate internamente da PHP in vari punti del flusso della sessione. -HttpFoundation di Symfony2 ne fornisce alcuni predefiniti, che possono facilmente servire +HttpFoundation di Symfony ne fornisce alcuni predefiniti, che possono facilmente servire da esempi, se se ne vuole scrivere uno. * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\PdoSessionHandler` @@ -148,7 +148,7 @@ o al metodo :method:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Nativ Scadenza della sessione ~~~~~~~~~~~~~~~~~~~~~~~ -Quando viene creata una nuova sessione, quindi quando Symfony2 invia un nuovo cookie di +Quando viene creata una nuova sessione, quindi quando Symfony invia un nuovo cookie di sessione al client, il cookie sarà emesso con un tempo di scadenza. Questo tempo è calcolato aggiungendo il valore di configurazione di PHP in ``session.cookie_lifetime`` al tempo attuale del server. @@ -186,7 +186,7 @@ la sessione parte. La sessione può essere distrutta, come richiesto. Questo met consentire di integrare la scadenza delle sessioni nell'esperienza utente, per esempio, mostrando un messaggio. -Symfony2 registra alcuni meta-dati di base su ogni sessione, per dare completa libertà +Symfony registra alcuni meta-dati di base su ogni sessione, per dare completa libertà in quest'area. Meta-dati di sessione @@ -229,7 +229,7 @@ librerie. :phpclass:`SessionHandler` è una classe interna speciale di PHP, che espone i gestori del salvataggio nativi nello user space di PHP. -Per poter fornire una soluzione a chi usa PHP 5.4, Symfony2 ha una classe speciale, +Per poter fornire una soluzione a chi usa PHP 5.4, Symfony ha una classe speciale, chiamata :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeSessionHandler`, che sotto PHP 5.4 estende da `\SessionHandler` e sotto PHP 5.3 è solo una classe di base vuota. Questo dà alcune interessanti opportunità, per sfruttare le diff --git a/components/http_foundation/session_php_bridge.rst b/components/http_foundation/session_php_bridge.rst index ed96411d..e2c2aaf6 100644 --- a/components/http_foundation/session_php_bridge.rst +++ b/components/http_foundation/session_php_bridge.rst @@ -43,7 +43,7 @@ migrare la propria applicazione per utilizzare le sessioni di Symfony. Le sessioni di Symfony salvano i dati come attributi in una speciale 'sacca' che utilizza una chiave nell'array superglobale ``$_SESSION``. Questo vuol dire che la sessione di Symfony - non puo accedere a chiavi arbitrarie di ``$_SESSION``, le quali potrebbero appartenere all'applicazione + non può accedere a chiavi arbitrarie di ``$_SESSION``, le quali potrebbero appartenere all'applicazione preesistente, anche se tutto il contenuto di ``$_SESSION`` verrà salvato quando la sessione viene salvata. diff --git a/components/http_foundation/session_testing.rst b/components/http_foundation/session_testing.rst index c9c37c63..14753456 100644 --- a/components/http_foundation/session_testing.rst +++ b/components/http_foundation/session_testing.rst @@ -5,7 +5,7 @@ Test con le sessioni ==================== -Symfony2 è stato progettato fin dall'inizio con la testabilità in mente. Per rendere +Symfony è stato progettato fin dall'inizio con la testabilità in mente. Per rendere facilmente testabile un codice che usa le sessioni, vengono forniti due diversi mock di meccanismi di memorizzazione, sia per test unitari che per test funzionali. diff --git a/components/http_foundation/sessions.rst b/components/http_foundation/sessions.rst index 4f491f40..1e4274d4 100644 --- a/components/http_foundation/sessions.rst +++ b/components/http_foundation/sessions.rst @@ -5,7 +5,7 @@ Gestione della sessione ======================= -Il componente HttpFoundation di Symfony2 ha un sotto-sistema per le sessioni molto potente +Il componente HttpFoundation di Symfony ha un sotto-sistema per le sessioni molto potente e flessibile, progettato per fornire una gestione delle sessioni tramite una semplice interfaccia orientata agli oggetti, usando una varietà di driver per memorizzare la sessione. @@ -141,16 +141,16 @@ Gestori del salvataggio La gestione delle sessioni di PHP richiede l'uso della variabile ``$_SESSION``, tuttavia questo interferisce in qualche modo con la testabilità e l'incapsulamento del codcie -in un paradigma OOP. Per superare questo problema, Symfony2 usa delle "bag" di sessione, collegate +in un paradigma OOP. Per superare questo problema, Symfony usa delle "bag" di sessione, collegate alla sessione, che incapsulano dati specifici di "attributi" o "messaggi flash". Questo approccio mitiga anche l'inquinamento dello spazio dei nomi all'interno di `$_SESSION`, perché ogni bas memorizza i suoi dati sotto uno spazio dei nomi univoco. -Questo consente a Symfony2 di coesistere in modo pacifico con altre applicazioni o librerie +Questo consente a Symfony di coesistere in modo pacifico con altre applicazioni o librerie che potrebbero usare `$_SESSION`, mantenendo tutti i dati completamente compatibili -con la gestione delle sessioni di Symfony2. +con la gestione delle sessioni di Symfony. -Symfony2 fornisce due tipi di bag, con due implementazioni separate. +Symfony fornisce due tipi di bag, con due implementazioni separate. Ogni cosa è scritta su interfacce, quindi si può estendere o creare i propri tipi di bag, se necessario. @@ -162,7 +162,7 @@ seguente API, intesa principalmente per scopi interni: In generale questo valore può essere lasciato al suo predefinito ed è per uso interno. :method:`Symfony\\Component\\HttpFoundation\\Session\\SessionBagInterface::initialize` - richiamato internamente dalle classi memorizzazione della sessione di Symfony2 per collegare + richiamato internamente dalle classi memorizzazione della sessione di Symfony per collegare i dati del bag alla sessione. :method:`Symfony\\Component\\HttpFoundation\\Session\\SessionBagInterface::getName` diff --git a/components/http_foundation/trusting_proxies.rst b/components/http_foundation/trusting_proxies.rst index a56f3359..10a23c37 100644 --- a/components/http_foundation/trusting_proxies.rst +++ b/components/http_foundation/trusting_proxies.rst @@ -15,7 +15,7 @@ Per esempio, l'header HTTP ``Host`` di solito si usa per restituire l'host richiesto. Ma, quando ci si trova dietro a un proxy, il vero host potrebbe trovarsi nell'header ``X-Forwarded-Host``. -Poiché gli header HTTP possono essere falsificati, Symfony2 *non* si fida degli +Poiché gli header HTTP possono essere falsificati, Symfony *non* si fida degli header dei proxy. Se si è dietro a un proxy, si deve indicare manualmente che tale proxy è fidato. diff --git a/components/http_kernel/introduction.rst b/components/http_kernel/introduction.rst index 53c4ff62..00b1a872 100644 --- a/components/http_kernel/introduction.rst +++ b/components/http_kernel/introduction.rst @@ -118,7 +118,7 @@ Per informazioni generali sull'aggiunta di ascoltatori agli eventi qui sotto, ve .. tip:: Fabien Potencier ha anche scritto una bella serie sull'uso del componente HttpKernel - e altri componenti di Symfony2 per creare un proprio framework. Vedere + e altri componenti di Symfony per creare un proprio framework. Vedere `Create your own framework... on top of the Symfony2 Components`_. .. _component-http-kernel-kernel-request: @@ -167,6 +167,11 @@ una ``Response`` direttamente oppure di aggiungere informazioni alla ``Request`` (p.e. impostando il locale o altre informaioni sugli attributi della ``Request``). +.. note:: + + Quando si imposta una risposta per l'evento ``kernel.request``, la propagazione + si ferma. Questo vuol dire che ascoltatori con priorità inferiore non saranno eseguiti. + .. sidebar:: ``kernel.request`` nel framework Symfony L'ascoltatore più importante di ``kernel.request`` nel framework Symfony @@ -226,7 +231,7 @@ alle informazioni della richiesta. Il secondo metodo, :method:`Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface::getArguments`, sarà richiamato dopo che un altro evento, ``kernel.controller``, è stato distribuito. -.. sidebar:: Resolving the Controller in the Symfony2 Framework +.. sidebar:: Risolvere il controllore nel framework Symfony Il framework Symfony usa la classe :class:`Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver` @@ -243,10 +248,10 @@ sarà richiamato dopo che un altro evento, ``kernel.controller``, è stato distr a) Il formato ``AcmeDemoBundle:Default:index`` della chiave ``_controller`` viene cambiato in un'altra stringa che contiene il nome completo di classe e metodo - del controllore, seguendo la convenzione di Symfony2, cioè + del controllore, seguendo la convenzione di Symfony, cioè ``Acme\DemoBundle\Controller\DefaultController::indexAction``. Questa trasformazione è specifica della sotto-classe :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerResolver` - usata dal framework Symfony2. + usata dal framework Symfony. b) Viene istanziata una nuova istanza della classe controllore, senza parametri al costruttore. @@ -254,7 +259,7 @@ sarà richiamato dopo che un altro evento, ``kernel.controller``, è stato distr c) Se il controllore implementa :class:`Symfony\\Component\\DependencyInjection\\ContainerAwareInterface`, viene richiamato ``setContainer`` sull'oggetto controllore e gli viene passato il contenitore. Anche questo passo è specifico della sotto-classe :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerResolver` - usata dal framework Symfony2. + usata dal framework Symfony. Ci possono essere alcune piccole variazioni nel processo appena visto, p.e. se i controllori sono stati registrati come servizi). @@ -273,7 +278,7 @@ Dopo che il callable controllore è stato determinato, ``HttpKernel::handle`` distribuisce l'evento ``kernel.controller``. Gli ascoltatori di questo evento possono inizializzare alcune parti del sistema che devono essere inizializzate dopo che alcune cose sono state determinate (p.e. il controllore, informazioni sulle rotte) ma prima -che il controllore sia eseguito. Per alcuni esempi, vedere la sezione Symfony2 più avanti. +che il controllore sia eseguito. Per alcuni esempi, vedere la sezione Symfony più avanti. .. image:: /images/components/http_kernel/06-kernel-controller.png :align: center @@ -315,7 +320,7 @@ ne sia un buon esempio. A questo punto il kernel ha un callable PHP (il controllore) e un array di parametri che vanno passati durante l'esecuzione di tale callable. -.. sidebar:: Ottenere i parametri del controllore nel framework Symfony2 +.. sidebar:: Ottenere i parametri del controllore nel framework Symfony Ora che sappiamo esattamente cosa sia il callable controllore (solitamente un metodo dentro all'oggetto controllore), ``ControllerResolver`` usa `reflection`_ @@ -391,6 +396,11 @@ A questo punto, ne nessun ascoltatore imposta una risposta sull'evento, viene la un'eccezione: o il controllore *o* uno degli ascoltatori della vista devono sempre restituire una ``Response``. +.. note:: + + Quando si imposta una risposta per l'evento ``kernel.request``, la propagazione + si ferma. Questo vuol dire che ascoltatori con priorità inferiore non saranno eseguiti. + .. sidebar:: ``kernel.view`` in the Symfony Framework Non c'è un ascoltatore predefinito nel framework Symfony per l'evento ``kernel.view``. @@ -469,6 +479,15 @@ si lancerà l'evento ``kernel.terminate``, in cui si possono eseguire alcune azioni che potrebbero essere state rimandate, per poter restituire la risposta nel modo più veloce possibile al client (p.e. invio di email). +.. caution:: + + Internamente, HttpKernel fa uso della funazione :phpfunction:`fastcgi_finish_request` di + PHP. Questo vuole dire che, al momento, solo le API del server `PHP FPM`_ sono + in grado di inviare al cliente una risposta mentre il processo PHP del server + esegue ancora alcuni compiti. Con le API di ogni altro server, gli acoltatori di ``kernel.terminate`` + sono comunque eseguiti, ma la risposta non viene inviata al cliente finché non + sono tutti completati. + .. note:: L'uso dell'evento ``kernel.terminate`` è facoltativo e va limitato al caso in cui @@ -476,10 +495,9 @@ più veloce possibile al client (p.e. invio di email). .. sidebar:: ``kernel.terminate`` in the Symfony Framework - Se si usa ``SwiftmailerBundle`` con Symfony2 e si usa lo spool ``memory``, - viene attivato :class:`Symfony\\Bundle\\SwiftmailerBundle\\EventListener\\EmailSenderListener`, - che invia effettivamente le email pianificate per essere inviate - durante la richiesta. + Se si usa SwiftmailerBundle con Symfony e si usa lo spool ``memory``, + viene attivato `EmailSenderListener`, che invia effettivamente le email + pianificate per essere inviate durante la richiesta. .. _component-http-kernel-kernel-exception: @@ -513,6 +531,11 @@ dispone di un :class:`Symfony\\Component\\HttpKernel\\EventListener\\ExceptionLi che, se usato, farà questo e anche di più in modo predefinito (si vedano dettagli più avanti). +.. note:: + + Quando si imposta una risposta per l'evento ``kernel.request``, la propagazione + si ferma. Questo vuol dire che ascoltatori con priorità inferiore non saranno eseguiti. + .. sidebar:: ``kernel.exception`` in the Symfony Framework Ci sono due ascoltatori principali di ``kernel.exception`` quando si usa il @@ -656,10 +679,6 @@ parametro, come segue:: $response = $kernel->handle($request, HttpKernelInterface::SUB_REQUEST); // fare qualcosa con questa risposta -.. versionadded:: 2.4 - Il metodo ``isMasterRequest()`` è stato introdotto in Symfony 2.4. - In precedenza veniva usato il metodo ``getRequestType()``. - Questo crea un altro ciclo richiesta-risposta, in cui la nuova ``Request`` è trasformata in una ``Response``. L'unica differenza interna è che alcuni ascoltatori (p.e. security) possono intervenire solo per la richiesta principale. A ggni @@ -690,3 +709,4 @@ assomigliare a questo:: .. _`SensioFrameworkExtraBundle`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html .. _`@ParamConverter`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html .. _`@Template`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/view.html +.. _`EmailSenderListener`: https://github.com/symfony/SwiftmailerBundle/blob/master/EventListener/EmailSenderListener.php diff --git a/components/security/secure_tools.rst b/components/security/secure_tools.rst index 58ae0c67..eb467f61 100644 --- a/components/security/secure_tools.rst +++ b/components/security/secure_tools.rst @@ -1,4 +1,60 @@ Sicurezza nel confronto di stringhe e nella generazione di numeri casuali ========================================================================= -(TODO da tradurre...) +Il componente Security di Symfony dispone di un insieme di utilità correlate +alla sicurezza. Queste utilità sono usate da Symfony, ma possono anche essere +usate in autonomia, per risolvere alcuni problemi. + +Confronto di stringhe +~~~~~~~~~~~~~~~~~~~~~ + +Il tempo che occorre per confrontare due stringhe dipende dalle loro differenze. Questo dettaglio +può essere usato da un attaccante, quando le due stringhe rappresentano una password, per esempio. +Questo attacco è noto come `timing attack`_. + +Internamente, quando confronta due password, Symfony usa un algoritmo a tempo +costante. Si può usare la stessa strategia nel proprio codice, grazie alla classe +:class:`Symfony\\Component\\Security\\Core\\Util\\StringUtils`:: + + use Symfony\Component\Security\Core\Util\StringUtils; + + // una stringa nota (p.e. una password) è uguale a una fornita dall'utente? + $bool = StringUtils::equals($stringaNota, $stingaUtente); + +.. caution:: + + Per evitare attacchi di tipo timing attack, la stringa nota deve essere il primo parametro + e la stringa inserita dall'utente il secondo parametro. + +Generazione di un numero casuale sicuro +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Ogni volta che si deve generare un numero casuale sicuro, si raccomanda caldamente +l'uso della classe +:class:`Symfony\\Component\\Security\\Core\\Util\\SecureRandom`:: + + use Symfony\Component\Security\Core\Util\SecureRandom; + + $generator = new SecureRandom(); + $random = $generator->nextBytes(10); + +Il metodo +:method:`Symfony\\Component\\Security\\Core\\Util\\SecureRandom::nextBytes` +restituisce una stringa casuale, composta dal numero di caratteri passati come +parametro (nell'esempio, 10). + +La classe funziona meglio quando è installato SSL. In caso in cui non sia disponibile, +ai appoggia a un algoritmo interno, che ha bisogno di un seme per funzionare +correttamente. In questo caso, passare un nome di file:: + + use Symfony\Component\Security\Core\Util\SecureRandom; + + $generator = new SecureRandom('/percorso/in/cui/si/trova/il/seme.txt'); + $random = $generator->nextBytes(10); + +.. note:: + + Se si usa il framework Symfony, si può accedere direttamente all'istanza della classe + dal contenitore: il nome del servizio è ``security.secure_random``. + +.. _`timing attack`: http://en.wikipedia.org/wiki/Timing_attack diff --git a/components/templating/introduction.rst b/components/templating/introduction.rst index 092196cf..9b66bcf3 100644 --- a/components/templating/introduction.rst +++ b/components/templating/introduction.rst @@ -135,7 +135,8 @@ personalizzato, usando il metodo Aiutanti -------- -Il componente Templating può essere facilmente esteso, tramite aiutanti. Il componente ha +Il componente Templating può essere facilmente esteso, tramite aiutanti. Gli aiutanti sono oggetti PHP, +che forniscono caratteristiche utili nel contesto di un template. Il componente ha due aiutanti predefiniti: * :doc:`/components/templating/helpers/assetshelper` @@ -195,7 +196,7 @@ scegliere quale motore usare per il template, viene usato il metodo $templating = new DelegatingEngine(array( new PhpEngine(...), - new CustomEngine(...) + new CustomEngine(...), )); .. _Packagist: https://packagist.org/packages/symfony/templating diff --git a/components/translation/introduction.rst b/components/translation/introduction.rst index 12d74d41..fec2d3b2 100644 --- a/components/translation/introduction.rst +++ b/components/translation/introduction.rst @@ -205,7 +205,7 @@ si deve specificare il dominio come terzo parametro di ``trans()``:: $translator->trans('Symfony is great', array(), 'admin'); -Symfony2 ora cercherà il messaggio nel dominio ``admin`` del locale +Symfony ora cercherà il messaggio nel dominio ``admin`` del locale specificato. Uso diff --git a/components/yaml/introduction.rst b/components/yaml/introduction.rst index b3c7be07..3be5a264 100644 --- a/components/yaml/introduction.rst +++ b/components/yaml/introduction.rst @@ -10,7 +10,7 @@ Il componente YAML Che cos'è? ---------- -Il componente YAML di Symfony2 analizza stringhe YAML da convertire in array PHP. +Il componente YAML di Symfony analizza stringhe YAML da convertire in array PHP. È anche in grado di convertire array PHP in stringhe YAML. `YAML`_, *YAML Ain't Markup Language*, è uno standard amichevole di serializzazione di dati @@ -18,7 +18,7 @@ per tutti i linguaggi di programmazione. YAML è un ottimo formato per i file di configurazione. I file YAML sono espressivi quanto i file XML e leggibili quanto i file INI. -Il componente YAML di Symfony2 implementa un sottoinsieme scelto di caratteristiche definite nella +Il componente YAML di Symfony implementa un sottoinsieme scelto di caratteristiche definite nella `versione 1.2 della specifica YAML`_. .. tip:: @@ -79,10 +79,10 @@ usando riferimenti a bit comuni di configurazione. .. _using-the-symfony2-yaml-component: -Usare il componente YAML di Symfony2 ------------------------------------- +Usare il componente YAML di Symfony +----------------------------------- -Il componente YAML di Symfony2 è molto semplice e consiste di due classi principali: +Il componente YAML di Symfony è molto semplice e consiste di due classi principali: una analizza le stringhe YAML (:class:`Symfony\\Component\\Yaml\\Parser`) e l'altra esporta un array PHP in una stringa YAML (:class:`Symfony\\Component\\Yaml\\Dumper`). diff --git a/contributing/code/bugs.rst b/contributing/code/bugs.rst index 51aadf1c..fd6ca8cf 100644 --- a/contributing/code/bugs.rst +++ b/contributing/code/bugs.rst @@ -1,40 +1,39 @@ Segnalare un bug ================ -Se doveste incontrare un bug in Symfony2, vi chiediamo di segnalarlo. Ci aiuta -a rendere migliore Symfony2. +A chi dovesse incontrare un bug in Symfony, chiediamo di segnalarlo. Questo aiuta +a rendere migliore Symfony. .. caution:: - Se pensate di aver trovato un problema di sicurezza, per favore, seguite + Chi ritenga di aver trovato un problema di sicurezza, per favore, segua invece l'apposita :doc:`procedura `. Prima di inviare un bug: -* Ricontrollare la `documentazione`_ ufficiale per verificare che non si stia facendo +* Ricontrollare la :doc:`documentazione ` ufficiale, per verificare che non si stia facendo un uso scorretto del framework; * Chiedere assistenza alla `lista degli utenti`_ , al `forum`_ o al `canale IRC`_ #symfony, se non si è sicuri che sia effettivamente un bug. Se il problema è effettivamente un bug, segnalarlo utilizzando -il bug `tracker`_ ufficiale e seguendo alcune regole: +il `tracker`_ ufficiale e seguendo alcune regole: * Utilizzare il campo titolo per descrivere chiaramente la questione; -* Descrivere i passi necessari per riprodurre il bug con brevi esempi di codice +* Descrivere i passi necessari per riprodurre il bug, con brevi esempi di codice (la cosa migliore è fornire un test unitario per replicare il bug) * Se il bug riscontrato affligge più livelli, fornire un semplice test unitario che fallisca potrebbe non essere sufficiente. In questo caso, eseguire un fork di `Symfony Standard Edition`_ e riprodurre il problema su un nuovo ramo; -* Fornire il maggior numero di dettagli possibile sul proprio ambiente (sistema operativo, versione PHP +* Fornire il maggior numero di dettagli possibile sul proprio ambiente (sistema operativo, versione di PHP, versione di Symfony, estensioni abilitate, ...) * *(facoltativo)* Allegare una :doc:`patch `. -.. _documentazione: http://symfony.com/doc/current .. _lista degli utenti: http://groups.google.com/group/symfony2 .. _forum: http://forum.symfony-project.org/ .. _canale IRC: irc://irc.freenode.net/symfony diff --git a/contributing/code/license.rst b/contributing/code/license.rst index e60bcc7a..10fca136 100644 --- a/contributing/code/license.rst +++ b/contributing/code/license.rst @@ -1,9 +1,9 @@ .. _symfony2-license: -Licenza di Symfony2 -=================== +Licenza di Symfony +================== -Symfony2 è distribuito sotto licenza MIT. +Symfony è distribuito sotto licenza MIT. Secondo `Wikipedia`_: diff --git a/contributing/code/patches.rst b/contributing/code/patches.rst index fcac6daf..0dffb896 100644 --- a/contributing/code/patches.rst +++ b/contributing/code/patches.rst @@ -2,7 +2,7 @@ Inviare una patch ================= Una patch è il modo migliore per rimediare a un bug e per proporre dei miglioramenti -a Symfony2 +a Symfony Passo 1: preparare l'ambiente ----------------------------- @@ -10,12 +10,12 @@ Passo 1: preparare l'ambiente Installare il software ---------------------- -Prima di lavorare con Symfony2, preparare l'ambiente con il seguente +Prima di lavorare con Symfony, preparare l'ambiente con il seguente software: * Git; * PHP versione 5.3.3 o successive; -* PHPUnit 3.6.4 o successivi. +* `PHPUnit`_ 4.2 o successivi. Configurare Git ~~~~~~~~~~~~~~~ @@ -69,7 +69,7 @@ Ottenere il codice sorgente di Symfony: * Creare un account su `GitHub`_ ed entrare; -* Forkare il `repository di Symfony2`_ (cliccando sul bottone "Fork"); +* Forkare il `repository di Symfony`_ (cliccando sul bottone "Fork"); * Dopo che l'azione "hardcore forking" è stata completata, clonare il fork in locale (creerà una cartella ``symfony``): @@ -88,7 +88,7 @@ Ottenere il codice sorgente di Symfony: Verificare che i test passino ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Ora che Symfony2 è installato, verifcare che tutti i test unitari passino nel proprio +Ora che Symfony è installato, verifcare che tutti i test unitari passino nel proprio ambiente, come spiegato nel :doc:`documento ` dedicato. Passo 2: lavorare su una patch @@ -266,7 +266,7 @@ richiesta di pull, come in: La descrizione della richiesta di pull deve includere la seguente lista in cima, per assicurare che i contributi siano rivisti senza continui giri di feedback e che quindi possano -essere inclusi in Symfony2 il prima +essere inclusi in Symfony il prima possibile: .. code-block:: text @@ -402,7 +402,7 @@ i commit. Dopo aver finito, eseguire il push. .. _ProGit: http://git-scm.com/book .. _GitHub: https://github.com/signup/free .. _`documentazione di Github`: https://help.github.com/articles/ignoring-files -.. _repository di Symfony2: https://github.com/symfony/symfony +.. _repository di Symfony: https://github.com/symfony/symfony .. _lista dev: http://groups.google.com/group/symfony-devs .. _travis-ci.org: https://travis-ci.org/ .. _`icona di stato di travis-ci.org`: http://about.travis-ci.org/docs/user/status-images/ @@ -411,3 +411,4 @@ i commit. Dopo aver finito, eseguire il push. .. _`fabbot`: http://fabbot.io .. _`PSR-1`: http://www.php-fig.org/psr/psr-1/ .. _`PSR-2`: http://www.php-fig.org/psr/psr-2/ +.. _PHPUnit: https://phpunit.de/manual/current/en/installation.html diff --git a/contributing/code/security.rst b/contributing/code/security.rst index b831204e..86d8612d 100644 --- a/contributing/code/security.rst +++ b/contributing/code/security.rst @@ -2,8 +2,8 @@ Problemi di sicurezza ===================== Questo documento spiega la gestione da parte della squadra di Symfony dei problemi di sicurezza -di Symfony (in cui "Symfony" è il codice ospitato nel `repository Git`_ ``symfony/symfony``). - +di Symfony (in cui "Symfony" è il codice ospitato nel `repository Git`_ +``symfony/symfony``). Segnalare un problema di sicurezza ---------------------------------- @@ -19,10 +19,10 @@ Processo di risoluzione Per ogni rapporto, prima si cercherà di confermare la vulnerabilità. Quando confermata, la squadra di sviluppo lavorerà a una soluzione seguendo questi passi: -1. Inviare un riconoscimento al segnalatore; -2. Lavorare su una patch; -3. Ottenere un identificatore CVE da mitre.org; -4. Scrivere un annuncio sul `blog`_ di Symfony, che descriva la vulnerabilità. +#. Inviare un riconoscimento al segnalatore; +#. Lavorare su una patch; +#. Ottenere un identificatore CVE da mitre.org; +#. Scrivere un annuncio sul `blog`_ di Symfony, che descriva la vulnerabilità. Tale post dovrebbe contenere le seguenti informazioni: * un titolo che includa sempre la stringa "Security release"; @@ -32,12 +32,12 @@ confermata, la squadra di sviluppo lavorerà a una soluzione seguendo questi pas * come applicare patch/aggiornamenti/workaround alle applicazioni afflitte; * l'identificatore CVE; * riconoscimenti. -5. Inviare patch e annuncio al segnalante per una revisione; -6. Applicare la patch a tutte le versioni di Symfony in manutenzione; -7. Pacchettizzare nuove versioni per tutte le versioni afflitte; -8. Pubblicare il post sul `blog`_ ufficiale di Symfony (va anche aggiunti alla +#. Inviare patch e annuncio al segnalante per una revisione; +#. Applicare la patch a tutte le versioni di Symfony in manutenzione; +#. Pacchettizzare nuove versioni per tutte le versioni afflitte; +#. Pubblicare il post sul `blog`_ ufficiale di Symfony (va anche aggiunti alla categoria "`Security Advisories`_"); -9. Aggiornare la lista degli avvisi di sicurezza (vedere sotto). +#. Aggiornare la lista degli avvisi di sicurezza (vedere sotto). .. note:: @@ -61,23 +61,23 @@ Poiché Symfony è usato da molti progetti open source, il modo in cui la squadra di sicurezza di Symfony collabora sulle problematiche di sicurezza è stata standardizzata con i progetti a valle. Il progetto funziona come segue: -1. Dopo che la squadra di sicurezza di Symfony ha riconosciuto la problematica, invia -immediatamente una email alle squadre di sicurezza dei progetti a valle, per informarli -della probelamtica; +#. Dopo che la squadra di sicurezza di Symfony ha riconosciuto la problematica, invia + immediatamente una email alle squadre di sicurezza dei progetti a valle, per informarli + della probelamtica; -2. La squadra di sicurezza di Symfony crea un repository Git privato, per facilitare la -collaborazione sulla problematica. L'accesso a tale repository è fornito all -squadra di sicurezza di Symfony, ai contributori du Symfony che hanno avuto impatto sulla -problematica e a un rappresentante i ogni progetto a valle; +#. La squadra di sicurezza di Symfony crea un repository Git privato, per facilitare la + collaborazione sulla problematica. L'accesso a tale repository è fornito all + squadra di sicurezza di Symfony, ai contributori du Symfony che hanno avuto impatto sulla + problematica e a un rappresentante i ogni progetto a valle; -3. Le persone che accedono al repository privato lavorano a una soluzione per -risolvere la problematica, tramire richieste di pull, revisioni di codice e commenti; +#. Le persone che accedono al repository privato lavorano a una soluzione per + risolvere la problematica, tramire richieste di pull, revisioni di codice e commenti; -4. Una volta trovata la soluzione, tutti i progetti coinvolti collaborano per trovare -la data migliore per un rilascio congiunto (non c'è garanzia che tutti i rllasci saranno -contempoaranei, ma si tenterà il più possibili di pubblicarli nello stesso periodo). Quando -non si ritiene che la problematica abbia subito degli exploit, un periodo di due settimane -sembra essere ragionevole. +#. Una volta trovata la soluzione, tutti i progetti coinvolti collaborano per trovare + la data migliore per un rilascio congiunto (non c'è garanzia che tutti i rllasci saranno + contempoaranei, ma si tenterà il più possibili di pubblicarli nello stesso periodo). Quando + non si ritiene che la problematica abbia subito degli exploit, un periodo di due settimane + sembra essere ragionevole. La lista dei progetti a valle partecipanti a tale processo è manutenuta più corta possibile, per meglio gestire il flusso di informazioni riservate, prima @@ -96,11 +96,17 @@ Bollettini di sicurezza Questa sezione elenca le vulnerabilità di sicurezza che sono state risolte in Symfony, partendo da Symfony 1.0.0: +* 1 aprile 2015: `CVE-2015-2309: Unsafe methods in the Request class `_ (Symfony 2.3.27, 2.5.11 e 2.6.6) +* 1 aprile 2015: `CVE-2015-2308: Esi Code Injection `_ (Symfony 2.3.27, 2.5.11 e 2.6.6) +* 3 settembre 2014: `CVE-2014-6072: CSRF vulnerability in the Web Profiler `_ (Symfony 2.3.19, 2.4.9 e 2.5.4) +* 3 settembre 2014: `CVE-2014-6061: Security issue when parsing the Authorization header `_ (Symfony 2.3.19, 2.4.9 e 2.5.4) +* 3 settembre 2014: `CVE-2014-5245: Direct access of ESI URLs behind a trusted proxy `_ (Symfony 2.3.19, 2.4.9 e 2.5.4) +* 3 settembre 2014: `CVE-2014-5244: Denial of service with a malicious HTTP Host header `_ (Symfony 2.3.19, 2.4.9 e 2.5.4) * 15 luglio 2014: `Security releases: Symfony 2.3.18, 2.4.8, and 2.5.2 released `_ (`CVE-2014-4931 `_) * 10 ottobre 2013: `Security releases: Symfony 2.0.25, 2.1.13, 2.2.9, and 2.3.6 released `_ (`CVE-2013-5958 `_) -* 7 agosto 2013: `Security releases: Symfony 2.0.24, 2.1.12, 2.2.5, and 2.3.3 released `_ (`CVE-2013-4751 `_ and `CVE-2013-4752 `_) -* 17 gennaio 2013: `Security release: Symfony 2.0.22 and 2.1.7 released `_ (`CVE-2013-1348 `_ and `CVE-2013-1397 `_) -* 20 dicembre 2012: `Security release: Symfony 2.0.20 and 2.1.5 `_ (`CVE-2012-6431 `_ and `CVE-2012-6432 `_) +* 7 agosto 2013: `Security releases: Symfony 2.0.24, 2.1.12, 2.2.5, and 2.3.3 released `_ (`CVE-2013-4751 `_ e `CVE-2013-4752 `_) +* 17 gennaio 2013: `Security release: Symfony 2.0.22 and 2.1.7 released `_ (`CVE-2013-1348 `_ e `CVE-2013-1397 `_) +* 20 dicembre 2012: `Security release: Symfony 2.0.20 and 2.1.5 `_ (`CVE-2012-6431 `_ e `CVE-2012-6432 `_) * 29 novembre 2012: `Security release: Symfony 2.0.19 and 2.1.4 `_ * 25 novembre 2012: `Security release: symfony 1.4.20 released `_ * 28 agosto 2012: `Security Release: Symfony 2.0.17 released `_ @@ -119,6 +125,6 @@ partendo da Symfony 1.0.0: * 21 marzo 2008: `symfony 1.0.12 is (finally) out ! `_ * 25 giugno 2007: `symfony 1.0.5 released (security fix) `_ -.. _repository Git: https://github.com/symfony/symfony -.. _blog: http://symfony.com/blog/ +.. _repository Git: https://github.com/symfony/symfony +.. _blog: http://symfony.com/blog/ .. _Security Advisories: http://symfony.com/blog/category/security-advisories diff --git a/contributing/code/standards.rst b/contributing/code/standards.rst index 04b8bfe2..6e153f88 100644 --- a/contributing/code/standards.rst +++ b/contributing/code/standards.rst @@ -1,9 +1,9 @@ Standard del codice =================== -Contribuendo al codice di Symfony2, bisogna seguire i suoi standard. Per farla -breve, ecco una regola d'oro: **imitare il codice esistente di Symfony2**. -La maggior parte dei bundle e delle librerie open source usati da Symfony2 +Contribuendo al codice di Symfony, bisogna seguire i suoi standard. Per farla +breve, ecco una regola d'oro: **imitare il codice esistente di Symfony**. +La maggior parte dei bundle e delle librerie open source usati da Symfony segue le stesse linee guida. Ricordare che il vantaggio principale degli standard è che ogni pezzo di codice @@ -135,7 +135,7 @@ Convenzioni sui nomi * Usare gli spazi dei nomi per tutte le classi; -* Aggiungere il prefisso ``Abstract`` alle classi astratte. Si noti che alcune vecchie classi di Symfony2 +* Aggiungere il prefisso ``Abstract`` alle classi astratte. Si noti che alcune vecchie classi di Symfony non seguono questa convenzione e non sono state rinominate per questioni di retrocompatibilità. Tuttavia, tutte le nuove classi astratte devono seguire questa convenzione; diff --git a/contributing/code/tests.rst b/contributing/code/tests.rst index 80fd55bd..60619b77 100644 --- a/contributing/code/tests.rst +++ b/contributing/code/tests.rst @@ -1,21 +1,21 @@ .. _running-symfony2-tests: -Eseguire i test di Symfony2 -=========================== +Eseguire i test di Symfony +========================== Prima di inviare una :doc:`patch `, occorre eseguire -tutti i test di Symfony2, per assicurarsi di non aver rotto nulla. +tutti i test di Symfony, per assicurarsi di non aver rotto nulla. PHPUnit ------- -Per eseguire i test di Symfony2, `installare`_ prima PHPUnit 3.7 o successivi. +Per eseguire i test di Symfony, `installare`_ prima PHPUnit 3.7 o successivi. Dipendenze (opzionali) ---------------------- Per eseguire tutti i test, inclusi quelli che hanno dipendenze esterne, -Symfony2 deve poterle scaricare. Per impostazione predefinita, sono +Symfony deve poterle scaricare. Per impostazione predefinita, sono auto-caricati dalla cartella ``vendor/`` (vedere ``autoload.php.dist``). @@ -28,49 +28,31 @@ I test necessitano delle seguenti librerie di terze parti: Per installarle tutte, usare `Composer`_: -Passo 1: installare `Composer`_ - -.. code-block:: bash - - $ curl -s http://getcomposer.org/installer | php - -Assicurasi di scaricare ``composer.phar`` nella stessa cartella in cui si trova -il file ``composer.json``. +Passo 1: :doc:`installare Composer a livello globale ` Passo 2: installare i venditori .. code-block:: bash - $ php composer.phar --dev install + $ composer install .. note:: Si noti che lo script ha bisogno di tempo per terminare. -.. note:: - - Se non si ha ``curl`` installato, si può anche scaricare a mano il file ``installer`` - da http://getcomposer.org/installer. Mettere tale file nel progetto ed - eseguirlo: - - .. code-block:: bash - - $ php installer - $ php composer.phar --dev install - Dopo l'installazione, si possono aggiornare i venditori alle loro ultime versioni, con il comando seguente: .. code-block:: bash - $ php composer.phar --dev update + $ composer --dev update Esecuzione ---------- Prima di tutto, aggiornare i venditori (vedere sopra). -Quindi, eseguire i test dalla cartella radice di Symfony2, con il comando +Quindi, eseguire i test dalla cartella radice di Symfony, con il comando seguente: .. code-block:: bash diff --git a/contributing/community/releases.rst b/contributing/community/releases.rst index 3a19f638..e0bd5784 100644 --- a/contributing/community/releases.rst +++ b/contributing/community/releases.rst @@ -60,6 +60,8 @@ Rilasci standard Un rilascio standard è mantenuto per un periodo di *otto mesi* per i bug e per un periodo di *quattordici mesi* per i problemi di sicurezza. +.. _releases-lts: + Rilasci a supporto prolungato ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -94,13 +96,13 @@ Versione Freeze Rilascio Fine manutenzione Fine vita 2.2 01/2013 03/2013 11/2013 (8 mesi) 05/2014 **2.3** 03/2013 05/2013 05/2016 (36 mesi) 05/2017 2.4 09/2013 11/2013 09/2014 (10 mesi [1]_) 01/2015 -2.5 02/2014 05/2014 01/2015 (8 mesi) 07/2015 +2.5 03/2014 05/2014 01/2015 (8 mesi) 07/2015 2.6 09/2014 11/2014 07/2015 (8 mesi) 01/2016 -**2.7** 02/2015 05/2015 05/2018 (36 mesi [2]_) 05/2019 +**2.7** 03/2015 05/2015 05/2018 (36 mesi [2]_) 05/2019 3.0 09/2015 11/2015 07/2016 (8 mesi) 01/2017 -3.1 02/2016 05/2016 01/2017 (8 mesi) 07/2017 +3.1 03/2016 05/2016 01/2017 (8 mesi) 07/2017 3.2 09/2016 11/2016 07/2017 (8 mesi) 01/2018 -**3.3** 02/2017 05/2017 05/2020 (36 mesi) 05/2021 +**3.3** 03/2017 05/2017 05/2020 (36 mesi) 05/2021 ... ... ... ... ... ======== ======= ======== ====================== ========= diff --git a/contributing/documentation/format.rst b/contributing/documentation/format.rst index 3741b627..f85a51eb 100644 --- a/contributing/documentation/format.rst +++ b/contributing/documentation/format.rst @@ -40,7 +40,7 @@ con la direttiva ``code-block``: .. code-block:: yaml - { foo: bar, bar: { foo: bar, bar: baz } } + { pippo: pluto, pluto: { pippo: pluto, pluto: paperino } } .. note:: @@ -91,19 +91,19 @@ Il precedente snippet reST mostra un blocco come di seguito: Ecco la lista dei formati attualmente supportati: -=================== ========================= -Formato markup Mostrato -=================== ========================= -``html`` HTML -``xml`` XML -``php`` PHP -``yaml`` YAML -``jinja`` Twig puro -``html+jinja`` Twig mescolato con HTML -``html+php`` PHP mescolato con HTML -``ini`` INI -``php-annotations`` Annotazioni PHP -=================== ========================= +=================== ========================= +Formato markup Mostrato +=================== ========================= +``html`` HTML +``xml`` XML +``php`` PHP +``yaml`` YAML +``jinja`` Twig puro +``html+jinja`` Twig mescolato con HTML +``html+php`` PHP mescolato con HTML +``ini`` INI +``php-annotations`` Annotazioni PHP +=================== ========================= Collegamenti ~~~~~~~~~~~~ @@ -190,7 +190,7 @@ in che modo il comportamento sia cambiato. La funzione ``include()`` è una nuova caratteristica di Twig, disponibile in Symfony 2.3. In precedenza, si usava il tag ``{% include %}``. -A ogni rilascio di una versione minore di Symofny (p.e.. 2.4, 2.5, ecc), +A ogni rilascio di una versione minore di Symfony (p.e. 2.4, 2.5, ecc), viene creato un nuovo ramo della documentazione, a partire da ``master``. A questo punto, i tag ``versionadded`` per versioni di Symfony che hanno raggiunto il fine vita saranno rimossi. Per esempio, se Symfony 2.5 fosse rilasciato oggi e @@ -209,7 +209,6 @@ seguire questi passi: * Installare `Sphinx`_; * Installare le estensioni di Sphinx, eseguendo ``$ git submodule update --init``; -* (Opzionale) Installare la documentazione dei bundle e di CMF: ``$ bash install.sh``; * Eseguire ``make html`` e controllare l'HTML generato nella cartella ``build/``. .. _reStructuredText: http://docutils.sourceforge.net/rst.html diff --git a/contributing/documentation/license.rst b/contributing/documentation/license.rst index f08ba704..197d8e4b 100644 --- a/contributing/documentation/license.rst +++ b/contributing/documentation/license.rst @@ -3,7 +3,7 @@ Licenza della documentazione di Symfony ======================================= -La documentazione di Symfony2 è rilasciata sotto `licenza`_ Creative Commons +La documentazione di Symfony è rilasciata sotto `licenza`_ Creative Commons Attribuzione - Condividi allo stesso modo 3.0 Unported. **Si è liberi:** diff --git a/contributing/documentation/translations.rst b/contributing/documentation/translations.rst index 053a6f66..04b1d733 100644 --- a/contributing/documentation/translations.rst +++ b/contributing/documentation/translations.rst @@ -40,7 +40,7 @@ Se si vuole aiutare nella traduzione di alcuni documenti nella propria lingua o processo da seguire per far parte del team: * Presentarsi sulla `lista Symfony docs`_; -* *(opzionale)* Chiedere su quali documenti si puo lavorare; +* *(opzionale)* Chiedere su quali documenti si può lavorare; * Forkare il repository *master* della propria lingua (cliccare il bottone "Fork" nella pagina di Github); * Tradurre qualche documento; @@ -56,7 +56,7 @@ processo da seguire per far parte del team: Aggiungere una nuova lingua --------------------------- -Questa sezione fornisce alcune guide per iniziare la traduzione di Symfony2 per una nuova +Questa sezione fornisce alcune guide per iniziare la traduzione di Symfony per una nuova lingua. Iniziare la trduzione in una nuova lingua comporta molto lavoro, è necessario parlarne sulla diff --git a/cookbook/assetic/apply_to_option.rst b/cookbook/assetic/apply_to_option.rst index 8cf48e08..6fd2d792 100644 --- a/cookbook/assetic/apply_to_option.rst +++ b/cookbook/assetic/apply_to_option.rst @@ -20,15 +20,15 @@ I valori predefiniti sono ``/usr/bin/coffee`` e ``/usr/bin/node``: assetic: filters: coffee: - bin: /usr/bin/coffee - node: /usr/bin/node - node_paths: [ /usr/lib/node_modules/ ] + bin: /usr/bin/coffee + node: /usr/bin/node + node_paths: [/usr/lib/node_modules/] .. code-block:: xml - @@ -59,18 +59,18 @@ come se fosse un normale JavaScript: .. code-block:: html+jinja - {% javascripts '@AcmePippoBundle/Resources/public/js/esempio.coffee' filter='coffee' %} - + {% javascripts '@AppBundle/Resources/public/js/esempio.coffee' filter='coffee' %} + {% endjavascripts %} .. code-block:: html+php javascripts( - array('@AcmePippoBundle/Resources/public/js/esempio.coffee'), + array('@AppBundle/Resources/public/js/esempio.coffee'), array('coffee') ) as $url): ?> - - + + Questo è tutto quel che serve per compilare il file CoffeeScript e restituirlo come un normale JavaScript. @@ -84,26 +84,25 @@ Filtrare file multpili .. code-block:: html+jinja - {% javascripts '@AcmePippoBundle/Resources/public/js/esempio.coffee' - '@AcmePippoBundle/Resources/public/js/altro.coffee' + {% javascripts '@AppBundle/Resources/public/js/esempio.coffee' + '@AppBundle/Resources/public/js/altro.coffee' filter='coffee' %} - + {% endjavascripts %} .. code-block:: html+php javascripts( array( - '@AcmePippoBundle/Resources/public/js/esempio.coffee', - '@AcmePippoBundle/Resources/public/js/altro.coffee', + '@AppBundle/Resources/public/js/esempio.coffee', + '@AppBundle/Resources/public/js/altro.coffee', ), array('coffee') ) as $url): ?> - - + + -Tutti i file verranno restituiti e compilati in un unico, regolare file -JavaScript. +Tutti i file verranno restituiti e compilati in un unico, regolare file JavaScript. .. _cookbook-assetic-apply-to: @@ -130,10 +129,10 @@ dovrà applicarsi a tutti e soli i file ``.coffee``: assetic: filters: coffee: - bin: /usr/bin/coffee - node: /usr/bin/node - node_paths: [ /usr/lib/node_modules/ ] - apply_to: "\.coffee$" + bin: /usr/bin/coffee + node: /usr/bin/node + node_paths: [/usr/lib/node_modules/] + apply_to: "\.coffee$" .. code-block:: xml @@ -170,20 +169,20 @@ dal filtro CoffeeScript): .. code-block:: html+jinja - {% javascripts '@AcmePippoBundle/Resources/public/js/esempio.coffee' - '@AcmePippoBundle/Resources/public/js/altro.coffee' - '@AcmePippoBundle/Resources/public/js/regolare.js' %} - + {% javascripts '@AppBundle/Resources/public/js/esempio.coffee' + '@AppBundle/Resources/public/js/altro.coffee' + '@AppBundle/Resources/public/js/regolare.js' %} + {% endjavascripts %} .. code-block:: html+php javascripts( array( - '@AcmePippoBundle/Resources/public/js/esempio.coffee', - '@AcmePippoBundle/Resources/public/js/altro.coffee', - '@AcmePippoBundle/Resources/public/js/regolare.js', + '@AppBundle/Resources/public/js/esempio.coffee', + '@AppBundle/Resources/public/js/altro.coffee', + '@AppBundle/Resources/public/js/regolare.js', ) ) as $url): ?> - - + + diff --git a/cookbook/assetic/asset_management.rst b/cookbook/assetic/asset_management.rst index 897e9da4..f7dc4630 100644 --- a/cookbook/assetic/asset_management.rst +++ b/cookbook/assetic/asset_management.rst @@ -1,8 +1,8 @@ .. index:: single: Assetic; Introduzione -Come usare Assetic per la gestione delle risorse -================================================ +Usare Assetic per la gestione delle risorse +=========================================== Assetic unisce due idee principali: :ref:`risorse ` e :ref:`filtri `. Le risorse sono file come CSS, @@ -18,11 +18,11 @@ nell'applicazione: .. code-block:: html+jinja - + .. code-block:: php - + Ma *con* Assetic è possibile manipolare queste risorse nel modo che si preferisce (o caricarle da qualunque parte) prima di servirli. Questo significa che si può: @@ -59,30 +59,30 @@ Per includere file JavaScript, usare il tag ``javascript`` in un template. .. code-block:: html+jinja - {% javascripts '@AcmePippoBundle/Resources/public/js/*' %} - + {% javascripts '@AppBundle/Resources/public/js/*' %} + {% endjavascripts %} .. code-block:: html+php javascripts( - array('@AcmePippoBundle/Resources/public/js/*') + array('@AppBundle/Resources/public/js/*') ) as $url): ?> - - + + .. note:: Se si usano i nomi di blocchi predefiniti di Symfony Standard Edition, - il tag ``javascripts`` si troverà solitamente nel blocco ``javascripts``: - + il tag ``javascripts`` si troverà solitamente nel blocco + ``javascripts``: .. code-block:: html+jinja {# ... #} {% block javascripts %} - {% javascripts '@AcmeFooBundle/Resources/public/js/*' %} - + {% javascripts '@AppBundle/Resources/public/js/*' %} + {% endjavascripts %} {% endblock %} {# ... #} @@ -115,18 +115,18 @@ sopra, tranne per l'uso del tag ``stylesheets``. .. code-block:: html+jinja - {% stylesheets 'bundles/acme_foo/css/*' filter='cssrewrite' %} + {% stylesheets 'bundles/app/css/*' filter='cssrewrite' %} {% endstylesheets %} .. code-block:: html+php stylesheets( - array('bundles/acme_foo/css/*'), + array('bundles/app/css/*'), array('cssrewrite') ) as $url): ?> - + .. note:: @@ -138,7 +138,7 @@ sopra, tranne per l'uso del tag ``stylesheets``. {# ... #} {% block stylesheets %} - {% stylesheets 'bundles/acme_foo/css/*' filter='cssrewrite' %} + {% stylesheets 'bundles/app/css/*' filter='cssrewrite' %} {% endstylesheets %} {% endblock %} @@ -168,17 +168,17 @@ Per includere un'immagine, si può usare il tag ``image``. .. code-block:: html+jinja - {% image '@AcmePippoBundle/Resources/public/images/esempio.jpg' %} + {% image '@AppBundle/Resources/public/images/esempio.jpg' %} Esempio {% endimage %} .. code-block:: html+php image( - array('@AcmePippoBundle/Resources/public/images/esempio.jpg') + array('@AppBundle/Resources/public/images/esempio.jpg') ) as $url): ?> Esempio - + Si può usare Assetic anche per l'ottimizzazione delle immagini. Maggiori informazioni in :doc:`/cookbook/assetic/jpeg_optimize`. @@ -215,7 +215,7 @@ come un unico file: .. code-block:: html+jinja {% javascripts - '@AcmePippoBundle/Resources/public/js/*' + '@AppBundle/Resources/public/js/*' '@AcmePlutoBundle/Resources/public/js/form.js' '@AcmePlutoBundle/Resources/public/js/calendar.js' %} @@ -225,13 +225,13 @@ come un unico file: javascripts( array( - '@AcmePippoBundle/Resources/public/js/*', + '@AppBundle/Resources/public/js/*', '@AcmePlutoBundle/Resources/public/js/form.js', '@AcmePlutoBundle/Resources/public/js/calendar.js', ) ) as $url): ?> - + Nell'ambiente ``dev``, ciascun file è ancora servito individualmente, in modo che sia possibile eseguire il debug dei problemi più facilmente. Tuttavia, nell'ambiente ``prod``, @@ -254,8 +254,8 @@ combinare risorse di terze parti (come jQuery) con i propri, in un singolo file: .. code-block:: html+jinja {% javascripts - '@AcmePippoBundle/Resources/public/js/thirdparty/jquery.js' - '@AcmePippoBundle/Resources/public/js/*' %} + '@AppBundle/Resources/public/js/thirdparty/jquery.js' + '@AppBundle/Resources/public/js/*' %} {% endjavascripts %} @@ -263,12 +263,12 @@ combinare risorse di terze parti (come jQuery) con i propri, in un singolo file: javascripts( array( - '@AcmePippoBundle/Resources/public/js/thirdparty/jquery.js', - '@AcmePippoBundle/Resources/public/js/*', + '@AppBundle/Resources/public/js/thirdparty/jquery.js', + '@AppBundle/Resources/public/js/*', ) ) as $url): ?> - + Uso di risorse per nome ~~~~~~~~~~~~~~~~~~~~~~~ @@ -287,8 +287,8 @@ configurazione, nella sezione ``assetic``. Si può approfondire nel assets: jquery_and_ui: inputs: - - '@AcmePippoBundle/Resources/public/js/thirdparty/jquery.js' - - '@AcmePippoBundle/Resources/public/js/thirdparty/jquery.ui.js' + - '@AppBundle/Resources/public/js/thirdparty/jquery.js' + - '@AppBundle/Resources/public/js/thirdparty/jquery.ui.js' .. code-block:: xml @@ -299,8 +299,8 @@ configurazione, nella sezione ``assetic``. Si può approfondire nel - @AcmePippoBundle/Resources/public/js/thirdparty/jquery.js - @AcmePippoBundle/Resources/public/js/thirdparty/jquery.ui.js + @AppBundle/Resources/public/js/thirdparty/jquery.js + @AppBundle/Resources/public/js/thirdparty/jquery.ui.js @@ -312,8 +312,8 @@ configurazione, nella sezione ``assetic``. Si può approfondire nel 'assets' => array( 'jquery_and_ui' => array( 'inputs' => array( - '@AcmePippoBundle/Resources/public/js/thirdparty/jquery.js', - '@AcmePippoBundle/Resources/public/js/thirdparty/jquery.ui.js', + '@AppBundle/Resources/public/js/thirdparty/jquery.js', + '@AppBundle/Resources/public/js/thirdparty/jquery.ui.js', ), ), ), @@ -328,7 +328,7 @@ usando la notazione ``@nome_risorsa``: {% javascripts '@jquery_and_ui' - '@AcmePippoBundle/Resources/public/js/*' %} + '@AppBundle/Resources/public/js/*' %} {% endjavascripts %} @@ -337,11 +337,11 @@ usando la notazione ``@nome_risorsa``: javascripts( array( '@jquery_and_ui', - '@AcmePippoBundle/Resources/public/js/*', + '@AppBundle/Resources/public/js/*', ) ) as $url): ?> - + .. _cookbook-assetic-filters: @@ -406,21 +406,21 @@ nel template: .. code-block:: html+jinja - {% javascripts '@AcmePippoBundle/Resources/public/js/*' filter='uglifyjs2' %} + {% javascripts '@AppBundle/Resources/public/js/*' filter='uglifyjs2' %} {% endjavascripts %} .. code-block:: html+php javascripts( - array('@AcmePippoBundle/Resources/public/js/*'), + array('@AppBundle/Resources/public/js/*'), array('uglifyjs2') ) as $url): ?> - + Una guida più dettagliata sulla configurazione e l'utilizzo dei filtri di Assetic, oltre a -dettagli della modalità di debug di Assetic, si trova in :doc:`/cookbook/assetic/yuicompressor`. +dettagli della modalità di debug di Assetic, si trova in :doc:`/cookbook/assetic/uglifyjs`. Controllare l'URL utilizzato ---------------------------- @@ -432,19 +432,19 @@ fatto dal template ed è relativo alla radice del documento pubblico: .. code-block:: html+jinja - {% javascripts '@AcmePippoBundle/Resources/public/js/*' output='js/compiled/main.js' %} + {% javascripts '@AppBundle/Resources/public/js/*' output='js/compiled/main.js' %} {% endjavascripts %} .. code-block:: html+php javascripts( - array('@AcmePippoBundle/Resources/public/js/*'), + array('@AppBundle/Resources/public/js/*'), array(), array('output' => 'js/compiled/main.js') ) as $url): ?> - + .. note:: @@ -487,7 +487,7 @@ da Symfony (visto che i file di risorse sono nell'ambiente ``dev``). Lasciare generare a Symfony questi file dinamicamente in un ambiente di produzione sarebbe troppo lento. -.. _cookbook-asetic-dump-prod: +.. _cookbook-assetic-dump-prod: Invece, ogni volta che si utilizza l'applicazione nell'ambiente ``prod`` (e quindi, ogni volta che si fa un nuovo rilascio), è necessario eseguire il seguente task: @@ -540,12 +540,16 @@ bisognerà copiarle manualmente. Per fare ciò, eseguire il seguente comando: Questo scrive fisicamente tutti i file delle risorse necessari per l'ambiente ``dev``. Il grande svantaggio è che è necessario eseguire questa operazione ogni volta -che si aggiorna una risorsa. Per fortuna, passando l'opzione ``--watch``, il +che si aggiorna una risorsa. Per fortuna, usando il comando ``assetic:watch``, il comando rigenererà automaticamente le risorse *che sono cambiate*: .. code-block:: bash - $ php app/console assetic:dump --watch + $ php app/console assetic:watch + +Il comando ``assetic:watch`` è stato introdotto in AsseticBundle 2.4. Nelle versioni +precedenti, si doveva usare l'opzione ``--watch`` del comando ``assetic:dump``, +per ottenere lo stesso comportamento. Dal momento che l'esecuzione di questo comando nell'ambiente ``dev`` può generare molti file, di solito è una buona idea far puntare i file con le risorse generate in @@ -555,16 +559,16 @@ una cartella separata (ad esempio ``/js/compiled``), per mantenere ordinate le c .. code-block:: html+jinja - {% javascripts '@AcmePippoBundle/Resources/public/js/*' output='js/compiled/main.js' %} + {% javascripts '@AppBundle/Resources/public/js/*' output='js/compiled/main.js' %} {% endjavascripts %} .. code-block:: html+php javascripts( - array('@AcmePippoBundle/Resources/public/js/*'), + array('@AppBundle/Resources/public/js/*'), array(), array('output' => 'js/compiled/main.js') ) as $url): ?> - + diff --git a/cookbook/assetic/jpeg_optimize.rst b/cookbook/assetic/jpeg_optimize.rst index 29d7e6d0..6197e6de 100644 --- a/cookbook/assetic/jpeg_optimize.rst +++ b/cookbook/assetic/jpeg_optimize.rst @@ -13,8 +13,9 @@ eliminare problemi di prestazioni per l'utente finale. Usare Jpegoptim --------------- -`Jpegoptim`_ è uno strumento per ottimizzare i file JPEG. Per poterlo usare, -si aggiunge il seguente codice alla configurazione di Assetic: +`Jpegoptim`_ è uno strumento per ottimizzare i file JPEG. Per poterlo usare con Assetic, +assicurarsi di averlo già installato sul proprio sistema, quindi configurare la sua posizione, +usando l'opzione ``bin`` del filtro ``jpegoptim``: .. configuration-block:: @@ -46,18 +47,13 @@ si aggiunge il seguente codice alla configurazione di Assetic: ), )); -.. note:: - - Per poter utilizzare jpegoptim è necessario che sia già installato sul - proprio computer. L'opzione ``bin`` indica la posizione del programma eseguibile. - Sarà ora possibile usarlo nei propri template: .. configuration-block:: .. code-block:: html+jinja - {% image '@AcmeFooBundle/Resources/public/images/esempio.jpg' + {% image '@AppBundle/Resources/public/images/esempio.jpg' filter='jpegoptim' output='/images/esempio.jpg' %} Esempio {% endimage %} @@ -65,7 +61,7 @@ Sarà ora possibile usarlo nei propri template: .. code-block:: html+php image( - array('@AcmeFooBundle/Resources/public/images/esempio.jpg'), + array('@AppBundle/Resources/public/images/esempio.jpg'), array('jpegoptim') ) as $url): ?> Esempio @@ -206,7 +202,8 @@ A questo punto il template di Twig può essere modificato nel seguente modo: Esempio -È possibile specificare la cartella di output nel seguente modo: +Si può anche specificare la cartella di output delle immagini nella configurazione di +Assetic: .. configuration-block:: diff --git a/cookbook/assetic/uglifyjs.rst b/cookbook/assetic/uglifyjs.rst index 87076c18..2bffcf76 100644 --- a/cookbook/assetic/uglifyjs.rst +++ b/cookbook/assetic/uglifyjs.rst @@ -16,48 +16,53 @@ se ne parlerà in modo meno approfondito. Installare UglifyJS ------------------- -UglifyJS è disponibile come modulo npm di `Node.js`_ e può essere installato utilizzando -npm. Per iniziare è necessario `installare node.js`_. Successivamente si potrà installare UglifyJS -usando npm: +UglifyJS è disponibile come modulo npm di `Node.js`_. Per iniziare è necessario `installare node.js`_. +Successivamente si potrà decidere se eseguire un'installazione globale o locale. + +Installazione globale +~~~~~~~~~~~~~~~~~~~~~ + +L'installazione globale consente a tutti i progetti di usare la stessa versione di UglifyJS, +il che semplifica la manutenzione. Aprire la console dei comandi ed eseguire +il seguente comando (potrebbero essere necessari privilegi di root): .. code-block:: bash $ npm install -g uglify-js -Questo comando installerà UglifyJs globalmente e potrebbe quindi richiedere l'esecuzione con -privilegi di root. +Ora si può eseguire il comando globale ``uglifyjs``, da qualsiasi punto del sistema: -.. note:: +.. code-block:: bash - È anche possibile installare UglifyJs solo all'interno di un progetto. Per poterlo - fare, sarà necessario omettere l'opzione ``-g`` e specificare il percorso d'installazione - del modulo: + $ uglifyjs --help - .. code-block:: bash +Installazione locale +-------------------- - $ cd /percorso/di/symfony - $ mkdir app/Resources/node_modules - $ npm install uglify-js --prefix app/Resources +È anche possibile installare UglifyJs solo all'interno di un progett, che è utile +se si devono usare versioni differenti di UglifyJs. Per poterlo fare, sarà necessario +omettere l'opzione ``-g`` e specificare il percorso d'installazione del modulo: - Si raccomanda di installare UglifyJs nella cartella ``app/Resources`` - e di aggiungere la cartella ``node_modules`` al controllo di versione. In alternativ, - si può creare un file `package.json`_ per npm e specificarne all'interno - le dipendenze. +.. code-block:: bash -A seconda del metodo di installazione utilizzato, sarà possibile eseguire il -programma globale ``uglifyjs`` o eseguire il file fisico presente all'interno -della cartella ``node_modules``: + $ cd /percorso/di/symfony + $ npm install uglify-js --prefix app/Resources -.. code-block:: bash +Si raccomanda di installare UglifyJs nella cartella ``app/Resources`` e +di aggiungere la cartella ``node_modules`` al controllo di versione. In alternativa, +si può creare un file `package.json`_ per npm e specificarne all'interno le dipendenze. - $ uglifyjs --help +Or si può eseguire il comando ``uglifyjs``, che si trova nella +cartella ``node_modules``: - $ ./app/Resources/node_modules/.bin/uglifyjs --help +.. code-block:: bash + + $ "./app/Resources/node_modules/.bin/uglifyjs" --help Configurare il filtro uglifyjs2 ------------------------------- -Vediamo ora come configurare Symfony2 per utilizzare il filtro ``uglifyjs2`` +Vediamo ora come configurare Symfony per utilizzare il filtro ``uglifyjs2`` nel trattamento del codice javascript: .. configuration-block:: @@ -96,8 +101,7 @@ nel trattamento del codice javascript: .. note:: Il percorso di installazione di UglifyJs può essere differente a seconda del sistema utilizzato. - Per scoprire dove npm salvi la sua cartella ``bin``, si può usare il seguente - comando: + Per scoprire dove npm salvi la sua cartella ``bin``, si può usare il seguente comando: .. code-block:: bash @@ -133,7 +137,7 @@ si può configurare la sua posizione, usando la voce ``node``: .. code-block:: xml - {% endjavascripts %} .. code-block:: html+php javascripts( - array('@AcmePippoBundle/Resources/public/js/*'), + array('@AppBundle/Resources/public/js/*'), array('uglifyj2s') ) as $url): ?> - + .. note:: - L'esempio precedente presuppone l'esistenza di un bundle chiamato ``AcmePippoBundle`` - e che i file JavaScript si trovino nella cartella ``Resources/public/js`` all'interno - del bundle. Tutto ciò non è comunque fondamentale, dato che è possibile includere i file JavaScript - indipendentemente dal loro posizionamento. + L'esempio precedente presuppone l'esistenza di un bundle chiamato AppBundle e che i file + JavaScript si trovino nella cartella ``Resources/public/js`` all'interno del + bundle. Tuttavia è possibile includere i file JavaScript indipendentemente dal loro posizionamento. Con l'aggiunta del filtro ``uglifyjs2`` ai tag delle risorse precedenti, si vedranno i file JavaScript minimizzati fluire molto più velocemente sulla rete. @@ -191,37 +194,34 @@ I file javascript minimizzati sono difficili da leggere e, a maggior ragione, da motivo Assetic permette di disabilitare alcuni filtri quando l'applicazione è eseguita in modalità debug (ad esempio ``app_dev.php``). Per fare ciò è possibile aggiungere un punto interrogativo ``?`` come prefisso del filtro all'interno del template. In questo modo Assetic viene -informato di applicare i filtri solo quando la modalità debug è spenta (come in ``app.php``): +informato di applicare i filtri solo quando la modalità debug è inattiva (come in ``app.php``): .. configuration-block:: .. code-block:: html+jinja - {% javascripts '@AcmePippoBundle/Resources/public/js/*' filter='?uglifyjs2' %} + {% javascripts '@AppBundle/Resources/public/js/*' filter='?uglifyjs2' %} {% endjavascripts %} .. code-block:: html+php javascripts( - array('@AcmePippoBundle/Resources/public/js/*'), + array('@AppBundle/Resources/public/js/*'), array('?uglifyjs2') ) as $url): ?> - + Per provarlo, basta passare all'ambiente ``prod`` (``app.php``). Ma prima non -bisogna scordarsi di :ref:`pulire la cache` -e di :ref:`esportare le risorse di assetic`. +bisogna scordarsi di :ref:`pulire la cache ` +e di :ref:`esportare le risorse di assetic `. .. tip:: - Invece di aggiungere il filtro all'interno dei tag delle risorse, è possibile - abilitarlo globalmente aggiungendo l'attributo applay-to nella configurazione. - Ad esempio, per il filtro ``uglifyjs2``, ``apply_to: "\.js$"``. Per abilitare - il filtro nel solo ambiente di produzione, è possibile aggiungere il precedente - attributo nel file ``config_prod`` piuttosto che nel file di configurazione comune. Per ulteriori dettagli - sull'applicazione dei filtri, si veda :ref:`cookbook-assetic-apply-to`. + Invece di aggiungere il filtro all'interno dei tag delle risorse, è possibile configurare + i filtri da applicare per ogni file, nella configurazione dell'applicazione. + Vedere :ref:`cookbook-assetic-apply-to` per maggiori dettagli. Installare, configurare e utilizzare UglifyCSS ---------------------------------------------- @@ -231,8 +231,13 @@ si installa il pacchetto npm: .. code-block:: bash + # installazione globale $ npm install -g uglifycss + # installazione locale + $ cd /percorso/del/progetto/symfony + $ npm install uglifycss --prefix app/Resources + Successivamente, aggiungere il filtro alla configurazione: .. configuration-block:: @@ -272,19 +277,19 @@ di Assetic: .. code-block:: html+jinja - {% stylesheets 'bundles/AcmePippo/css/*' filter='uglifycss' filter='cssrewrite' %} + {% stylesheets 'bundles/App/css/*' filter='uglifycss' filter='cssrewrite' %} {% endstylesheets %} .. code-block:: html+php stylesheets( - array('bundles/AcmePippo/css/*'), + array('bundles/App/css/*'), array('uglifycss'), array('cssrewrite') ) as $url): ?> - + Così come per il filtro ``uglifyjs2``, se si premette ``?`` al nome del filtro (come in ``?uglifycss``), la minimizzazione avverrà solamente quando non si è diff --git a/cookbook/assetic/yuicompressor.rst b/cookbook/assetic/yuicompressor.rst index dc0e6013..4b3baa85 100644 --- a/cookbook/assetic/yuicompressor.rst +++ b/cookbook/assetic/yuicompressor.rst @@ -1,22 +1,18 @@ .. index:: single: Assetic; YUI Compressor -Minimizzare i file JavaScript e i fogli di stile con YUI Compressor -=================================================================== - -Yahoo! mette a disposizione un eccellente strumento per minimizzare i file JavaScipt -e i fogli di stile, che così possono viaggiare più velocemente sulla rete: lo `YUI Compressor`_. -Grazie ad Assetic utilizzare questo strumento è semplicissimo. +Minimizzare file JavaScript e fogli di stile con YUI Compressor +=============================================================== .. caution:: - YUI Compressor `non è più mantenuto da Yahoo`_, ma da un volontario - indipendente. Inoltre, Yahoo ha deciso di `fermare ogni nuovo sviluppo su YUI`_ - e di spostarsi su alternative moderne, come Node.js. + YUI Compressor `non è più mantenuto da Yahoo`_. Per questo motivo, è + **caldamente consigliato di evitare l'uso di YUI**, a meno che non sia strettamente + necessario. Leggere :doc:`/cookbook/assetic/uglifyjs` per un'alternativa aggiornata. - Per questi motivi, è **caldamente consigliato** di evitare l'uso di YUI, a meno che non - sia strettamente necessario. Leggere :doc:`/cookbook/assetic/uglifyjs` per un'alternativa - aggiornata. +Yahoo! mette a disposizione un eccellente strumento per minimizzare i file JavaScipt +e i fogli di stile, che così possono viaggiare più velocemente sulla rete: lo `YUI Compressor`_. +Grazie ad Assetic utilizzare questo strumento è semplicissimo. Scaricare il JAR di YUI Compressor ---------------------------------- @@ -91,18 +87,18 @@ livello della vista, questo lavoro dovrà essere svolto nei template: .. code-block:: html+jinja - {% javascripts '@AcmeFooBundle/Resources/public/js/*' filter='yui_js' %} + {% javascripts '@AppBundle/Resources/public/js/*' filter='yui_js' %} {% endjavascripts %} .. code-block:: html+php javascripts( - array('@AcmeFooBundle/Resources/public/js/*'), + array('@AppBundle/Resources/public/js/*'), array('yui_js') ) as $url): ?> - + .. note:: @@ -119,18 +115,18 @@ ripetuto per minimizzare i fogli di stile. .. code-block:: html+jinja - {% stylesheets '@AcmeFooBundle/Resources/public/css/*' filter='yui_css' %} + {% stylesheets '@AppBundle/Resources/public/css/*' filter='yui_css' %} {% endstylesheets %} .. code-block:: html+php stylesheets( - array('@AcmeFooBundle/Resources/public/css/*'), + array('@AppBundle/Resources/public/css/*'), array('yui_css') ) as $url): ?> - + Disabilitare la minimizzazione in modalità debug ------------------------------------------------ @@ -145,18 +141,18 @@ ad Assetic di applicarli solamente quando la modalità debug è inattiva. .. code-block:: html+jinja - {% javascripts '@AcmeFooBundle/Resources/public/js/*' filter='?yui_js' %} + {% javascripts '@AppBundle/Resources/public/js/*' filter='?yui_js' %} {% endjavascripts %} .. code-block:: html+php javascripts( - array('@AcmeFooBundle/Resources/public/js/*'), + array('@AppBundle/Resources/public/js/*'), array('?yui_js') ) as $url): ?> - + .. tip:: @@ -168,6 +164,5 @@ ad Assetic di applicarli solamente quando la modalità debug è inattiva. vedere :ref:`cookbook-assetic-apply-to`. .. _`YUI Compressor`: http://developer.yahoo.com/yui/compressor/ -.. _`scaricare il file JAR`: http://yuilibrary.com/projects/yuicompressor/ +.. _`scaricare il file JAR`: https://github.com/yui/yuicompressor/releases .. _`non è più mantenuto da Yahoo`: http://www.yuiblog.com/blog/2013/01/24/yui-compressor-has-a-new-owner/ -.. _`fermare ogni nuovo sviluppo su YUI`: http://yahooeng.tumblr.com/post/96098168666/important-announcement-regarding-yui diff --git a/cookbook/bundles/best_practices.rst b/cookbook/bundles/best_practices.rst index 4bf2cf05..9a624620 100644 --- a/cookbook/bundles/best_practices.rst +++ b/cookbook/bundles/best_practices.rst @@ -15,6 +15,11 @@ per i bundle dell'applicazione, perché non dovranno restare il più semplici possibile. Per i bundle dell'applicazione, basta seguire le pratiche mostrate nel libro e nel ricettario. +.. seealso:: + + Le best practice per i bundle specifici di applicazioni sono analizzate in + :doc:`/best_practices/introduction`. + .. index:: pair: Bundle; Convenzioni di nomenclatura @@ -26,8 +31,7 @@ Nome del bundle Un bundle è anche uno spazio dei nomi di PHP. Lo spazio dei nomi deve seguire gli `standard`_ tecnici di interoperabilità di PHP 5.3 per gli spazi dei nomi e i nomi delle classi: inizia con un segmento del venditore, seguito da zero o più segmenti di categoria -e finisce con il nome breve dello spazio dei nomi, che deve terminare col suffisso -``Bundle``. +e finisce con il nome breve dello spazio dei nomi, che deve terminare col suffisso ``Bundle``. Uno spazio dei nomi diventa un bundle non appena vi si aggiunge una classe Bundle. La classe Bundle deve seguire queste semplici regole: @@ -62,7 +66,7 @@ nome della classe. .. note:: - I bundle del nucleo di Symfony2 non hanno il prefisso ``Symfony`` e + I bundle del nucleo di Symfony non hanno il prefisso ``Symfony`` e hanno sempre un sotto-spazio dei nomi ``Bundle``; per esempio: :class:`Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle`. @@ -75,8 +79,7 @@ d'utilizzo). Struttura della cartella ------------------------ -La struttura di base delle cartella di un bundle ``HelloBundle`` deve essere come -segue: +La struttura di base delle cartella di un bundle HelloBundle deve essere come segue: .. code-block:: text @@ -155,8 +158,7 @@ Per esempio, un controllore ``HelloController`` è posto in ``Bundle/HelloBundle/Controller/HelloController.php`` e il nome pienamente qualificato della classe è ``Bundle\HelloBundle\Controller\HelloController``. -Tutte le classi e i file devono seguire gli :doc:`standard di codice -` di Symfony2. +Tutte le classi e i file devono seguire gli :doc:`standard di codice ` di Symfony. Alcune classi vanno viste solo come facciate e devono essere più corte possibile, come comandi, helper, ascoltatori e controllori. @@ -170,7 +172,7 @@ Venditori --------- Un bundle non deve includere librerie PHP di terze parti. Deve invece appoggiarsi -all'auto-caricamento standard di Symfony2. +all'auto-caricamento standard di Symfony. Un bundle non dovrebbe includere librerie di terze parti scritte in JavaScript, CSS o altro linguaggio. @@ -243,13 +245,13 @@ seguenti istruzioni standardizzate, nel file ``README.md``. { $bundles = array( // ... - + new \\(), ); - + // ... } - + // ... } ``` @@ -286,10 +288,10 @@ Configurazione -------------- Per fornire maggiore flessibilità, un bundle può fornire impostazioni configurabili, -usando i meccanismi di Symfony2. +usando i meccanismi di Symfony. Per semplici impostazioni di configurazione, appoggiarsi alla voce predefinita -``parameters`` della configurazione di Symfony2. I parametri di Symfony2 sono semplici +``parameters`` della configurazione di Symfony. I parametri di Symfony sono semplici coppie chiave/valore; un valore può essere un qualsiasi valore valido in PHP. Ogni nome di parametro dovrebbe iniziare con l'alias del bundle, anche se questo è solo un suggerimento. Gli altri nomi di parametri useranno un punto (``.``) per separare le varie parti (p.e. @@ -335,6 +337,48 @@ della configurazione semantica, descritta nel ricettario. Se si definiscono servizi, devono avere anch'essi come prefisso l'alias del bundle. +Vincoli di validazione personalizzati +------------------------------------- + +A partire da Symfony 2.5, è stata introdotta una nuova API di validazione. In effetti, +ci sono 3 modalità che l'utente può configurare in un progetto: + +* 2.4: l'API originaria delle versioni 2.4 e precedenti; +* 2.5: la nuova API di validazione della versione 2.5; +* 2.5-BC: la nuova API 2.5 con un livello di retrocompatibilità, in modo che + l'API 2.4 funzioni ancora. Richiede PHP 5.3.9+. + +Come autore di bundle, si dovrebbero supportare *entrambe* le API, poiché alcuni utenti +potrebbero usare ancora l'API 2.4. Nello specifico, se un bundle aggiunge una violazione +direttamente a :class:`Symfony\\Component\\Validator\\Context\\ExecutionContext` +(come nel caso di un vincolo di validazione personalizzato), si dovrà verificare quale +API è in uso. Il codice seguente funzionerà per *tutti* i casi:: + + use Symfony\Component\Validator\ConstraintValidator; + use Symfony\Component\Validator\Constraint; + use Symfony\Component\Validator\Context\ExecutionContextInterface; + // ... + + class ContainsAlphanumericValidator extends ConstraintValidator + { + public function validate($value, Constraint $constraint) + { + if ($this->context instanceof ExecutionContextInterface) { + // API 2.5 + $this->context->buildViolation($constraint->message) + ->setParameter('%string%', $value) + ->addViolation() + ; + } else { + // API 2.4 + $this->context->addViolation( + $constraint->message, + array('%string%' => $value) + ); + } + } + } + Imparare di più dal ricettario ------------------------------ diff --git a/cookbook/bundles/configuration.rst b/cookbook/bundles/configuration.rst index 2be928fa..24b4160a 100644 --- a/cookbook/bundles/configuration.rst +++ b/cookbook/bundles/configuration.rst @@ -129,7 +129,7 @@ Per prima cosa, occorre creare una classe Extension, come spiegato in Ogni volta che un utente include la voce ``acme_social`` (che è l'alias DI) in un file di configurazione, la configurazione ivi presente viene aggiunta a un array di -configurazioni e passata al metodo ``load()`` dell'estensione (Symfony2 +configurazioni e passata al metodo ``load()`` dell'estensione (Symfony converte automaticamente XML e YAML in array). Per l'esempio di configurazione nella sezione precedente, l'array passato al metodo @@ -384,7 +384,8 @@ Ipotizzando che il file XSD si chiami ``hello-1.0.xsd``, la posizione dello sche + xsi:schemaLocation="http://acme_company.com/schema/dic/hello + http://acme_company.com/schema/dic/hello/hello-1.0.xsd"> diff --git a/cookbook/bundles/extension.rst b/cookbook/bundles/extension.rst index 4f9ee4c6..f48d942e 100644 --- a/cookbook/bundles/extension.rst +++ b/cookbook/bundles/extension.rst @@ -23,8 +23,9 @@ convenzioni: * Deve trovarsi nello spazio dei nomi ``DependencyInjection`` del bundle; * Il nome deve essere uguale a quello del bundle, con il suffisso ``Bundle`` sostituito da - ``Extension`` (p.e. la classe Extension di ``AcmeHelloBundle`` si deve - chiamare ``AcmeHelloExtension``). + ``Extension`` (p.e. la classe Extension di AppBundle si deve chiamare + ``AppExtension`` e quella per AcmeHelloBundle si deve chiamare + ``AcmeHelloExtension``). La classe Extension deve implementare :class:`Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface`, @@ -41,7 +42,7 @@ ma solitamente estende semplicemente la classe { public function load(array $configs, ContainerBuilder $container) { - // qui verranno caricati i file + // ... qui verranno caricati i file } } diff --git a/cookbook/bundles/inheritance.rst b/cookbook/bundles/inheritance.rst index 46e2e7ec..0f556ad0 100644 --- a/cookbook/bundles/inheritance.rst +++ b/cookbook/bundles/inheritance.rst @@ -12,8 +12,8 @@ di un bundle. Per esempio, si supponga di aver installato `FOSUserBundle`_, ma di voler sovrascrivere il suo template base ``layout.html.twig``, così come uno dei suoi -controllori. Si supponga anche di avere il proprio ``AcmeUserBundle``, -in cui si vogliono mettere i file sovrascritti. Si inizi registrando ``FOSUserBundle`` +controllori. Si supponga anche di avere il proprio AcmeUserBundle, +in cui si vogliono mettere i file sovrascritti. Si inizi registrando FOSUserBundle come "genitore" del proprio bundle:: // src/Acme/UserBundle/AcmeUserBundle.php @@ -29,7 +29,7 @@ come "genitore" del proprio bundle:: } } -Con questa semplice modifica, si possono ora sovrascrivere diverse parti di ``FOSUserBundle``, +Con questa semplice modifica, si possono ora sovrascrivere diverse parti di FOSUserBundle, semplicemente creando un file con lo stesso nome. .. note:: @@ -81,9 +81,9 @@ stesso percorso del bundle genitore. Per esempio, è molto comune l'esigenza di sovrascrivere il template ``layout.html.twig`` di ``FOSUserBundle``, in modo che usi il layout di base dell'applicazione. -Poiché il file si trova in ``Resources/views/layout.html.twig`` di ``FOSUserBundle``, -si può creare il proprio file nello stesso posto in ``AcmeUserBundle``. -Symfony ignorerà completamente il file dentro ``FOSUserBundle`` e +Poiché il file si trova in ``Resources/views/layout.html.twig`` di FOSUserBundle, +si può creare il proprio file nello stesso posto in AcmeUserBundle. +Symfony ignorerà completamente il file dentro FOSUserBundle e userà il nuovo file al suo posto. Lo stesso vale per i file delle rotte, della configurazione della validazione e di altre risorse. diff --git a/cookbook/bundles/override.rst b/cookbook/bundles/override.rst index 6f7508a6..f1322ed7 100644 --- a/cookbook/bundles/override.rst +++ b/cookbook/bundles/override.rst @@ -18,7 +18,7 @@ Per informazioni su come sovrascrivere i template, vedere Rotte ----- -Le rotte non sono mai importate automaticamente in Symfony2. Se si vogliono includere rotte +Le rotte non sono mai importate automaticamente in Symfony. Se si vogliono includere rotte da un bundle, occorre importarle manualmente da qualche parte nell'applicazione (p.e. ``app/config/routing.yml``). diff --git a/cookbook/bundles/prepend_extension.rst b/cookbook/bundles/prepend_extension.rst index fe6fbb25..32ed25ca 100644 --- a/cookbook/bundles/prepend_extension.rst +++ b/cookbook/bundles/prepend_extension.rst @@ -68,9 +68,10 @@ nel caso in cui un altro specifico bundle non sia registrato:: switch ($name) { case 'acme_something': case 'acme_other': - // imposta use_acme_goodbye a false nella configurazione di acme_something e acme_other - // notaree che se l'utente configura a mano use_acme_goodbye a true in - // app/config/config.yml, l'impostazione finale sarà true e non false + // imposta use_acme_goodbye a false nella configurazione di + // acme_something e acme_other. Notare che se l'utente configura + // a mano use_acme_goodbye a true in app/config/config.yml, + // l'impostazione finale sarà true e non false $container->prependExtensionConfig($name, $config); break; } @@ -79,7 +80,8 @@ nel caso in cui un altro specifico bundle non sia registrato:: // processa la configurazione di AcmeHelloExtension $configs = $container->getExtensionConfig($this->getAlias()); - // usa la classe Configuration per generare un array di configurazione con le impostazioni ``acme_hello`` + // usa la classe Configuration per generare un array di configurazione con + // le impostazioni "acme_hello" $config = $this->processConfiguration(new Configuration(), $configs); // verifica se entity_manager_name sia impostato nella configurazione ``acme_hello`` @@ -90,9 +92,9 @@ nel caso in cui un altro specifico bundle non sia registrato:: } } -Quanto visto sarebbe equivalente a scrivere quanto segue in ``app/config/config.yml``, -nel caso in cui ``AcmeGoodbyeBundle`` non sia registrato e l'impostazione ``entity_manager_name`` -per ``acme_hello`` sia impostata a ``non_default``: +Quanto visto sarebbe equivalente a scrivere quanto segue in +``app/config/config.yml``, nel caso in cui AcmeGoodbyeBundle non sia registrato e +l'impostazione ``entity_manager_name`` per ``acme_hello`` sia impostata a ``non_default``: .. configuration-block:: @@ -121,11 +123,11 @@ per ``acme_hello`` sia impostata a ``non_default``: // app/config/config.php $container->loadFromExtension('acme_something', array( - ..., + // ... 'use_acme_goodbye' => false, 'entity_manager_name' => 'non_default', )); $container->loadFromExtension('acme_other', array( - ..., + // ... 'use_acme_goodbye' => false, )); diff --git a/cookbook/bundles/remove.rst b/cookbook/bundles/remove.rst index 1a1043ce..062cbb62 100644 --- a/cookbook/bundles/remove.rst +++ b/cookbook/bundles/remove.rst @@ -4,7 +4,7 @@ Rimuovere AcmeDemoBundle ======================== -La Standard Edition di Symfony2 dispone di una demo completa, che si trova in un bundle +La Standard Edition di Symfony dispone di una demo completa, che si trova in un bundle chiamato AcmeDemoBundle. È un ottimo riferimento durante l'inizio di un progetto, ma probabilmente si vorrà rimuoverlo in un secondo momento. diff --git a/cookbook/cache/form_csrf_caching.rst b/cookbook/cache/form_csrf_caching.rst index ab8da1ae..bd948351 100644 --- a/cookbook/cache/form_csrf_caching.rst +++ b/cookbook/cache/form_csrf_caching.rst @@ -4,4 +4,39 @@ Cache di pagine contenenti form protette da CSRF ================================================ -(TODO da tradurre...) \ No newline at end of file +I token CSRF sono pensati per variare da utente a utente. Per questo motivo, occorre +cautela se si provano a mettere in cache pagine con form che li includano. + +Per maggiori informazioni su come funziona la protezione CSRF in Symfony, fare +riferimento a :ref:`protezione CSRF `. + +Perché una pagina in cache con CSRT è problematica +-------------------------------------------------- + +Di solito, a ciascun utente è assegnato un token CSRF univoco, memorizzato nella +sessione per la validazione. Questo vuol dire che se si mette in cache una pagina con +un form che contiene token CSRF, si metterà in cache il token CSRF solo per il *primo* +utente. Quando un utente compila il form, il token non corrisponderà più a quello +memorizzato in sessione e tutti gli utenti (tranne il primo) vedreanno fallire la +validazione all'invio del form. + +In effetti, molti reverse proxy (come Varnish) rifiuteranno di mettere in cache una pagina +con un token CSRF. Questo perché viene inviato un cookie, per preservare +la sessione PHP aperta e il comportamento predefinito di Varnish è di non mettere in cache +richieste HTTP con cookie. + +Come mettere in cache le pagine e avere ugualmente protezione CSRF +------------------------------------------------------------------ + +Per mettere in cache una pagina che contenga un token CSRF, si possono usare tecniche più avanzate +di cache, come i :ref:`frammenti ESI `, in cui si mette in cache +l'intera pagina e si include il form in un tag ESI, senza alcuna cache. + +Un'altra opzione è quella dicaricare il form tramite una richiesta AJAX non in cache, ma +mettendo in cache il resto della risposta HTML. + +Si può anche solo caricare il token CSRF con una richiesta AJAX e sostituire il valore +del campo. + +.. _`Cross-site request forgery`: http://en.wikipedia.org/wiki/Cross-site_request_forgery +.. _`Security CSRF Component`: https://github.com/symfony/security-csrf \ No newline at end of file diff --git a/cookbook/cache/varnish.rst b/cookbook/cache/varnish.rst index 24a762c8..4d01ada7 100644 --- a/cookbook/cache/varnish.rst +++ b/cookbook/cache/varnish.rst @@ -4,10 +4,13 @@ Usare Varnish per accelerare il proprio sito ============================================ -Poiché la cache di Symfony2 usa gli header standard della cache HTTP, +Poiché la cache di Symfony usa gli header standard della cache HTTP, :ref:`symfony-gateway-cache` può essere facilmente sostituito da qualsiasi altro reverse proxy. `Varnish`_ è un acceleratore HTTP potente e open source, che è in grado di servire -contenuti in cache in modo veloce e che include il supporto per :ref:`Edge Side Include`. +contenuti in cache in modo veloce e che include il supporto per :ref:`Edge Side Include `. + +.. index:: + single: Varnish; configurazione Reverse proxy fidati -------------------- @@ -16,229 +19,218 @@ Perché ESI funzioni correttamente e per usare gli header :ref:`X-FORWARDED `. -.. index:: - single: Varnish; Configurazione - -Configurazione --------------- - -Come visto in precedenza, Symfony2 è abbastanza intelligente da capire se sta parlando -a un reverse proxy che comprenda ESI o meno. Funziona immediatamente, se si usa il reverse -proxy di Symfony2, mentre occorre una configurazione speciale per poter funzionare -con Varnish. Fortunatamente, Symfony2 si appoggia a uno standard scritto -da Akamaï (`Architettura Edge`_), quindi i suggerimenti di configurazione in questo -capitolo possono essere utili anche non usando Symfony2. +.. _varnish-x-forwarded-headers: -.. note:: +Rotte e header X-FORWARDED +-------------------------- - Varnish supporta solo l'attributo ``src`` per i tag ESI (``onerror`` e - ``alt`` vengono ignorati). +Per essere sicuri che Symfony generi correttamente URL con Varnish, +ci deve essere un header ``X-Forwarded-Port``, in modo che Symfony usi il +numero giusto di porta. -Prima di tutto, configurare Varnish in modo che pubblicizzi il suo supporto a ESI, -aggiungendo un header ``Surrogate-Capability`` alle richieste girate all'applicazione -sottostante: +Questa porta dipende dalla configurazione. Ipotizziamo che le connessioni esterne vengano +sulla porta HTTP predefinita, la 80. Per le connessioni HTTPS, c'è un altro proxy +(non facendo Varnish HTTPS) sulla porta HTTPS predefinita, la 443, che gestisce +SSL e gira le richieste come richieste HTTP a +Varnish, con un header ``X-Forwarded-Proto``. In questo case, si deve aggiungere +la seguente parte di configurazione: -.. code-block:: text +.. code-block:: varnish4 sub vcl_recv { - // Aggiunge un header Surrogate-Capability per dichiarare il supporto a ESI. - set req.http.Surrogate-Capability = "abc=ESI/1.0"; + if (req.http.X-Forwarded-Proto == "https" ) { + set req.http.X-Forwarded-Port = "443"; + } else { + set req.http.X-Forwarded-Port = "80"; + } } .. note:: - La parte ``abc`` dell'header non è importante, a meno che non si abbiano più "surrogati" - che debbano avveritire delle loro capacità. Vedere `Header Surrogate-Capability`_ per dettagli. + Ricordarsi di configurare :ref:`framework.trusted_proxies ` + nella configurazione di Symfony, in modo che Varnish sia visto come proxy fidato + e gli header ``X-Forwarded-*`` usati. -Quindi, ottimizzare Varnish in modo che analizzi i contenuti della risposta solo quando -ci sia almeno un tag ESI, verificando l'header ``Surrogate-Control``, che -Symfony2 aggiunge automaticamente: + Varnish gira automaticamente l'IP come ``X-Forwarded-For`` e lascia + l'header ``X-Forwarded-Proto`` nella richiesta. Se non si configura + Varnish come proxy fidato, Symfony vedrà tutte le richieste come provenienti tramite + connessioni HTTP non sicure da Varnish, invece che dall'effettivo client. -.. code-block:: text +Se non si imposta correttamente l'header ``X-Forwarded-Port``, Symfony appenderà +la porta in cui gira l'applicazione PHP, quando genererà URL assoluti, +p.e. ``http://example.com:8080/my/path``. - sub vcl_fetch { - /* - Verifica il riconoscimento di ESI - e rimuove l'header Surrogate-Control - */ - if (beresp.http.Surrogate-Control ~ "ESI/1.0") { - unset beresp.http.Surrogate-Control; +Cookie e cache +-------------- - // per Varnish >= 3.0 - set beresp.do_esi = true; - // per Varnish < 3.0 - // esi; - } - /* Per impostazione predefinita, Varnish ignora Cache-Control: nocache - (https://www.varnish-cache.org/docs/3.0/tutorial/increasing_your_hitrate.html#cache-control), - quindi per evitare la messa in cache va reso esplicito */ - if (beresp.http.Pragma ~ "no-cache" || - beresp.http.Cache-Control ~ "no-cache" || - beresp.http.Cache-Control ~ "private") { - return (hit_for_pass); - } - } +Di solito, un proxy non mette in cache quando una richiesta è inviata +con :ref:`cookie o header basic authentication`. +Questo perché ipotizza che il contenuto della pagina dipenda dal valore del cookie +o dell'header di autenticazione. -.. caution:: +Se si è certi che il backend non userà mai sessioni o basic +authentication, fare in modo che varnish rimuova il rispettivo header dalle richieste, per +impedire che i client aggirino la cache. In pratica, si avrà bisogno delle sessioni +almeno per alcune parti del sito, p.e. usando form con +:ref:`protezione CSRF `. In questa situazione, assicurarsi solo di far partire +una sessione quando effettivamente necessario e di pulire la sessione quando non più +necessaria. In alternativa, si può dare un'occhiata a :doc:`../cache/form_csrf_caching`. - La compressione con ESI non era supportata in Varnish fino alle versione 3.0 - (leggere `GZIP e Varnish`_). Se non si usa Varnish 3.0, inserire un server web - davanti a Varnish per eseguire la compressione. +.. todo link "only start a session when actually needed" to cookbook/session/avoid_session_start once https://github.com/symfony/symfony-docs/pull/4661 is merged -.. index:: - single: Varnish; Invalidare +I cookie creati in JavaScript e usati solo in frontend, p.e. quando si usa +Google analytics sono comunque inviati al server. Questi cookie non sono +rilevanti per il backend e non dovrebbero influire sulle decisioni di cache. Configurare +Varnish per `pulire gli header dei cookie`_. È desiderabile mantenere i +cookie di sessione, se presenti, e togliere ogni altro cookie, in modo che le pagine +vengano messe in cache in assenza di sessioni attive. A meno di non vaer modificato la +configurazione predefinita di PHP, il cookie di sessione si chiama PHPSESSID: -Invalidare la cache -------------------- +.. code-block:: varnish4 -Se si vogliono mettere in cache contenuti che cambiano frequentemente e servirne -la versione più recente agli utenti, occorre invalidare tali contenuti. -Se l'`invalidazione della cache`_ consente di eliminare contenuti da un -proxy prima della loro scadenza, aggiunge complessità alle impostazioni della cache. + sub vcl_recv { + // Rimuove tutti i cookie, tranne quello della sessione + if (req.http.Cookie) { + set req.http.Cookie = ";" + req.http.Cookie; + set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";"); + set req.http.Cookie = regsuball(req.http.Cookie, ";(PHPSESSID)=", "; \1="); + set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", ""); + set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", ""); + + if (req.http.Cookie == "") { + // Se non ci sono altri cookie, rimuove l'header per far in modo che la pagina vada in cache + remove req.http.Cookie; + } + } + } .. tip:: - Il bundle `FOSHttpCacheBundle`_ allevia le pene - dell'invalidazione della cache, aiutando a organizzare le impostazioni di - cache e di invalidazione. + Se il contenuto non è diverso per ciascun utente, ma dipende dai ruoli di un + utente, una soluzione è separare la cache per gruppo. Questo schema è + implementato e spiegato da FOSHttpCacheBundle_ sotto la voce + `User Context`_. + +Assicurare comportamenti di cache coerenti +------------------------------------------ + +Varnish usa gli header di cache inviati dall'applicazione per determinare in che modo +mettere in cache il contenuto. Tuttavia, le versioni precedenti a Varnish 4 non rispettavano +``Cache-Control: no-cache``, ``no-store`` e ``private``. Per assicurare un +comportamento coerente, usare la seguente configurazione, se si usa +ancora Varnish 3: + +.. configuration-block:: + + .. code-block:: varnish3 + + sub vcl_fetch { + /* Varnish3 ignora Cache-Control: no-cache e private + https://www.varnish-cache.org/docs/3.0/tutorial/increasing_your_hitrate.html#cache-control + */ + if (beresp.http.Cache-Control ~ "private" || + beresp.http.Cache-Control ~ "no-cache" || + beresp.http.Cache-Control ~ "no-store" + ) { + return (hit_for_pass); + } + } -Varnish può essere configurato per accettare un metodo HTTP speciale ``PURGE``, -che invalida la cache per una data risorsa: +.. tip:: -.. code-block:: text + Si può vedere il comportamento predefinito di Varnish in forma di file VCL: + `default.vcl`_ per Varnish 3, `builtin.vcl`_ per Varnish 4. - /* - Connessione al server di backend - sulla porta 8080 della macchina locale - */ - backend default { - .host = "127.0.0.1"; - .port = "8080"; - } +Abilitare Edge Side Include (ESI) +--------------------------------- - sub vcl_recv { - /* - Il comportamento predefinito di Varnish non supporta PURGE. - Individua le richieste PURGE e fa immediatamente una ricerca in cache, - altrimenti Varnish girerebbe direttamente la richiesta al backend - e aggirerebbe la cache - */ - if (req.request == "PURGE") { - return(lookup); - } - } +Come spiegato nella :ref:`sezione Edge Side Include `, +Symfony capisce se sta parlando o meno a un reverse proxy che capisca ESI. +Quando si usa il reverse proxy di Symfony, non occorre fare nulla. +Se invece si usa Varnish per risolvere i tag ESI, serve una ulteriore +configurazione in Varnish. Symfony usa l'header ``Surrogate-Capability`` +da `Edge Architecture`_, descritto da Akamai. - sub vcl_hit { - // Individua la richiesta PURGE - if (req.request == "PURGE") { - // Forza la scadenza dell'oggetto per Varnish < 3.0 - set obj.ttl = 0s; - // Fa un vero purge per Varnish >= 3.0 - // purge; - error 200 "Purged"; - } - } +.. note:: - sub vcl_miss { - /* - Individua la richiesta PURGE e - indica che la richiesta non è stata messa in cache. - */ - if (req.request == "PURGE") { - error 404 "Not purged"; - } + Varnish supporta solo l'attributo ``src`` dei tag ESI (``onerror`` e + ``alt`` vengono ignorati). + +Innanzitutto, configurare Varnish in modo che pubblicizzi il supporto ESI, aggiungendo un header +``Surrogate-Capability`` alle richieste rimandate all'applicazione di +backend: + +.. code-block:: varnish4 + + sub vcl_recv { + // Aggiunge un header Surrogate-Capability per dichiarare il supporto a ESI. + set req.http.Surrogate-Capability = "abc=ESI/1.0"; } -.. caution:: +.. note:: - Bisogna proteggere il metodo HTTP ``PURGE`` in qualche modo, per evitare che qualcuno - pulisca i dati in cache in modo casuale. + La parte ``abc`` dell'header non è importante, a meno non si abbiamo più surrogati + che debbano pubblicizzare le loro capacità. Vedere `Surrogate-Capability Header`_ per dettagli. - .. code-block:: text +Quindi, ottimizzare Varnish, in modo che analizzi solo il contenuto di risposte quando ci +sia almeno un tag ESI, verificando l'header ``Surrogate-Control``, aggiunto automaticamente da +Symfony: - /* - Connessione al server di backend - sulla porta 8080 della macchina locale - */ - backend default { - .host = "127.0.0.1"; - .port = "8080"; - } +.. configuration-block:: - // Le ACL possono contenere IP, sottoreti e nomi di host - acl purge { - "localhost"; - "192.168.55.0"/24; - } + .. code-block:: varnish4 - sub vcl_recv { - // Individua la richiesta PURGE per evitare l'aggiramento della cache - if (req.request == "PURGE") { - // Individua l'IP del client corrispondente all'acl - if (!client.ip ~ purge) { - // Accesso negato - error 405 "Not allowed."; - } - // Esegue una ricerca in cache - return(lookup); + sub vcl_backend_response { + // Verifica il riconoscimento di ESI e rimuove l'header Surrogate-Control + if (beresp.http.Surrogate-Control ~ "ESI/1.0") { + unset beresp.http.Surrogate-Control; + set beresp.do_esi = true; } } - sub vcl_hit { - // Individua la richiesta PURGE - if (req.request == "PURGE") { - // Forza la scadenza dell'oggetto per Varnish < 3.0 - set obj.ttl = 0s; - // Fa un vero purge per Varnish >= 3.0 - // purge; - error 200 "Purged"; - } - } + .. code-block:: varnish3 - sub vcl_miss { - // Individua la richiesta PURGE - if (req.request == "PURGE") { - // Indica che l'oggetto non è in cache - error 404 "Not purged"; + sub vcl_fetch { + // Verifica il riconoscimento di ESI e rimuove l'header Surrogate-Control + if (beresp.http.Surrogate-Control ~ "ESI/1.0") { + unset beresp.http.Surrogate-Control; + set beresp.do_esi = true; } } -.. _varnish-x-forwarded-headers: +.. tip:: -Rotte e header X-FORWARDED --------------------------- + Per chi ha seguito il consiglio che assicura il comportamento coerente di cache, + queste funzioni vcl esistono già. Basta aggiungere il codice all + fine della funzione, non interferiranno a vicenda. -Per assicurarsi che le rotte di Symfony generino URL corrette con Varnish, -occorre aggiungere gli appropriati header ```X-Forwarded``, in modo che Symfony sia consapevole -del numero originale di porta della richiesta. Il modo in cui farlo dipende dalla -configurazione. Come semplice esempio, supponiamo che Varnish e il server web siano sulla -stessa macchina e che Varnish ascolti su una porta (p.e. 80) e Apache -su un'altra (p.e. 8080). In tale situazionen, Varnish dovrebbe aggiungere l'header ``X-Forwarded-Port``, -in modo tale che l'applicazione Symfony sappia che il numero originale di porta -è 80 e non 8080. +.. index:: + single: Varnish; Invalidazione -Se questo header non è stato impostato, Symfony potrebbe aggiungere ``8080`` agli URL -assoluti generati: +Invalidare la cache +------------------- -.. code-block:: text +Se si vuole mettere in cache un contenuto che cambia di frequente e servire comunque +agli utenti la sua versione più recente, occorre invalidare tale contenuto. +Anche se l'`invalidazione della cache`_ consente di purgare il contenuto dal +proxy prima che scada, aggiunge complessità al sistema di cache. - sub vcl_recv { - if (req.http.X-Forwarded-Proto == "https" ) { - set req.http.X-Forwarded-Port = "443"; - } else { - set req.http.X-Forwarded-Port = "80"; - } - } +.. tip:: -.. note:: + Il bundle `FOSHttpCacheBundle`_ si occupa di invalidazione di cache, + aiutando a organizzare la strategia di cache e di + invalidazione. - Ricordarsi di impostare :ref:`framework.trusted_proxies ` - nella configurazione di Symfony, in modo che Varnish sia visto come proxy fidato - e gli header ``X-Forwarded-`` usati. + La documentazione di `FOSHttpCacheBundle`_ spiega come configurare + Varnish e altri reverse proxy per l'invalidazione della cache. .. _`Varnish`: https://www.varnish-cache.org -.. _`Architettura Edge`: http://www.w3.org/TR/edge-arch +.. _`Edge Architecture`: http://www.w3.org/TR/edge-arch .. _`GZIP e Varnish`: https://www.varnish-cache.org/docs/3.0/phk/gzip.html -.. _`Header Surrogate-Capability`: http://www.w3.org/TR/edge-arch +.. _`pulire gli header dei cookie`: https://www.varnish-cache.org/trac/wiki/VCLExampleRemovingSomeCookies +.. _`Surrogate-Capability Header`: http://www.w3.org/TR/edge-arch .. _`invalidazione della cache`: http://tools.ietf.org/html/rfc2616#section-13.10 .. _`FOSHttpCacheBundle`: http://foshttpcachebundle.readthedocs.org/ +.. _`default.vcl`: https://www.varnish-cache.org/trac/browser/bin/varnishd/default.vcl?rev=3.0 +.. _`builtin.vcl`: https://www.varnish-cache.org/trac/browser/bin/varnishd/builtin.vcl?rev=4.0 +.. _`User Context`: http://foshttpcachebundle.readthedocs.org/en/latest/features/user-context.html diff --git a/cookbook/composer.rst b/cookbook/composer.rst index e69de29b..ecf63c09 100644 --- a/cookbook/composer.rst +++ b/cookbook/composer.rst @@ -0,0 +1,44 @@ +.. index:: + double: Composer; Installazione + +Installare Composer +=================== + +`Composer`_ è il gestore di pacchetti usato dalle applicazioni PHP moderne ed lo +strumento raccomandato per installare Symfony. + +Installare Composer su Linux e Mac OS X +--------------------------------------- + +Per installare Composer su Linux e Mac OS X, eseguire questi due comandi: + +.. code-block:: bash + + $ curl -sS https://getcomposer.org/installer | php + $ sudo mv composer.phar /usr/local/bin/composer + +.. note:: + + Se non si dispone di ``curl``, si può anche semplicemente scaricare il file + ``installer`` a mano, da http://getcomposer.org/installer, ed + eseguire: + + .. code-block:: bash + + $ php installer + $ sudo mv composer.phar /usr/local/bin/composer + +Installre Composer su Windows +----------------------------- + +Scaricare l'installatore da `getcomposer.org/download`_, eseguirlo e seguire +le istruzioni. + +Saperne di più +-------------- + +Si può approfondire Composer nella sua `documentazione`_. + +.. _`Composer`: https://getcomposer.org/ +.. _`getcomposer.org/download`: https://getcomposer.org/download +.. _`documentazione`: https://getcomposer.org/doc/00-intro.md diff --git a/cookbook/configuration/apache_router.rst b/cookbook/configuration/apache_router.rst index c74a058e..c42d2973 100644 --- a/cookbook/configuration/apache_router.rst +++ b/cookbook/configuration/apache_router.rst @@ -1,11 +1,21 @@ .. index:: - single: Rotte su Apache + single: Rotte su Apache -Come usare le rotte su Apache -============================= +Usare le rotte su Apache +======================== -Symfony2, pur essendo veloce di suo, fornisce anche molti modi per incrementare la sua velocità, -tramite piccole modifiche. Una di queste è delegare la gestione delle rotte ad Apache, invece di usare Symfony2. +.. caution:: + + **L'uso di rotte su Apache non è più considerato una buona pratica**. + Il piccolo incremento ottenuto sulla prestazioni delle rotte dell'applicazione non + vale lo sforzo di aggiornare continuamente la configurazione delle rotte. + + Le rotte su Apache saranno rimosse in Symfony 3 e si raccomanda di non + usarle in un'applicazione. + +Symfony, pur essendo veloce di suo, fornisce anche molti modi per incrementare la sua +velocità, tramite piccole modifiche. Una di queste è delegare la gestione delle rotte ad Apache, +invece di usare Symfony. .. caution:: @@ -18,7 +28,7 @@ Modificare i parametri di configurazione delle rotte ---------------------------------------------------- Per esportare in Apache le rotte, occorre prima sistemare alcuni parametri di configurazione, -per dire a Symfony2 di usare ``ApacheUrlMatcher`` invece di quello predefinito: +per dire a Symfony di usare ``ApacheUrlMatcher`` invece di quello predefinito: .. configuration-block:: @@ -59,7 +69,7 @@ per dire a Symfony2 di usare ``ApacheUrlMatcher`` invece di quello predefinito: Generare le regole per mod_rewrite ---------------------------------- -Per testare che tutto funzioni, creiamo una rotta molto semplice per il bundle demo: +Per testare che tutto funzioni, creiamo una rotta molto semplice per AppBundle: .. configuration-block:: @@ -68,23 +78,23 @@ Per testare che tutto funzioni, creiamo una rotta molto semplice per il bundle d # app/config/routing.yml hello: path: /hello/{name} - defaults: { _controller: AcmeDemoBundle:Demo:hello } + defaults: { _controller: AppBundle:Greet:hello } .. code-block:: xml - AcmeDemoBundle:Demo:hello + AppBundle:Greet:hello .. code-block:: php // app/config/routing.php $collection->add('hello', new Route('/hello/{name}', array( - '_controller' => 'AcmeDemoBundle:Demo:hello', + '_controller' => 'AppBundle:Greet:hello', ))); -Ora generiamo le regole di **url_rewrite**: +Ora generiamo le regole di mod_rewrite: .. code-block:: bash @@ -100,7 +110,7 @@ Il risultato dovrebbe essere simile a questo: # hello RewriteCond %{REQUEST_URI} ^/hello/([^/]+?)$ - RewriteRule .* app.php [QSA,L,E=_ROUTING__route:hello,E=_ROUTING_name:%1,E=_ROUTING__controller:AcmeDemoBundle\:Demo\:hello] + RewriteRule .* app.php [QSA,L,E=_ROUTING__route:hello,E=_ROUTING_name:%1,E=_ROUTING__controller:AppBundle\:Greet\:hello] Ora possiamo riscrivere `web/.htaccess` per usare le nuove regole, quindi con il nostro esempio dovrebbe risultare in questo modo: @@ -116,12 +126,13 @@ esempio dovrebbe risultare in questo modo: # hello RewriteCond %{REQUEST_URI} ^/hello/([^/]+?)$ - RewriteRule .* app.php [QSA,L,E=_ROUTING__route:hello,E=_ROUTING_name:%1,E=_ROUTING__controller:AcmeDemoBundle\:Demo\:hello] + RewriteRule .* app.php [QSA,L,E=_ROUTING__route:hello,E=_ROUTING_name:%1,E=_ROUTING__controller:AppBundle\:Greet\:hello] .. note:: - La procedura appena vista andrebbe fatta ogni volta che si aggiunge o cambia una rotta + La procedura appena vista andrebbe fatta ogni volta che si aggiunge o cambia una rotta, + se si vuole sfruttare questa configurazione. Ecco fatto! Ora è tutto pronto per usare le rotte di Apache. diff --git a/cookbook/configuration/configuration_organization.rst b/cookbook/configuration/configuration_organization.rst index 01b974e2..03df0073 100644 --- a/cookbook/configuration/configuration_organization.rst +++ b/cookbook/configuration/configuration_organization.rst @@ -4,7 +4,7 @@ Organizzare i file di configurazione ==================================== -Symfony2 Standard Edition definisce tre +Symfony Standard Edition definisce tre :doc:`ambienti `, chiamati ``dev``, ``prod`` e ``test``. Un ambiente è semplicemente un modo per eseguire lo stesso codice con diverse configurazioni. @@ -127,8 +127,10 @@ necessaria per il file ``app/config/dev/config.yml``: + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony + http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> @@ -237,8 +239,10 @@ predefiniti (``.yml``, ``.xml``, ``.php``, ``.ini``): + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony + http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> @@ -299,8 +303,10 @@ da un altro file di configurazione: + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony + http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> @@ -340,8 +346,10 @@ non esiste: + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony + http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> diff --git a/cookbook/configuration/environments.rst b/cookbook/configuration/environments.rst index 274cb1c2..bb8e792a 100644 --- a/cookbook/configuration/environments.rst +++ b/cookbook/configuration/environments.rst @@ -1,13 +1,13 @@ .. index:: single: Ambienti -Come padroneggiare e creare nuovi ambienti -========================================== +Padroneggiare e creare nuovi ambienti +===================================== Ogni applicazione è la combinazione di codice e di un insieme di configurazioni che determinano come il codice dovrà lavorare. La configurazione può definire la base dati da utilizzare, cosa dovrà essere messo in cache e cosa non, o quanto -esaustivi dovranno essere i log. In Symfony2, l'idea di ambiente è quella di +esaustivi dovranno essere i log. In Symfony, l'idea di ambiente è quella di eseguire il codice, utilizzando differenti configurazioni. Per esempio, l'ambiente ``dev`` dovrebbe usare una configurazione che renda lo sviluppo semplice e ricco di informazioni, mentre l'ambiente ``prod`` dovrebbe usare un @@ -19,16 +19,16 @@ insieme di configurazioni che ottimizzino la velocità. Ambienti differenti, differenti file di configurazione ------------------------------------------------------ -Una tipica applicazione Symfony2 inizia con tre ambienti: ``dev``, ``prod`` +Una tipica applicazione Symfony inizia con tre ambienti: ``dev``, ``prod`` e ``test``. Come si è già detto, ogni "ambiente " rappresenta un modo in cui eseguire l'intero codice con differenti configurazioni. Non dovrebbe destare sorpresa il fatto che ogni ambiente carichi i suoi propri file di configurazione. Se si utilizza il formato di configurazione YAML, verranno utilizzati i seguenti file: - * per l'ambiente ``dev``: ``app/config/config_dev.yml`` - * per l'ambiente ``prod``: ``app/config/config_prod.yml`` - * per l'ambiente ``test``: ``app/config/config_test.yml`` +* per l'ambiente ``dev``: ``app/config/config_dev.yml`` +* per l'ambiente ``prod``: ``app/config/config_prod.yml`` +* per l'ambiente ``test``: ``app/config/config_test.yml`` Il funzionamento si basa su di un semplice comportamento predefinito all'interno della classe ``AppKernel``: @@ -49,7 +49,7 @@ della classe ``AppKernel``: } } -Come si può vedere, quando Symfony2 viene caricato, utilizza l'ambiente +Come si può vedere, quando Symfony viene caricato, utilizza l'ambiente per determinare quale file di configurazione caricare. Questo permette di avere ambienti differenti in modo elegante, efficace e trasparente. @@ -84,9 +84,10 @@ ottenuto facilmente e in modo trasparente: Per condividere una configurazione comune, i file di configurazione di ogni ambiente importano, per iniziare, un file di configurazione comune (``config.yml``). Il resto del file potrà deviare dalla configurazione predefinita, sovrascrivendo -i singoli parametri. Ad esempio, nell'ambiente ``dev``, la barra delle applicazioni -viene attivata modificando, nel file di configurazione di ``dev``, il relativo -parametro predefinito: +i singoli parametri. Per esempio, l'opzione ``web_profiler`` è +disabilitata. Tuttavia, in ambiente ``dev``, la barra degli strumenti +viene attivata modificando il valore dell'opzione ``toolbar`` nel file di +configurazione ``config_dev.yml``: .. configuration-block:: @@ -107,9 +108,7 @@ parametro predefinito: - + .. code-block:: php @@ -140,8 +139,8 @@ utilizzando il front controller ``app_dev.php`` (per l'ambiente ``dev``): .. note:: Le precedenti URL presuppongono che il server web sia configurato in modo da - usare la cartella ``web/`` dell'applicazione, come radice. Per approfondire, si legga - :doc:`Installare Symfony2`. + usare la cartella ``web/`` dell'applicazione come radice. Per approfondire, si legga + :doc:`installare Symfony `. Guardando il contenuto di questi file, si vede come l'ambiente utilizzato da entrambi, sia definito in modo esplicito:: @@ -154,7 +153,7 @@ sia definito in modo esplicito:: // ... Si può vedere come la chiave ``prod`` specifica che l'ambiente di esecuzione -sarà l'ambiente ``prod``. Un'applicazione Symfony2 può essere esguita in qualsiasi +sarà l'ambiente ``prod``. Un'applicazione Symfony può essere esguita in qualsiasi ambiente utilizzando lo stesso codice, cambiando la sola stringa relativa all'ambiente. .. note:: @@ -172,7 +171,7 @@ ambiente utilizzando lo stesso codice, cambiando la sola stringa relativa all'am Importante, ma non collegato all'argomento *ambienti*, è il valore ``false`` come secondo parametro di ``AppKernel``. Questo valore specifica se l'applicazione dovrà essere eseguità in "modalità debug" o meno. Indipendentemente - dall'ambiente, un'applicazione Symfony2 può essere eseguita con la modalità + dall'ambiente, un'applicazione Symfony può essere eseguita con la modalità debug configurata a ``true`` o a ``false``. Questo modifica diversi aspetti dell'applicazione, come il fatto che gli errori vengano mostrati o se la cache debba essere ricreata dinamicamente a ogni richiesta. Sebbene non sia obbligatorio, la modalità debug @@ -212,21 +211,54 @@ ambiente utilizzando lo stesso codice, cambiando la sola stringa relativa all'am debug. Occorrerà abilitarla nel fron controller, richiamando :method:`Symfony\\Component\\Debug\\Debug::enable`. +Scegliere l'ambiente per i comandi di console +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +I comandi di Symfony sono eseguiti in ambiente ``dev`` e con la modalità di +debug abilitata. Usaree le opzioni ``--env`` e ``--no-debug`` per modificare questo +comportamento: + +.. code-block:: bash + + # ambiente 'dev' e debug abilitato + $ php app/console nome_comando + + # ambiente 'prod' (debug sempre disabilitato per 'prod') + $ php app/console nome_comando --env=prod + + # ambiente 'test' e debug disabilitato + $ php app/console nome_comando --env=test --no-debug + +Oltre alle opzioni ``--env`` e ``--debug``, il comportamento dei comandi di Symfony +può essere controllato tramite variabili d'ambiente. La console di Symfony +verifica l'esistenza e il valore di queste variabili, prima di +eseguire ogni comando: + +``SYMFONY_ENV`` + Imposta l'ambiente di esecuzione dei comandi al valore di questa variabile + (``dev``, ``prod``, ``test``, ecc.); +``SYMFONY_DEBUG`` + Se ``0``, la modalità di debug è disabilitata. Altrimenti, è abilitata. + +Queste variabili d'ambiente sono molto utili su server di produzione, perché +consentono di assicurarsi che i comandi girino sempre in ambiente ``prod``, senza dover +specificare alcuna opzione. + .. index:: single: Ambienti; Creare un nuovo ambiente Creare un nuovo ambiente ------------------------ -Un'applicazione Symfony2 viene generata con tre ambienti preconfigurati per +Un'applicazione Symfony viene generata con tre ambienti preconfigurati per gestire la maggior parte dei casi. Ovviamente, visto che un ambiente non è nient'altro che una stringa che corrisponde a un insieme di configurazioni, creare un nuovo ambiente è abbastanza semplice. Supponiamo, per esempio, di voler misurare le prestazioni dell'applicazione prima del suo invio in produzione. Un modo è quello di usare una configurazione -simile a quella del rilascio ma che utilizzasse il ``web_profiler`` di Symfony2. -Queso permetterebbe a Symfony2 di registrare le informazioni dell'applicazione mentre se ne misura le prestazioni. +simile a quella del rilascio ma che utilizzasse il ``web_profiler`` di Symfony. +Queso permetterebbe a Symfony di registrare le informazioni dell'applicazione mentre se ne misura le prestazioni. Il modo migliore per ottenere tutto ciò è tramite un ambiente che si chiami, per esempio, ``benchmark``. Si parte creando un nuovo file di configurazione: @@ -276,7 +308,7 @@ necessario creare un apposito front controller. Basterà copiare il file ``web/a nel file ``web/app_benchmark.php`` e modificare l'ambiente in modo che punti a ``benchmark``:: // web/app_benchmark.php - + // ... // basta cambiare questa riga $kernel = new AppKernel('benchmark', false); @@ -294,9 +326,7 @@ Il nuovo ambiente sarà accessibile tramite:: il debug, potrebbero fornire troppe informazioni relative all'infrastruttura sottostante l'applicazione. Per essere sicuri che questi ambienti non siano accessibili, il front controller è solitamente protetto dall'accesso da parte di - indirizzi IP esterni tramite il seguente codice, posto in cima al controllore: - - .. code-block:: php + indirizzi IP esterni tramite il seguente codice, posto in cima al controllore:: if (!in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1'))) { die('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.'); @@ -308,7 +338,7 @@ Il nuovo ambiente sarà accessibile tramite:: Gli ambienti e la cartella della cache -------------------------------------- -Symfony2 sfrutta la cache in diversi modi: la configurazione dell'applicazione, +Symfony sfrutta la cache in diversi modi: la configurazione dell'applicazione, la configurazione delle rotte, i template di Twig vengono tutti immagazzinati in oggetti PHP e salvati su file nella cartella della cache. @@ -330,17 +360,20 @@ bisogna ricordarsi di guardare nella cartella dell'ambiente che si sta utilizzan (solitamente, in fase di sviluppo e debug, il ``dev``). Sebbene possa variare, il contenuto della cartella ``app/cache/dev`` includerà i seguenti file: -* ``appDevDebugProjectContainer.php`` - il "contenitore di servizi" salvato in cache - che rappresenta la configurazione dell'applicazione; +``appDevDebugProjectContainer.php`` + Il "contenitore di servizi" salvato in cache che rappresenta la configurazione + dell'applicazione. -* ``appDevUrlGenerator.php`` - la classe PHP generata a partire dalla configurazione - delle rotte e usata nella generazione degli URL; +``appDevUrlGenerator.php`` + La classe PHP generata a partire dalla configurazione delle rotte e usata + nella generazione degli URL. -* ``appDevUrlMatcher.php`` - la classe PHP utilizzata per ricercare le rotte: qui - è possibile vedere le espressioni regolari utilizzate per associare gli URL in ingresso - con le rotte disponibili; +``appDevUrlMatcher.php`` + La classe PHP utilizzata per ricercare le rotte: qui è possibile vedere le + espressioni regolari utilizzate per associare gli URL in ingresso con le rotte disponibili. -* ``twig/`` - questa cartella contiene la cache dei template di Twig. +``twig/`` + Questa cartella contiene la cache dei template di Twig. .. note:: diff --git a/cookbook/configuration/external_parameters.rst b/cookbook/configuration/external_parameters.rst index d08c406b..72b40db0 100644 --- a/cookbook/configuration/external_parameters.rst +++ b/cookbook/configuration/external_parameters.rst @@ -14,12 +14,12 @@ Variabili d'ambiente -------------------- Symfony recupera qualsiasi variabile d'ambiente, il cui prefisso sia ``SYMFONY__`` -e la usa come un parametro all'interno del contenitore dei servizi. Al nome di -parametro risultante vengono applicate alcune trasformazioni: +e la usa come un parametro all'interno del contenitore dei servizi. Al nome del +parametro vengono applicate alcune trasformazioni: -* viene rimosso il prefisso ``SYMFONY__`` -* il nome del parametro viene convertito in minuscolo -* il doppio trattino basso viene sostituito da un punto, dato che il punto non è un +* Il prefisso ``SYMFONY__`` viene rimosso; +* Il nome del parametro viene convertito in minuscolo; +* Il doppio trattino basso viene sostituito da un punto, dato che il punto non è un carattere valido per i nomi delle variabili d'ambiente. Ad esempio, se si usa l'ambiente Apache, le variabili d'ambiente possono @@ -98,14 +98,6 @@ A questo punto, sarà possibile richiamare questi parametri ovunque sia necessar ) )); -.. note:: - - Anche in modalità di debug, impostare o modificare una variabile di ambiente - richiede una pulizia della cache, per rendere il parametro disponibile. - In modalità di debug, questo è necessario poiché solo una modifica a un file di - configurazione caricato da Symfony provoca una nuova lettura della - configurazione. - Costanti -------- diff --git a/cookbook/configuration/front_controllers_and_kernel.rst b/cookbook/configuration/front_controllers_and_kernel.rst index 4715a84f..e8540e9d 100644 --- a/cookbook/configuration/front_controllers_and_kernel.rst +++ b/cookbook/configuration/front_controllers_and_kernel.rst @@ -1,6 +1,6 @@ .. index:: - single: Come interagiscono front controller, ``AppKernel`` e - ambienti + single: Come interagiscono front controller, ``AppKernel`` e + ambienti Capire come interagiscono front controller, Kernel e ambienti ============================================================= @@ -18,7 +18,7 @@ tre elementi che lavorano assieme: .. note:: Normalmente non si ha bisogno di definire un proprio front controller - o la classe ``AppKernel``, dato che `Symfony2 Standard Edition`_ fornisce + o la classe ``AppKernel``, dato che `Symfony Standard Edition`_ fornisce delle ragionevoli implementazioni predefinite Questa sezione di documentazione viene fornita per spiegare cosa succeda @@ -30,7 +30,7 @@ Il front controller Il `front controller`_ è un design pattern molto conosciuto; è un pezzo di codice attraverso il quale passano *tutte* le richieste soddisfatte da una applicazione. -In `Symfony2 Standard Edition`_, questo ruolo viene svolto dai file `app.php`_ +In `Symfony Standard Edition`_, questo ruolo viene svolto dai file `app.php`_ e `app_dev.php`_ che si trovano nella cartella ``web/``. Questi sono i primi file in assoluto che vengono eseguiti quando una richiesta viene processata. @@ -83,7 +83,7 @@ La classe Kernel ---------------- La classe :class:`Symfony\\Component\\HttpKernel\\Kernel` è il cuore di -Symfony2. È responsabile del setup di tutti i bundle che compongono +Symfony. È responsabile del setup di tutti i bundle che compongono l'applicazione e fornisce loro la configurazione dell'applicazione. Il Kernel crea poi un contenitore di servizi, prima di gestire le richieste col suo metodo @@ -94,18 +94,16 @@ Ci sono due metodi dichiarati nell'interfaccia nella classe :class:`Symfony\\Component\\HttpKernel\\Kernel`, servendo quindi come `metodi template`_: -* :method:`Symfony\\Component\\HttpKernel\\KernelInterface::registerBundles`, - che deve restituire un array di tutti i Bundle necessari per eseguire - l'applicazione. - -* :method:`Symfony\\Component\\HttpKernel\\KernelInterface::registerContainerConfiguration`, - che carica la configurazione dell'applicazione. +:method:`Symfony\\Component\\HttpKernel\\KernelInterface::registerBundles` + Deve restituire un array di tutti i Bundle necessari per eseguire l'applicazione. +:method:`Symfony\\Component\\HttpKernel\\KernelInterface::registerContainerConfiguration`, + Carica la configurazione dell'applicazione. Per riempire questi (piccoli) buchi, l'applicazione deve essere una sottoclasse del Kernel e implementare questi metodi. La classe che ne risulta viene convenzionalmente chiamata ``AppKernel``. -Ancora una volta Symfony2 Standard Edition fornisce un `AppKernel`_ nella cartella ``app/``. +Ancora una volta Symfony Standard Edition fornisce un `AppKernel`_ nella cartella ``app/``. Per decidere quali Bundle creare questa classe usa il nome dell'ambiente, che viene passato al :method:`costruttore` del Kernel ed è ottenibile tramite il metodo :method:`Symfony\\Component\\HttpKernel\\Kernel::getEnvironment`, @@ -124,8 +122,7 @@ front controller (o aggiungerne uno nuovo) perché usi il nuovo kernel. può avere senso aggiungere sotto-cartelle aggiuntive, ad esempio: ``app/admin/AdminKernel.php`` e ``app/api/ApiKernel.php``. Quello che conta è che il front - controller sia in grado di creare una istanza del kernel - appropriato. + controller sia in grado di creare una istanza del kernel appropriato. Avere diversi ``AppKernel`` può essere utile per abilitare diversi front controller (potenzialmente su diversi server) per eseguire indipendentemente parti dell'applicazione @@ -162,7 +159,7 @@ Si è ovviamente liberi di implementare questo metodo diversamente, se serve un sistema più sofisticato per caricare la configurazione. .. _front controller: http://en.wikipedia.org/wiki/Front_Controller_pattern -.. _Symfony2 Standard Edition: https://github.com/symfony/symfony-standard +.. _Symfony Standard Edition: https://github.com/symfony/symfony-standard .. _app.php: https://github.com/symfony/symfony-standard/blob/master/web/app.php .. _app_dev.php: https://github.com/symfony/symfony-standard/blob/master/web/app_dev.php .. _app/console: https://github.com/symfony/symfony-standard/blob/master/app/console diff --git a/cookbook/configuration/override_dir_structure.rst b/cookbook/configuration/override_dir_structure.rst index 2952937e..58db815c 100644 --- a/cookbook/configuration/override_dir_structure.rst +++ b/cookbook/configuration/override_dir_structure.rst @@ -80,6 +80,8 @@ con la sola differenza che occorre sovrascrivere il metodo Abbiamo cambiato la posizione della cartella in ``app/{ambiente}/logs``. +.. _override-web-dir: + Spostare la cartella ``web`` ---------------------------- @@ -95,7 +97,7 @@ necesario modificare i percorsi nei file:: Da Symfony 2.1 (in cui è stato introdotto Composer), occorre anche modificare l'opzione ``extra.symfony-web-dir`` nel file ``composer.json``: -.. code-block:: json +.. code-block:: javascript { ... @@ -152,4 +154,37 @@ l'opzione ``extra.symfony-web-dir`` nel file ``composer.json``: .. code-block:: bash + $ php app/console cache:clear --env=prod $ php app/console assetic:dump --env=prod --no-debug + +Spostare la cartella ``vendor`` +------------------------------- + +Per spostare la cartella ``vendor``, si devono modificare i file +``app/autoload.php`` e ``composer.json``. + +La modifica in ``composer.json`` sarà simile a questa: + +.. code-block:: json + + { + ... + "config": { + "bin-dir": "bin", + "vendor-dir": "/una/cartella/vendor" + }, + ... + } + +In ``app/autoload.php``, si deve modificare il percorso che punta al file +``vendor/autoload.php``:: + + // app/autoload.php + // ... + $loader = require '/some/dir/vendor/autoload.php'; + +.. tip:: + + Questa modifica può essere interessante se si lavora in un ambiente virtuale e + non si può usare NFS, per esempio eseguendo un'applicazione Symfony con + Vagrant/VirtualBox in un sistema operativo ospite. diff --git a/cookbook/configuration/pdo_session_storage.rst b/cookbook/configuration/pdo_session_storage.rst index 9485d912..976566d5 100644 --- a/cookbook/configuration/pdo_session_storage.rst +++ b/cookbook/configuration/pdo_session_storage.rst @@ -4,15 +4,20 @@ Usare PdoSessionStorage per salvare le sessioni nella base dati =============================================================== +.. caution:: + + Ci sono stati alcuni cambiamenti non retrocomptabili in Symfony 2.6: lo schema della + base dati è cambiato leggermente. Vedere :ref:`Symfony 2.6 Changes ` + per dettagli. + Normalmente, nella gestione delle sessioni, Symfony2 salva le relative informazioni all'interno di file. Solitamente, i siti web di dimensioni medio grandi utilizzano la basi dati, invece dei file, per salvare i dati di sessione. Questo perché le basi dati sono più semplici da utilizzare e sono più scalabili in ambienti multi-webserver. -Symfony2 ha, al suo interno, una soluzione per l'archiviazione delle sessioni su base dati, chiamata +Symfony ha, al suo interno, una soluzione per l'archiviazione delle sessioni su base dati, chiamata :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\PdoSessionStorage`. -Per utilizzarla è sufficiente cambiare alcuni parametri di ``config.yml`` (o del -proprio formato di configurazione): +Per utilizzarla è sufficiente cambiare alcuni parametri nel file di configurazione principale: .. configuration-block:: @@ -22,28 +27,15 @@ proprio formato di configurazione): framework: session: # ... - handler_id: session.handler.pdo - - parameters: - pdo.db_options: - db_table: sessione - db_id_col: id_sessione - db_data_col: valore_sessione - db_time_col: tempo_sessione + handler_id: session.handler.pdo services: - pdo: - class: PDO - arguments: - dsn: "mysql:dbname=basedati" - user: utente - password: password - calls: - - [setAttribute, [3, 2]] # \PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION - session.handler.pdo: class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler - arguments: ["@pdo", "%pdo.db_options%"] + public: false + arguments: + - "mysql:dbname=miabasedati" + - { db_username: mioutente, db_password: miapassword } .. code-block:: xml @@ -52,29 +44,13 @@ proprio formato di configurazione): - - - sessione - id_sessione - valore_sessione - tempo_sessione - - - - - mysql:dbname=basedati - utente - password - - PDO::ATTR_ERRMODE - PDO::ERRMODE_EXCEPTION - - - - - - %pdo.db_options% + + mysql:dbname=miabasedati + + mioutente + miapassword + @@ -92,31 +68,81 @@ proprio formato di configurazione): ), )); - $container->setParameter('pdo.db_options', array( - 'db_table' => 'sessione', - 'db_id_col' => 'id_sessione', - 'db_data_col' => 'valore_sessione', - 'db_time_col' => 'tempo_sessione', + $storageDefinition = new Definition('Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler', array( + 'mysql:dbname=miabasedati', + array('db_username' => 'mioutente', 'db_password' => 'miapassword') )); + $container->setDefinition('session.handler.pdo', $storageDefinition); - $pdoDefinition = new Definition('PDO', array( - 'mysql:dbname=basedati', - 'utente', - 'password', - )); - $pdoDefinition->addMethodCall('setAttribute', array(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION)); - $container->setDefinition('pdo', $pdoDefinition); +Configurare i nomi di tabelle e colonne +--------------------------------------- + +Ci deve essere una tabella ``sessioni``, con varie colonne. +Il nome della tabella e i nomi delle colonne possono essere configurati, passando +un secondo array di parametri a ``PdoSessionHandler``: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + services: + # ... + session.handler.pdo: + class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler + public: false + arguments: + - "mysql:dbname=miabasedati" + - { db_table: sessions, db_username: mioutente, db_password: miapassword } + + .. code-block:: xml + + + + + mysql:dbname=miabasedati + + sessions + mioutente + miapassword + + + + + .. code-block:: php + + // app/config/config.php + + use Symfony\Component\DependencyInjection\Definition; + // ... $storageDefinition = new Definition('Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler', array( - new Reference('pdo'), - '%pdo.db_options%', + 'mysql:dbname=miabasedati', + array('db_table' => 'sessions', 'db_username' => 'mioutente', 'db_password' => 'miapassword') )); $container->setDefinition('session.handler.pdo', $storageDefinition); -* ``db_table``: Nome della tabella, nella base dati, per le sessioni -* ``db_id_col``: Nome della colonna id della tabella delle sessioni (VARCHAR(255) o maggiore) -* ``db_data_col``: Nome della colonna dove salvare il valore della sessione (TEXT o CLOB) -* ``db_time_col``: Nome della colonna per la registrazione del tempo della sessione (INTEGER) +.. versionadded:: 2.6 + L'opzione ``db_lifetime_col`` è stata introdotta in Symfony 2.6. In precedenza, + tale colonna non esisteva. + +Questi sono i parametri da configurare: + +``db_table`` (predefinito ``sessions``): + Nome della tabella, nella base dati, per le sessioni. + +``db_id_col`` (predefinito ``sess_id``): + Nome della colonna id della tabella delle sessioni (VARCHAR(128) o maggiore). + +``db_data_col`` (predefinito ``sess_data``): + Nome della colonna dove salvare il valore della sessione (BLOB) + +``db_time_col`` (predefinito ``sess_time``): + Nome della colonna per la registrazione del tempo della sessione (INTEGER) + +``db_lifetime_col`` (predefinito ``sess_lifetime``): + Nome della colonna per il tempo di vita della sessione (INTEGER). + Condividere le informazioni di connessione della base dati ---------------------------------------------------------- @@ -126,53 +152,80 @@ solo per l'archiviazione dei dati di sessione. La qual cosa è perfetta se si us una base dati differente per i dati di sessione. Ma se si preferisce salvare i dati di sessione nella stessa base dati in cui -risiedono i rimanenti dati del progetto, è possibile utilizzare i parametri di -connessione di parameter.ini, richiamandone la configurazione della base dati: +risiedono i rimanenti dati del progetto, è possibile utilizzare i parametri di connessione di +``parameter.yml``, richiamandone la configurazione della base dati: .. configuration-block:: .. code-block:: yaml - pdo: - class: PDO - arguments: - - "mysql:host=%database_host%;port=%database_port%;dbname=%database_name%" - - "%database_user%" - - "%database_password%" + services: + session.handler.pdo: + class: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler + public: false + arguments: + - "mysql:host=%database_host%;port=%database_port%;dbname=%database_name%" + - { db_username: %database_user%, db_password: %database_password% } .. code-block:: xml - - mysql:host=%database_host%;port=%database_port%;dbname=%database_name% - %database_user% - %database_password% + + mysql:host=%database_host%;port=%database_port%;dbname=%database_name% + + %database_user% + %database_password% + .. code-block:: php - $pdoDefinition = new Definition('PDO', array( + $storageDefinition = new Definition('Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler', array( 'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%', - '%database_user%', - '%database_password%', + array('db_username' => '%database_user%', 'db_password' => '%database_password%') )); Esempi di dichiarazioni SQL --------------------------- +.. _pdo-session-handle-26-changes: + +.. sidebar:: Modifiche allo schema necessarie se si aggiorna a Symfony 2.6 + + Se si usava ``PdoSessionHandler`` prima di Symfony 2.6 e si vuole aggiornare, occorrono + alcune modifiche alla tabella delle sessioni: + + * Si deve aggiungere una colonna per la vita della sessione (predefinito: ``sess_lifetime``), di + tipo INTEGER; + * Il tipo della colonna dei dati (predefinito: ``sess_data``) va cambiato in + BLOB. + + Vedere le istruzioni SQL più avanti, per maggiori dettagli. + + Per mantenere la vecchia funzionalità, cambiare il nome della classe + in ``LegacyPdoSessionHandler``, al posto di ``PdoSessionHandler`` (la + classe legacy è stata aggiunta in Symfony 2.6.2). + MySQL ~~~~~ -La dichiarazione SQL per creare la necessaria tabella nella base dati potrebbe essere +L'istruzione SQL per creare la necessaria tabella nella base dati potrebbe essere simile alla seguente (MySQL): .. code-block:: sql CREATE TABLE `sessione` ( - `id_sessione` varchar(255) NOT NULL, - `valore_sessione` text NOT NULL, - `tempo_sessione` int(11) NOT NULL, - PRIMARY KEY (`id_sessione`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + `id_sessione` VARBINARY(128) NOT NULL PRIMARY KEY, + `valore_sessione` BLOB NOT NULL, + `tempo_sessione` INTEGER UNSIGNED NOT NULL, + `vita_sessione` MEDIUMINT NOT NULL + ) COLLATE utf8_bin, ENGINE = InnoDB; + +.. note:: + + Una colonna di tipo ``BLOB`` può memorizzare fino a 64 kb. Se i dati memorizzati nella + sessione sono maggiori, potrebbe essere lanciata un'eccezione oppure la sessione potrebbe + essere azzerata in modo silenzioso. Si consideri l'uso di ``MEDIUMBLOB``, nel caso in cui + occorra più spazio. PostgreSQL ~~~~~~~~~~ @@ -182,10 +235,10 @@ Per PostgreSQL, la dichiarazione sarà simile alla seguente: .. code-block:: sql CREATE TABLE sessione ( - id_sessione character varying(255) NOT NULL, - valore_sessione text NOT NULL, - tempo_sessione integer NOT NULL, - CONSTRAINT session_pkey PRIMARY KEY (id_sessione), + id_sessione VARCHAR(128) NOT NULL PRIMARY KEY, + valore_sessione BYTEA NOT NULL, + tempo_sessione INTEGER NOT NULL, + vita_sessione INTEGER NOT NULL ); Microsoft SQL Server @@ -196,16 +249,17 @@ Per MSSQL, l'istruzione potrebbe essere come la seguente: .. code-block:: sql CREATE TABLE [dbo].[sessione]( - [id_sessione] [nvarchar](255) NOT NULL, - [valore_sessione] [ntext] NOT NULL, + [id_sessione] [nvarchar](255) NOT NULL, + [valore_sessione] [ntext] NOT NULL, [tempo_sessione] [int] NOT NULL, - PRIMARY KEY CLUSTERED( - [id_sessione] ASC - ) WITH ( - PAD_INDEX = OFF, - STATISTICS_NORECOMPUTE = OFF, - IGNORE_DUP_KEY = OFF, - ALLOW_ROW_LOCKS = ON, - ALLOW_PAGE_LOCKS = ON - ) ON [PRIMARY] + [vita_sessione] [int] NOT NULL, + PRIMARY KEY CLUSTERED( + [id_sessione] ASC + ) WITH ( + PAD_INDEX = OFF, + STATISTICS_NORECOMPUTE = OFF, + IGNORE_DUP_KEY = OFF, + ALLOW_ROW_LOCKS = ON, + ALLOW_PAGE_LOCKS = ON + ) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] diff --git a/cookbook/configuration/web_server_configuration.rst b/cookbook/configuration/web_server_configuration.rst index 9f648715..66973b33 100644 --- a/cookbook/configuration/web_server_configuration.rst +++ b/cookbook/configuration/web_server_configuration.rst @@ -1,10 +1,10 @@ .. index:: - single: Server web + single: Server web Configurare un server web ========================= -La modalità preferita per lo sviluppo di un'applicazione Symfony2 è l'uso del +La modalità preferita per lo sviluppo di un'applicazione Symfony è l'uso del :doc:`server web interno di PHP `. Tuttavia, quando si usa una vecchia versione di PHP o quando si esegue l'applicazione in produzione, occorrerà usare un server web "classico". Questa ricetta @@ -25,14 +25,16 @@ per usare PHP :ref:`con Nginx `. web. Negli esempi successivi, la cartella ``web/`` si troverà nella document root. Questa cartella è ``/var/www/progetto/web/``. + Se un fornitore di hosting impone il cambiamento della cartella ``web/`` a una posizione + differente (come ``public_html/``), assicurarsi di + :ref:`modificare la posizione della cartella web/ `. + .. _web-server-apache-mod-php: -Apache2 con mod_php/PHP-CGI ---------------------------- +Apache con mod_php/PHP-CGI +-------------------------- -Per opzioni avanzate di configurazione di Apache, vedere la documentazione ufficiale di `Apache`_. -La basi minime per far funzionare un'applicazione sotto Apache2 -sono: +La basi minime per far funzionare un'applicazione sotto Apache sono: .. code-block:: apache @@ -42,47 +44,83 @@ sono: DocumentRoot /var/www/progetto/web - # abilita la lettura di .htaccess AllowOverride All - Order allow,deny + Order allow, deny Allow from All - ErrorLog /var/log/apache2/project_error.log - CustomLog /var/log/apache2/project_access.log combined + # scommentare le seguenti righe se si installano risorse come collegamenti simbolici + # o si avranno problemi compilando riosorse LESS/Sass/CoffeScript + # + # Option FollowSymlinks + # + + ErrorLog /var/log/apache2/progetto_error.log + CustomLog /var/log/apache2/progetto_access.log combined -.. note:: +.. tip:: - Su un sistema che supporti la variabile ``APACHE_LOG_DIR``, si potrebbe - preferire l'uso di ``${APACHE_LOG_DIR}/`` a ``/var/log/apache2/``. + Su un sistema che supporti la variabile ``APACHE_LOG_DIR``, si potrebbe voler + usare ``${APACHE_LOG_DIR}/`` al posto di ``/var/log/apache2/``. -.. note:: +Usando la seguente **configurazione ottimizzata**, si può disabilitare il supporto a ``.htaccess`` +e quindi incrementare le prestazioni del server web: - Per questioni di prestazione, probabilmente si vorrà impostare - ``AllowOverride None`` e implementare le regole di riscrittura presenti in ``web/.htaccess`` - direttamente nella cofigurazione dell'host virtuale. +.. code-block:: apache -Se si usa **php-cgi**, Apache non passa nome utente e password di HTTP basic -a PHP, per impostazione predefinita. Per aggirare tale limitazione, si dovrebbe usare -la seguente configurazione: + + ServerName dominio.tld + ServerAlias www.dominio.tld -.. code-block:: apache + DocumentRoot /var/www/progetto/web + + AllowOverride None + Order allow, deny + Allow from All + + + Options -MultiViews + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^(.*)$ app.php [QSA,L] + + + + # scommentare le seguenti righe se si installano risorse come collegamenti simbolici + # o si avranno problemi compilando riosorse LESS/Sass/CoffeScript + # + # Option FollowSymlinks + # - RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + ErrorLog /var/log/apache2/progetto_error.log + CustomLog /var/log/apache2/progetto_access.log combined + -.. caution:: +.. tip:: - In Apache 2.4, ``Order allow,deny`` è stato sostituito da ``Require all granted``, - quindi occorre modificare le impostazioni in questo modo: + Se si usa **php-cgi**, Apache non passa nome utente e password di HTTP basic + a PHP, per impostazione predefinita. Per aggirare tale limitazione, si dovrebbe usare + la seguente configurazione: .. code-block:: apache - - # enable the .htaccess rewrites - AllowOverride All - Require all granted - + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + +Usare mod_php/PHP-CGI con Apache 2.4 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In Apache 2.4, ``Order allow,deny`` è stato sostituito da ``Require all granted``, +quindi occorre modificare le impostazioni in questo modo: + +.. code-block:: apache + + + Require all granted + # ... + + +Per opzioni avanzate di configurazione di Apache, leggere la `documentazione di Apache`_. .. _web-server-apache-fpm: @@ -127,7 +165,24 @@ per passare richieste di file PHP a PHP FPM: ServerName dominio.tld ServerAlias www.dominio.tld - ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/progetto/web/$1 + # Scommentare la riga seguente per forzare Apache a passare l'header di autenticazione + # a PHP: necessario per "basic_auth" sotto PHP-FPM e FastCGI + # + # SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1 + + # Per Apache 2.4.9 e successivi + # Usando SetHandler si evitano problemi con ProxyPassMatch in combinazione + # con mod_rewrite o mod_autoindex + + SetHandler proxy:fcgi://127.0.0.1:9000 + + + # Se si usa Apache prima di 2.4.9, si consideri di aggiornare o usare invece questo + # ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/progetto/web/$1 + + # Se si fa girare l'applicazione Symfony in una sottocartella della document root, + # cambiare l'espressione regolare di conseguenza: + # ProxyPassMatch ^/percorso-app/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/progetto/web/$1 DocumentRoot /var/www/progetto/web @@ -136,19 +191,15 @@ per passare richieste di file PHP a PHP FPM: Require all granted - ErrorLog /var/log/apache2/project_error.log - CustomLog /var/log/apache2/project_access.log combined - - -.. caution:: - - Se si fa girare un'applicaizone Symfony in una sottocartella della document root, - l'espressione regolare usata nella direttiva ``ProxyPassMatch`` deve cambiare - di conseguenza: + # scommentare le seguenti righe se si installano risorse come collegamenti simbolici + # o si avranno problemi compilando riosorse LESS/Sass/CoffeScript + # + # Option FollowSymlinks + # - .. code-block:: apache - - ProxyPassMatch ^/percorso-applicazione/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/progetto/web/$1 + ErrorLog /var/log/apache2/progetto_error.log + CustomLog /var/log/apache2/progetto_access.log combined + PHP-FPM con Apache 2.2 ~~~~~~~~~~~~~~~~~~~~~~ @@ -176,8 +227,14 @@ dovrebbe essere come questa: Allow from all - ErrorLog /var/log/apache2/project_error.log - CustomLog /var/log/apache2/project_access.log combined + # scommentare le seguenti righe se si installano risorse come collegamenti simbolici + # o si avranno problemi compilando riosorse LESS/Sass/CoffeScript + # + # Option FollowSymlinks + # + + ErrorLog /var/log/apache2/progetto_error.log + CustomLog /var/log/apache2/progetto_access.log combined Se si preferisce usare un socket unix, si deve invece usare l'opzione @@ -192,9 +249,7 @@ Se si preferisce usare un socket unix, si deve invece usare l'opzione Nginx ----- -Per opzioni avanzate di configurazione di Nginx, vedere la documentazione ufficiale di `Nginx`_. -La basi minime per far funzionare un'applicazione sotto Nginx -sono: +La basi minime per far funzionare un'applicazione sotto Nginx sono: .. code-block:: nginx @@ -206,17 +261,31 @@ sono: # prova a servire direttamente i file, fallback su app.php try_files $uri /app.php$is_args$args; } - - location ~ ^/(app|app_dev|config)\.php(/|$) { + # DEV + # Questa regola va messa solo in ambiente di sviluppo + # In produzione, non includerla e non eseguire deploy di app_dev.php né di config.php + location ~ ^/(app_dev|config)\.php(/|$) { + fastcgi_pass unix:/var/run/php5-fpm.sock; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param HTTPS off; + } + # PROD + location ~ ^/app\.php(/|$) { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param HTTPS off; + # Previene URI che includono il front controller. Questa andrà in 404: + # http://dominio.tld/app.php/un-percorso + # Rimuovere la direttiva internal per consentire questi URI + internal; } - error_log /var/log/nginx/project_error.log; - access_log /var/log/nginx/project_access.log; + error_log /var/log/nginx/progetto_error.log; + access_log /var/log/nginx/progetto_access.log; } .. note:: @@ -235,7 +304,9 @@ sono: Se si hanno altri file PHP nella cartella web e si vuole che siano eseguiti, assicurarsi di includerli nel blocco ``location`` visto sopra. -.. _`Apache`: http://httpd.apache.org/docs/current/mod/core.html#documentroot +Per opzioni avanzate di configurazione di Nginx, leggere la `documentazione di Nginx`_. + +.. _`documentazione di Apache`: http://httpd.apache.org/docs/ .. _`non supporta i socket unix`: https://issues.apache.org/bugzilla/show_bug.cgi?id=54101 .. _`FastCgiExternalServer`: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html#FastCgiExternalServer -.. _`Nginx`: http://wiki.nginx.org/Symfony +.. _`documentazione di Nginx`: http://wiki.nginx.org/Symfony diff --git a/cookbook/console/command_in_controller.rst b/cookbook/console/command_in_controller.rst new file mode 100644 index 00000000..4473daf1 --- /dev/null +++ b/cookbook/console/command_in_controller.rst @@ -0,0 +1,7 @@ +.. index:: + single: Console; Richiamare un comando da un controllore + +Richiamare un comando da un controllore +======================================= + +(TODO da tradurre...) diff --git a/cookbook/console/commands_as_services.rst b/cookbook/console/commands_as_services.rst index bc8c8b42..9534bb76 100644 --- a/cookbook/console/commands_as_services.rst +++ b/cookbook/console/commands_as_services.rst @@ -114,11 +114,11 @@ avere un servizio ``NameRepository``, da usare per ricavare il valore predefinit } } -Ora, basta aggiornare i parametri della configurazione del servizio, per +Ora, basta aggiornare i parametri della configurazione del servizio per iniettare ``NameRepository``. Ottimo, ora si ha a disposizione un valore predefinito dinamico! .. caution:: - Fare attenzione a non fare troppe cose ``configure`` (come query alla base + Fare attenzione a non fare troppe cose in ``configure`` (come query alla base dati), perché il codice viene eseguito anche se si usa la console per eseguire un comando diverso. diff --git a/cookbook/console/console_command.rst b/cookbook/console/console_command.rst index 42ce6240..add6be74 100644 --- a/cookbook/console/console_command.rst +++ b/cookbook/console/console_command.rst @@ -17,8 +17,8 @@ Per rendere disponibili automaticamente i comandi in Symfony2, creare una cartel estendere AcmeDemoBundle per mandare un saluto dalla linea di comando, creare ``GreetCommand.php`` e aggiungervi il codice seguente:: - // src/Acme/DemoBundle/Command/GreetCommand.php - namespace Acme\DemoBundle\Command; + // src/AppBundle/Command/GreetCommand.php + namespace AppBundle\Command; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; use Symfony\Component\Console\Input\InputArgument; @@ -33,8 +33,17 @@ estendere AcmeDemoBundle per mandare un saluto dalla linea di comando, creare $this ->setName('demo:greet') ->setDescription('Saluta qualcuno') - ->addArgument('name', InputArgument::OPTIONAL, 'Chi vuoi salutare?') - ->addOption('yell', null, InputOption::VALUE_NONE, 'Se impostato, urlerà in lettere maiuscole') + ->addArgument( + 'name', + InputArgument::OPTIONAL, + 'Chi vuoi salutare?' + ) + ->addOption( + 'yell', + null, + InputOption::VALUE_NONE, + 'Se impostato, urlerà in lettere maiuscole' + ) ; } @@ -59,7 +68,7 @@ Ora il comando sarà automaticamente disponibile: .. code-block:: bash - $ app/console demo:greet Fabien + $ php app/console demo:greet Fabien .. _cookbook-console-dic: @@ -103,7 +112,9 @@ tradurre dei contenuti usando un comando di console:: $name = $input->getArgument('name'); $translator = $this->getContainer()->get('translator'); if ($name) { - $output->writeln($translator->trans('Hello %name%!', array('%name%' => $name))); + $output->writeln( + $translator->trans('Hello %name%!', array('%name%' => $name)) + ); } else { $output->writeln($translator->trans('Hello!')); } @@ -137,7 +148,9 @@ prima di tradurre i contenuti:: $translator->setLocale($locale); if ($name) { - $output->writeln($translator->trans('Hello %name%!', array('%name%' => $name))); + $output->writeln( + $translator->trans('Hello %name%!', array('%name%' => $name)) + ); } else { $output->writeln($translator->trans('Hello!')); } @@ -181,11 +194,6 @@ al posto di } } -.. versionadded:: 2.4 - A partire da Symfony 2.4, ``CommandTester`` individua automaticamente il nome - del comando da eseguire. Non è quindi più necessario passarlo tramite la chiave - ``command``. - .. note:: Nel caso specifico appena visto, il parametro ``name`` e l'opzione ``--yell`` @@ -199,7 +207,7 @@ si può estendere il test da use Symfony\Component\Console\Tester\CommandTester; use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; - use Acme\DemoBundle\Command\GreetCommand; + use AppBundle\Command\GreetCommand; class ListCommandTest extends KernelTestCase { diff --git a/cookbook/console/index.rst b/cookbook/console/index.rst index 6f1f939d..c3628beb 100644 --- a/cookbook/console/index.rst +++ b/cookbook/console/index.rst @@ -6,6 +6,7 @@ Console console_command usage + command_in_controller sending_emails logging commands_as_services diff --git a/cookbook/controller/error_pages.rst b/cookbook/controller/error_pages.rst index a47f1e6b..3de77ec9 100644 --- a/cookbook/controller/error_pages.rst +++ b/cookbook/controller/error_pages.rst @@ -5,23 +5,38 @@ Personalizzare le pagine di errore ================================== -Quando in Symfony2 viene lanciata una qualsiasi eccezione, questa viene catturata all'interno -della classe ``Kernel`` e successivamente inoltrata a un controllore speciale, -``TwigBundle:Exception:show``, per la gestione. Questo controllore, che si trova -all'interno di TwigBundle, determina quale template di errore visualizzare e -il codice di stato che dovrebbe essere impostato per la data eccezione. +Quando viene lanciata un'eccezione, la classe ``HttpKernel`` la cattura e +distribuisce un evento ``kernel.exception``. Questo fornisce la possibilità di convertire +l'eccezione in una ``Response``, in vari modi. -Le pagine di errore possono essere personalizzate in due diversi modi, a seconda di quanto +Il bundle TwigBundle ha un ascoltatore per tale evento, che eseguirà un controllore configurabile +(anche se arbitrario), per generare la risposta. Il controllore predefinito ha un modo +intelligente per scegliere uno dei template di errore +a disposizione. + +Quindi, le pagine di errore possono essere personalizzate in diversi modi, a seconda di quanto controllo si vuole avere: -1. Personalizzare i template di errore delle diverse pagine di errore (spiegato più avanti); +#. :ref:`Usare ExceptionController predefinito e creare alcuni + template, che consentono di personalizzare l'aspetto delle varie + pagine di errore (facile); ` + +#. :ref:`Sostituire il controllore predefinito con uno personalizzato + (intermedio). ` -2. Sostituire il controllore predefinito delle eccezioni ``twig.controller.exception:showAction``. +#. :ref:`Usare l'evento kernel.exception e implementare una gestione + personalizzata (avanzato). ` + +.. _use-default-exception-controller: ExceptionController predefinito ------------------------------- -L'``ExceptionController`` predefinito mostrerà una pagina di +Il metodo ``showAction()`` del controllore +:class:`Symfony\\Bundle\\TwigBundle\\Controller\\ExceptionController` +sarà richiamato al verificarsi di un'eccezione. + +Questo controllore mostrerà una pagina di *eccezione* o di *errore*, a seconda dell'impostazione di ``kernel.debug``. Mentre le pagine di *eccezione* forniscono varie informazioni utili durante lo sviluppo, le pagine di *errore* sono rivolte @@ -31,20 +46,59 @@ all'utente finale. Non si dovrebbe impostare ``kernel.debug`` a ``false`` per poter vedere una pagina di errore durante lo sviluppo. Questo impedirebbe anche a - Symfony2 di ricompilare i template Twig, tra le altre cose. + Symfony di ricompilare i template Twig, tra le altre cose. Il bundle `WebfactoryExceptionsBundle`_ fornisce uno speciale controllore che consente di mostrare le pagine di errore personalizzate per codici di stato HTTP arbitrari, anche quando ``kernel.debug`` è impostato a ``true``. +.. _`WebfactoryExceptionsBundle`: https://github.com/webfactory/exceptions-bundle + +.. _cookbook-error-pages-by-status-code: + +Come sono scelti i template per le pagine di errore e di eccezione +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Il bundle TwigBundle ha dei template predefiniti per le pagine di errore e +di eccezione, nella sua cartella ``Resources/views/Exception``. + +.. tip:: + + In una tipica installazione di Symfony, si può trovare TwigBundle sotto + ``vendor/symfony/symfony/src/Symfony/Bundle/TwigBundle``. Oltre alla pagina + di errore standard HTML, fornisce anche una pagina di errore per molti + dei formati di risposta più comuni, inclusi + JSON (``error.json.twig``), XML (``error.xml.twig``) e anche + JavaScript (``error.js.twig``), solo per citarne alcuni. + +Ecco come ``ExceptionController`` sceglierà uno dei template +disponibili, in base al codice di stato HTTP e al formato della richiesta: + +* Per le pagine di *errore*, cerca prima un template per il formato e il codice + di stato dati (come ``error404.json.twig``); + +* Se non lo trova, cerca per un template generico per il formato + dato (come ``error.json.twig`` o + ``exception.json.twig``); + +* Infine, ignora il formato e usa il template HTML + (come ``error.html.twig`` o ``exception.html.twig``). + +.. tip:: + + Se l'eccezione implementa l'interfaccia + :class:`Symfony\\Component\\HttpKernel\\Exception\\HttpExceptionInterface`, + il metodo ``getStatusCode()`` sarà richiamato per + ricavare il codice di stato HTTP da utilizzare. Altrimenti, + il codice di stato sarà "500". + Sovrascrivere i template degli errori ------------------------------------- -Tutti i template degli errori sono presenti all'interno di TwigBundle. Per sovrascrivere i -template, si può semplicemente utilizzare il metodo standard per sovrascrivere i template che -esistono all'interno di un bundle. Per maggiori informazioni, vedere -:ref:`overriding-bundle-templates`. +Per sovrascrivere questi template, si può semplicemente utilizzare il metodo standard +per sovrascrivere i template che esistono all'interno di un bundle. Per maggiori informazioni, +vedere :ref:`overriding-bundle-templates`. Ad esempio, per sovrascrivere il template di errore predefinito che è mostrato all'utente finale, creare un nuovo template posizionato in @@ -75,81 +129,162 @@ all'utente finale, creare un nuovo template posizionato in .. tip:: Non bisogna preoccuparsi, se non si ha familiarità con Twig. Twig è un semplice, potente - e opzionale motore per i template che si integra con Symfony2. Per maggiori + e opzionale motore per i template che si integra con Symfony. Per maggiori informazioni su Twig, vedere :doc:`/book/templating`. -In aggiunta alla pagina di errore standard HTML, Symfony fornisce una pagina di errore -predefinita per molti dei formati di risposta più comuni, tra cui JSON -(``error.json.twig``), XML, (``error.xml.twig``) e anche JavaScript -(``error.js.twig``), per citarne alcuni. Per sovrascrivere uno di questi template, basta -creare un nuovo file con lo stesso nome nella cartella -``app/Resources/TwigBundle/views/Exception``. Questo è il metodo standard -per sovrascrivere qualunque template posizionato dentro a un bundle. +Questa logica funziona non solo per sostituire i template predefiniti, ma anche per +crearne di nuovi. -.. _cookbook-error-pages-by-status-code: +Per esempio, creare un template ``app/Resources/TwigBundle/views/Exception/error404.html.twig``, +per mostrare una pagina speciale per gli errori 404 (non trovato). +Fare riferimento alla sezione precedente per l'ordine in cui +``ExceptionController`` cerca i vari nomi di template. -Personalizzazione della pagina 404 e di altre pagine di errore --------------------------------------------------------------- +.. tip:: + + Spesso, il modo più semplice per personalizzare una pagina di errore è quello di copiarla + da TwigBundle in ``app/Resources/TwigBundle/views/Exception`` e + poi modificarla. + +.. note:: + + Anche le pagine di eccezione mostrate allo sviluppatore durante il debug possono essere + personalizzate, creando template come + ``exception.html.twig``, per la pagina di eccezione standard HTML, o + ``exception.json.twig``, per la pagina di eccezione JSON. -È anche possibile personalizzare specializzare specifici template di errore in base al -codice di stato. Per esempio, creare un template -``app/Resources/TwigBundle/views/Exception/error404.html.twig`` per -visualizzare una pagina speciale per gli errori 404 (pagina non trovata). +.. _custom-exception-controller: -Symfony utilizza il seguente algoritmo per determinare quale template deve usare: +Sostituire ExceptionController +------------------------------ -* Prima, cerca un template per il dato formato e codice di stato (tipo - ``error404.json.twig``); +Chi avesse bisogno di un po' più di flessibilità, oltre a riscrivere il +template, può cambiare il controllore che rende la pagina di errore. +Per esempio, si potrebbero voler passare variabili aggiuntive +al template. -* Se non esiste, cerca un per il dato formato (tipo - ``error.json.twig``); +.. caution:: -* Se non esiste, si ricade nel template HTML (tipo - ``error.html.twig``). + Assicurarsi di non perdere le pagine di eccezione che rendono gli utili + messaggi di errore durante lo sviluppo. + +Per farlo, basta creare un nuovo controllore e impostare l'opzione +:ref:`twig.exception_controller ` per +puntarvi. + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + twig: + exception_controller: AppBundle:Exception:showException + + .. code-block:: xml + + + + + + + AppBundle:Exception:showException + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('twig', array( + 'exception_controller' => 'AppBundle:Exception:showException', + // ... + )); .. tip:: - Per vedere l'elenco completo dei template di errore predefiniti, vedere la - cartella ``Resources/views/Exception`` di TwigBundle. In una - installazione standard di Symfony2, si può trovareTwigBundle in - ``vendor/symfony/src/Symfony/Bundle/TwigBundle``. Spesso, il modo più semplice - per personalizzare una pagina di errore è quello di copiarlo da TwigBundle in - ``app/Resources/TwigBundle/views/Exception`` e poi modificarlo. + Si può anche impostare il controllore come servizio. -.. note:: + Il valore predefinito di ``twig.controller.exception:showAction`` si riferisce + al metodo ``showAction`` di ``ExceptionController``, descritto + in precedenza, che è registrato nel contenitore dei servizi come + ``twig.controller.exception``. - Le pagine "amichevoli" di debug delle eccezioni mostrate allo sviluppatore possono ugualmente - essere personalizzate, creando template come - ``exception.html.twig`` per la pagina di eccezione standard in HTML o - ``exception.json.twig`` per la pagina di eccezione JSON. +Al controllore saranno passati due parametri: ``exception``, +che è un'istanza di :class:`\\Symfony\\Component\\Debug\\Exception\\FlattenException`, +creata dall'eccezione gestita, e ``logger``, +un'istanza di :class:`\\Symfony\\Component\\HttpKernel\\Log\\DebugLoggerInterface` +(che potrebbe essere ``null``). -.. _`WebfactoryExceptionsBundle`: https://github.com/webfactory/exceptions-bundle +.. tip:: + + La Request che sarà inviata al controllore è creata + in :class:`Symfony\\Component\\HttpKernel\\EventListener\\ExceptionListener`. + Questo ascoltatore di eventi è impostato da TwigBundle. -Sostituire il controllore Exception predefinito ------------------------------------------------ +Ovviamente, si può anche estendere +:class:`Symfony\\Bundle\\TwigBundle\\Controller\\ExceptionController`, come descritto prima. +In tal caso, si potrebbe voler sovrascrivere uno o entrambi i metodi +``showAction`` e ``findTemplate``. Il secondo individua il +template da usare. -Se dovesse servire più flessibilità, oltre a sovrascrivere solo il template -(p.e. se serve passare variabili aggiuntive a un template), -si può sovrascrivere il controllore che rende la pagina di errore. +.. caution:: + + Attualmente, ``ExceptionController`` *non* fa parte delle API di + Symfony, quindi fare attenzione: potrebbe cambiare in futuro. -Il controllore predefinito delle eccezioni è registrato come servizio, la classe -effettiva è ``Symfony\Bundle\TwigBundle\Controller\ExceptionController``. +.. _use-kernel-exception-event: + +Usare l'evento kernel.exception +------------------------------- -Per poterlo fare, creare una nuova classe controllore e farle estendere la classe -``Symfony\Bundle\TwigBundle\Controller\ExceptionController`` di Symfony. +Come menzionato in precedenza, l'evento ``kernel.exception`` viene distribuito +quando il kernel di Symfony Kernel deve gestire un'eccezione. +Per approfondire, si veda :ref:`kernel-kernel.exception`. -Ci sono molti metodi da poter sovrascrivere per personalizzare le varie parti della -resa della pagina di errore. Si può, per esempio, sovrascrivere l'intera -``showAction`` oppure solo il meteodo ``findTemplate``, che individua quale -template vada reso. +L'utilizzo di questo evento è in realtà molto più potente di quanto sia stato detto in +precedenza, ma richiede anche una chiara comprensione del funzionamento +interno di Symfony. -Per far usare a Symfony il nuovo controllore al posto di quello predefinito, impostare l'opzione -:ref:`twig.exception_controller ` -in app/config/config.yml. +Per fornire solo un esempio, ipotizziamo che un'applicazione lanci eccezioni +specializzate, con un significato particolare per il suo dominio. + +In questo caso, tutto quello che ``ExceptionListener`` e +``ExceptionController`` possono fare è provare a immaginare il codice +di stato HTTP corretto e mostrare una pagina di errore generica. + +La :doc:`scrittura di un ascoltatore di eventi personalizzato ` +per l'evento ``kernel.exception`` consente di dare uno sguardo più da vicino +all'eccezione e intraprendere azioni diverse. Tali azioni possono +includere il log dell'eccezione, il rinvio dell'utente a +un'altra pagina o la resa di pagine di errore specializzate. + +.. note:: + + Se l'ascoltatore richiama ``setResponse()`` su + :class:`Symfony\\Component\\HttpKernel\\Event\\GetResponseForExceptionEvent`, + la propagazione dell'evento sarà stoppata e la risposta inviata + al client. + +Questo approccio consente di creare una gestione centralizzata e strutturata degli +errori: invece di catturare (e gestire) le stesse eccezioni +in vari controllori ogni volta, si può avere un solo ascoltatore (ma anche più +di uno) che se ne occupi. .. tip:: - La personalizzazione della gestione delle eccezioni in realtà è molto più potente - di quanto scritto qui. Viene lanciato un evento interno, ``kernel.exception``, - che permette un controllo completo sulla gestione delle eccezioni. Per maggiori - informazioni, vedere :ref:`kernel-kernel.exception`. + Per un esempio, dare un'occhiata a `ExceptionListener`_ nel componente + Security. + + Gestisce varie eccezioni legate alla sicurezza, lanciate in + un'applicazione (come :class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException`) + e mette in atto misure come il rinvio dell'utente alla pagina di login, + la disconnessione e altre cose. + +Buona fortuna! + +.. _`ExceptionListener`: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php diff --git a/cookbook/controller/service.rst b/cookbook/controller/service.rst index 5503ce9e..d1219ded 100644 --- a/cookbook/controller/service.rst +++ b/cookbook/controller/service.rst @@ -25,7 +25,7 @@ servizi. di essere separato in più controllori. Quindi, anche se non si specificano i controllori come servizi, probabilmente lo - si vedrà fatto in qualche bundle open source di Symfony2. È anche importante + si vedrà fatto in qualche bundle open source di Symfony. È anche importante capire i pro e i contro di entrambi gli approcci. Definire il controllore come servizio diff --git a/cookbook/deployment/azure-website.rst b/cookbook/deployment/azure-website.rst index d3f56a67..a9e8fcad 100644 --- a/cookbook/deployment/azure-website.rst +++ b/cookbook/deployment/azure-website.rst @@ -5,7 +5,7 @@ Deploy su Microsoft Azure ========================= Questa ricetta descrive come eseguire passo-passo il deploy di una piccola -applicazione Symfony2 sulla piattaforma di cloud Microsoft Azure. Spiegherà come +applicazione Symfony sulla piattaforma di cloud Microsoft Azure. Spiegherà come preparare un nuovo sito Azure, inclusa la configurazione della corretta versione di PHP e delle variabili di ambiente. Verrà anche mostrato come si possono sfruttare Git e Composer per il deploy di un'applicazione Symfony nel cloud. @@ -355,7 +355,7 @@ seguente. Ovviamente, i valori dipendono da quanto configurato. .. code-block:: text - Database=mysymfony2MySQL;Data Source=eu-cdbr-azure-north-c.cloudapp.net;User Id=bff2481a5b6074;Password=bdf50b42 + Database=mysymfonyMySQL;Data Source=eu-cdbr-azure-north-c.cloudapp.net;User Id=bff2481a5b6074;Password=bdf50b42 Tornare al terminale e rispondere alle domande, fornendo le seguenti risposte. Non dimenticare di adattare i valori seguenti ai valori reali @@ -366,7 +366,7 @@ della stringa di connessione MySQL. database_driver: pdo_mysql database_host: u-cdbr-azure-north-c.cloudapp.net database_port: null - database_name: mysymfony2MySQL + database_name: mysymfonyMySQL database_user: bff2481a5b6074 database_password: bdf50b42 // ... diff --git a/cookbook/deployment/heroku.rst b/cookbook/deployment/heroku.rst index ab562e26..70f43c1b 100644 --- a/cookbook/deployment/heroku.rst +++ b/cookbook/deployment/heroku.rst @@ -4,7 +4,7 @@ Deploy su Heroku Cloud ====================== -Questa ricetta descrive passo-passo come eseguire il deploy di un'applicazione Symfony2 +Questa ricetta descrive passo-passo come eseguire il deploy di un'applicazione Symfony sulla piattaforma cloud Heroku. Il contenuto si basa sull'`articolo originale`_ pubblicato Heroku. @@ -21,14 +21,14 @@ acquisire familiarità con le specifiche di come funzionano le applicazioni PHP Preparare l'applicazione ~~~~~~~~~~~~~~~~~~~~~~~~ -Il deploy di un'applicazione Symfony2 su Heroku non richiede alcuna modifica nel +Il deploy di un'applicazione Symfony su Heroku non richiede alcuna modifica nel codice, ma richiede alcuni piccoli aggiustamenti alla configurazione. -La posizione standard dei log di Symfony2 è la cartella ``app/log/``. +La posizione standard dei log di Symfony è la cartella ``app/log/``. Questo non è idale, perché Heroku usa un `filesystem effimero`_. Su Heroku, il modo migliore per salvare i log è `Logplex`_. Il modo migliore per inviare dati di log a Logplex è la scrittura su ``STDERR`` o ``STDOUT``. Fortunamente, -Symfony2 usa l'eccellente libreria Monolog per gestire i log. Quindi, il cambio di +Symfony usa l'eccellente libreria Monolog per gestire i log. Quindi, il cambio di destinazione per i log implica una semplice modifica nella configurazione. Aprire il file ``app/config/config_prod.yml``, individuare la sezione @@ -69,20 +69,27 @@ Si è ora pronti per il deploy dell'applicazione, come spiegato nella prossima s Deploy dell'applicazione su Heroku ---------------------------------- -Per il deploy dell'applicazione su Heroku, si deve prima creare un profilo ``Procfile``, -che dice a Heroku quale comando usare per lanciare il server web con le -impostazioni corrette. Dopo averlo fatto, basta eseguire ``git push``, -ecco fatto! +Perima del primo deploy, occorrono solo altri due passi, descritti +qui: -Creare un Procfile -~~~~~~~~~~~~~~~~~~ +#. :ref:`Creare un Procfile ` + +#. :ref:`Impostare l'ambiente a prod ` + +#. :ref:`Fare un push su Heroku ` + +.. _heroku-procfile: +.. _creating-a-procfile: + +1) Creare un Procfile +~~~~~~~~~~~~~~~~~~~~~ Heroku lancerà un server web Apache insieme a PHP, per servire le applicazioni. Tuttavia, alle applicazioni Symfony si applicano due circostanze speciali: -1. La document root è nella cartella ``web/`` e non nella cartella radice +#. La document root è nella cartella ``web/`` e non nella cartella radice dell'applicazione; -2. La cartella ``bin-dir`` di Composer, in cui sono posti i binari dei venditori (compresi gli +#. La cartella ``bin-dir`` di Composer, in cui sono posti i binari dei venditori (compresi gli script di avvio di Heroku), è ``bin/`` e non la predefinita ``vendor/bin``. .. note:: @@ -110,8 +117,42 @@ per creare il file ``Procfile`` e aggiungerlo al repository: [master 35075db] Procfile for Apache and PHP 1 file changed, 1 insertion(+) -Push su Heroku -~~~~~~~~~~~~~~ +.. _heroku-setting-env-to-prod: +.. _setting-the-prod-environment: + +2) Impostare l'ambiente a prod +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Durante un deploy, Heroku esegue ``composer install --no-dev`` per installare tutte le +dipendenze richieste dall'applicazione. Tuttavia, tipici `comandi post-installazione`_ +in ``composer.json``, p.e. per installare risorse o pulire la cache, sarebbero +eseguiti nell'ambiente ``dev`` di Symfony. + +Questo comportamento non è quello desiderato, essendo l'applicazione in produzione (anche se +la si usa solo come esperimento o come stage), quindi ogni passo di build +dovrebbe usare lo stesso ambiente, ``prod``. + +Per fortuna, la soluzione al problema è molto semplice: Symfony cercherà una +variabile d'ambiente di nome ``SYMFONY_ENV`` e la userà, a meno che l'ambiente +non sia esplicitamente impostato. Heroku espone tutte le `variabili di configurazione`_ come +variabili d'ambiente, quindi basta un singolo comando per preparare il deploy: + +.. code-block:: bash + + $ heroku config:set SYMFONY_ENV=prod + +.. caution:: + + Fare attenzione, perché le dipendenze di ``composer.json`` elencate nella sezione ``require-dev`` + non sono mai installate, durante un deploy su Heroku. Questo potrebbe causare problemi, + se il proprio ambiente Symfony si appoggia a tali pacchetti. La soluzione è spostare i + pacchetti dall sezione ``require-dev`` alla sezione ``require``. + +.. _heroku-push-code: +.. _pushing-to-heroku: + +3) Push su Heroku +~~~~~~~~~~~~~~~~~ Il passo successivo è quello eseguire il deploy dell'applicazione su Heroku. La prima volta che lo si fa, si potrebbe vedere un messaggio simile al seguente: @@ -184,7 +225,15 @@ l'applicazione risponderà: $ heroku open Opening mighty-hamlet-1981... done -Si dovrebbe vedere l'applicazione Symfony2 nel browser. +Si dovrebbe vedere l'applicazione Symfony nel browser. + +.. caution:: + + Se si intraprendono i primi passi su Heroku usando una nuova installazione + di Symfony Standard Edition, si potrebbe ottenere una pagina di errore 404. + Questo perché la rotta per ``/`` è definita da AcmeDemoBundle, ma + AcmeDemoBundle è caricato solo in ambiente dev (lo si può verificare nella classe + ``AppKernel``). Provare ad aprire ``/app/example`` da AppBundle. .. _`articolo originale`: https://devcenter.heroku.com/articles/getting-started-with-symfony2 .. _`iscriversi a Heroku`: https://signup.heroku.com/signup/dc @@ -193,3 +242,5 @@ Si dovrebbe vedere l'applicazione Symfony2 nel browser. .. _`filesystem effimero`: https://devcenter.heroku.com/articles/dynos#ephemeral-filesystem .. _`Logplex`: https://devcenter.heroku.com/articles/logplex .. _`verified that the RSA key fingerprint is correct`: https://devcenter.heroku.com/articles/git-repository-ssh-fingerprints +.. _`comandi post-installazione`: https://getcomposer.org/doc/articles/scripts.md +.. _`variabili di configurazione`: https://devcenter.heroku.com/articles/config-vars diff --git a/cookbook/deployment/platformsh.rst b/cookbook/deployment/platformsh.rst index af77a17a..e5e0b584 100644 --- a/cookbook/deployment/platformsh.rst +++ b/cookbook/deployment/platformsh.rst @@ -4,4 +4,187 @@ Deploy su Platform.sh ===================== -(TODO da tradurre...) \ No newline at end of file +Questa ricetta descrive passo-passo il deploy di un'applicazione web Symfony su +`Platform.sh`_. Si può saperne di più sull'uso di Symfony con Platform.sh leggendo +la `documentazione di Platform.sh`_. + +Deploy di un sito esistente +--------------------------- + +In questa guida si ipotizzerà di avere del codice già versionato con Git. + +Creare un progetto su Platform.sh +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Ci seve iscrivere a un `progetto Platform.sh`_. Scegliere il piano sviluppo +e seguire il processo di checkout. Una volta che il progetto è pronto, dargli un nome +e scegliere **Import an existing site**. + +Preparare l'applicazione +~~~~~~~~~~~~~~~~~~~~~~~~ + +Per il deploy di u'applicazione Symfony su Platform.sh, basta aggiungere un file +``.platform.app.yaml`` nella radice del repository Git. Tale file dira à +Platform.sh come eseguire il deploy dell'applicazione (si possono approfondire i +`file di configurazione Platform.sh`_). + +.. code-block:: yaml + + # .platform.app.yaml + + # Questo file descrive un'applicazione. Si possono avere più applicazioni + # nello stesso progetto. + + # Il nome dell'app. Deve essere univoco in un progetto. + name: mioprogetto + + # Il toolstack usato per costruire l'applicazione. + toolstack: "php:symfony" + + # Le relazioni tra applicazione e servizi o altre applicazioni. + # La parte a sinistra è il nome della relazione, esposto + # all'applicazione nella variabile PLATFORM_RELATIONSHIPS. La parte + # destra è nella forma `:`. + relationships: + database: "mysql:mysql" + + # La configurazione dell'app, quando esposta al web. + web: + # La cartella pubblica dell'app, relativa alla sua radice. + document_root: "/web" + # Il front controller a cui inviare richieste non statiche. + passthru: "/app.php" + + # La dimensione del disco persistente dell'applicazione (in MB). + disk: 2048 + + # I percorsi da montare al deploy del pacchetto. + mounts: + "/app/cache": "shared:files/cache" + "/app/logs": "shared:files/logs" + + # Gli agganci da eseguire al deploy del pacchetto. + hooks: + build: | + rm web/app_dev.php + app/console --env=prod assetic:dump --no-debug + deploy: | + app/console --env=prod cache:clear + +Come best practice, si dovrebbe aggiungere una cartella ``.platform`` nella radice del +repository Git, con i seguenti file: + +.. code-block:: yaml + + # .platform/routes.yaml + "http://{default}/": + type: upstream + upstream: "php:php" + +.. code-block:: yaml + + # .platform/services.yaml + mysql: + type: mysql + disk: 2048 + +Si può trovare un esempio di queste configurazioni su `GitHub`_. L'elenco dei +`servizi disponibili`_ si trova nella documentazione di Platform.sh. + +Configurare l'accesso alla base dati +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Platform.sh sovrascrive la configurazione specifica della base dati, importando il +seguente file:: + + // app/config/parameters_platform.php + setParameter('database_driver', 'pdo_' . $endpoint['scheme']); + $container->setParameter('database_host', $endpoint['host']); + $container->setParameter('database_port', $endpoint['port']); + $container->setParameter('database_name', $endpoint['path']); + $container->setParameter('database_user', $endpoint['username']); + $container->setParameter('database_password', $endpoint['password']); + $container->setParameter('database_path', ''); + } + + # Memorizza la sessione in /tmp. + ini_set('session.save_path', '/tmp/sessions'); + +Assicurarsi che questo file sia negli *imports*: + +.. code-block:: yaml + + # app/config/config.yml + imports: + - { resource: parameters_platform.php } + +Deploy dell'applicazione +~~~~~~~~~~~~~~~~~~~~~~~~ + +Ora si deve aggiungere un remote verso Platform.sh nel repository Git (copiare il +comando visibile nell'interfaccia web di Platform.sh): + +.. code-block:: bash + + $ git remote add platform [ID-PROGETTO]@git.[CLUSTER].platform.sh:[ID-PROGETTO].git + +``ID-PROGETTO`` + Identificatore univoco del progetto. Qualcosa come ``kjh43kbobssae`` +``CLUSTER`` + Posizione del server verso cui avviene il deploy del progetto. Può essere ``eu`` oppure ``us`` + +Eseguire un commit dei file specifici di Platform.sh, creati nella sezione precedente: + +.. code-block:: bash + + $ git add .platform.app.yaml .platform/* + $ git add app/config/config.yml app/config/parameters_platform.php + $ git commit -m "Aggiunge i file di configurazione di Platform.sh" + +Eseguire un push al nuovo remote: + +.. code-block:: bash + + $ git push platform master + +Ecco fatto! Il deploy dell'applicazione su Platform.sh è concluso e presto si sarà in grado +di accedervi tramite browser. + +Si dovra eseguire d'ora in poi il push di ogni modifica del codice su Git, per eseguire +un nuovo deploy su Platform.sh. + +Si possono trovare più informazioni su `migrazione di basi dati e file `_ nella +documentazione di Platform.sh. + +Deploy di un nuovo sito +----------------------- + +Si può creare un nuovo `progetto Platform.sh`_. Scegliere il piano di sviluppo e +seguire il processo di checkout. + +Una volta pronto il progetto, dargli un nome e scegliere **Create a new site**. +Scegliere lo stack *Symfony* e un nuovo punto di partenza, come *Standard*. + +Fatto! L'applicazione Symfony sarà inizializzata e deployata. Sarà presto +visibile tramite browser. + +.. _`Platform.sh`: https://platform.sh +.. _`documentazione di Platform.sh`: https://docs.platform.sh/toolstacks/symfony/symfony-getting-started +.. _`progetto Platform.sh`: https://marketplace.commerceguys.com/platform/buy-now +.. _`file di configurazione Platform.sh`: https://docs.platform.sh/reference/configuration-files +.. _`GitHub`: https://github.com/platformsh/platformsh-examples +.. _`servizi disponibili`: https://docs.platform.sh/reference/configuration-files/#configure-services +.. _`migrate-existing-site`: https://docs.platform.sh/toolstacks/symfony/migrate-existing-site/ diff --git a/cookbook/deployment/tools.rst b/cookbook/deployment/tools.rst index 6deb59c1..97f6cf77 100644 --- a/cookbook/deployment/tools.rst +++ b/cookbook/deployment/tools.rst @@ -3,8 +3,8 @@ .. _how-to-deploy-a-symfony2-application: -Deploy di un'applicazione Symfony2 -================================== +Deploy di un'applicazione Symfony +================================= .. note:: @@ -14,10 +14,10 @@ Deploy di un'applicazione Symfony2 .. _symfony2-deployment-basics: -Basi per i deploy su Symfony2 ------------------------------ +Basi per i deploy su Symfony +---------------------------- -I tipici passi durante il deploy di un'applicazione Symfony2 includono: +I tipici passi durante il deploy di un'applicazione Symfony includono: #. Caricare il nuovo codice su un server; #. Aggiornare le dipendenze (tipicamente eseguito tramite Composer, potrebbe anche @@ -27,18 +27,19 @@ I tipici passi durante il deploy di un'applicazione Symfony2 includono: Un deploy può anche includere altro, come: -* Assegnazione di un tag a una versione del codice, come rilascio nel proprio repository di gestione dei sorgenti; +* Assegnazione di un tag a una versione del codice, come rilascio nel proprio repository + di gestione dei sorgenti; * Creazione di un'area di stage temporanea, per costruire il proprio ambiente aggiornato "offline"; * Esecuzione dei test disponibili, per assicurarsi la stabilità del codice e/o del server; -* Rimozione dei file non necessari da ``web``, per mantenere pulito l'ambiente di produzione; +* Rimozione dei file non necessari da ``web``, per mantenere pulito l'ambiente + di produzione; * Pulizia dei sistemi di cache esterni (come `Memcached`_ o `Redis`_). Come eseguire il deploy ----------------------- -Ci sono molti modi per eseguire il deploy di un'applicazione Symfony2. - -Iniziamo con alcune strategie di deploy di base. +Ci sono molti modi per eseguire il deploy di un'applicazione Symfony. Meglio iniziare con poche +strategie di base e poi incrementare. Trasferimento semplice di file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -63,11 +64,38 @@ Uso di script e di altri strumenti ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Ci sono alcuni strumenti di alta qualità, che facilitano i deploy. Alcuni di questi -sono stati adattati in modo specifico ai requisiti di -Symfony2, assicurandosi di tenere conto di ogni cosa prima, durante e -dopo che un deploy sia stato eseguito correttamente. +sono stati adattati in modo specifico ai requisiti di Symfony. + +`Capifony`_ + Fornisce un insieme specializzato di strumenti basati su Capistrano, adattati in + modo specifico per i progetti symfony e Symfony. + +`sf2debpkg`_ + Aiuta a costruire un pacchetto Debian nativo per un progetto Symfony. + +`Magallanes`_ + Simile a Capistrano, ma scritto in PHP, potrebbe essere più facile + per uno sviluppatore PHP da estendere in base alle necessità. -Vedere `Strumenti`_ per un elenco di strumenti che possono aiutare con i deploy. +`Fabric`_ + Questa libreria, scritta in Python, fornisce un insieme basilare di operazioni per eseguire + comandi da terminale in locale o in remoto, nonché caricamento e scaricamento di file. + +Bundle + Ci sono molti `bundle che aggiungono strumenti di deploy`_ direttamente alla + console di Symfony. + +Script di base + Ovviamente si può usare il terminale, `Ant`_ o altri strumenti di script per + il deploy di un progetto. + +Fornitori di PaaS + Il ricettario di Symfony include varie ricette per alcuni dei più noti fornitori + di PaaS: + + * :doc:`Microsoft Azure ` + * :doc:`Heroku ` + * :doc:`Platform.sh ` Azioni comuni post-deploy ------------------------- @@ -87,9 +115,8 @@ Verificare che il server soddisfi i requisiti, eseguendo: B) Configurare il file ``app/config/parameters.yml`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Questo file andrebbe personalizzato su ogni sistema. Il metodo usato per il -deploy del codice *non* dovrebbe modificare questo file. Invece, lo si dovrebbe -modificare manualmente (o tramite un processo) direttamente sul server. +Questo file *non* dovrebbe essere incluso nel deploy, ma gestito tramite utilità automatiche +fornite da Symfony. C) Aggiornare i venditori ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -101,14 +128,13 @@ fa normalmente: .. code-block:: bash - $ php composer.phar install --no-dev --optimize-autoloader + $ composer install --no-dev --optimize-autoloader .. tip:: L'opzione ``--optimize-autoloader`` rende l'autoloader di Composer più performante, costruendo una "mappa di classi". L'opzionoe ``--no-dev`` - assicura che i pacchetti di sviluppo non siano installati in ambiente - di produzione. + assicura che i pacchetti di sviluppo non siano installati in ambiente di produzione. .. caution:: @@ -163,51 +189,12 @@ Non dimenticare che il deploy di un'applicazione coinvolge anche l'aggiornamento (tipicamente via Composer), migrazioni della base dati, pulizia della cache e altre possibili questioni, come inviare risorse a un CDN (vedere `Azioni comuni post-deploy`_). -Strumenti ---------- - -`Capifony`_: - - Fornisce un insieme specializzato di strumenti basati su Capistrano, adattati in - modo specifico per i progetti symfony e Symfony2. - -`sf2debpkg`_: - - Aiuta a costruire un pacchetto Debian nativo per un progetto Symfony2. - -`Magallanes`_: - - Simile a Capistrano, ma scritto in PHP, potrebbe essere più facile - per uno sviluppatore PHP da estendere in base alle necessità. - -Bundle: - - Ci sono molti `bundle che aggiungono strumenti di deploy`_ direttamente alla - console di Symfony2. - -Script di base: - - Ovviamente si può usare il terminale, `Ant`_ o altri strumenti di script per - il deploy di un progetto. - -Fornitori di PaaS: - - Un modo relativamente nuovo per il deploy è rappresentato dai PaaS. Tipicamente, un PaaS - userà un singolo file di configurazione nella cartella radice del progetto per - determinare come costruire al volo un ambiente che supporti il proprio software. - Un fornitore che ha confermato supporto a Symfony2 è `PagodaBox`_. - -.. tip:: - - In cerca di altro? Si può parlare con la comunità sul `canale IRC di Symfony`_ #symfony - (su freenode) per maggiori informazioni. - .. _`Capifony`: http://capifony.org/ +.. _`Capistrano`: http://capistranorb.com/ .. _`sf2debpkg`: https://github.com/liip/sf2debpkg -.. _`Ant`: http://blog.sznapka.pl/deploying-symfony2-applications-with-ant -.. _`PagodaBox`: https://github.com/jmather/pagoda-symfony-sonata-distribution/blob/master/Boxfile +.. _`Fabric`: http://www.fabfile.org/ .. _`Magallanes`: https://github.com/andres-montanez/Magallanes +.. _`Ant`: http://blog.sznapka.pl/deploying-symfony2-applications-with-ant .. _`bundle che aggiungono strumenti di deploy`: http://knpbundles.com/search?q=deploy -.. _`canale IRC di Symfony`: http://webchat.freenode.net/?channels=symfony .. _`Memcached`: http://memcached.org/ .. _`Redis`: http://redis.io/ diff --git a/cookbook/doctrine/common_extensions.rst b/cookbook/doctrine/common_extensions.rst index 7397faba..dc2e814f 100644 --- a/cookbook/doctrine/common_extensions.rst +++ b/cookbook/doctrine/common_extensions.rst @@ -20,7 +20,7 @@ Per farlo, si hanno due possibilità: #. Usare `StofDoctrineExtensionsBundle`_, che integra la libreria di cui sopra. #. Implementare questi servizi direttamente, seguendo la documentazione per l'integrazione - con Symfony2: `installare le estensioni Gedmo di Doctrine2 in Symfony2`_ + con Symfony: `installare le estensioni Gedmo di Doctrine2 in Symfony`_ .. _`DoctrineExtensions`: https://github.com/l3pp4rd/DoctrineExtensions .. _`StofDoctrineExtensionsBundle`: https://github.com/stof/StofDoctrineExtensionsBundle @@ -30,4 +30,4 @@ Per farlo, si hanno due possibilità: .. _`Loggable`: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/loggable.md .. _`Tree`: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/tree.md .. _`Sortable`: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/sortable.md -.. _`installare le estensioni Gedmo di Doctrine2 in Symfony2`: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/symfony2.md +.. _`installare le estensioni Gedmo di Doctrine2 in Symfony`: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/symfony2.md diff --git a/cookbook/doctrine/file_uploads.rst b/cookbook/doctrine/file_uploads.rst index 42e5ecd4..515ea83c 100644 --- a/cookbook/doctrine/file_uploads.rst +++ b/cookbook/doctrine/file_uploads.rst @@ -213,7 +213,7 @@ regole di validazione:: .. note:: - Grazie al fatto che si utilizza il vincolo ``File``, Symfony2 ipotizzerà + Grazie al fatto che si utilizza il vincolo ``File``, Symfony ipotizzerà automaticamente che il campo del form sia un file upload. È per questo motivo che non si rende necessario impostarlo esplicitamente al momento di creazione del form precedente (``->add('file')``). diff --git a/cookbook/doctrine/multiple_entity_managers.rst b/cookbook/doctrine/multiple_entity_managers.rst index c137edf6..8b6932af 100644 --- a/cookbook/doctrine/multiple_entity_managers.rst +++ b/cookbook/doctrine/multiple_entity_managers.rst @@ -4,7 +4,7 @@ Lavorare con gestori di entità multipli ======================================= -Si possono usare gestori di entità multipli in un'applicazione Symfony2. +Si possono usare gestori di entità multipli in un'applicazione Symfony. Questo si rende necessario quando si usano diverse basi dati o addirittura venditori con insiemi di entità completamente differenti. In altre parole, un gestore di entità che si connette a una base dati gestirà alcune entità, mentre un altro gestore di entità @@ -49,7 +49,7 @@ La configurazione seguente mostra come configurare due gestori di entità: default: connection: default mappings: - AcmeDemoBundle: ~ + AppBundle: ~ AcmeStoreBundle: ~ customer: connection: customer @@ -90,7 +90,7 @@ La configurazione seguente mostra come configurare due gestori di entità: - + @@ -134,7 +134,7 @@ La configurazione seguente mostra come configurare due gestori di entità: 'default' => array( 'connection' => 'default', 'mappings' => array( - 'AcmeDemoBundle' => null, + 'AppBundle' => null, 'AcmeStoreBundle' => null, ), ), @@ -150,8 +150,8 @@ La configurazione seguente mostra come configurare due gestori di entità: In questo caso, sono stati definiti due gestori di entità, chiamati ``default`` e ``customer``. Il gestore di entità ``default`` gestisce le entità in -``AcmeDemoBundle`` e ``AcmeStoreBundle``, mentre il gestore di entità ``customer`` -gestisce le entità in ``AcmeCustomerBundle``. Sono state definite anche due +AppBundle e AcmeStoreBundle, mentre il gestore di entità ``customer`` +gestisce le entità in AcmeCustomerBundle. Sono state definite anche due connessioni, una per ogni gestore di entità. .. note:: diff --git a/cookbook/email/cloud.rst b/cookbook/email/cloud.rst index 0c52116e..e97b778f 100644 --- a/cookbook/email/cloud.rst +++ b/cookbook/email/cloud.rst @@ -46,8 +46,10 @@ e completare la configurazione con ``username`` e ``password`` forniti: + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/swiftmailer + http://symfony.com/schema/dic/swiftmailer/swiftmailer-1.0.xsd"> - + .. code-block:: php @@ -115,15 +114,15 @@ l'indirizzo sostituito, così da poter vedere a chi sarebbe stata inviata l'emai .. note:: Oltre alle email inviate all'indirizzo ``to``, questa configurazione - blocca anche quelle inviate a qualsiasi indirizzo ``CC`` e ``BCC``. - Swiftmailer aggiungerà ulteriori intestazioni contenenti gli indirizzi - ignorati. Le intestazioni usate saranno ``X-Swift-Cc`` e ``X-Swift-Bcc`` + blocca anche quelle inviate a qualsiasi indirizzo ``CC`` e ``BCC``. Swift Mailer + aggiungerà ulteriori intestazioni contenenti gli indirizzi ignorati. + Le intestazioni usate saranno ``X-Swift-Cc`` e ``X-Swift-Bcc`` rispettivamente per gli indirizzi in ``CC`` e per quelli in ``BCC``. -Visualizzazione tramite Web Debug Toolbar ------------------------------------------ +Visualizzazione tramite barra di debug +-------------------------------------- -Utilizzando la Web Debug Toolbar è possibile visualizzare le email inviate +Utilizzando la barra di debug, è possibile visualizzare le email inviate durante la singola risposta nell'ambiente ``dev``. L'icona dell'email apparirà nella barra mostrando quante email sono state spedite. Cliccandoci sopra, un rapporto mostrerà il dettaglio delle email inviate. diff --git a/cookbook/email/email.rst b/cookbook/email/email.rst index 830cf2aa..98053eb0 100644 --- a/cookbook/email/email.rst +++ b/cookbook/email/email.rst @@ -7,30 +7,25 @@ Spedire un'email Spedire email è una delle azioni classiche di ogni applicazione web, ma rappresenta anche l'origine di potenziali problemi e complicazioni. Invece di reinventare la ruota, una soluzione per l'invio di email è l'uso di -``SwiftmailerBundle``, il quale sfrutta la potenza della libreria `Swiftmailer`_. - -.. note:: - - Non dimenticare di abilitare il bundle all'interno del kernel prima di utilizzarlo:: - - public function registerBundles() - { - $bundles = array( - // ... - - new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), - ); - - // ... - } +``SwiftmailerBundle``, il quale sfrutta la potenza della libreria `Swift Mailer`_. +Questo bundle fa parte di Symfony Standard Edition. .. _swift-mailer-configuration: Configurazione -------------- -Prima di utilizzare Swiftmailer, assicurarsi di includerne la configurazione. -L'unico parametro obbligatorio della configurazione è il parametro ``transport``: +Per usare Swift Mailer, occorre configurarlo per il server di posta. + +.. tip:: + + Invece di usare un server di posta interno, si potrebbe voler usare + un fornitore con hosting, come `Mandrill`_, `SendGrid`_, `Amazon SES`_ + o altri. In questo modo si ottiene un server SMTP, username e password (a volte + chiamate chiavi), da usare con la configirazione di Swift Mailer. + +In una tipica installazione di Symfony è già inclusa una configurazione +per ``swiftmailer``: .. configuration-block:: @@ -38,12 +33,10 @@ L'unico parametro obbligatorio della configurazione è il parametro ``transport` # app/config/config.yml swiftmailer: - transport: smtp - encryption: ssl - auth_mode: login - host: smtp.gmail.com - username: nome_utente - password: password + transport: "%mailer_transport%" + host: "%mailer_host%" + username: "%mailer_user%" + password: "%mailer_password%" .. code-block:: xml @@ -55,27 +48,24 @@ L'unico parametro obbligatorio della configurazione è il parametro ``transport` --> + transport="%mailer_transport%" + host="%mailer_host%" + username="%mailer_user%" + password="%mailer_password%" /> .. code-block:: php // app/config/config.php $container->loadFromExtension('swiftmailer', array( - 'transport' => "smtp", - 'encryption' => "ssl", - 'auth_mode' => "login", - 'host' => "smtp.gmail.com", - 'username' => "nome_utente", - 'password' => "password", + 'transport' => "%mailer_transport%", + 'host' => "%mailer_host%", + 'username' => "%mailer_user%", + 'password' => "%mailer_password%", )); -La maggior parte della configurazione di Swiftmailer è relativa al come -i messaggi debbano essere inoltrati. +Questi valori (come ``%mailer_transport%``) sono presi dai parametri, +impostati nel file :ref:`parameters.yml `. Si possono +modificare i valori lì o direttamente qui. Sono disponibili i seguenti parametri di configurazione: @@ -103,18 +93,31 @@ In generale, spedire un'email è abbastanza intuitivo:: public function indexAction($nome) { - $messaggio = \Swift_Message::newInstance() + $mailer = $this->get('mailer'); + $messaggio = $mailer->createMessage() ->setSubject('Ciao') ->setFrom('mittente@example.com') ->setTo('destinatario@example.com') ->setBody( $this->renderView( - 'HelloBundle:Hello:email.txt.twig', + // app/Resources/views/Emails/registrazione.html.twig + 'Emails/registration.html.twig', + array('nome' => $nome) + ), + 'text/html' + ) + /* + * Se si vuole includere anche una parte in testo semplice + ->addPart( + $this->renderView( + 'Emails/registrazione.txt.twig', array('nome' => $nome) - ) + ), + 'text/plain' ) + */ ; - $this->get('mailer')->send($messaggio); + $mailer->send($messaggio); return $this->render(...); } @@ -123,17 +126,20 @@ Per tenere i vari aspetti separati, il corpo del messaggio è stato salvato in un template che viene poi restituito tramite il metodo ``renderView()``. L'oggetto ``$messaggio`` supporta molte altre opzioni, come l'aggiunta di allegati, -l'inserimento di HTML e molto altro. Fortunatamente la documentazione di Swiftmailer affronta +l'inserimento di HTML e molto altro. Fortunatamente la documentazione di Swift Mailer affronta questo argomento dettagliatamente nel capitolo sulla `creazione di messaggi`_ . .. tip:: Diversi altri articoli di questo ricettario spiegano come spedire le - email in Symfony2: + email in Symfony: * :doc:`gmail` * :doc:`dev_environment` * :doc:`spool` -.. _`Swiftmailer`: http://swiftmailer.org/ +.. _`Swift Mailer`: http://swiftmailer.org/ .. _`creazione di messaggi`: http://swiftmailer.org/docs/messages.html +.. _`Mandrill`: https://mandrill.com/ +.. _`SendGrid`: https://sendgrid.com/ +.. _`Amazon SES`: http://aws.amazon.com/ses/ diff --git a/cookbook/email/gmail.rst b/cookbook/email/gmail.rst index 1428a93f..c2f7ecd4 100644 --- a/cookbook/email/gmail.rst +++ b/cookbook/email/gmail.rst @@ -33,8 +33,10 @@ l'opzione ``gmail`` e ai parametri ``username`` e ``password`` le credenziali de + xsi:schemaLocation="http://symfony.com/schema/dic/services + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/swiftmailer + http://symfony.com/schema/dic/swiftmailer/swiftmailer-1.0.xsd"> @@ -49,7 +50,7 @@ Swiftmailer con l'opzione memory, usare la seguente configurazione: // app/config/config.php $container->loadFromExtension('swiftmailer', array( - ..., + // ... 'spool' => array('type' => 'memory') )); @@ -75,7 +76,8 @@ Per usare lo spool con un file, usare la seguente configurazione: diff --git a/cookbook/email/testing.rst b/cookbook/email/testing.rst index 081cf5c4..a7c41168 100644 --- a/cookbook/email/testing.rst +++ b/cookbook/email/testing.rst @@ -4,11 +4,11 @@ Testare l'invio di un'email in un test funzionale ================================================= -L'invio di email con Symfony2 è alquanto semplice, grazie a -``SwiftmailerBundle``, che sfrutta la potenza della libreria `Swiftmailer`_. +L'invio di email con Symfony è alquanto semplice, grazie a +SwiftmailerBundle, che sfrutta la potenza della libreria `Swift Mailer`_. Per testare in modo funzionale l'invio di un'email, anche facendo asserzioni su oggetto -o contenuto dell'email, o su qualsiasi altro header, si può usare il :ref:`profilatore di Symfony2 `. +o contenuto dell'email, o su qualsiasi altro header, si può usare il :ref:`profilatore di Symfony `. Iniziamo con una semplice azione in un controllore, che invia un'email:: @@ -33,7 +33,7 @@ Iniziamo con una semplice azione in un controllore, che invia un'email:: Nel test funzionale, usare il raccoglitore ``swiftmailer`` del profilatore, per ottnere informazioni sui messaggi inviati nella richiesta precedente:: - // src/Acme/DemoBundle/Tests/Controller/MailControllerTest.php + // src/AppBundle/Tests/Controller/MailControllerTest.php use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class MailControllerTest extends WebTestCase @@ -67,4 +67,4 @@ per ottnere informazioni sui messaggi inviati nella richiesta precedente:: } } -.. _Swiftmailer: http://swiftmailer.org/ +.. _`Swift Mailer`: http://swiftmailer.org/ diff --git a/cookbook/event_dispatcher/before_after_filters.rst b/cookbook/event_dispatcher/before_after_filters.rst index c2f34cc7..17a9cbff 100755 --- a/cookbook/event_dispatcher/before_after_filters.rst +++ b/cookbook/event_dispatcher/before_after_filters.rst @@ -9,7 +9,7 @@ po' di logica subito prima o subito dopo che l'azione di un controllore abbia ag filtro o da hook. In Symfony1 lo si poteva fare con i metodi preExecute e postExecute e ci sono metodi -simili in molti grossi framework, ma non in Symfony2. +simili in molti grossi framework, ma non in Symfony. La buona notizia è che c'è un modo molto migliore per intervenire nel processo richiesta/risposta, usando il componente EventDispatcher. @@ -125,7 +125,7 @@ eventi, si possono ottenere maggiori informazioni su :doc:`/cookbook/service_con $controller = $event->getController(); /* - * $controller passato può essere una classe o una Closure. Non è frequente in Symfony2 ma può accadere. + * $controller passato può essere una classe o una Closure. Non è frequente in Symfony ma può accadere. * Se è una classe, è in formato array */ if (!is_array($controller)) { diff --git a/cookbook/form/data_transformers.rst b/cookbook/form/data_transformers.rst index 037ace64..844df014 100644 --- a/cookbook/form/data_transformers.rst +++ b/cookbook/form/data_transformers.rst @@ -17,6 +17,11 @@ Lo si potrebbe fare nel controllore, ma non è la soluzione migliore. Sarebbe meglio se questa issue fosse cercata automaticamente e convertita in un oggetto Issue. In questi casi entrano in gioco i trasformatori di dati. +.. caution:: + + Quando un campo ha l'opzione ``inherit_data`` impostata, i trasformatori di dati + non saranno applicati. + Creare il trasformatore ----------------------- @@ -47,7 +52,7 @@ della conversione da numero di issue a oggetto Issue e viceversa:: } /** - * Transforms an object (issue) to a string (number). + * Trasforma un oggetto (issue) in una stringa (number). * * @param Issue|null $issue * @return string @@ -62,13 +67,13 @@ della conversione da numero di issue a oggetto Issue e viceversa:: } /** - * Transforms a string (number) to an object (issue). + * Trasforma una stringa (number) in un oggetto (issue). * * @param string $number * * @return Issue|null * - * @throws TransformationFailedException if object (issue) is not found. + * @throws TransformationFailedException se l'oggetto (issue) non viene trovato. */ public function reverseTransform($number) { @@ -83,7 +88,7 @@ della conversione da numero di issue a oggetto Issue e viceversa:: if (null === $issue) { throw new TransformationFailedException(sprintf( - 'An issue with number "%s" does not exist!', + 'Non essite una issue con numero "%s"!', $number )); } @@ -94,7 +99,7 @@ della conversione da numero di issue a oggetto Issue e viceversa:: .. tip:: - Se si vuole che sia create una nuova issue all'inserimento di un numero non trovato, si + Se si vuole che sia creata una nuova issue all'inserimento di un numero non trovato, si può crearne l'istanza invece di lanciare ``TransformationFailedException``. .. note:: @@ -109,49 +114,47 @@ Usare il trasformatore Dopo aver creato il trasformatore, basta aggiungerlo al campo issue in un form. - Si possono anche usare i trasformatori senza creare un nuovo tipo di form, - richiamando ``addModelTransformer`` (o ``addViewTransformer``, vedere - `Trasformatore per modelli e viste`_) sul builder di un campo:: +Si possono anche usare i trasformatori senza creare un nuovo tipo di form, +richiamando ``addModelTransformer`` (o ``addViewTransformer``, vedere +`Trasformatore per modelli e viste`_) sul builder di un campo:: - use Symfony\Component\Form\FormBuilderInterface; - use Acme\TaskBundle\Form\DataTransformer\IssueToNumberTransformer; + use Symfony\Component\Form\FormBuilderInterface; + use Acme\TaskBundle\Form\DataTransformer\IssueToNumberTransformer; - class TaskType extends AbstractType + class TaskType extends AbstractType + { + public function buildForm(FormBuilderInterface $builder, array $options) { - public function buildForm(FormBuilderInterface $builder, array $options) - { - // ... - - // si assume che il gestore di entità sia stato passato come opzione - $entityManager = $options['em']; - $transformer = new IssueToNumberTransformer($entityManager); - - // aggiunge un normale campo testuale, ma vi aggiunge il trasformatore - $builder->add( - $builder->create('issue', 'text') - ->addModelTransformer($transformer) - ); - } + // ... - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver - ->setDefaults(array( - 'data_class' => 'Acme\TaskBundle\Entity\Task', - )) - ->setRequired(array( - 'em', - )) - ->setAllowedTypes(array( - 'em' => 'Doctrine\Common\Persistence\ObjectManager', - )); - - // ... - } + // "em" è un'opzione da passare alla creazione del form. Vedere + // il terzo parametro di createForm nel prossimo blocco di codice per capire + // in che modo è passata al form (vedere anche setDefaultOptions). + $entityManager = $options['em']; + $transformer = new IssueToNumberTransformer($entityManager); + + // aggiunge un normale campo testuale, ma vi aggiunge il trasformatore + $builder->add( + $builder->create('issue', 'text') + ->addModelTransformer($transformer) + ); + } + + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver + ->setDefaults(array( + 'data_class' => 'Acme\TaskBundle\Entity\Task', + )) + ->setRequired(array('em')) + ->setAllowedTypes('em', 'Doctrine\Common\Persistence\ObjectManager') // ... } + // ... + } + Questo esempio richiede il passaggio del gestore di entità come opzione, al momento di creare il form. Successivamente, si vedrà come si può creare un tipo di campo ``issue`` personalizzato, per evitare di doverlo fare nel controllore:: @@ -280,7 +283,7 @@ Prima di tutto, creare una classe:: public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( - 'invalid_message' => 'The selected issue does not exist', + 'invalid_message' => 'La issue scelta non esiste', )); } diff --git a/cookbook/form/dynamic_form_modification.rst b/cookbook/form/dynamic_form_modification.rst index a7e0d067..b7eece27 100644 --- a/cookbook/form/dynamic_form_modification.rst +++ b/cookbook/form/dynamic_form_modification.rst @@ -4,23 +4,23 @@ Modificare dinamicamente form usando gli eventi =============================================== -Capita spesso che non un form non possa essere creato staticamente. In questa ricetta +Capita spesso che un form non possa essere creato staticamente. In questa ricetta vedremo come personalizzare un form, in base a tre casi d'uso. 1) :ref:`cookbook-form-events-underlying-data` -Eesempio: si ha un form "Product" e occorre modificare/aggiungere/rimuovere un campo, +Esempio: si ha un form "Product" e occorre modificare/aggiungere/rimuovere un campo, in base ai dati sull'oggetto Product sottostante. 2) :ref:`cookbook-form-events-user-data` -Eesempio: si crea un form "Friend Message" e occorre costruire un menù a tendina, +Esempio: si crea un form "Friend Message" e occorre costruire un menù a tendina, che contenga solo utenti che sono amici dell'utente attualmente autenticato. 3) :ref:`cookbook-form-events-submitted-data` -Eesempio: in un form di registrazione, si ha un campo "country" e un campo "state", +Esempio: in un form di registrazione, si ha un campo "country" e un campo "state", che va popolato automaticamente in base al valore del campo "country". @@ -36,8 +36,8 @@ Personalizzare un form in base ai dati sottostanti Prima di addentrarci nella generazione dinamica dei form, diamo un'occhiata veloce alla classe dei form:: - // src/Acme/DemoBundle/Form/Type/ProductType.php - namespace Acme\DemoBundle\Form\Type; + // src/AppBundle/Form/Type/ProductType.php + namespace AppBundle\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -54,7 +54,7 @@ alla classe dei form:: public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( - 'data_class' => 'Acme\DemoBundle\Entity\Product' + 'data_class' => 'AppBundle\Entity\Product' )); } @@ -77,7 +77,7 @@ oppure se sta per essere modificato un prodotto esistente (cioè un prodotto ott Si supponga ora di non voler abilitare l'utente alla modifica del campo ``name``, una volta che l'oggetto è stato creato. Lo si può fare grazie al componente -:doc:`Event Dispatcher `, +:doc:`EventDispatcher `, che analizza l'oggetto e modifica il form basato sull' oggetto Product. In questa ricetta si imparerà come aggiungere questo livello di flessibilità ai form. @@ -90,8 +90,8 @@ Aggiungere un ascoltatore di eventi alla classe di un form Quindi, invece di aggiungere direttamente ``name``, la responsabilità di creare tale campo è delegata a un ascoltatore di eventi:: - // src/Acme/DemoBundle/Form/Type/ProductType.php - namespace Acme\DemoBundle\Form\Type; + // src/AppBundle/Form/Type/ProductType.php + namespace AppBundle\Form\Type; // ... use Symfony\Component\Form\FormEvent; @@ -120,14 +120,14 @@ l'ascoltatore di eventi potrebbe somigliare a questo:: public function buildForm(FormBuilderInterface $builder, array $options) { // ... - $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){ + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { $product = $event->getData(); $form = $event->getForm(); // verifica se l'oggetto Product sia "nuovo" // Se non sono stati passati dati al form, i dati sono "null". // Questo va considerato un nuovo Product - if (!$product || null !== $product->getId()) { + if (!$product || null === $product->getId()) { $form->add('name', 'text'); } }); @@ -151,11 +151,11 @@ Per una migliore riusabilità o se c'è della logica in un ascoltatore di eventi si può spostare la logica per creare il campo ``name`` in un :ref:`sottoscrittore di eventi `:: - // src/Acme/DemoBundle/Form/Type/ProductType.php - namespace Acme\DemoBundle\Form\Type; + // src/AppBundle/Form/Type/ProductType.php + namespace AppBundle\Form\Type; // ... - use Acme\DemoBundle\Form\EventListener\AddNameFieldSubscriber; + use AppBundle\Form\EventListener\AddNameFieldSubscriber; class ProductType extends AbstractType { @@ -172,8 +172,8 @@ si può spostare la logica per creare il campo ``name`` in un Ora la logica per creare il campo ``name`` si trova nella propria classe sottoscrittore:: - // src/Acme/DemoBundle/Form/EventListener/AddNameFieldSubscriber.php - namespace Acme\DemoBundle\Form\EventListener; + // src/AppBundle/Form/EventListener/AddNameFieldSubscriber.php + namespace AppBundle\Form\EventListener; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; @@ -216,8 +216,8 @@ Creare il form Type Usando un ascoltatore di eventi, il form potrebbe assomigliare a questo:: - // src/Acme/DemoBundle/Form/Type/FriendMessageFormType.php - namespace Acme\DemoBundle\Form\Type; + // src/AppBundle/Form/Type/FriendMessageFormType.php + namespace AppBundle\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -234,14 +234,14 @@ Usando un ascoltatore di eventi, il form potrebbe assomigliare a questo:: ->add('subject', 'text') ->add('body', 'textarea') ; - $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event){ + $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) { // ... aggiungere una lista di amici dell'utente attuale }); } public function getName() { - return 'acme_friend_message'; + return 'friend_message'; } public function setDefaultOptions(OptionsResolverInterface $resolver) @@ -278,7 +278,7 @@ Personalizzare il Form Type Ora che si dispone di tutto il necessario, si può sfruttare ``securityContext`` e scrivere la logica dell'ascoltatore:: - // src/Acme/DemoBundle/FormType/FriendMessageFormType.php + // src/AppBundle/FormType/FriendMessageFormType.php use Symfony\Component\Security\Core\SecurityContext; use Doctrine\ORM\EntityRepository; @@ -314,7 +314,7 @@ e scrivere la logica dell'ascoltatore:: $form = $event->getForm(); $formOptions = array( - 'class' => 'Acme\DemoBundle\Entity\User', + 'class' => 'AppBundle\Entity\User', 'property' => 'fullName', 'query_builder' => function (EntityRepository $er) use ($user) { // usare una query personalizzata @@ -384,29 +384,29 @@ Per definire il form come servizio, creare un normale serizio e aggiungere il ta # app/config/config.yml services: - acme.form.friend_message: - class: Acme\DemoBundle\Form\Type\FriendMessageFormType + app.form.friend_message: + class: AppBundle\Form\Type\FriendMessageFormType arguments: ["@security.context"] tags: - - { name: form.type, alias: acme_friend_message } + - { name: form.type, alias: friend_message } .. code-block:: xml - + - + .. code-block:: php // app/config/config.php - $definition = new Definition('Acme\DemoBundle\Form\Type\FriendMessageFormType'); - $definition->addTag('form.type', array('alias' => 'acme_friend_message')); + $definition = new Definition('AppBundle\Form\Type\FriendMessageFormType'); + $definition->addTag('form.type', array('alias' => 'friend_message')); $container->setDefinition( - 'acme.form.friend_message', + 'app.form.friend_message', $definition, array('security.context') ); @@ -420,7 +420,7 @@ al form factory, si può usare:: { public function newAction(Request $request) { - $form = $this->get('form.factory')->create('acme_friend_message'); + $form = $this->get('form.factory')->create('friend_message'); // ... } @@ -428,14 +428,14 @@ al form factory, si può usare:: Se si estende la classe ``Symfony\Bundle\FrameworkBundle\Controller\Controller``, basta chiamare:: - $form = $this->createForm('acme_friend_message'); + $form = $this->createForm('friend_message'); Si può anche includere il form type in un altro form:: // dentro un'altra classe "form type" public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('message', 'acme_friend_message'); + $builder->add('message', 'friend_message'); } .. _cookbook-form-events-submitted-data: @@ -454,8 +454,8 @@ le opzioni giuste impostate, per poter passare la validazione. La riunione sarà passata come campo nascosto al form. In questo modo si può accedere a ciascuno sport in questo modo:: - // src/Acme/DemoBundle/Form/Type/SportMeetupType.php - namespace Acme\DemoBundle\Form\Type; + // src/AppBundle/Form/Type/SportMeetupType.php + namespace AppBundle\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -469,7 +469,7 @@ accedere a ciascuno sport in questo modo:: { $builder ->add('sport', 'entity', array( - 'class' => 'AcmeDemoBundle:Sport', + 'class' => 'AppBundle:Sport', 'empty_value' => '', )) ; @@ -523,12 +523,12 @@ nuovo campo automaticamente e lo mapperà ai dati inviati dal client. La classe ora sarà così:: - // src/Acme/DemoBundle/Form/Type/SportMeetupType.php - namespace Acme\DemoBundle\Form\Type; + // src/AppBundle/Form/Type/SportMeetupType.php + namespace AppBundle\Form\Type; // ... use Symfony\Component\Form\FormInterface; - use Acme\DemoBundle\Entity\Sport; + use AppBundle\Entity\Sport; class SportMeetupType extends AbstractType { @@ -536,7 +536,7 @@ La classe ora sarà così:: { $builder ->add('sport', 'entity', array( - 'class' => 'AcmeDemoBundle:Sport', + 'class' => 'AppBundle:Sport', 'empty_value' => '', )); ; @@ -545,7 +545,7 @@ La classe ora sarà così:: $positions = null === $sport ? array() : $sport->getAvailablePositions(); $form->add('position', 'entity', array( - 'class' => 'AcmeDemoBundle:Position', + 'class' => 'AppBundle:Position', 'empty_value' => '', 'choices' => $positions, )); @@ -587,13 +587,13 @@ Un pezzo ancora mancante è l'aggiornamento lato client del form, dopo la scelta dello sport. Lo si può gestire tramite una chiamata AJAX all'applicazione. Ipotizzando di avere un controllore per la creazione:: - // src/Acme/DemoBundle/Controller/MeetupController.php - namespace Acme\DemoBundle\Controller; + // src/AppBundle/Controller/MeetupController.php + namespace AppBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; - use Acme\DemoBundle\Entity\SportMeetup; - use Acme\DemoBundle\Form\Type\SportMeetupType; + use AppBundle\Entity\SportMeetup; + use AppBundle\Form\Type\SportMeetupType; // ... class MeetupController extends Controller @@ -608,7 +608,7 @@ all'applicazione. Ipotizzando di avere un controllore per la creazione:: } return $this->render( - 'AcmeDemoBundle:Meetup:create.html.twig', + 'AppBundle:Meetup:create.html.twig', array('form' => $form->createView()) ); } @@ -623,7 +623,7 @@ a seconda del valore selezionato nel campo ``sport``: .. code-block:: html+jinja - {# src/Acme/DemoBundle/Resources/views/Meetup/create.html.twig #} + {# src/AppBundle/Resources/views/Meetup/create.html.twig #} {{ form_start(form) }} {{ form_row(form.sport) }} {#