In Lyra la categorizzazione dei contenuti avviene tramite etichette, se si preferisce si possono chiamare categorie perché il concetto è quello. Le etichette sono suddivise in cataloghi, questo per permettere criteri di classificazione multipli.
Ad esempio, nei dati predisposti per il test iniziale dell'applicazione abbiamo creato questi cataloghi ed etichette:
Argomento <- catalogo
PHP <- etichetta
Javascript <- etichetta
Mootools <- etichetta
jQuery <- etichetta
Livello <- catalogo
Elementare <- etichetta
Intermedio <- etichetta
Avanzato <- etichetta
In questo modo gli articoli possono essere classificati in base all'argomento e al livello di difficoltà. Quindi potremmo avere un articolo
"L'uso delle variabili in PHP"
Argomento (catalogo): PHP (etichetta)
Livello (catalogo): Elementare (etichetta)
ed un altro articolo
"La programmazione a oggetti in PHP"
Argomento (catalogo): PHP (etichetta)
Livello (catalogo): Avanzato (etichetta)
Ogni etichetta appartiene ad un catalogo (e ad uno solo), esistono inoltre relazioni gerarchiche (padre-figlio) tra etichette (nell'esempio l'etichetta Mootools è figlia di Javascript). Ad un contenuto possono essere assegnate più etichette appartenenti a più cataloghi.
I cataloghi utilizzabili per un contenuto dipendono dal tipo di contenuto. In questo momento è gestito un solo tipo di contenuto (articolo), ma in futuro ne saranno creati altri ed ognuno potrà avere i propri cataloghi. Immaginiamo ad esempio un tipo di contenuto 'galleria di immagini': difficilmente le etichette usate per gli articoli, potranno andare bene per categorizzare una galleria, quindi si potrà creare un catalogo (o anche più di uno) specifico per questo tipo di contenuto.
Quanto descritto sopra a parole trova riscontro nello schema dati in termini di relazioni tra le tabelle catalogs, labels, articles, article_label (tabella intermedia della relazione molti a molti tra articoli ed etichette), content_types, content_type_catalog (tabella intermedia della relazione molti a molti tra tipi di contenuto e cataloghi) e le rispettive classi del modello: LyraCatalog, LyraLabel, LyraArticle, LyraArticleLabel, LyraContentType e LyraContentTypeCatalog.
Riporto per ogni classe solo le chiavi primarie e le relazioni che ci interessano in questo momento come definite in config/doctrine/schema.yml.
LyraCatalog:
tableName: catalogs
...
columns:
id:
type: integer(4)
primary: true
autoincrement: true
...
LyraLabel:
tableName: labels
...
columns:
id:
type: integer(4)
primary: true
autoincrement: true
catalog_id:
type: integer(4)
...
relations:
LabelCatalog:
class: LyraCatalog
local: catalog_id
foreign: id
foreignAlias: CatalogLabels
onDelete: CASCADE
...
LyraArticle:
tableName: articles
...
columns:
id:
type: integer(4)
primary: true
autoincrement: true
...
relations:
ArticleLabels:
class: LyraLabel
refClass: LyraArticleLabel
local: article_id
foreign: label_id
foreignAlias: LabelArticles
...
LyraArticleLabel:
tableName: article_label
columns:
article_id:
type: integer(4)
primary: true
label_id:
type: integer(4)
primary: true
relations:
Article:
class: LyraArticle
local: article_id
foreign: id
onDelete: CASCADE
Label:
class: LyraLabel
local: label_id
foreign: id
onDelete: CASCADE
LyraContentTypeCatalog:
tableName: content_type_catalog
columns:
ctype_id:
type: integer(4)
primary: true
catalog_id:
type: integer(4)
primary: true
relations:
ContentType:
class: LyraContentType
local: ctype_id
foreign: id
onDelete: CASCADE
Catalog:
class: LyraCatalog
local: catalog_id
foreign: id
onDelete: CASCADE
Con queste premesse e tenendo presente la gestione delle relazioni tra tabelle in Doctrine, si può capire meglio il codice per la personalizzazione del form di inserimento e modifica di un articolo lasciato in sospeso la volta scorsa. In particolare la parte che genera le liste di selezione utilizzate per assegnare una o più etichette all'articolo.
lib/form/doctrine/LyraArticleForm.class.php
class LyraArticleForm extends BaseLyraArticleForm
{
public function configure()
{
...
$ctype = Doctrine::getTable('LyraContentType')
->findOneByModule('article');
Recuperiamo il record del tipo di contenuto gestito dal modulo article.
$def = array();
if(!$this->isNew()) {
$def = $this->getObject()
->getArticleLabels()
->getPrimaryKeys();
}
Se stiamo modificando un articolo esistente (metodo isNew() dell'oggetto form ritorna false), il metodo getPrimaryKeys() ci ritorna un array con i valori delle chiavi primarie dei record etichetta collegati all'articolo a loro volta ritornati da getArticleLabels(): ArticleLabels è il nome della relazione articoli-etichette definita nello schema, vedere sopra la classe LyraArticle. Questi valori sono utilizzati come default per le liste di selezione delle etichette.
$after = 'subtitle';
foreach ($ctype->ContentTypeCatalogs as $cg) {
$query = Doctrine_Query::create()
->from('LyraLabel l')
->where('l.catalog_id = ? AND l.level > 0', $cg->id);
$k = 'label_'.$cg->getId();
$this->widgetSchema[$k] = new sfWidgetFormDoctrineChoiceMany(array('model'=>'LyraLabel', 'query'=>$query, 'label'=>$cg->name, 'default'=>$def, 'method'=>'getIndentName'));
$this->validatorSchema[$k] = new sfValidatorDoctrineChoiceMany(array('model'=>'LyraLabel', 'required'=>false));
$this->widgetSchema->moveField($k, sfWidgetFormSchema::AFTER, $after);
$after = $k;
}
} //fine configure()
Viene creata una lista di selezione per ciascun catalogo legato al tipo di contenuto. Gli elementi delle liste vengono estratti dalla tabella labels in base all'ID del catalogo: la query esclude l'elemento a livello zero nel nested set, la radice del catalogo che non deve essere visualizzata nella lista.
Per i dettagli sul widget utilizzato per le liste di selezione, rimando alla documentazione ufficiale: symfony forms - Widgets, paragrafo "Scelta legata ad un modello Doctrine".
Le liste vengono posizionate (con moveField()) una dopo l'altra dopo il campo subtitle
protected function doSave($con = null)
{
parent::doSave($con);
$this->saveLabels($con);
}
Implementando il metodo doSave() in LyraArticleForm possiamo eseguire codice quando il record principale viene salvato. In questo caso eseguiamo saveLabels() per salvare i legami articolo / etichette.
Tralascio l'esame in dettaglio del metodo saveLabels(), richiamo solo l'attenzione di chi è interessato sui metodi link() e unlink() per costruire e rimuovere i legami tra i record delle tabelle Articoli ed Etichette che sono tra loro in una relazione molti a molti attraverso la tabella intermedia article_label (classe modello LyraArticleLabel).
Nessuna modifica sul repository in quanto tutto il codice sopra riportato era già incluso nella revisione 12.
0 commenti:
Posta un commento