Symfony: Quando i filtri non fanno parte del modello

L’admin generator di symfony è un componente fenomenale, se non ci fosse bisognerebbe inventarlo. Permette di creare un’applicazione basica (CRUD di tutti i modelli) in pochissimo tempo. In più man mano che lo si utilizza si impara sempre meglio a personalizzarlo per i propri scopi.

Ultimamente mi è capitato di dover filtrare la lista di risultati di un modello non in base ad uno dei suoi attribuiti (quindi una delle sue colonne) ma in base ad un attributo di un altro modello strettamente collegato a quello di interesse.

Immaginate di avere tre differenti modelli: nazione, regione, città. Tra nazione e regione una relazione uno a molti cosi come pure tra regione e città. Ma se volessimo sapere tutte le città di una nazione senza impostare una regione, come bisognerebbe comportarsi con i filtri del modello città?

Prima di tutto dovremo impostare una nuova query da far eseguire all’azione list del generator. Questo si fa banalmente indicando nel file generator.yml il nome del metodo:


list:
title:                  Lista Città
display:                [nazione, regione, citta, nome]
max_per_page:           10
table_method:           backendCittaList

La funzione  backendCittaList da definire sarà nel file CittaTable.class.php nella quale inseriremo:


public function backendCittaList(Doctrine_Query $q)
{
$rootAlias = $q->getRootAlias();
$q->leftJoin($rootAlias . ‘.Regione r’)
->leftJoin(‘r.Nazione’)
return $q;
}

A questo punto, si va avanti inserendo nel filtro (cittaFormFilter.class.php) i due widget (menu a tendina in questo caso) per la nazione e per la regione. Anche questo è abbastanza semplice, basta aggiungere un paio di righe come si fa sempre anche per i form (ne mostro uno solo, l’altro è uguale).


$this->widgetSchema['regione_id'] = new sfWidgetFormDoctrineChoice(array(
'model' => 'Regione' ,
'table_method' => 'RegioneList',
'add_empty' => true,
'multiple' => false,
));
$this->validatorSchema['regione_id'] = new sfValidatorDoctrineChoice(array(
'required' => false,
'model' => 'Regione',
'column' => 'id'
));

Nel codice mostrato a riga 3 viene esplicitata la query con la quale recupere la lista delle regioni e immancabile anche il validatore per il widget appena inserito.

Fino a qui è tutto abbastanza semplice. Attualmente nel nostro filtro sono stati inseriti altri due campi, in particolare, due menu a tendina, uno per stabilire la nazione ed uno per stabilire la regione. Ma manca ancora un pezzo. Se, scegliamo una regione e inviamo il form la lista delle città non sarà minimamente toccata dalla nostra richiesta. Questo dipende dal fatto che i nostri cambi aggiuntivi, ancora non si inseriscono nella composizione della query.

Per fare in modo che i nostri due nuovi widget siano presi in considerazione quando viene elaborata la query dobbiamo fare l’overload del metodo doBuildQuery() sempre nel file cittaFormFilter.class.php


/**
*restutisce una Doctrine_Query
*@param array $values
*@return Doctrine_Query $query
*/
public function doBuildQuery(array $values)
{
...
// build query
$query = parent::doBuildQuery($values);
if (!empty($regione_id))
  $query->addWhere('r.id = ?',$values['regione_id']);
if(!empty($nazione_id))
$query->addWhere('n.id = ?', $values['nazione_id']);
  return $query;
}

Questo metodo prende come parametro un array, ovvero i valori che inseriamo dentro ai filtri e restituisce una query. In prima istanza ci prendiamo la query che sarebbe fatta di default dal generator richiamando il doBuild query della class padre. A questa query non dobbiamo far altro che aggiungere i nostri filtri. In particolare in questo caso aggiungiamo delle where sulle tabelle che avevamo già inserito in precedenza nel metodo chiamato dall’azione lista. Dopo aver modificato utilizziamo la query come ritorno della funzione.
In poche parole abbiamo intercettato la query, l’abbiamo modificata e l’abbiamo re-inserita nel suo flusso.

A questo punto i risultati della lista prenderanno in considerazione i filtri aggiuntivi che abbiamo inserito.

2 pensieri su “Symfony: Quando i filtri non fanno parte del modello

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...