Relations

Une fois de plus, nous allons utiliser la couche d'abstraction (et la console) pour l'aspect relationnel de notre schéma de base de données

OneToOne

Extrêmement rare (généralement table unique).
Parfois utilisé pour préparer la migration vers un autre type de relation ou pour des questions de performances.
class Profile
{
    /**
     * @ORM\OneToOne(targetEntity="App\Entity\Photo", mappedBy="profile", cascade={"persist", "remove"})
     */
    private $photo;
}
		

ManyToOne

Une ligne est liée à plusieurs lignes dans une autre table.
Exemple : plusieurs héros est lié à un seul héros.
class Hero
{
    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Profile", inversedBy="heroes")
     * @ORM\JoinColumn(nullable=false)
     */
    private $profile;
}
	

ManyToMany

Plusieurs lignes sont liées à plusieurs lignes dans une autre table.
On utilise alors une table de jointure (qui a pour clé primaire les éléments de la jointure).
Exemple : le lien entre un héros et des objets (un héros est liée à plusieurs objets, chaque objet est lié à plusieurs héros).
Cette relation peut aussi porter des données complémentaires (ces données seront alors portées par la table de jointure).
class Hero
{
    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Item", mappedBy="hero")
     */
    private $items;
}
	

Sens des relations

Les relations que nous avons vues sont unidirectionnelles. Au besoin, il faudra définir leur réciproque.

La classe portant la référence (ici une colonne profile_id dans la table commentaire) utilisera inversedBy . Dans l'autre sens, on utilisera mappedBy .

class Hero
{
    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Profile", inversedBy="heroes")
     * @ORM\JoinColumn(nullable=false)
     */
    private $profile;
}
class Profile
{
    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Hero", mappedBy="profile", orphanRemoval=true)
     */
    private $heroes;
}
cla
	

Il faut noter que par convention, une relation faisant un lien ToMany est appelée au pluriel.

Compléments

Relation facultative

class Profil
{
    /**
     * @ORM\OneToOne(targetEntity="App\Entity\Photo", mappedBy="profile", cascade={"persist", "remove"})
     * @ORM\JoinColumn(nullable=false)
     */
    private $photo;
}
		

Opération Doctrine

Accesseurs

Les accesseurs sont générés par défaut par la console.

    /**
     * @return Collection|Hero[]
     */
    public function getHeroes(): Collection
    {
        return $this->heroes;
    }

    public function addHero(Hero $hero): self
    {
        if (!$this->heroes->contains($hero)) {
            $this->heroes[] = $hero;
            $hero->setProfile($this);
        }

        return $this;
    }

    public function removeHero(Hero $hero): self
    {
        if ($this->heroes->contains($hero)) {
            $this->heroes->removeElement($hero);
            // set the owning side to null (unless already changed)
            if ($hero->getProfile() === $this) {
                $hero->setProfile(null);
            }
        }

        return $this;
    }
        

Pour forcer la génération des accesseurs (après une modification manuelle), on peut utiliser :

php bin/console doctrine:generate:entities Profile

Mise à jour du schéma

php bin/console doctrine:schema:update