Symfony è un framework che adotta il paradigma convention over configuration. Tale paradigma prevede una configurazione minima o addirittura assente da parte del programmatore a meno che questi non abbia bisogno di implementare qualcosa che esca al di fuori degli standard di Symfony.
Per quanto riguarda il controller, che è il livello dell'architettura che contiene la vera e propria logica implementativa, è possibile suddividerlo in tre parti:
- Front controller: carica le configurazioni e determina le actions da eseguire;
- Actions: contiene la logica applicativa;
- oggetti Request, Response e Session: hanno accesso ai parametri di request, all'header del response e alle variabili di sessione; sono molto utilizzati nel controller.
Le action
A partire dalla URL presente sul browser, il front controller, in base ad una sorta di sitema di routing, richiama una ben determinata action di un ben determinato modulo. Ad esempio l'URL http://localhost/index.php/NomeModulo/NomeAction viene interpretata come una chiamata all'action NomeAction del modulo NomeModulo.
In realtà il front controller non si limita solo a "smistare" le richieste web associando una URL ad un'action ma si occupa anche di eseguire il codice comune a tutte le action, ovvero:
- definisce le costanti principali;
- localizza le librerie Symfony;
- carica e inizializza le classi principali del framework;
- carica la configurazione;
- decodifica la URL per determinare l'action da eseguire e i parametri di request;
- se l'action richiesta non esiste reirige verso l'action di errore 404;
- attiva i filtri (ad esempio per l'autenticazione);
- esegue i filtri (primo passaggio);
- esegue l'action e costruisce la view;
- esegue i filtri (secondo passaggio);
- fornisce la risposta in uscita.
Ogni applicativo sviluppato con Symfony ha un front controller di default chiamato index.php e posizionato nella directory web del progetto.
Se si esplora il file system di un progetto sviluppato in Symfony si nota che all'interno della directory principale del progetto (la sandbox, ne parliamo più avanti) troveremo la directory chiamata apps all'interno della quale una o più directory di applicazioni (tipicamente backend e frontend). All'interno di quest'ultima c'è la sottodirectory modules nella quale sono contenute le directory relative ai moduli appartenenti all'applicazione. Dentro ciascuna di esse vi è ancora una sottodirectory denominata actions nella quale vengono inseriti i file relativi alle action di quel determinato modulo.
La convenzione utilizzata da Symfony indica due strade per sviluppare le action. La prima prevede l'utilizzo di un unico file, chiamato actions.class.php contenuto nella directory action di ciascun modulo. Questo file ha, al suo interno, una serie di classi con un nome del tipo nomeModuloActions che ereditano tutte dalla classe sfActions (tale classe si trova in ..libsymfonyaction). Queste classi espongono dei metodi denominati executeNomeAction che non sono altro quelle che in Symfony vengono chiamati action. Il Listato 6.2 mostra un esempio di classi di action.
Listato 3: Un esempio di classe contenente action
class nazioneActions extends sfActions
{
public function executeIndex(sfWebRequest $request)
{
$this->nazione_list = NazionePeer::doSelect(new Criteria());
}
public function executeShow(sfWebRequest $request)
{
$this->nazione = NazionePeer::retrieveByPk($request->getParameter('id'));
$this->forward404Unless($this->nazione);
}
E' buona norma scrivere il minor numero di codice possibile nelle action (al più poche righe) e spostare la parte più "sostanziosa" nel model che contiene la logica applicativa. Quando il numero di action scritte in un solo modulo diventa troppo grande si può pesnsare di suddividere il modulo in più parti.
La seconda strada indicata dalle convenzioni utilizzate da Symfony per scrivere le action è quello di inserire una sola action per file. In questo caso ogni classe eredita dalla clsse sfAction (contenuta sempre in ..libsymfonyaction) e il suo nome è del tipo nomeActionAction. Il metodo della classe è semplicemente chiamato execute. Il nome del file coincide con quello della classe. Utilizzando questo metodo il Listato 6.2 si può riscrivere nel seguente modo.
Listato 4: Un modo alternativo per scrivere le action del Listato 3
--- File indexAction.php ---
class indexAction extends sfAction
{
public function execute(sfWebRequest $request)
{
$this->nazione_list = NazionePeer::doSelect(new Criteria());
}
}
--- File showAction.php ---
class showAction extends sfAction
{
public function execute(sfWebRequest $request)
{
$this->nazione = NazionePeer::retrieveByPk($request->getParameter('id'));
$this->forward404Unless($this->nazione);
}