Connexion à la base de données
Dans la plupart des projets Symfony, la connexion à la base de données est effectuée grâce à Doctrine.
Doctrine est un ORM (Object-Relational Mapping).
Cela veut dire que les tables SQL ne sont pas manipulées directement (grâce à des requêtes SQL classiques), mais que chaque table est représenté par une classe.
Dans la précédente partie du TP, nous avons créé un objet Article
qui est la représentation d’un Article de blog
dans notre application.
Doctrine va prendre une classe comme celle-là et va la faire correspondre (mapper) à une table SQL.
Par exemple, le champ title
de notre classe correspondra ua champ title
dans notre table SQL article
.
Cette notion est assez compliquée à comprendre, nous allons essayer de comprendre par l’exemple.
Installation
ici encore, on installe Doctrine grâce à composer. orm
est un alias de symfony/orm-pack qui installe toutes les
dépendances nécessaires à Doctrine pour fonctionner.
composer require orm
Suite à ça, Symfony Flex modifie le fichier .env
pour y ajouter une variable DATABASE_URL
avec un valeur
En général, les valeurs par défaut pour MySQL sont le user root
et pas de mot de passe.
La valeur de db_name
n’a pas d’importance, c’est Doctrine qui va créer la DB tout seul, vous pouvez donc mettre ce
que vous voulez.
Enfin pour la version, vérifier que vous ayez bien la 5.7
, si ce n’est pas le cas, remplacez 5.7
par votre version actuelle
Si vous avez une base mariadb, elle est considérée par Doctrine comme mysql donc faites comme si c’était un MySQL.
Vous devriez donc avoir cela :
Dans la VM avec PostgreSQL :
DATABASE_URL="postgresql://symfony:symfony@127.0.0.1:5432/symfony?serverVersion=12.6&charset=utf8"
Pour MySQL :
mysql://root:@127.0.0.1:3306/my_blog?serverVersion=5.7
NB : Doctrine possède une partie nommée DBAL (Database abstraction layer), qui fait abstraction du SGBDR utilisé. Il est donc possible d’utiliser PostgreSQL ou SQLite par exemple. Pour éviter les problèmes spécifiques à chaque plateforme, nous allons tous utiliser MySQL dans le cadre de ce TP.
Commandes pour créer la base de données :
php bin/console doctrine:database:drop --force --if-exists
⚠ si vous avez mis comme nom de db, une db qui existe déjà, elle sera suppriméephp bin/console doctrine:database:create
⚠ Renommez ou supprimez votre classe Article.php afin de pouvoir faire la commande qui suit.
Créer une entité App\Entity\Article
avec l’aide de php bin/console make:entity
.
Pour les différents champs à ajouter et leur type, référez vous à la partie sur Twig à l’exception
de body
où vous mettrez text
au lieu de string
.
Observez la classe Article créée par la commande.
Vous remarquerez l’annotation @ORM\Entity
en haut de classe, qui permet de spécifier à Doctrine que cette classe est une entité.
Il y a également des annotations @ORM\Colum
au dessus de chaque propriété qui servent à définir le type et les contraintes de chaque colonne
en base de données.
Cette commande a également généré une classe ArticleRepository
mais nous y reviendrons plus tard.
Voici un exemple tiré de la documentation officielle qui illustre le travail effectué par Doctrine.
Une fois votre entité complète, il faut créer et exécuter une migration. Une migration est un fichier qui est créé par Doctrine et qui contient les requêtes SQL a exécuter pour créer, modifier ou supprimer une table.
Pour cela Doctrine compare le mapping (annotations dans la classe Article) et l’état actuel de la base de données.
Comme la table article n’existe pas, Doctrine va la créer avec tous les champs de notre entité.
Exécuter la commande php bin/console doctrine:migration:diff
qui calcule la différence entre le mapping et la DB.
Observez le fichier généré dans src/Migrations
Pour l’exécuter, il faut taper la commande php bin/console doctrine:migration:migrate
Cette commande va exécuter toutes les migrations qui n’ont pas encore été appliquées à la DB. Ainsi, si vous taper cette commande à nouveau, Doctrine devrait vous dire qu’il n’y a rien a exécuter.
Il en est de même pour bin/console doctrine:migration:diff
, cela va générer un fichier de migration vide car
il n’y a plus de différences entre le mapping et la DB.
Fixtures
Afin de faciliter le développement et avant d’avoir à notre disposition un formulaire pour créer des articles, nous allons créer des fixtures.
Ce sont des fichiers php dans lesquels nous allons créer de faux articles pour le développement.
Regardez la documentation des fixtures
pour comprendre comment elles marchent et appliquez cette logique à nos articles pour en créer 10 avec l’aide
de Faker pour générer des données aléatoire lisibles : Librairie Faker pour rappel via composer require
.
Puis chargez ces fixtures avec la commande php bin/console doctrine:fixtures:load
Et si on affichait tout ça ?
Si tout s’est bien passé, on devrait avoir 10 articles en DB.
Comment vérifier ça ?
Il faut récupérer les articles grâce à la classe ArticleRepository
que nous avions volontairement
mis de côté plus tôt dans le TP.
Un Repository, dans Doctrine, c’est une classe qui possède des méthodes permettant de récupérer des entités.
Par défaut, un répository possède plusieurs méthodes, dont la méthode findAll()
que nous allons utiliser dans notre Controller.
Comment récupérer un repository ?
Grâce au Dependency Injection Container (DIC).
En Symfony, chaque classe créée dans src
est considérée comme un service à l’exception des classes définies dans
Entity
et Migrations
ainsi que la classe Kernel.php
.
Et un service, c’est un object qui a une fonction précise et qui sont gérés par le DIC.
Ce DIC nous permet d’injecter les services dans nos controlleurs par exemple (mais aussi dans d’autres services !), c’est à dire rendre disponible le service dans le controlleur.
Généralement, l’injection de dépendances est réalisée dans le constructeur de notre controlleur et depuis Symfony 4, nous pouvons utiliser l’autowiring pour l’injection de dépendances.
L’autowiring consiste à utiliser le typage des paramètres du constructeur pour injecter nos dépendances automatiquement.
Plus d’informations sur les services et le DIC ici.
Ici, en ajoutant le code ci-dessous à notre HomeController
, nous avons maintenant accès à $this->articleRepository
.
private $articleRepository;
public function __construct(ArticleRepository $articleRepository)
{
$this->articleRepository = $articleRepository;
}
⚠ n’oubliez pas le use
en haut de votre fichier pour importer ArticleRepository
.
Utiliser maintenant la méthode findAll()
du repository pour remplacer le tableau articles
que nous passions au template
Twig.
En actualisant la page, vous devriez voir vos articles créés grâce aux fixtures !
Débugger le SQL généré par Doctrine
Cliquez sur l’icône dans la debug bar.
Vous arrivez sur une page du Profiler qui vous indique quelles sont les requêtes SQL qui ont été exécutées.
On voit ici que Doctrine génère une requête SQL qui SELECT
tous nos champs de la table article
.
Ok, mais là on affiche tous les articles ?!
Oui… Si demain on a 100, 1000, 10000 articles, ils seront tous affichés sur la page d’accueil.
Vous pouvez même tester en augmentant le nombre d’itérations dans vos fixtures pour générer des centaines ou milliers d’articles 😉
Pas terrible tout ça…
C’est là qu’intervient : le repository !
Nous allons ici créer une méthode findlast
dans le repository qui va nous permettre de récupérer les derniers articles.
public function findLast($count) {
return $this->createQueryBuilder('article')
->getQuery()
->getResult()
;
}
Nous créons ici un QueryBuilder
, c’est l’objet que nous allons manipuler afin de construire nos requêtes dans un
langage assez proche du SQL, le DQL (Doctrine Query Language).
Le code ci-dessus revient à exécuter la requête SQL SELECT * FROM article
, sauf que Doctrine va automatiquement
créer des objets Article
à partir du résultat de la requête SQL. C’est ce qu’à également fait la méthode findAll
que
nous avons utilisé précédemment. Ce processus est appelé hydratation.
A l’aide du code ci-dessus et de la documentation du QueryBuilder, récupérez les 4 derniers articles et affichez les sur la page d’accueil, du plus récent au plus ancien.
A nouveau, regardez l’onglet Doctrine dans le profiler et observez la nouvelle requête générée.
Résumons…
Dans cette partie nous avons vu comment ajouter une connexion à la base de données grâce à Doctrine, les entités et les repositories.
Nous avons aussi vu comment générer des tables SQL grâce aux entités et aux migrations et comment générer de fausses données pour le développement.
Nous avons également abordé l’injection de dépendances.
Avec tout ça, nous avons maintenant une page d’accueil fonctionnelle à l’exception de deux chose :
- Le bouton
Older Posts
, nous y reviendrons peut-être à la fin du TP - Les liens sur le titre des articles qui doit nous rediriger vers l’article en question, c’est ce que nous allons voir maintenant.