Molte applicazioni sono basate su dati memorizzati in un database e offrono un'interfaccia per accedervi. Symfony automatizza il processo ripetitivo della creazione di un modulo che fornisca capacità di manipolazione dei dati basati su Propel o Doctrine. Se l'oggetto del modello è definito in modo appropriato, symfony può addirittura generare un intero sito di amministrazione automaticamente. Questo capitolo descrive l'utilizzo dell'admin generator, distribuito con i plugin di Propel e Doctrine. Esso si basa su uno speciale file di configurazione con una sintassi completa, quindi la maggior parte di questo capitolo ne descrive le varie possibilità.
Generazione del codice basato sul modello
In un'applicazione web, le operazioni di accesso ai dati possono essere categorizzate come segue:
- Creazione di una riga
- Recupero di una o più righe
- Aggiornamento di una riga (e modifica delle sue colonne)
- Eliminazione di una riga
Queste operazioni sono così comuni che hanno un acronimo: CRUD (dalle iniziali inglesi di Create, Replace, Update, Delete). Molte pagine possono essere ridotte a una di esse. Per esempio, in un'applicazione forum, la lista degli ultimi messaggi è un'operazione di recupero, mentre la risposta è un'operazione di creazione.
Le azioni e i template di base che implementano le operazioni CRUD per una data tabella sono create ripetutamente nelle applicazioni web. In symfony, il livello del modello contiene sufficienti informazioni per consentire la generazione del codice per le operazioni CRUD, in modo da accelerare la parte iniziale delle interfacce di backend.
Esempio di modello di dati
Lungo questo capitolo, i listati dimostreranno le capacità dell'admin generator di symfony
basandosi su un semplice esempio, che ricorderà il capitolo 8. Questo è il ben noto
esempio dell'applicazione blog, contenente le due classi BlogArticle
e BlogComment
.
Il listato 14-1 mostra lo schema, illustrato in figura 14-1.
Listato 14-1 - Schema Propel dell'esempio di applicazione blog
propel: blog_category: id: ~ name: varchar(255) blog_author: id: ~ name: varchar(255) blog_article: id: ~ title: varchar(255) content: longvarchar blog_author_id: ~ blog_category_id: ~ is_published: boolean created_at: ~ blog_comment: id: ~ blog_article_id: ~ author: varchar(255) content: longvarchar created_at: ~
Figura 14-1 - Esempio di modello dei dati
Non c'è una regola particolare da seguire durante lo schema, per consentire la generazione del codice. Symfony userà lo schema così com'è e interpreterà i suoi attributi per generare l'amministrazione.
tip
Per ottenere il massimo da questo capitolo, occorre implementare effettivamente gli
esempi. Si otterrà una migliore comprensione di cosa symfony genera e di cosa può essere
realizzato col codice generate, se si ha una visione di ogni passo descritto nei listati.
L'inizializzazione del modello è semplice: basta richiamare il task propel:build
(o doctrine:build
):
$ php symfony propel:build --all --no-confirmation
Poiché l'interfaccia di amministrazione si basa su alcuni metodi magici per facilitare
i compiti, occorre creare un metodo __toString()
in ogni classe del modello.
class BlogAuthor extends BaseBlogAuthor { public function __toString() { return $this->getName(); } } class BlogCategory extends BaseBlogCategory { public function __toString() { return $this->getName(); } } class BlogArticle extends BaseBlogArticle { public function __toString() { return $this->getTitle(); } }
tip
Si può fare in modo che Propel aggiunga automaticamente il metodo magico __toString()
.
Basta aggiungere la proprietà primaryString: true
alla colonna desiderata.
Doctrine invece lo aggiunge automaticamente alla prima colonna di testo disponibile.
Amministrazione
Symfony può generare moduli del backend, basati sulle definizioni delle classi del modello trovate nel
file schema.yml
. Si può creare un intero sito di amministrazione, composto interamente
da moduli di amministrazione generati. Gli esempi di questa sezione descriveranno i moduli
di amministrazione aggiunti a un'applicazione chiamata backend
. Se il progetto non ha
ancora un'applicazione con questo nome, occorre crearla richiamando il seguente task:
$ php symfony generate:app backend
I moduli di amministrazione interpretano il modello tramite uno speciale file di
configurazione chiamato generator.yml
, che può essere modificato per estendere tutte le
componenti generate e l'apparenza del modulo stesso. Tali moduli beneficiano del consueto
meccanismo descritto nei capitoli precedenti (layout, rotte, configurazione
personalizzata, caricamento automatico, eccetera). Si possono anche sovrascrivere azioni e
template generati, per poter integrare le caratteristiche desiderate nell'amministrazione
generate, ma generator.yml
dovrebbe soddisfare la maggior parte delle esigenze comuni e
restringere l'uso del codice PHP a quelle veramente specifiche.
note
Anche se la maggior parte delle esigenze è coperta dal file di configurazione
generator.yml
, si può anche configurare un modulo di amministrazione tramite una classe
di configurazione, come vedremo più avanti in questo capitolo.
Inizializzare un modulo di amministrazione
Con symonfy, si può costruire un'amministrazione basandosi sui modelli. Un modulo viene generato in base a un oggetto Propel o Doctrine, usando uno dei seguenti task:
// Propel $ php symfony propel:generate-admin backend BlogArticle --module=article // Doctrine $ php symfony doctrine:generate-admin backend BlogArticle --module=article
note
I moduli di amministrazione sono basati su un'architettura REST. Il task
propel:generate-admin
aggiunge automaticamente al file di configuraizone routing.yml
una rotta di questo tipo:
# apps/backend/config/routing.yml article: class: sfPropelRouteCollection options: model: BlogArticle module: article with_wildcard_routes: true
Si può anche creare una propria rotta e passare il nome come parametro del task, al posto del nome della classe del modello:
$ php symfony propel:generate-admin backend article --module=article
Questa chiamata genera un modulo article
nell'applicazione backend
, basato sulla
definizione della classe BlogArticle
, accessibile da:
http://localhost/backend_dev.php/article
L'aspetto del modulo generato, illustrato nelle figure 14-2 e 14-3, è abbastanza sofisticato da renderlo subito usabile per un'applicazione commerciale.
tip
Se non si vede questo aspetto (mancano stili e immagini), occorre installare i file
necessari nel progetto, eseguendo il task plugin:publish-assets
task:
$ php symfony plugin:publish-assets
Figura 14-2 - Vista list
del modulo article
nell'applicazione backend
Figura 14-3 - Vista edit
del modulo article
nell'applicazione backend
Uno sguardo al codice generato
Il codice del modulo amministrativo article
, nella cartella
apps/backend/modules/article/
, sembra vuoto perché è stato solo inizializzato. Il modo
migliore per controllare il codice generato è quello di interagire tramite il browser,
quindi andare a guardare nella cartella cache/
. Il listato 14-2 elenca le azioni e i
template generati nella cache.
Listato 14-2 - Elementi amministrativi generati, in cache/backend/ENV/modules/autoArticle/
// Azioni in actions/actions.class.php index // Mostra l'elenco delle righe della tabelle filter // Aggiorna i filtri usati dalla lista new // Mostra il form per inserire una nuova riga create // Crea una nuova riga edit // Mostra un form per modificare una riga update // Aggiorna una riga esistente delete // Elimina una riga batch // Esegue un'azione su una lista di righe scelte batchDelete // Esegue un'eliminazione su una lista di righe scelte // In templates/ _assets.php _filters.php _filters_field.php _flashes.php _form.php _form_actions.php _form_field.php _form_fieldset.php _form_footer.php _form_header.php _list.php _list_actions.php _list_batch_actions.php _list_field_boolean.php _list_footer.php _list_header.php _list_td_actions.php _list_td_batch_actions.php _list_td_stacked.php _list_td_tabular.php _list_th_stacked.php _list_th_tabular.php _pagination.php editSuccess.php indexSuccess.php newSuccess.php
Questo mostra che un modulo amministrativo generato è composto principalmente da tre viste,
list
, new
e edit
. Se si guarda nel codice, lo si troverà molto modulare, leggibile
ed estensibile.
Introduzione al file di configurazione generator.yml
I moduli amministrativi generati si basano su paremetri trovati nel file di configurazione
generator.yml
. Per vedere la configurazione predefinita di un nuovo modulo
amministrativo, aprire il file generator.yml
, che si trova nella cartella
backend/modules/article/config/generator.yml
, riprodotto nel listato 14-3.
Listato 14-3 - Configurazione predefinta del generatore, in backend/modules/article/config/generator.yml
generator: class: sfPropelGenerator param: model_class: BlogArticle theme: admin non_verbose_templates: true with_show: false singular: BlogArticle plural: BlogArticles route_prefix: blog_article with_propel_route: 1 actions_base_class: sfActions config: actions: ~ fields: ~ list: ~ filter: ~ form: ~ edit: ~ new: ~
Questa configurazione è sufficiente per generare l'amministrazione di base. Ogni
personalizzazione va aggiunta sotto la chiave config
. Il listato 14-4 mostra un tipico
file generator.yml
personalizzato.
Listato 14-4 - Configurazione tipica completa del generatore
generator: class: sfPropelGenerator param: model_class: BlogArticle theme: admin non_verbose_templates: true with_show: false singular: BlogArticle plural: BlogArticles route_prefix: blog_article with_propel_route: 1 actions_base_class: sfActions config: actions: _new: { label: "Crea un nuovo articolo" } fields: author_id: { label: Article author } published_on: { credentials: editor } list: title: Articoli display: [title, blog_author, blog_category] fields: published_on: { date_format: dd/MM/yy } layout: stacked params: | %%is_published%%<strong>%%=title%%</strong><br /><em>da %%blog_author%% in %%blog_category%% (%%created_at%%)</em><p>%%content%%</p> max_per_page: 2 sort: [title, asc] filter: display: [title, blog_category_id, blog_author_id, is_published] form: display: "Post": [title, blog_category_id, content] "Workflow": [blog_author_id, is_published, created_at] fields: published_at: { help: "Data di pubblicazione" } title: { attributes: { style: "width: 350px" } } new: title: Nuovo articolo edit: title: Modifica articolo "%%title%%"
In questa configurazione ci sono sei sezioni. Quattro di esse rappresentano le viste
(list
, filter
, new
e edit
) e due di esse sono "virtuali" (fields
e form
)
ed esistono solo per scopi di configurazione.
Le sezioni seguenti spiegano in dettaglio tutti i parametri che possono essere usati nel file di configurazione.
Configurazione del generatore
Il file di configurazione del generatore è molto potente e consente di alterare la generazione in molti modi. Ma queste capacità hanno un prezzo: la descrizione globale della sintassi è lunga da leggere e da imparare, rendendo questo capitolo il più lungo di questo libro.
Gli esempi di questa sezione modificheranno il modulo article
e il modulo comment
,
basato sulla definizione della classe BlogComment
. Per creare ques'ultimo, basta
lanciare il comando:
$ php symfony propel:generate-admin backend BlogComment --module=comment
Figura 14-4 - Cheat sheet dell'administration generator
Campi
Le colonne predefinite della vista list
sono quelle definite in schema.yml
. I campi
delle viste new
e edit
sono quelli definiti nel form associato al modello
(BlogArticleForm
). Nel file generator.yml
si può scegliere quali campi mostrare,
quali nascondere e aggiungere campi nuovi, anche se non hanno una corrispondenza diretta
con l'oggetto del modello.
Impostazioni dei campi
Il generatore dell'amministrazione crea un campo per ogni colonna nel file schema.yml
.
Sotto la chiave fields
si può modificare il modo in cui i campi sono mostrati,
formattati, ecc. Per esempio, le impostazioni dei campi mostrate nel listato 14-5
definiscono una classe personalizzata per la label del campo title
e una label e un
testo di aiuto per il campo content
. Le sezioni seguenti descrivono nel dettaglio il
funzionamento di ogni parametro.
Listato 14-5 - Impostare una label personalizzata per un evento
config: fields: title: label: Titolo articolo attributes: { class: foo } content: { label: Body, help: Inserire il corpo dell'articolo }
Oltre alla definizione per tutte le viste, si possono configurare le impostazioni solo
per una vista specifica (list
, filter
, form
, new
o edit
), come mostrato nel
listato 14-6.
Listato 14-6 - Impostazioni globali vista per vista
config: fields: title: { label: Titolo articolo } content: { label: Corpo } list: fields: title: { label: Titolo } form: fields: content: { label: Corpo articolo }
C'è un principio generale: ogni impostazione inserita sotto la chiave fields
può
essere sovrascritta nelle aree specifiche delle viste. Le regole di sovrascrittura sono
le seguenti:
new
eedit
ereditano daform
, che eredita dafields
list
eredita dafields
filter
eredita dafields
Aggiungere dei campi
I campi definiti nella sezione fields
possono essere mostrati, nascosti, ordinati e
raggruppati in vari modi per ogni vista. La chiave display
è usata per questo scopo.
Per esempio, per riordinare i campi del modulo comment
, usare il codice del listato 14-7.
Listato 14-7 - Scegliere i campi da mostrare, in modules/comment/config/generator.yml
config: fields: article_id: { label: Articolo } created_at: { label: Data pubblicazione } content: { label: Corpo } list: display: [id, blog_article_id, content] form: display: NONE: [blog_article_id] Editable: [author, content, created_at]
La vista list
mostrerà tre colonne, come mostrato in figura 14-5, mentre le viste new
e edit
mostreranno quattro campi, divisi in due gruppi, come in figura 14-6.
Figura 14-5 - Impostazioni personalizzate delle colonne nella vista list
Figura 14-6 - Campi raggruppati nella vista edit
Dunque si possono usare le impostazioni display
in due modi:
- Per la vista
list
: inserire i campi in un array per scegliere le colonne da mostrare e l'ordine in cui appaiono. - Per le viste
form
,new
eedit
: usare un array associativo per raggruppare i campi col nome del gruppo come chiave, oppureNONE
per un gruppo senza nome. I valori sono ancora un array di colonne ordinate. Si faccia attenzione a elencare tutti i campi obbligatori del form o si potrebbero avere problemi con la validazione (vedere capitolo 10).
Campi personalizzati
Di fatto, i campi configurati in generator.yml
non necessitano di colonne reali
corrispondenti nello schema. Se la classe relativa offre un getter, può essere usato come
un campo per la vista list
. Se non ci sono getter o setter, si può comunque usare nella
vista edit
. Per esempio, si può estendere il modello BlogArticle
con un metodo
getNbComments()
simile a quello nel listato 14-8.
Listato 14-8 - Aggiungere un getter personalizzato nel modello, in lib/model/BlogArticle.php
public function getNbComments() { return $this->countBlogComments(); }
In questo modo nb_comments
è disponibile come campo nel modulo generato (si noti che
il getter usa una versione camelCase del nome del campo), come nel listato 14-9.
Listato 14-9 - I getter personalizzati forniscono colonne aggiuntive, in backend/modules/article/config/generator.yml
config: list: display: [title, blog_author, blog_category, nb_comments]
La vista list
dell'articolo article
è mostrata in figura 14-07.
Figura 14-07 - Campo personalizzato nella vista list
Campi con partial
Il codice che si trova nel modello deve essere indipendente dalla presentazione. L'esempio
del metodo getArticleLink()
visto prima non rispecchia questo principio di separazione
tra i livelli, perché del codice della vista sta nel livello del modello. Di fatto, se si
prova a usare questa configurazione, ci si troverà con un collegamento mostrato come un
tag <a>
, perché sottoposto a escape. Per raggiungere lo stesso scopo in modo corretto,
si dovrebbe inserire il codice che mostra HTML per un campo personalizzato in un partial.
Fortunatamente, il generatore di amministrazione consente di dichiarare un campo con un
trattino basso come prefisso. In questo caso, il file generator.yml
del listato 14-11 va
modificato come nel listato 14-12.
Listato 14-12 - Partial usato come colonna aggiuntiva. Usare il prefisso _
config: list: display: [id, _article_link, created_at]
Per funzionare, un partial _article_link.php
deve essere creato nella cartella
modules/comment/templates/
, come nel listato 14-13.
Listato 14-13 - Esempio di partial per la vista list
, in modules/comment/templates/_article_link.php
<?php echo link_to($BlogComment->getBlogArticle()->getTitle(), 'blog_article_edit', $BlogComment->getBlogArticle()) ?>
Si noti che il template del partial ha accesso all'oggetto corrente tramite una variabile
chiamata come la classe (in questo esempio, $BlogComment
).
Figura 14-08 - Campo partial nella vista list
La separazione dei livelli è stata rispettata. Se ci si abitua a questa seprazione, ci si ritroverà con applicazioni più facili da mantenere.
Se occorre personalizzare le proprietà di un campo partial, si può fare come per un campo
normale, sotto la chiave fields
. Basta non includere il prefisso (_
) nella chiave.
Vedere come esempio il listato 14-14.
Listato 14-14 - Proprietà di un campo partial personalizzate sotto la chiave fields
config: fields: article_link: { label: Articolo }
Se un partial si affolla con troppa logica, probabilmente andrebbe sostituito con un
component. Basta cambiare il prefisso _
in ~
, come si può vedere nel listato 14-15.
Listato 14-15 - I component possono essere usati come colonne aggiuntive. Usare il prefisso ~
config: list: display: [id, ~article_link, created_at]
Nel template generato, questo risulterà in una chiamata al componente articleLink
del
modulo corrente.
note
I campi personalizzati e i campi partial possono essere usati nelle viste list
, new
,
edit
e filter
. Se si usa lo stesso partial per viste diverse, il contesto (list
,
new
, edit
o filter
) viene memorizzato nella variabile $type
.
Personalizzazione della vista
Per cambiare l'aspetto delle viste new
, edit
e list
, si potrebbe essere tentati di
modificare i template. Ma siccome sono generati automaticamente, non è una buona idea.
Invece, si dovrebbe usare il file generator.yml
, che può fare quasi tutto senza
sacrificare la modularità.
Cambiare il titolo di una vista
Oltre a un insieme personalizzato di campi, le pagine list
, new
e edit
possono
avere un titolo personalizzato. Per esempio, se si vuole personalizzare il titolo delle
viste article
, basta fare come nel listato 14-16. La vista edit
risultante è
illustrata in figura 14-09.
Listato 14-16 - Impostare un titolo per ogni vista, in backend/modules/article/config/generator.yml
config: list: title: Lista di articoli new: title: Nuovo articolo edit: title: Modifica articolo %%title%% (%%id%%)
Figura 14-09 - Titolo personalizzato nella vista edit
Poiché i titoli predefiniti usano il nome della classe, spesso vanno bene, a patto di aver usato dei nomi di classi espliciti.
tip
Nei valori stringa di generator.yml
, si può accedere al valore di un campo tramite il
nome del campo stesso, preceduto e seguito da %%
.
Aggiungere degli aiuti
Nelle viste list
, new
, edit
e filter
si possono aggiungere dei testi di aiuto, per
descrivere meglio i campi mostrati. Per esempio, per aggiungere un aiuto al campo
blog_article_id
della vista edit
del modulo comment
, aggiungere una proprietà help
sotto la chiave fields
, come nel listato 14-17. Il risultato è mostrato in figura 14-10.
Listato 14-17 - Impostare un testo di aiuto nella vista edit
, in modules/comment/config/generator.yml
config: edit: fields: blog_article_id: { help: Il commento correlato a questo articolo }
Figura 14-10 - Testo di aiuto nella vista edit
Nella vista list
, i testi di aiuto sono mostrati nell'intestazione della colonna, mentre
nelle viste new
, edit
e filter
sono mostrati sotto ciascun campo.
Modificare il formato delle date
Si possono mostrare le date con un formato personalizzato, usando l'opzione date_format
,
come nel listato 14-18.
Listato 14-18 - Formattare una data nella vista list
config: list: fields: created_at: { label: Pubblicato, date_format: dd/MM }
Accetta gli stessi parametri dell'helper format_date()
, descritto nel capitolo
precedente.
Personalizzazioni specifiche della vista list
La vista list
può mostrare i dettagli di una riga in modo tabulare o impilato. Contiene
inoltre filtri, paginazione e opzioni di ordinamento. Queste caratteristiche possono
essere modificate dalla configurazione, come descritto nelle sezioni seguenti.
Cambiare il layout
I collegamenti predefiniti tra la vista list
e la vista edit
avviene nella colonna
della chiave primaria. Tornando alla figura 14-08, si vede che la colonna id
nella lista
dei commenti non solo mostra la chiave primaria di ogni commento, ma anche un collegamento
che consente agli utenti di accedere alla vista edit
.
Se si preferisce che il collegamento ai dettagli di una riga appaiono su una colonna
diversa, basta aggiungere un prefisso =
al nome della colonna, sotto la chiave display
.
Il listato 14-19 mostra come rimuovere id
dai campi mostrati da list
e come inserire
il collegamento nel campo content
. Vedere la figura 14-11 per una schermata.
Listato 14-19 - Spostare il collegamento per la vista edit
nella vista list
, in modules/comment/config/generator.yml
config: list: display: [_article_link, =content]
Figura 14-11 - Spostare il collegamento per la vista edit
su un'altra colonna
La vista list
usa il layout predefinito tabular
, in cui i campi appaiono come colonne,
come mostrato in precedenza. Si può usare anche il layout stacked
, in cui i campi sono
concatenati in una singola stringa, che si espande per tutta la larghezza della tabella.
Se si sceglie il layout stacked
, bisogna impostare nella chiave params
lo schema che
definisce il valore di ciascuna linea della lista. Per esempio, il listato 14-20 definisce
un layout stacked
per la vista list
del modulo comment
. Il risultato appare in
figura 14-12.
Listato 14-20 - Usare un layout stacked
nella vista list
, in modules/comment/config/generator.yml
config: list: layout: stacked params: | %%=content%%<br /> (inviato da %%author%% in data %%created_at%% riguardo %%_article_link%%) display: [created_at, author, content]
Figura 14-12 - Layout stacked
nella vista list
Si noti che un layout tabular
si aspetta un array di campi sotto la chiave display
,
mentre un layout stacked
usa la chiave params
per la generazione del codice HTML di
ciascuna riga. Tuttavia, l'array display
è usato ugualmente nel layout stacked
, per
determinare quali intestazioni delle colonne sono disponibili, ai fini dell'ordinamento.
Filtrare i risultati
In una vista list
si possono aggiungere un insieme di filtri interattivi. Con questi
filtri gli utenti possono visualizzare meno risultati e trovare più velocemente quelli
che cercano. Si possono configurare i filtri sotto la chiave filter
, con un array di
nomi di campi. Per esempio, aggiungere un filtro sui campi blog_article_id
, author
e
created_at
della vista list
del modulo comment
, come nel listato 14-21, per mostrare
un riquadro di filtri simile a quello in figura 14-13.
Listato 14-21 - Impostare i filtri nella vista list
, in modules/comment/config/generator.yml
config: list: layout: stacked params: | %%=content%% <br /> (inviato da %%author%% in data %%created_at%% riguardo %%_article_link%%) display: [created_at, author, content] filter: display: [blog_article_id, author, created_at]
Figura 14-13 - Filtri nella vista list
I filtri mostrati da symfony dipendono dal tipo di colonna definito nello schema e possono essere personalizzati nella classe del form del filtro:
- Per le colonne di testo (come il campo
author
nel modulocomment
), il filtro è un input text, che consente ricerche basate su testi (aggiungendo automaticamente i caratteri jolly). - Per le chiavi esterne (come il campo
blog_article_id
nel modulocomment
), il filtro è un elenco a tendina delle righe della tabella correlata. Le opzioni sono quelle restituite dal metodo__toString()
della classe correlata. - Per le colonne data (come il campo
created_at
nel modulocomment
), il filtro è una coppia di date, che consentono di scegliere un intervallo di tempo. - Per le colonne booleane, il filtro è un elenco a tendina con i valori
true
,false
etrue or false
, con l'ultimo come predefinito.
Come le viste new
e edit
sono legate a classi di form, i filtri usano le classi di
form di filtri associate col modello (per esempio BlogArticleFormFilter
per il modello
BlogArticle
). Si possono personalizzare i campi dei filtri definendo una classe per il
form dei filtri, sfruttando la potenza del framework dei form e usando tutti i widget dei
filtri disponibili. È molto facile, basta definire una classe class
sotto la chiave
filter
, come mostrato nel listato 14-22.
Listato 14-22 - Personalizzare la classe del form per i filtri
config: filter: class: BackendArticleFormFilter
tip
Per disabilitare completamente i filtri, si può specificare false
come valore di
class
.
Si possono anche usare dei partial per implementare una logica personalizzata nei filtri.
Ogni partial riceve il form form
e gli attributi HTML attributes
, da usare per la resa
dell'elemento del form. Il listato 14-23 mostra un esempio di implementazione di un
partial.
Listato 14-23 - Uso di un partial nel filtro
// Definire il partial, in templates/_state.php <?php echo $form[$name]->render($attributes->getRawValue()) ?>
--
# Aggiungere il partial alla lista dei filtri, in config/generator.yml config: filter: [created_at, _state]
Ordinare la lista
In una vista list
, le intestazioni della tabelle sono collegamenti che possono essere
usati per riordinare la lista, come mostrato in figura 14-18. Questa intestazioni sono
mostrate in entrambi i layout, tabular
e stacked
. Cliccando questi collegamenti, la
pagina viene ricaricata con un parametro sort
, che riordina la lista di conseguenza.
Figura 14-14 - Le intestazioni della tabella della vista list
sono controlli di ordinamento
Si può riutilizzare la sintassi per puntare a una lista direttamente ordinata per una colonna:
<?php echo link_to('Lista dei commenti per data', '@blog_comment?sort=created_at&sort_type=desc' ) ?>
Si può anche definire un ordinamento predefinito per la vista list
direttamente nel
file generator.yml
. La sintassi segue l'esempio nel listato 14-24.
Listato 14-24 - Impostare un ordinamento predefinito su un campo nella vista list
config: list: sort: created_at # Sintassi alternativa per specificare un verso di ordinamento sort: [created_at, desc]
note
Solo i campi corrispondenti a vere colonne possono essere ordinabili, non le colonne personalizzate o partial.
Personalizzare la paginazione
L'amministrazione generata gestisce efficacemente grandi tabelle, perché la vista list
usa la paginazione. Quando il numero di righe in una tabella supera il numero massimo di
righe per pagina, compaiono i controlli per la paginazione in fondo alla lista. Per
esempio, la figura 14-19 mostra la lista dei commenti con sei commenti di prova nella
tabella e un limite di cinque commenti a pagina. La paginazione assicura buone
prestazioni, perché solo le righe mostrate sono estratte effettivamente dal database, e
una buona usabilità, perché anche tabelle con milioni di righe sono gestibili.
Figura 14-15 - Controlli di paginazione per liste lunghe
Si può personalizzare il numero di righe mostrate in ogni pagina col parametro
max_per_page
:
config: list: max_per_page: 5
Usare una join per accelerare le pagine
Il generatore di amministrazione usa un semplice doSelect
per recuperare una lista di
righe. Ma se si usano oggetto correlati nella lista, il numero di query richieste per
mostrare la lista potrebbe aumentare rapidamente. Per esempio, se si vuole mostrare il
nome dell'articolo in una lista di commenti, è necessaria una query in più per ogni riga
della lista, per poter recuperare l'oggetto BlogArticle
correlato. Ma si può forzare
il paginatore a usare un metodo doSelectJoinXXX()
per ottimizzare il numero di query,
usando il parametro peer_method
(table_method
per Doctrine).
config: list: peer_method: doSelectJoinBlogArticle
Il capitolo 18 spiega il concetto di join più approfonditamente.
Personalizzazioni specifiche per le viste new
e edit
In una vista new
o edit
, l'utente può modificare il valore di ogni colonna di un
record. Il form predefinito usato dall'admin generator è il form associato col modello:
BlogArticleForm
per il modello BlogArticle
. Si può personalizzare la classe da usare,
definendo una voce class
sotto form
, come mostrato nel listato 14-25.
Listato 14-25 - Personalizzare la classe del form per le viste new
e edit
config: form: class: BackendBlogArticleForm
L'uso di una classe personalizzata consente la personalizzazione di tutti i widget e di tutti i validatori usati dall'admin generator. La classe predefinita del form può quindi essere usata e personalizzata specificatamente per l'applicazione di frontend.
Si possono anche personalizzare label, messaggi di aiuto e l'aspetto del form,
direttamente nel file di configurazione generator.yml
, come mostrato nel listato 14-26.
Listato 14-26 - Personalizzare l'aspetto del form
config: form: display: NONE: [article_id] Editable: [author, content, created_at] fields: content: { label: corpo, help: "Il contenuto può essere in formato Markdown" }
Gestire i campi partial
I campi partial possono essere usati nelle viste new
e edit
, proprio come nelle viste
list
.
Gestire le chiavi esterne
Se lo schema definisce relazioni tra tabelle, i moduli di amministrazione generati se ne possono avvantaggiare e offrire maggiori controlli automatici, semplificando quindi di molto la gestione delle relazioni.
Relazioni uno a molti
Le relazioni 1-n sono prese in considerazione dal generatore di amministrazione. Come
illustrato precedentemente in figura 14-1, la tabella blog_comment
è legata alla tabella
blog_article
tramite un campo blog_article_id
. Se si inizializza il modulo della
classe BlogComment
col generatore di amministrazione, la vista edit
mostrerà
automaticamente blog_article_id
come un elenco a tendina, con i valori degli ID delle
righe della tabella blog_article
(si veda ancora la figura 14-9 per un'illustrazione).
Lo stesso accade nella lista dei commenti legati a un articolo, nel modulo article
(relazione n-1).
Relazioni molti a molti
Symfony gestisce automaticamente anche le relazioni n-n, come mostrato in figura 14-16.
Figura 14-16 - Relazioni molti a molti
Personalizzando il widget usato per rendere la relazione, si può anche modificare la resa del campo (illustrata in figura 14-17):
Figura 14-17 - Controlli disponibili per relazioni molti a molti
Aggiungere interazioni
I moduli di amministrazione consentono agli utenti di eseguire le normali operazioni CRUD,
ma si possono anche aggiungere le proprie interazioni o restringere le possibili
interazioni per una vista. Per esempio, la definizione di interazione mostrata nel
listato 14-27 dà accesso a tutte le azioni CRUD predefinite nel modulo article
.
Listato 14-27 - Definire le interazioni per ogni vista, in backend/modules/article/config/generator.yml
config: list: title: Lista di articoli object_actions: _edit: ~ _delete: ~ batch_actions: _delete: ~ actions: _new: ~ edit: title: Corpo dell'articolo %%title%% actions: _delete: ~ _list: ~ _save: ~ _save_and_add: ~
In una vista list
, ci sono tre impostazioni di azioni: le azioni disponibili per ogni
oggetto (object_actions
), le azioni disponibili per una selezione di oggetti
(batch_actions
) e le azioni disponibili per l'intera pagina (actions
). La lista delle
interazioni definite nel listato 14-27 è resa come in figura 14-18. Ogni linea mostra un
bottone per modificare la riga e uno per cancellarla, più una spunta per cancellare una
selezione di righe. In fondo alla lista, un bottone consente la creazione di una nuova
riga.
Figura 14-18 - Interazioni nella vista list
Nelle viste new
e edit
, essendoci una sola riga alla volta, c'è un solo insieme di
azioni da definire (sotto actions
). Le interazioni edit
definite nel listato 14-27
rendono come in figura 14-23. Le azioni save
e save_and_add
salvano la riga corrente,
con la differenza che save
mostra ancora la vista edit
dopo il salvataggio, mentre
save_and_add
mostra una vista new
per aggiungere un'altra riga. L'azione
save_and_add
è una scorciatoia molto utile per aggiungere diverse righe in successione.
Come per la posizione dell'azione delete
, è separata dagli altri bottoni in modo da
evitare che sia cliccata per sbaglio.
I nomi delle interazioni che iniziano con un trattino basso (_
) dicono a symfony di
usare l'icona e l'azione corrispondenti a tali interazioni. Il generatore di
amministrazione accetta _edit
, _delete
, _new
, _list
, _save
, _save_and_add
e
_create
.
Figura 14-19 - Interazioni nella vista edit
Ma si possono anche aggiungere interazioni personalizzate, nel qual caso occorre specificare un nome che non inizi con un trattino basso e un'azione del modulo corrente, come nel listato 14-28.
Listato 14-28 - Definire un'interazione personalizzata
list: title: Lista di articoli object_actions: _edit: - _delete: - addcomment: { label: Aggiungi un commento, action: addComment }
Ogni articolo nella lista ora mostrerà un collegamento Aggiungi un commento
, come
mostrato in figura 14-20. Cliccandoci, si attiverà l'azione addComment
del modulo
corrente. La chiave primaria dell'oggetto è aggiunta automaticamente ai parametri
della richiesta.
Figura 14-20 - Interazioni personalizzate nella vista list
L'azione addComment
può essere implementata come nel listato 14-29.
Listato 14-29 - Implementare l'azione di interazione personalizzata, in actions/actions.class.php
public function executeAddComment($request) { $comment = new BlogComment(); $comment->setArticleId($request->getParameter('id')); $comment->save(); $this->redirect('blog_comment_edit', $comment); }
Le azioni batch ricevono un array di chiavi primarie delle righe selezionate, nel
parametro della richiesta ids
.
Un'ultima nota sulle azioni: se si vogliono rimuovere completamente le azioni per una categoria, usare una lista vuota, come nel listato 14-30.
Listato 14-30 - Rimuovere tutte le azioni nella vista list
config: list: title: Lista di articoli actions: {}
Validazione di form
La validazione è presa in carico automaticamente dal form usato nelle viste new
e edit
.
Si può personalizzare modificando le corrispondenti classi dei form.
Limitare le azioni usando le credenziali
Per un dato modulo di amministrazione, i campi e le interazioni disponibili possono variare a seconda delle credenziali dell'utente autenticato (fare riferimento al capitolo 6 per una descrizione delle caratteristiche di sicurezza di symfony).
I campi nel generatore accettano un parametro credentials
, per apparire solo agli utenti
con le credenziali giuste. Questo per la voce list
. Inoltre, il generatore può
nascondere delle interazioni, a seconda delle credenziali. Il listato 14-31 dimostra
queste caratteristiche.
Listato 14-31 - Uso delle credenziali in generator.yml
config: # La colonna id viene mostrata solo agli utenti con credenziale admin list: title: Lista di articoli display: [id, =title, content, nb_comments] fields: id: { credentials: [admin] } # L'interazione addcomment è ristretta agli utenti con credenziale admin actions: addcomment: { credentials: [admin] }
Modificare la presentazione dei moduli generati
Si può modificare la presentazione dei moduli generati, in modo che rispondano a schemi grafici esistenti, non solo applicando un foglio di stile personalizzato, ma anche sovrascrivendo i template predefiniti.
Usare un foglio di stile personalizzato
Poiché il codice HTML generato è un contenuto strutturato, si può fare quasi tutto con la presentazione.
Si può definire un CSS alternativo da usare per un modulo di amministrazione, al posto di
quello predefinito, aggiungendo un parametro css
alla configurazione del generatore,
come nel listato 14-32.
Listato 14-32 - Usare un foglio di stile personalizzato al posto di quello predefinito
generator: class: sfPropelGenerator param: model_class: BlogArticle theme: admin non_verbose_templates: true with_show: false singular: BlogArticle plural: BlogArticles route_prefix: blog_article with_propel_route: 1 actions_base_class: sfActions css: mystylesheet
In alternativa, si può usare il meccanismo fornito da view.yml
del modulo, per
sovrascrivere gli stili in base alle viste.
Creare header e footer personalizzati
Le viste list
, new
e edit
includono automaticamente un partial per header e footer.
Questi partial non sono definiti nella cartella templates/
del modulo, ma basta
aggiungerne uno con uno dei nomi seguenti, per vederli automaticamente inclusi:
_list_header.php _list_footer.php _form_header.php _form_footer.php
Per esempio, se si vuole aggiungere un header personalizzato nella vista article/edit
,
basta creare un file chiamato _form_header.php
, come nel listato 14-33. Non sono
necessarie ulteriori configurazioni.
Listato 14-33 - Esempio di partial header edit
, in modules/article/templates/_form_header.php
<?php if ($blog_article->getNbComments() > 0): ?> <h2>Questo articolo ha <?php echo $blog_article->getNbComments() ?> commenti.</h2> <?php endif; ?>
Si noti che un partial in edit
ha sempre accesso all'oggetto corrente, tramite una
variabile con lo stesso nome della classe, e che un partial in list
ha sempre accesso
al paginatore corrente, tramite la variabile $pager
.
Personalizzazione del tema
Ci sono altri partial ereditati dal framework che possono essere sovrascritti nella
cartella templates/
del modulo, per soddisfare delle esigenze personali.
I template del generatore sono spezzati in piccole parti, che possono essere sovrascritte indipendentemente, e le azioni possono essere cambiate una per una.
Tuttavia, se si vogliono sovrascrivere tanti moduli nello stesso modo, probabilmente
conviene creare un tema riusabile. Un tema è un sottoinsieme di template e di azioni che
possono essere usati in un modulo di amministrazione, se specificato nel valore di theme
all'inizio di generator.yml
. Col tema predefinito, symfony usa i file definiti in
sfConfig::get('sf_symfony_lib_dir')/plugins/sfPropelPlugin/data/generator/sfPropelModule/admin/
.
I file del tema devono trovarsi in una struttura alberata del progetto, in una cartella
dal nome data/generator/sfPropelModule/[nome_tema]/
. Si può creare un nuovo tema
copiando i file da quello predefinito:
// Partial, in [nome_tema]/template/templates/ _assets.php _filters.php _filters_field.php _flashes.php _form.php _form_actions.php _form_field.php _form_fieldset.php _form_footer.php _form_header.php _list.php _list_actions.php _list_batch_actions.php _list_field_boolean.php _list_footer.php _list_header.php _list_td_actions.php _list_td_batch_actions.php _list_td_stacked.php _list_td_tabular.php _list_th_stacked.php _list_th_tabular.php _pagination.php editSuccess.php indexSuccess.php newSuccess.php // Azioni, in [nome_tema]/parts actionsConfiguration.php batchAction.php configuration.php createAction.php deleteAction.php editAction.php fieldsConfiguration.php filterAction.php filtersAction.php filtersConfiguration.php indexAction.php newAction.php paginationAction.php paginationConfiguration.php processFormAction.php sortingAction.php sortingConfiguration.php updateAction.php
Si faccia attenzione, perché i file dei template sono in realtà template di template, cioè sono dei file PHP che saranno analizzati da un programma speciale per generare dei template basati sulle impostazioni del generatore (questo processo è chiamato fase di compilazione). I template generati devono comunque contenere codice PHP da eseguire durante la navigazione, quindi i template di template usano una sintassi alternativa per mantenere il codice PHP ineseguito durante il primo passo. Il listato 14-34 mostra un estratto di un template di template predefinito.
Listato 14-34 - Sintassi dei template di template
<h1>[?php echo <?php echo $this->getI18NString('edit.title') ?> ?]</h1> [?php include_partial('<?php echo $this->getModuleName() ?>/flashes') ?]
In questo listato, il codice PHP introdotto da <?
viene eseguito immediatamente (in fase
di compilazione), mentre quello introdotto da [?
viene eseguito solo durante l'esecuzione
vera e propria, ma il motore di template trasforma i tag [?
in tag <?
, in modo che il
template risultante appaia come questo:
<h1><?php echo __('Lista di tutti gli articoli') ?></h1> <?php include_partial('article/flashes') ?>
Non è facile gestire i template di template, quindi il consiglio migliore per chi volesse
creare un tema è quello di partire dal tema admin
, modificarlo a piccoli passi e
testarlo in modo intensivo.
tip
Si può anche impacchettare un tema per il generatore in un plugin, il che lo rende ancora più riusabile e facile da rilasciare in applicazioni multiple. Si faccia riferimento al capitolo 17 per maggiori informazioni.
Riepilogo
Per generare automaticamente le applicazioni di backend, le basi sono uno schema ben definito e il modello degli oggetti. La personalizzazione dei moduli di amministrazione generati andrebbe fatta tramite la configurazione.
Il file generator.yml
è il cuore della programmazione dei backend generati. Esso consente
una personalizzazione completa di contenuti, caratteristiche e aspetto delle viste list
,
new
e edit
. Si possono gestire label, testi di aiuto, filtri, ordinamento, dimensione
della pagine, tipi di input, relazioni esterne, interazioni personalizzate e credenziali
direttamente in YAML, senza una singola riga di codice PHP.
Se il generatore di amministrazione non supporta nativamente una caratteristica richiesta, i campi partial e la possibilità di sovrascrivere le azioni forniscono una completa estensibilità. Inoltre, si possono riusare le personalizzazioni fatte sul generatore, grazie al meccanismo dei temi.
This work is licensed under the GFDL license.