TD6-3: La base de données

Dans cette partie du TD, nous allons créer la base de données associée à notre application web.

Lecture recommandée: la documentation officielle de Symfony.com sur Doctrine

Configuration

Nous allons dans un premier temps configurer Symfony pour qu'il accède à la base de données.

Pour cela, éditez le fichier .env et modifiez la valeur de la variable DATABASE_URL. Cette dernière ressemblera à ceci:

DATABASE_URL="mysql://127.0.0.1:3306/database?charset=utf8mb4&serverVersion=5.7&user=pizza&password=pizza"

Ici, il faut éventuellement adapter:

  • L'adresse du serveur
  • Le nom de la base de données
  • L'identifiant et le mot de passe

Vous pouvez par exemple vérifier en lançant une commande doctrine comme:

symfony console doctrine:schema:validate

Cette commande sert à vérifier que votre base de données est en accord avec votre application, dans votre cas vous n'avez pas encore décrit de classes mappées avec la base de données mais cela peut vous permettre de tester que la connexion fonctionne.

Entités

Création

Nous allons maintenant créer nos entités. Pour cela, nous allons utiliser le maker bundle:

symfony console make:entity

Il vous sera alors demandé de nommer votre entité, appellez là Pizza, nous utiliserons ici aussi la configuration par annotations.

Vous pourrez alors saisir les champs de manière interactive, ajouter un champ name de type string, un champ description de type text, un champ price de type float.

Regarder attentivement le fichier Entity/Pizza.php qui aura été généré dans vos sources, son contenu en terme de code est trivial, mais les annotations décrivent la correspondance avec la base de données.

Génération de la base

Maintenant que nous avons créé une entité, nous allons demander à Doctrine de créer la base de données correspondante, pour cela, utilisez:

$ symfony console doctrine:schema:create 
ATTENTION: This operation should not be executed in a production environment.

Creating database schema...
Database schema created successfully!

Rendez-vous dans votre base de données, avec par exemple phpMyAdmin et constatez que la table Pizza a été créée.

Ajout d'une entité

Nous allons ajouter une entité ingrédient, de la même manière que précédemment, créez l'entité App:Ingredient ayant juste un champ name de type string.

Une deuxième entité Entity/Ingredient.php apparaîtra.

Maintenant, nous pouvons demander à Doctrine de mettre à jour la base de données, essayez:

$ php bin/console doctrine:schema:update --dump-sql
CREATE TABLE Ingredient (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB

Ici, doctrine nous affiche la requête qui permet de mettre à jour la base pour qu'elle corresponde à nos entités. Vous pouvez également lui demandez d'exécuter les requêtes nécéssaire avec --force:

$ php bin/console doctrine:schema:update --force
Updating database schema...
Database schema updated successfully! "1" queries were executed

Mise en relation

Une pizza doit avoir plusieurs ingrédients, et un ingrédient doit pouvoir être dans plusieurs pizzas. Pour mettre en relation ces deux entités, il faudrait normalement créer manuellement une table intéremédiaire. Doctrine va également s'en charger pour nous!

Pour cela, modifiez l'entité pizza à l'aide du maker bundle:

symfony console make:entity

Entrez Pizza, pour y ajouter l'entrée ingredients, et saisissez le type ManyToMany. Ensuite, indiquez que la classe est en relation avec Ingredient.

Enfin, exécutez à nouveau doctrine:schema:update, en regardant tout d'abord les modifications qui seront apportées avec --dump-sql puis en les exécutant avec --force.

Requêtage

Nous allons maintenant requêter la base de données.

Insertion

Nous allons créer des pizzas, pour ne pas parler tout de suite des formulaires, nous écrirons une action qui inserera les pizzas.

Voici un exemple:

<?php
    // ...
    public function insertPizzasAction() {
        $em = $this->getDoctrine()->getManager();

        $mozarella = new Ingredient;
        $mozarella->setName('Mozarella');
        $parmesan = new Ingredient;
        $parmesan->setName('Parmesan');
        $quatreFromages = new Pizza;
        $quatreFromages
            ->setName('4 fromages')
            ->setPrice(32.2)
            ->setDescription('Pour les fans de fromage')
            ;   
        $quatreFromages->addIngredient($mozarella);
        $quatreFromages->addIngredient($parmesan);
        $em->persist($quatreFromages);
        $em->persist($mozarella);
        $em->persist($parmesan);
        $em->flush();

        return new Response('Pizzas créées');
    }

Remarquez l'utilisation des accesseurs (setName et setDescription) qui ont été générés par Doctrine et que l'on peut appeler à la chaîne.

Executez cette requêtes et allez voir dans la base de données pour vérifier la présence des nouvelles lignes dans les tables.

Listage

Nous allons maintenant récupérer les pizzas pour les lister. Vous pourrez par exemple utiliser:

<?php
    
    $pizzas = $em->getRepository(Pizza::class)
                ->findAll();

Ainsi, vous pourrez passer les pizzas en paramètres à une vue comme dans la partie précédente et en afficher la liste. Voici un exemple de code twig:

<ul>
{% for pizza in pizzas %}
    <li>{{ pizza.name }}</li>
{% endfor %}
</ul>

Remarquez ici que pizza.name fera appel à $pizza->getName(), Twig est assez intelligent pour utiliser les accesseurs

Vous pourriez également écrire {{ pizza }}, moyennant une surcharge de la méthode __toString() de la classe Pizza

Affichez également entre parenthèse tous les ingrédients d'une pizza. Pour cela, c'est très simple, vous pouvez accéder à l'entrée ingredients, qui appellera elle-même la méthode getIngredients() qui retournera un tableau (un peu spécial car géré par Doctrine) contenant tous les ingrédients.

Utilisez le filtre join de Twig pour cela.

Génération CRUD

Lancez la commande:

symfony console make:crud

Et demandez à Symfony de générer le CRUD pour l'entité Pizza. Consultez les pages générés (/pizzas).