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 }}
by {{ article.authorName }}
@@ -523,7 +523,7 @@ template. Primo, creare il template che occorrerà riusare.
.. code-block:: html+php
-
+
getTitle() ?>
by getAuthorName() ?>
@@ -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 %}