Questa associazione gestisce la classica relazione “molti-a-molti”, tipo quella che si può creare tra due oggetti quali “Articles” e “Keywords”.
Ogni articolo può avere associate più parole chiave e una parola chiave può essere associata a più articoli.
Supponiamo di disporre già delle tabelle articles e keywords.
Sarà necessario creare la tabella di join che permetta la relazione “molti-a-molti” tra le due tabelle.
Per convenzione in CakePHP questa tabella assumerà un nome che viene ricavato dai nomi delle due tabelle implicate ordinati alfabeticamente, separate da un carattere underscore ( _ ).
Nel nostro caso la join table verrà chiamata articles_keywords e avrà come unici campi le due chiavi esterne che fanno riferimento alla convenzione CakePHP: “article_id” e “keyword_id” che formeranno la chiave primaria della tabella.
Il passo successivo è quello di definire l’associazione nel model relativo agli articoli
var $hasAndBelongsToMany = array('Keyword' =>
array('className' => 'Keyword',
'joinTable' => 'articles_keywords',
'foreignKey' => 'article_id',
'associationForeignKey'=> 'keyword_id',
'conditions' => '',
'order' => 'Keyword.keyword ASC',
'limit' => '',
'unique' => true,
'finderQuery' => '',
'deleteQuery' => '',
);
‘joinTable’ è la tabella di join che abbiamo creato e ‘foreignKey’ e ‘associationForeignKey’ rappresentano i campi relative alle chiavi.
Secondo il manuale di CakePHP non sarebbe necessario specificare il nome dei campi se si rispettano le convenzioni.
Salvare i dati
Poniamo il caso che abbiamo un articolo già inserito nella tabella Articles (ma se non è ancora presente fa lo stesso) al quale vogliamo associare delle keyword da prelevare dalla tabella Keywords.
La procedura da seguire è semplicemente la seguente:
1. Si popola l’array $this->data con i valori da inserire.
L’array deve contenere i dati dell’articolo e quelli delle keyword da associare all’articolo. In particolare i dati relativi alla tabella associata devono avere un particolare formato.
Quindi immaginiamo di avere $this->data già popolato da un form compilato e inviato dall’utente che appare come segue:
Array
(
[Article] => Array
(
[id] => 4
[category_id] => 12
[titolo] => Questo è il titolo dell'articolo
[sottotitolo] => Sottotitolo
[testo] => Bla bla bla bla bla bla bla bla bla bla bla
[user_id] => 0
[created] => 2007-03-02 08:16:44
[modified] => 2007-03-06 14:00:45
[data_pub] =>
[data_fine_pub] =>
[onindex] => 0
[pubblicato] => 0
)
[Category] => Array
(
[descrizione] => Novità
)
[Keyword] => Array
(
[0] => Array
(
[id] => 2
[keyword] => aids
)
[1] => Array
(
[id] => 9
[keyword] => bambini
)
[2] => Array
(
[id] => 8
[keyword] => fame
)
[3] => Array
(
[id] => 4
[keyword] => popolazioni
)
)
)
A questo punto bisogna impostare l’elemento
$this->data['Keyword'] = array('Keyword' => array ( 23, 56, 67));
dove 23, 56 e 67 rappresentano l’id delle keyword da associare.
Volendo riscrivere l’array nel formato indicato dal manuale si può dire che l’array avrà un formato del tipo
['Keyword']['Keyword'][23]
['Keyword']['Keyword'][56]
['Keyword']['Keyword'][67]
2. Si invoca il metodo save del modello Article.
In questo modo si può salvare l’intero articolo e associare le keyword selezionate.
Per un passaggio più stringato basta impostare il seguente array
$data = array (‘Article’ => array(‘id’ => 4) ,
‘Keyword’ => array(‘Keyword’ => array (23,56,67))
)
Questo è sufficente per eseguire la sola associazione delle keyword
Quando le cose si fanno complicate
Sicuramente capiterà di dover gestire la relazione many-to-many impostando delle informazioni aggiuntive circa l’associazione, tipo la data di creazione dell’associazione (ad esempio l’associazione Users-Groups).
Per questa problematica è utilissimo leggere un post di ThinkingPHP and beyond che tratta l’argomento nei particolari:
Modeling relationships in CakePHP (faking Rails ThroughAssociation)
Un altro articolo interessante: