Retour
Symfony 6: ORM Doctrine

Ce support de cours mettra l'accent sur la gestion des bases de données avec Symfony.
Vous apprendrez à configurer et à utiliser Doctrine, l'ORM (Object-Relational Mapping) de Symfony, pour interagir avec votre base de données.
Plan du cours
- Introduction à Doctrine
- Avantage de l'utilisation de Doctrine
- Installation et configuration de Doctrine
- Connexion à la base de données
- Créer la base de données
- Entity et Repository
- Définitaion des entité
- Définition du Repository
- Migrations: Mise à jour de la base de données
- Cas pratique: CRUD
- Création d'éléments
- Récuperer tous les films
- Récupérer un film avec son identifiant
- Mettre à jour une film
- Supprimer un film
- Rélations entre entité
- Création de la relation
- Ajouter des commenaires
- récuperer des commentaires
Prérequis
- Connaissance de base en programmation web (HTML, CSS et PHP)
- Compréhension des concepts de base du modèle MVC (Modèle-Vue-Contrôleur)
- Connaissance sur la programmation orientée objet avec PHP
-
Familiarité avec le framework Symfony (concepts de base, installation, configuration)
-
Savoir créer et utiliser les contrôleur de symfony
Objectifs
- Comprendre le rôle de Doctrine dans la gestion de la base de données dans Symfony.
- Configurer la connexion à la base de données dans Symfony.
- Utiliser les attributes pour définir des entités et des relations.
- Créer des requêtes de lecture, d'écriture et de suppression à l'aide du langage DQL (Doctrine Query Language).
- Utiliser les migrations pour gérer les modifications de schéma de base de données.
- Gérer les transactions et les relations entre les entités.
1. Introduction à Doctrine
Doctrine est une bibliothèque PHP puissante qui facilite la manipulation des données dans une base de données relationnelle.
Il s'agit d'un ORM (Object-Relational Mapping), ce qui signifie qu'il permet de représenter les données de la base de données sous forme d'objets PHP.
Ainsi, au lieu de manipuler directement des requêtes SQL, nous travaillons avec des entités et des objets PHP.
1.1. Avantages de l'utilisation de Doctrine
L'utilisation de Doctrine présente plusieurs avantages :
- Productivité accrue : Avec Doctrine, vous pouvez vous concentrer sur les objets et la logique métier plutôt que sur les requêtes SQL. Cela permet d'accélérer le développement et de réduire les erreurs.
- Portabilité : Doctrine prend en charge plusieurs SGBD (Systèmes de Gestion de Bases de Données) tels que MySQL, PostgreSQL, SQLite, etc. Vous pouvez facilement changer de SGBD sans avoir à réécrire votre code.
- Gestion avancée des relations : Doctrine facilite la définition et la gestion des relations complexes entre les entités, telles que les relations
One-to-One
,One-to-Many
etMany-to-Many
.
1.2. Installation et configuration de Doctrine
Pour commencer à utiliser Doctrine, nous devons l'installer et le configurer dans notre projet Symfony. Voici les étapes à suivre :
Vous pouvez installer Doctrine en exécutant la commande suivante dans le répertoire racine de votre projet Symfony :
composer require orm
La configuration de Doctrine se fait dans le fichier config/packages/doctrine.yaml
.
Voici un exemple de la configuration par défaut :
doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'
# IMPORTANT: Vous devez configurer la version du serveurs de votre base de données ici, ou dans
# le fichier .env dans la variable DATABASE_URL
orm:
auto_generate_proxy_classes: true
enable_lazy_ghost_objects: true
report_fields_where_declared: true
validate_xml_mapping: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
when@test:
doctrine:
dbal:
# "TEST_TOKEN" is typically set by ParaTest
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
when@prod:
doctrine:
orm:
auto_generate_proxy_classes: false
proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies'
query_cache_driver:
type: pool
pool: doctrine.system_cache_pool
result_cache_driver:
type: pool
pool: doctrine.result_cache_pool
framework:
cache:
pools:
doctrine.result_cache_pool:
adapter: cache.app
doctrine.system_cache_pool:
adapter: cache.system
1.3. Connexion à la base de données
Vous pouvez indiquer le dsn
de connexion à la base de données dans le fichier .env
à la racine du projet.
Dépendant de quelle base de données vous utilisez, la valeur peut changer.
Voici comment connecter à une base de données MySql:
# IMPORTANT: Vous devez configurer votre version de serveur ici ou dans onfig/packages/doctrine.yaml
DATABASE_URL="mysql://username:password@127.0.0.1:3306/basededonnees?serverVersion=8.0.32&charset=utf8mb4"
Vous pouvez retrouver l'équivalent pour d'autres base de données dans la documentation officielle de Symfony 6
1.4. Créer la base de données
Doctrine offre plusieurs commandes utiles pour gérer la base de données.
Par exemple, vous pouvez créer la base de données en utilisant la commande :
php bin/console doctrine:database:create
Ou plus facilement avec Symfony CLI :
symfony console doctrine:database:create
2. Entité et Repository
Les entités sont des classes PHP qui représentent les objets métier de notre application, ils nous permettent de construire des objets représentant une ligne d'une table dans la base de données.
Ils nous permette d'avoir une répresentation des tables sous forme d'objets de la classe Entity
.
Les entités permettent aussi la synchronisation des colonnes des table avec les propriétés de la classe Entity
ce qui facilite la création et la mise à jour des tables.
Les repositories, quant à eux, sont des classes qui fournissent des méthodes pour interagir avec les entités dans la base de données.
Ils ressemblent un peu à la couche Model dans l'architecture MVC.
Par conventions, les entités sont généralement situées dans le répertoire src/Entity
et les repositories sont généralement situés dans le répertoire src/Repository
.
2.1. Définition des entités
Pour créer une entité, nous allons utiliser une classe PHP et y définir les propriétés correspondantes aux colonnes de la table dans la base de données, et contiendra aussi des accesseurs et mutateurs.
<?php
// /src/Entity/Film.php
namespace App\Entity;
use App\Repository\FilmRepository;
use Doctrine\ORM\Mapping as ORM;
// Lier la classe Repository pour les films
#[ORM\Entity(repositoryClass: FilmRepository::class)]
class Film {
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
private ?string $titre = null;
public function getId(): ?int {
return $this->id;
}
public function getTitre(): ?string {
return $this->titre;
}
public function setTitre(string $titre): static {
$this->titre = $titre;
return $this;
}
}
Dans cet exemple, nous avons défini une entité Film
avec des attributs Doctrine pour définir chaque propriété représentant une colonne de la table :
- une propriété
id
: générée automatiquement lors de la création. - une propriété
titre
: de typestring
et une taille maximale de 255 caractères.
Nous avons également utilisé des attributs de Doctrine pour spécifier quel FilmRepository
est lié à l'entité.
2.2. Définition du Repository
Le repository associé à une entité nous permet d'effectuer des opérations de persistance et de récupération des données.
Un Repository
doit étendre la classe ServiceEntityRepository
pour hériter de certaines méthodes permettant de récupérer des données :
find($id, $lockMode = null, $lockVersion = null)
: Permet de récupérer un élément en utilisant son identifiant.findOneBy(array $criteria, array $orderBy = null)
: Permet de récupérer une élément suivant des critère de sélectionfindAll()
: Récupérer tous les élémentsfindBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
: Récupérer plusieurs éléments en suivant des critères de sélection.
<?php
// src/Repository/FilmRepository.php
namespace App\Repository;
use App\Entity\Film;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Film>
* La classe hérite de ces méthodes
* @method Film|null find($id, $lockMode = null, $lockVersion = null)
* @method Film|null findOneBy(array $criteria, array $orderBy = null)
* @method Film[] findAll()
* @method Film[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class FilmRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $doctrine)
{
parent::__construct($doctrine, Film::class);
}
// Nous ajouterons plus tard ici des méthodes pour interagir avec la base de données
}
Nous injectons également un gestionnaire d'entités dans le constructeur de la classe, un objet de type ManagerRegistry
.
Le gestionnaire d'entités est responsable de la persistance des objets en base de données et de la coordination des opérations entre l'application Symfony et la base de données.
2.3. Migrations: Mise à jour de la base de données
Maintenant que nous avons défini nos entités, nous devons mettre à jour la base de données pour refléter ces changements.
À chaque changement de vos entités, vous devrez migrer votre base de données.
Nous allons installer un package afin de créer ces migrations en ligne de commande :
composer require --dev symfony/maker-bundle
Ensuite, nous allons créer une migration en lançant la commande suivante :
php bin/console make:migration
Cette commande générera un fichier de migration basé sur les différences détectées entre vos entités et la structure actuelle de la base de données.
Ensuite, exécutez la commande suivante pour appliquer la migration :
php bin/console doctrine:migrations:migrate
Cela mettra à jour votre base de données avec les nouvelles tables et les relations définies dans vos entités.
3. Cas pratique: CRUD
3.1. Création d'éléments
Nous allons ajouter une méthode dans la classe FilmRepository
nous permettant de supprimer un film de la base de données:
-
utiliser la méthode
persist()
du gestionnaire d'entités pour ajouter lenregistrement de l'entité dans la prochaine transaction. -
Tester si nous voulons executer la transaction:
- Utiliser la méthode
flush()
pour exécuter les opérations sur la base de données (INSERT
/UPDATE
).
- Utiliser la méthode
-
Retourner l'instance du nouveaux film.
<?php
// src/Repository/FilmRepository.php
class FilmRepository extends ServiceEntityRepository {
// ... Code précédent
// 1. Méthode pour ajouter une Film dans la base de donnée
public function save(Film $nouveauFilm, ?bool $flush = false) {
// 1.1. Persiste l'entité Film dans le gestionnaire d'entités (Doctrine)
$this->getEntityManager()->persist($nouveauFilm);
// 1.2. Tester si nous devons executer la transaction
if($flush){
// 1.2.2. Effectue les opérations de base de données (INSERT/UPDATE)
$this->getEntityManager()->flush();
}
// 1.3. Retourner l'instance du nouveau film
return $nouveauFilm;
}
}
Nous pouvons maintenant l'utiliser dans un controlleur en injectant un objet de type FilmRepository
.
Pour créer un élément dans la base de données, vous devez d'abord créer une instance de l'entité correspondante, puis définir les valeurs des propriétés nécessaires, en utilisant les méthodes d'accessibilité de l'entité.
Dans le Contrôleur FilmControlleur
:
- Créer une route sur l'url
/films
acceptant les requêtes de typePOST
. - Déclarer l'action associée, en injectant la requête et une instance du repository.
- Vérifier si le corps de la requête est vide ou ne contient pas le titre, retourner un message d'erreur.
- Sinon, Récuperer le
titre
du corps de la requête. - Créer une instance de l'entité
Film
. - Peupler l'entité avec les données reçues dans la requête.
- utiliser la méthode
save()
du repository pour enregistrer le film dans la base de données
<?php
// /src/Controller/FilmController.php
namespace App\Controller;
use App\Entity\Film;
use App\Repository\FilmRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class FilmController extends AbstractController {
// 1. Route associé a l'url '/films' pour ajouter un film
#[Route('/films', name: 'films.ajout', methods: ['POST'])]
// 2. Action pour ajouter une film dans la base données en utilisant le repository
function ajout(Request $req, FilmRepository $repository) {
// 2.1 Vérifier si le corps de la requête est vide ou si la clé titre n'existe pas
if (!$req->getContent() || !$req->getPayload()->has('titre')) {
return $this->json(
['erreur' => 'Il manque le titre!'],
Response::HTTP_BAD_REQUEST
);
}
// 2.2. Récuperer les données du corps de la requête
$titre = $req->getPayload()->get('titre');
// 2.3. Créer une instance de l'entité et la peupler
$film = (new Film())->setTitre($titre);
// 2.5 utiliser le repository pour enregistrer le nouveau film dans la base de données
$nouveauFilm = $repository->save($film, true);
return $this->json(
['film' => $nouveauFilm->getTitre() . ' ajouté. ID: ' . $nouveauFilm->getId()],
);
}
}
3.2. Récupérer tous les films
Pour récupérer tous les films de la base de données, vous pouvez utiliser la méthode findAll()
héritée de la classe ServiceEntityRepository
.
Cette méthode renvoie un tableau d'objets entité Film
.
Vous pouvez ensuite itérer sur ce tableau pour construire un tableau associatif des films à renvoyer en réponse JSON.
// Code précédent...
#[Route('/films', name: 'films.tout', methods: ['GET'])]
function tout(Request $req, FilmRepository $repository) {
// Récupérer un tableau d'entités Film
$films = $repository->findAll();
// Les mettre dans un tableau associatif pour les envoyer en JSON
$filmTableau = [];
foreach ($films as $film) {
$filmTableau[] = ['id' => $film->getId(), 'titre' => $film->getTitre()];
}
return $this->json(
['films' => $filmTableau]
);
}
Dans cet exemple, nous avons ajouté une route /films
avec une méthode GET
pour récupérer tous les films de la base de données.
Nous utilisons la méthode findAll()
du repository pour récupérer tous les objets entité Film
, puis nous itérons sur ce tableau pour construire un tableau associatif des films avec les propriétés id
et titre
.
Enfin, nous renvoyons une réponse JSON contenant ce tableau.
3.3. Récupérer un film avec son identifiant
Pour récupérer un film à partir de son identifiant, vous pouvez utiliser la méthode find()
héritée de la classe ServiceEntityRepository
.
Cette méthode prend l'identifiant en paramètre et renvoie l'objet entité Film
correspondant, ou null
si aucun film n'est trouvé.
-
Dans cet exemple, nous avons ajouté une route
/films/{id}
avec une méthodeGET
pour récupérer un film à partir de son identifiant. -
Nous utilisons la méthode
find()
du repository pour récupérer l'objet entitéFilm
correspondant à l'identifiant fourni. -
Si le film n'est pas trouvé, nous renvoyons une réponse JSON avec un message d'erreur.
-
Sinon, nous renvoyons une réponse JSON contenant les propriétés
id
ettitre
du film.
// Code précédent...
// 1. Route dynamique avec paramètre id pour récuperer un film
#[Route('/films/{id}', name: 'films.film', methods: ['GET'])]
function getById(FilmRepository $repository, int $id): Response {
// 2. Récupérer une entité Film avec son identifiant
$film = $repository->find($id);
// 3. Vérifier si elle n'existe pas
if (!$film) {
return $this->json(
['erreur' => 'Film introuvable'],
Response::HTTP_NOT_FOUND);
}
// 4. Retourner le film en tableau associatifs
return $this->json(
['film' => ['id' => $film->getId(), 'titre' => $film->getTitre()]]
);
}
3.4. Récupérer un film avec son titre
Pour récupérer une entité à partir de critéres, vous pouvez utiliser la méthode findOneBy()
héritée de la classe ServiceEntityRepository
.
Cette méthode prend un tableau de critères de recherche en paramètre et renvoie le premier objet entité correspondant à ces critères, ou null
si aucune entité n'est trouvé.
findOneBy(['propriété1' => 'critère1', 'propriété2' => 'critère2']) : Entity
Il existe l'équivalent pour recupérer plusieurs entités selon les critère:
findBy(['propriété1' => 'critère1', 'propriété2' => 'critère2']): Entity[]
Dans cet exemple, nous allons voir comment récuperer un film en utilisant son titre:
- Ajouté une route dynamique
/films/titre/{titre}
acceptant les méthode HTTPGET
. - Utilisé la méthode
findOneBy()
du repository en spécifiant le critère de recherche. - Si le film n'est pas trouvé, nous renvoyons une réponse JSON avec un message d'erreur.
- Sinon, nous renvoyons une réponse JSON contenant les propriétés
id
ettitre
du film.
// Code précédent...
//1. Route dynamique pour récuperer un film avec son titre acceptant les methode HTTP GET
#[Route('/films/titre/{titre}', name: 'films.film.titre', methods: ['GET'])]
function getByTitre(Request $req, FilmRepository $repository, string $titre): Response {
// 2. Récupérer une entité Film avec son titre
$film = $repository->findOneBy(['titre' => $titre]);
// 3. Vérifier si elle n'existe pas
if (!$film) {
return $this->json(
['erreur' => 'Film introuvable'],
Response::HTTP_NOT_FOUND
);
}
// 4. renvoyer une réponse JSON contenant les id et titre du film.
return $this->json(
['film' => ['id' => $film->getId(), 'titre' => $film->getTitre()]],
);
}
3.5. Mettre à jour un film
Pour mettre à jour une entité, vous devez d'abord la récupérer, puis modifier les propriétés de l'entité en utlisant les setteurs avec les nouvelles valeurs.
Une fois modifier, vous pouvez réutiliser la méthode save()
du repository pour enregistrer les modifications dans la base de données.
Dans cet exemple, nous allons ajouté la fonctionnalité permettant de mettre à jour un film:
- Créer une route
/films/{id}
avec une méthodePUT
pour mettre à jour le titre d'un film. - Si le corps de la requete est vide ou ne contient pas la clé
titre
, nous retournons une erreur. - Sinon, nous utilisons la méthode
find()
du repository pour récupérer l'objet entitéFilm
correspondant à l'identifiant fourni. - Si le film n'est pas trouvé, nous renvoyons une réponse JSON avec un message d'erreur.
- Sinon, nous mettons à jour le titre de l'entité avec la nouvelle valeur et utilisons la méthode
save()
du repository pour sauvegarder les modifications. - Enfin, nous renvoyons une réponse JSON avec les propriétés
id
ettitre
du film mis à jour.
// Code précédent...
// Route Dynamique pour mettre à jour le titre d'un film
#[Route('/films/{id}', name: 'films.update.titre', methods: ['PUT'])]
function updateTitre(Request $req, FilmRepository $repository, int $id): Response {
// 2. Tester et Retourner une erreur si le corps est vide ou pas de clé titre
if (!$req->getContent() || !$req->getPayload()->has('titre')) {
return $this->json(['erreur' => 'Titre obligatoire'], Response::HTTP_NOT_FOUND);
}
// 3. Récupérer une entité Film avec son identifiant
$film = $repository->find($id);
// 4. Retourner une erreur si le film n'existe pas
if (!$film) {
return $this->json(['erreur' => 'Film introuvable'], Response::HTTP_NOT_FOUND);
}
// 5. Mettre à jour le titre
$film->setTitre($req->getPayload()->get('titre'));
// 5. Effectuer une sauvegarde
$filmAjour = $repository->save($film);
// 6. Retourner le film mis à jour
return $this->json(
['film' => [
'id' => $filmAjour->getId(),
'titre' => $filmAjour->getTitre()
]],
);
}
3.6. Supprimer un film
Pour supprimer une entité, vous devezd'abord la récupérer, puis utiliser la méthode supprimer()
du repository pour supprimer l'entité de la base de données.
Pour ajouter la fonctionnalité de suppression de films, nous devons d'abord ajouter une méthode à la classe FilmRepository
permettant de supprimer une entité Film
reçue en paramètre:
- Ajouter une méthodes à la classe
FilmRepository
qui reçoit l'entité en paramètre.- Supprimer l'entité lors la prochaine transaction
- Effectuer l' opération sur la base de donnée
DELETE
.
<?php
// src/Repository/FilmRepository.php
class FilmRepository extends ServiceEntityRepository {
// ... Code précédent
// 1. Méthode pour supprimer une Film dans la base de donnée
public function remove(Film $film) : void {
// 1.1. AJouter la suppression de l'entité Filmpour la prochaine transaction
$this->getEntityManager()->remove($film);
// 1.2. Effectue les opérations de base de données (DELETE) pour supprimer le film
$this->getEntityManager()->flush();
}
}
Puis, nous allons ajouté une route /films/{id}
avec une méthode HTTP DELETE
pour supprimer un film.
- Nous utilisons la méthode
find()
du repository pour récupérer l'objet entitéFilm
correspondant à l'identifiant fourni - Si le film n'est pas trouvé, nous renvoyons une réponse JSON avec un message d'erreur.
- Sinon, nous utilisons la méthode
remove()
du repository pour supprimer l'entité de la base de données. - Enfin, nous renvoyons une réponse JSON avec un message de réussite.
// Code précédent...
#[Route('/films/{id}', name: 'films.supprimer', methods: ['DELETE'])]
function supprimer(Request $req, FilmRepository $repository, int $id): Response {
// 1. Récupérer une entité Film avec son identifiant
$film = $repository->find($id);
// 2. Retourner une erreur si le film n'existe pas
if (!$film) {
return $this->json(['erreur' => 'Film introuvable'], Response::HTTP_NOT_FOUND);
}
// 3. Supprimer le film
$statusSuppression = $repository->supprimer($film);
// 4. Retourner un message de réussite
return $this->json(
['message' => 'Le film ' . $film->getTitre() . ' est supprimé'],
Response::HTTP_OK
);
}
4. Relations entre entités
Dans le contexte de Doctrine, les relations entre entités sont définies à l'aide d'attributs au-dessus des propriétés correspondantes.
Il existe plusieurs types de relations :
-
Relation ManyToOne : Une relation ManyToOne signifie que plusieurs entités de la classe source peuvent être liées à une seule entité de la classe cible. Par exemple, plusieurs commentaire peuvent être liés à un seule film.
-
Relation OneToMany : Une relation OneToMany signifie que chaque entité de la classe source peut être liée à plusieurs entités de la classe cible. Par exemple, un film peut être lié à plusieurs commentaires.
-
Relation ManyToMany : Une relation ManyToMany signifie que plusieurs entités de la classe source peuvent être liées à plusieurs entités de la classe cible. Par exemple, plusieurs films peuvent être liés à un seule acteur et plusieurs acteurs peuvent être liés à ** une seule film**
4.1. Création de la relation
Pour l'exemple nous allons ajouter une relation entre notre entités Film
et un nouvelle entité Commentaire
que nous allons créer.
Cette relation sera de type OneToMany, c'est à dire un film peut avoir plusieurs commentaires, et un commentaire n'est lié qu'a un seul film.
Commençons par définir notre entité Commentaire
avec ses propriétés.
Pour garder les choses simple, ous supposerons que chaque commentaire possède un auteur, un message et une date.
L'entité Commentaire
aura aussi une proriétés representant le film ou l'en indiquera le type (ManyToOne):
<?php
// /src/Entity/Commentaire.php
namespace App\Entity;
use App\Repository\CommentaireRepository;
use App\Entity\Film;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: CommentaireRepository::class)]
class Commentaire {
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
private ?string $auteur = null;
#[ORM\Column(type: "text")]
private ?string $message = null;
#[ORM\Column(type: "date")]
private ?string $date = null;
#[ORM\ManyToOne(targetEntity: Film::class, inversedBy: 'commentaires')]
private $film;
public function getId(): ?int {
return $this->id;
}
public function getAuteur(): ?string {
return $this->auteur;
}
public function setAuteur(string $auteur): static {
$this->auteur = $auteur;
return $this;
}
public function getMessage(): ?string {
return $this->message;
}
public function setMessage(string $message): static {
$this->message = $message;
return $this;
}
public function getDate(): ?string {
return $this->date;
}
public function setDate(string $date): static {
$this->date = $date;
return $this;
}
public function getFilm(): ?Film {
return $this->film;
}
public function setFilm(?Film $film): self {
$this->film = $film;
return $this;
}
}
Maintenant, nous allons ajouter une relation OneToMany Dans l'entité Film
.
Noter qu'il faut intialiser le tableau de commentaires dans le constructeur.
// src/Entity/Film.php
use App\Repository\FilmRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Film
{
// Code précédent...
#[ORM\OneToMany(
targetEntity:"App\Entity\Commentaire",
mappedBy:"film",
cascade:['persist']
)]
private $commentaires;
public function __construct()
{
$this->commentaires = new ArrayCollection();
}
// Méthode pour récuperer la liste des commentaires
public function getCommentaires(): Collection
{
return $this->commentaires;
}
// Méthode pour ajouter un commentaire
public function addCommentaire(Commentaire $commentaire): Collection {
// Permet d'enregistrer le commentaire en enregistrant le film
$commentaire->setFilm($this);
// Ajouter le commentaire à la liste
$this->commentaires->add($commentaire);
return $this->commentaires;
}
}
Ici, nous avons utilisé l'attribut @ORM\OneToMany
pour définir la relation OneToMany entre les entités Film
et Commentaires
.
Nous ajoutons aussi le paramètre cascade
pour indiquer d'enregistrer les nouveaux commentaires lors de l'enregistement du film.
N'oubliez pas de migrer votre base de données pour ajouté la nouvelle table de commentaires.
4.2. Ajouter des commentaires
Maintenant nous pouvons ajouter à notre contrôleur une route pour pouvoir ajouter un commentaire un film:
- Si le corps de la requête est vide ou si les clés auteur et message ne sont pas réçues, retourner un message d'erreur.
- Récuperer l'entité film avec son
id
en utilisant leFilmRepository
. - Si le film n'exsite pas, retourner un message d'erreur.
- Recuperer les données du corps de la requête.
- Instancier et populer le commentaire avec les donnée réçues.
- Ajouter le commentaire dans le film.
- Enregistrer le film qui grâce à l'option
cascade:['persist']
va aussi enregistrer le commentaire dans la base de données.
// /src/Controller/FilmController.php
// Code précédent ...
#[Route('/films/{id}/commentaires', name: 'film.commentaires.add', methods: ['POST'])]
public function ajouterCommentaire(
Request $req,
FilmRepository $repository,
int $id
): Response {
// 1. Il faut verifier si les clés auteur, message sont réçues dans le corps de la requete
if (
!$req->getContent() ||
!$req->getPayload()->has('auteur') ||
!$req->getPayload()->has('message')
) {
return $this->json(
['erreur' => 'Veuillez fournir l\'auteur et le message!'],
Response::HTTP_BAD_REQUEST
);
}
// 2. Récuperer le film avec son id
$film = $repository->find($id);
// 3. Si le film n'exsite pas
if (!$film) {
return $this->json(
['erreur' => 'Film introuvable'],
Response::HTTP_NOT_FOUND
);
}
// 4. Recuperer les données du corps de la requête
$auteur = $req->getPayload()->get('auteur');
$message = $req->getPayload()->get('message');
$date = date_create();
// 5. Instancier et populer le commentaire avec les donnée réçues
$commentaire = (new Commentaire())
->setAuteur($auteur)
->setMessage($message)
->setDate($date)
->setFilm($film);
// 6. Ajouter le commentaire dans le film
$film->addCommentaire($commentaire);
// 7. Enregistrer le film et le commentaire grâce au cascade: persist
$repository->save($film);
return $this->json(['message' => 'Ajout du commentaire réussi!']);
}
4.3. Récuperer des commentaires
Pour récupérer les commentaire d'un film il suffit de récupérer le film puis d'utiliser la méthode getCommentaires
de la class Film:
// /src/Controller/FilmController.php
// Code précédent ...
// Récuperer tous les commentaire d'un film
#[Route('/films/{id}/commentaires', name: 'film.get.commentaires', methods: ['GET'])]
public function getCommentaires(
FilmRepository $repository,
int $id
): Response {
// Récuperer le film avec son id
$film = $repository->find($id);
// Si le film n'exsite pas
if (!$film) {
return $this->json(
['erreur' => 'Film introuvable'],
Response::HTTP_NOT_FOUND
);
}
// récuperer les commentaires automatiquement
$commentaires = $film->getCommentaires();
// Les transformer en un tableau associatif
$commantairesJson = [];
foreach ($commentaires as $c) {
$commantairesJson[] = [
'id' => $c->getId(),
'auteur' => $c->getAuteur(),
'message' => $c->getMessage()
];
}
return $this->json(['film' => $film->getTitre(), 'commentaires' => $commantairesJson]);
}
conclusion
Dans ce cours, nous avons exploré la gestion des bases de données avec Symfony 6 en utilisant Doctrine, l'ORM de Symfony.
Nous avons appris à configurer la connexion à la base de données, à définir des entités et des relations.
Puis nous avons vu comment créer des requêtes avec le langage DQL, à gérer les migrations et les transactions.
Doctrine facilite grandement la manipulation des données dans une base de données relationnelle en utilisant des objets PHP plutôt que des requêtes SQL.
Cela améliore la productivité, la portabilité et la gestion des relations complexes entre les entités.
Pour approfondir vos connaissances sur le sujet, voici quelques liens utiles :
- Documentation officielle de Doctrine
- Documentation Symfony sur Doctrine
- Tutoriel Symfony sur la gestion des bases de données avec Doctrine
Le prochain cours abordera les vues Twig avec Symfony.
Twig est un moteur de templates puissant et flexible intégré à Symfony qui facilite la création et la manipulation de vues dans les applications Symfony.
Nous verrons comment installer et configurer Twig, comment créer des templates Twig, comment utiliser les variables, les boucles et les conditions dans les templates.
Nous verrons aussi comment inclure des fragments de templates, ou faire hériter des templates d'autre templates pour composer votre front-end.
Ce cours vous permettra de maîtriser l'aspect front-end de vos applications Symfony en utilisant Twig pour générer des vues dynamiques et attrayantes.
Aller plus loin
Le prochain cours abordera les vues Twig avec Symfony et vous permettra de maîtriser l'aspect front-end de vos applications Symfony en utilisant Twig pour générer des vues dynamiques et attrayantes.
Commentaires

Symfony 6: Initiation
Au cours de cette série, vous découvrirez les concepts fondamentaux de Symfony 6, tels que la gestion des routes, la manipulation des bases de données, l'authentification et l'autorisation, la création de formulaires, ainsi que l'intégration de composants tiers populaires tels que Doctrine et Twig.
PHP
Initiation
Bases
Web
Programmation
Album

Symfony 6: Introduction
Ce support de cours vous fournira une introduction complète au Framework Symfony.
Vous découvrirez comment installer et configurer Symfony sur votre machine, ainsi que les principes fondamentaux, son architecture et la manière de configurer votre environnement de développement.
PHP
Symfony
Initiation
Bases
Web
Programmation
Introduction

Symfony 6: Les Contrôleurs
Ce support de cours vous introduira aux contrôleurs dans le contexte du développement web avec le Framework Symfony.
Vous apprendrez comment créer, configurer et utiliser des contrôleurs pour interagir avec les utilisateurs, traiter les données et générer des réponses dynamiques.
PHP
Symfony
Initiation
Bases
Contrôleur
Web
Programmation
Introduction

Symfony 6: Les vues avec twig
Dans cette partie du cours, nous allons explorer les vues et les templates TWIG, un moteur de templates puissant et flexible utilisé dans le Framework Symfony.
En comprenant ces concepts, vous serez en mesure de créer des interfaces utilisateur interactives et esthétiques pour vos applications Symfony.
PHP
Symfony
Initiation
Bases
View
Twig
Web
Programmation
Serveur

Symfony 6: Les Formulaires
Les formulaires jouent un rôle essentiel dans les applications web, permettant aux utilisateurs d'interagir avec le système en saisissant et en soumettant des données.
En comprenant les concepts et les fonctionnalités des formulaires dans Symfony 6, vous serez en mesure de développer des applications web dynamiques et interactives.
PHP
Symfony
Initiation
Bases
Formulaires
Validation
Web
Programmation
Serveur

Symfony 6: Authentification
Ce cours d'initiation à la programmation avec Symfony 6 se concentre sur l'authentification et l'autorisation, deux aspects essentiels de la sécurité des applications web.
Vous apprendrez à mettre en place un système d'authentification sécurisé pour gérer l'accès des utilisateurs à votre application et à contrôler leurs permissions.
PHP
Symfony
Initiation
Bases
Formulaires
Authentification
Web
Programmation
Serveur