Dopo aver introdotto brevemente come vengono gestite le rotte, i controllori e le viste in Symfony2, iniziamo ora ad approfondire le rotte e tutte le loro caratteristiche. Abbiamo visto che una rotta è una regola con cui Symfony Framework è in grado di associare un controllore ad un URL. Nella lezione precedente abbiamo visto quella di default contenuta all’interno del file src/Acme/DemoBundle/Resources/config/routing.yml
:
_welcome:
path: /
defaults: { _controller: AcmeDemoBundle:Welcome:index }
in cui associavamo il path /
(cioè la Home Page) al metodo indexAction
contenuto nella classe WelcomeController
.
Iniziamo quindi a creare le nostre rotte per vedere all’opera tutto il loro potenziale. Aggiungiamo alla fine del file routing.yml
la nostra regola:
_test:
path: /test
defaults: { _controller: AcmeDemoBundle:Welcome:test }
La regola è identica alla precedente, abbiamo semplicemente detto a Symfony che vogliamo lanciare il controller WelcomeController::testAction()
quando apriamo il browser sulla pagina /test
.
All’interno del file src/Acme/DemoBundle/Controller/WelcomeController.php
creiamo un metodo testAction
come il seguente:
public function testAction()
{
echo "Hello World!";
die();
}
Ora, aprendo il nostro browser al path /test
dovremmo visualizzare la stringa “Hello World!”. Questo metodo sarà la nostra base di partenza per studiare tutte le proprietà del routing.
Nota: per ora il metodo termina volutamente con una die()
; approfondiremo nella lezione relativa ai controllori il valore di ritorno di un controller.
Parametri
Finora abbiamo visto solo regole di routing semplici che mostravano una determinata pagina. Iniziamo ora ad analizzare il passaggio di parametri, chiamati placeholders in Symfony. Riprendendo la regola precedente, riscriviamola nella seguente maniera:
_test:
path: /test/{name}
defaults: { _controller: AcmeDemoBundle:Welcome:test }
In questo modo stiamo dicendo che il parametro name
è dinamico. Richiamando, quindi, il nostro browser con il path /test/simone
, il valore "simone" verrà passato al controllore. Per far sì che tutto funzioni correttamente, abbiamo la necessità di modificare il metodo testAction
come di seguito:
public function testAction( $name )
{
echo "Hello {$name}!";
die();
}
In questa maniera stamperemo sul browser la stringa "Hello simone!".
Ovviamente i parametri possono essere più di uno e seguono la stessa logica del primo. Ad esempio, inserendo nel path /test/{name}/{lastname}
, possiamo passare un ulteriore parametro lastname
.
Parametri con valori di default
Spesso si ha l’esigenza di configurare una regola di routing con un parametro che ha un valore di default. Si pensi per esempio alla paginazione, nel caso non venga passato il parametro page
, di default quel parametro deve assumere valore "1". In Symfony possiamo impostare un parametro con valore di default nella seguente maniera:
_test:
path: /test/{page}
defaults: { _controller: AcmeDemoBundle:Welcome:test, page: 1 }
All’interno dell’array defaults
passiamo il valore predefinito che intendiamo utilizzare. Dopo aver opportunamente modificato il metodo testAction
:
public function testAction( $page )
{
echo "Page {$page}";
die();
}
possiamo notare che aprendo il browser con path /test
verrà restituito un valore pari a "1", con path /test/10
invece un valore pari a "10".
Requisiti dei parametri
Nell’esempio che abbiamo appena visto, bisogna prestare particolare attenzione ad un dettaglio: il valore passato al parametro page
deve necessariamente essere un intero. Nel nostro caso invece qualsiasi valore inseriamo, esso risulterà valido. Vediamo quindi come possiamo comunicare a Symfony Framework 2 che il valore deve per forza essere intero:
_test:
path: /test/{page}
defaults: { _controller: AcmeDemoBundle:Welcome:test, page: 1 }
requirements:
page: \d+
All’interno dell’array requirements
possiamo definire i vincoli per ogni parametro. Nel nostro caso abbiamo usato \d+
che indica un pattern di uno o più valori numerici. Se proviamo ad aprire il path con un valore non numerico, a questo punto, noteremo che viene sollevata un’eccezione NotFoundHttpException
perché non viene trovata nessuna regola di routing corrispondente. I requisiti possono essere espressi sotto-forma di espressioni regolari, questo implica che si possono impostare regole di routing anche particolarmente complesse.
Priorità di regole
Riprendendo sempre l’esempio della paginazione, abbiamo detto che nel caso in cui alla rotta venga passato un valore non numerico viene sollevata un’eccezione, questo perché si possono impostare più regole di routing che corrispondono allo stesso indirizzo. Path come i seguenti:
/test
/test/1
/test/stringa
/test/stringa-123
possono essere tutti validi se impostiamo opportune regole di routing; come regola generale, prevale la rotta che viene impostata per prima rispetto alle altre. Vediamo un esempio.
_test:
path: /test/{page}
defaults: { _controller: AcmeDemoBundle:Welcome:test, page: 1 }
requirements:
page: \d+
_test_name:
path: /test/{name}
defaults: { _controller: AcmeDemoBundle:Welcome:testname }
requirements:
name: \w+
Utilizzando le due regole viste finora, verrà richiamato un differente controller a seconda del valore passato come parametro.
Debug delle rotte
Attraverso la console di Symfony possiamo anche fare debug delle nostre rotte per verificare se ci sono errori. Il primo comando utile è:
php app/console router:debug
Esso visualizza la lista di tutti le rotte settate nella nostra applicazione. Passando, invece, il nome della rotta al comando, visualizzeremo diverse informazioni che possono esserci utili. Ad esempio:
php app/console router:debug _test
restituirà:
[router] Route "test"
Name test
Path /test/{page}
Host ANY
Scheme ANY
Method ANY
Class Symfony\Component\Routing\Route
Defaults _controller: AcmeDemoBundle:Welcome:test
page: 1
Requirements page: \d+
Options compiler_class: Symfony\Component\Routing\RouteCompiler
Path-Regex #^/test(?:/(?P\d+))?$#s
L’ultimo comando utile è l’inverso di quello appena visto, dato un path ci restituirà la rotta corrispondente.
Attraverso il comando:
php app/console router:match /test/123
verrà restituito lo stesso risultato del comando router:debug
:
[router] Route "test"
Name test
Path /test/{page}
Host ANY
Scheme ANY
Method ANY
Class Symfony\Component\Routing\Route
Defaults _controller: AcmeDemoBundle:Welcome:test
page: 1
Requirements page: \d+
Options compiler_class: Symfony\Component\Routing\RouteCompiler
Path-Regex #^/test(?:/(?P\d+))?$#s
Esaurito l'approfondimento sul routing, nel prossimo capitolo verranno analizzati nel dettaglio gli aspetti legati ai controller in Symfony2.