Relations entre les entités
Comment gérer les relations entre les entités avec Doctrine

Petite vérification
Avant de commencer, vérifiez si vous savez...
- citer l'option qu'on ajoute à un champ
FileTypepour indiquer qu'il n'est pas lié directement à une propriété de l'entité, et expliquer pourquoi cette option est nécessaire - pour l'entité
Characterde la séance précédente (formulaireCharacterTypeavec le champimageFilenon mappé, méthodesetImage(?string $image)), prédire ce que contient la propriétéimagedu personnage après l'exécution de :$newFilename = uniqid() . '.' . $imageFile->guessExtension();$imageFile->move($this->getParameter('characters_directory'), $newFilename);$character->setImage($newFilename); - expliquer pourquoi on ne doit jamais utiliser
getClientOriginalName()comme nom de destination lors du déplacement d'un fichier envoyé avecmove()
📌 Réponse attendue
Notions théoriques
Dans une base de données relationnelle, les tables peuvent être liées entre elles par des relations.
Doctrine supporte les types de relations suivants :
- OneToOne,
- OneToMany,
- ManyToOne
- et ManyToMany.
📌 Exemple de relation 'Catégories d'un joueur'

Par exemple, si chaque joueur de notre jeu a plusieurs personnages,
nous pourrions avoir une relation OneToMany entre l'entité Player et une nouvelle entité Character.
Pour cela, nous devons :
- ajouter une propriété
charactersàPlayer - ajouter une propriété
playeràCharacter, - utiliser les attributs de Doctrine pour définir la relation.
Exemple de mise en application
Voici une entité Character dans le fichier src/Entity/Character.php :
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use App\Repository\CharacterRepository;
#[ORM\Entity(repositoryClass: CharacterRepository::class)]
#[ORM\Table(name: 'tbl_character')]
class Character
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column(type: "integer")]
private ?int $id = null;
#[ORM\Column(type: "string", length: 100)]
private string $name;
#[ORM\ManyToOne(targetEntity: Player::class, inversedBy: "characters")]
private Player $player;
public function getId(): ?int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getPlayer(): Player
{
return $this->player;
}
public function setPlayer(Player $player): self
{
$this->player = $player;
return $this;
}
}
📌 Exemple de relation 'Personnages d'un joueur'

Et voici l'ajout de la propriété characters dans l'entité Player :
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use App\Repository\PlayerRepository;
#[ORM\Entity(repositoryClass: PlayerRepository::class)]
#[ORM\Table(name: 'tbl_player')]
class Player
{
// ... autres propriétés ...
#[ORM\OneToMany(targetEntity: Character::class, mappedBy: "player")]
private Collection $characters;
public function __construct()
{
$this->characters = new ArrayCollection();
}
public function getCharacters(): Collection
{
return $this->characters;
}
public function addCharacter(Character $character): self
{
if (!$this->characters->contains($character)) {
$this->characters[] = $character;
$character->setPlayer($this);
}
return $this;
}
public function removeCharacter(Character $character): self
{
if ($this->characters->removeElement($character)) {
if ($character->getPlayer() === $this) {
$character->setPlayer(null);
}
}
return $this;
}
}
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Votre défi pour aujourd'hui consiste à créer une relation entre les joueurs et les personnages
Étape 1 : Créez l'entité Character avec une propriété player en relation ManyToOne vers Player, et ajoutez la relation OneToMany correspondante dans Player.
Étape 2 : Codez l'action createCharacter dans le GameController pour créer un personnage associé à un joueur existant.
Dans une relation bidirectionnelle (OneToMany / ManyToOne), il faut initialiser les deux côtés.
$character->setPlayer($player) définit le côté ManyToOne (côté base de données).
Pour que $player->getCharacters() reste cohérent en mémoire dans la même requête,
il faut aussi appeler $player->addCharacter($character).
Doctrine ne synchronise les deux côtés que lors du prochain chargement depuis la base de données.