Doctrine et le mapping d’un champ indélicat !

Lorsque l’on utilise Symfony 2 avec Doctrine, il se passe parfois des choses dans la récupération des données au travers des requêtes, que l’on aimerait vraiment, beaucoup … Eviter !

Ex : J’ai une base de données qui me permet de gérer ma collection musicale, pour ce faire j’ai créé les tables suivantes :

Artistes : avec l’id (integer autoincrement et en PK), nom.

labels : avec l’id (integer autoincrement et en PK), nom.

Albums : avec l’id (integer autoincrement et en PK), nom, année de sortie, id_artiste, id_label.

Tracks : avec l’id (integer autoincrement et en PK), titre, id_album, id_artiste.

Sacrebleu ! Dans les deux tables se trouve id_artiste. C’est redondant comme information et quel est le but de permettre une telle association ?

La raison, logique ou pas, est que un album peut être l’oeuvre d’un artiste, mais que dans cette album peu se trouver une chanson (reprise, tribute, piste bonus) provenant d’un autre artiste. Ce qui permet avec cette association de retrouver tous les titres d’un artiste même si ils ne sont pas dans sont propre album. C’est en quelque sorte une constitution de référence audio.

Passons la logique des tables … Ce n’est qu’un exemple.

Lorsque je vais vouloir faire une requête sur la table Tracks (chercher le nom d’un titre par exemple), Doctrine lui va aller regarder comment est fichu la class (Entity) de la table : Tracks.php.

Evidemment à l’intérieur, j’ai la relation de définit pour les clés étrangères qui sont id_artiste et id_album.

 /**
* @var \Albums
*@\Id
* @ORM\OneToOne(targetEntity= »Album »)
* @ORM\JoinColumns({
*   @ORM\JoinColumn(name= »id_album », referencedColumnName= »id »)
* })
*/

private $idAlbum

/**
* @var \Artistes
*@\Id
* @ORM\OneToOne(targetEntity= »Artistes »)
* @ORM\JoinColumns({
*   @ORM\JoinColumn(name= »id_artiste », referencedColumnName= »id »)
* })
*/

private $idArtiste

Et en regardant les déclarations de l’entité, doctrine va suivre, tout logiquement les clés étrangères et remonter à leur entités respectives pour récupérer dans la jointure les champs inhérents déclarés.

Mais comment faire si vous ne voulez pas avoir en supplément des informations de la table, la redondance des informations concernant l’id_artiste de l’album ? (car il va aller jusque là bas doctrine !)

Voilà ce que propose Doctrine, toujours sous forme d’annotation, à placer juste avant votre déclaration de class dans le fichier entité :

/**
* Tracks
*
* @ORM\Table(name= »games »)
* @ORM\Entity(repositoryClass= »Ressources\DatasBundle\Repository\GamesRepository »)
* @ORM\InheritanceType(« SINGLE_TABLE »)
* @ORM\DiscriminatorColumn(name= »id_album », type= »integer »)
*/

class Tracks {

…. vos méthodes, variables

}

L’ajout de discriminatorColumn permet donc d’omettre des champs que vous ne souhaitez pas voir dans votre résultat de requête.

Et si cela coince toujours, ne pas oublier la suppression du fameux:

*@ORM\Id

Sur les annotations des champs de jointures tel qu’ici :

 /**
* @var \Artistes
*@\Id
* @ORM\ManyToOne(targetEntity= »Artistes »)
* @ORM\JoinColumns({
*   @ORM\JoinColumn(name= »id_artiste », referencedColumnName= »id »)
* })
*/

L’autre solution, histoire aussi de rester propre au niveau du schema des tables, est de ne plus déclarer les jointures telles qu’elles le sont dans l’exemple ci-dessus, mais de faire une déclaration sous cette forme :

/**
* @ORM\OneToOne(targetEntity= »App\MonBundle\Entity\Artistes », mappedBy= »id »)
*/
private $idArtiste;

Mon exemple n’est pas forcément très clair, il faut le reconnaitre, mais pour le surplus d’informations, le lien vers la doc :

http://doctrine-orm.readthedocs.org/en/latest/reference/inheritance-mapping.html

Publicités

About this entry