UGA - MIASHS - S7 - BDD - Pierre Blarre
Les librairies Faker (disponibles dans de nombreux langages de programmation) permettent de générer des données factices pour peupler une base de données.
Dans cette section, nous allons voir comment générer des données factices pour notre base de données de boutique en ligne avec PHP Faker, la version PHP de Faker.
Installation
Dans un terminal à la racine de votre projet, installez la librairie Faker avec Composer :
composer require fakerphp/faker
Comme npm
pour Node.js, Composer est un gestionnaire de dépendances pour PHP. Il permet d’installer des librairies tierces dans votre projet.
Comme le dossier node_modules
pour Node.js, Composer crée un dossier vendor
dans lequel il stocke les librairies installées.
Comme pour Node.js, il est recommandé de ne pas versionner le dossier vendor
dans votre dépôt Git.
Dans le fichier .gitignore
, ajoutez la ligne suivante :
vendor/
Effectuez un commit pour versionner la modification du fichier .gitignore
puis publiez les modifications sur GitHub.
Utilisation de Faker (sans base de données)
Génération de données aléatoires
Créez un fichier faker-tests.php
à la racine de votre projet et ajoutez le code suivant :
<?phprequire_once 'vendor/autoload.php'; // load dependencies installed with Composer$faker = Faker\Factory::create('fr_FR'); // Create a Faker instance in French
echo $faker->name; // Generate a random name?>
Dans un terminal, exécutez le fichier PHP :
php faker-tests.php
Vous devriez voir un nom aléatoire s’afficher dans votre terminal.
Génération de données en masse
Pour générer des données en masse, on pourra utiliser des boucles. Par exemple :
<?phprequire_once 'vendor/autoload.php';$faker = Faker\Factory::create('fr_FR');
for ($i = 0; $i < 10; $i++) { // Generate 10 random names echo $faker->name . PHP_EOL; // PHP_EOL is a constant that represents a newline character}?>
Dans un terminal, exécutez le fichier PHP :
php faker-tests.php
Vous devriez voir 10 noms aléatoires s’afficher dans votre terminal.
Génération de requêtes SQL
Maintenant que nous savons générer des données aléatoires, il suffira de les insérer dans des requêtes SQL :
<?phprequire_once 'vendor/autoload.php';
$faker = Faker\Factory::create('fr_FR');
$sql = 'INSERT INTO Client (nom, adresse) VALUES '. PHP_EOL;
for ($i = 0; $i < 10; $i++) {$nom = $faker->name;$adresse = $faker->address;
$sql .= "('$nom', '$adresse'), ". PHP_EOL;}
$sql = rtrim($sql, ', '); // Remove the last comma$sql .= ';'; // Add a semicolon at the end
echo $sql;?>
Dans un terminal, exécutez le fichier PHP :
php faker-tests.php
Vous devriez voir 10 requêtes SQL d’insertion s’afficher dans votre terminal.
Génération de données pour une base de données
Maintenant que nous savons générer des données aléatoires et les insérer dans des requêtes SQL, nous allons voir comment insérer ces données dans une base de données.
Configuration de connexion : DOTENV
Pour des raisons de sécurité, mais aussi de praticité, il est recommandé de ne pas stocker les identifiants de connexion à la base de données directement dans le code source.
Pour cela, nous allons utiliser un fichier de configuration .env
pour stocker ces informations.
Créez un fichier .env
à la racine de votre projet et ajoutez les lignes suivantes :
DB_DRIVER=mysqlDB_HOST=localhostDB_PORT=3306DB_NAME=[YOUR_DB_NAME]DB_USER=[YOUR_DB_USERNAME]DB_PASS=[YOUR_DB_PASSWORD]
DBML_FILE=boutique-schema.dbmlSVG_FILE=boutique-erd.svgDDL_FILE=boutique-schema.sqlFAKER_FILE=boutique-data.phpDML_FILE=boutique-data.sql
Enfin, pour pouvoir lire les variables d’environnement du fichier .env
, nous allons utiliser la librairie PHP vlucas/phpdotenv
.
Installez cette librairie avec Composer :
composer require vlucas/phpdotenv
On souhaite ignorer le fichier .env
dans notre dépôt Git. Pour cela, ajoutez la ligne suivante dans le fichier .gitignore
:
.env
Cependant, il est important de versionner un fichier .env.example
qui servira de modèle pour les autres développeurs.
Créez un fichier .env.example
à la racine de votre projet et ajoutez les mêmes lignes que dans le fichier .env
, mais sans les valeurs :
DB_DRIVER=mysqlDB_HOST=localhostDB_PORT=3306DB_NAME=[YOUR_DB_NAME]DB_USER=[YOUR_DB_USERNAME]DB_PASS=[YOUR_DB_PASSWORD]
DBML_FILE=boutique-schema.dbmlSVG_FILE=boutique-erd.svgDDL_FILE=boutique-schema.sqlFAKER_FILE=boutique-data.phpDML_FILE=boutique-data.sql
Effectuez un commit pour versionner les modifications apportées à votre projet puis publiez les modifications sur GitHub.
Connexion à la base de données
Il est temps de regrouper tout ce que nous avons vu jusqu’à présent pour insérer des données aléatoires dans une base de données.
<?phprequire_once 'vendor/autoload.php';
//On récupère les variables d'environnement grâce à DOTENV$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);$dotenv->load();
// On se connecte à la base de données$pdo_connection = sprintf('%s:host=%s;dbname=%s', $_ENV['DB_DRIVER'], $_ENV['DB_HOST'], $_ENV['DB_NAME']);$pdo = new PDO($pdo_connection, $_ENV['DB_USER'], $_ENV['DB_PASS']);
// On supprime la base de données si elle existe$pdo->exec('DROP DATABASE IF EXISTS ' . $_ENV['DB_NAME']);// On crée la base de données$pdo->exec('CREATE DATABASE ' . $_ENV['DB_NAME']);// On sélectionne la base de données$pdo->exec('USE ' . $_ENV['DB_NAME']);
// On crée la table Client$pdo->exec('CREATE TABLE Client ( id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, nom VARCHAR(30) NOT NULL, adresse VARCHAR(50) NOT NULL)');
//On crée un objet Faker$faker = Faker\Factory::create('fr_FR');
// On insère des données dans la table Clientfor ($i = 0; $i < 10; $i++) { $nom = $faker->name; $adresse = $faker->address;
$stmt = $pdo->prepare('INSERT INTO Client (nom, adresse) VALUES (:nom, :adresse)'); // Prepare SQL statement $stmt->execute(['nom' => $nom, 'adresse' => $adresse]); // Execute SQL statement}
echo 'Données insérées avec succès !' . PHP_EOL;
$select = $pdo->query('SELECT * FROM Client'); // Select all records from the Client table$clients = $select->fetchAll(PDO::FETCH_ASSOC); // Fetch all records as an associative arrayforeach ($clients as $client) { echo $client['nom'] . ' - ' . $client['adresse'] . PHP_EOL;}
$pdo = null; // Close the connection
?>
Dans un terminal, exécutez le fichier PHP :
php faker-tests-db.php
Vous devriez voir 10 enregistrements aléatoires s’afficher dans votre terminal.
Cependant cette fois-ci, les données ont été insérées dans la base de données boutique
et la table Client
.
Le données affichées dans le terminal sont les données récupérées depuis la base de données.
Scénario de test
Nous souhaitons maintenant des données factices, mais qualitatives, pour notre boutique en ligne.
L’idée est de créer un jeu de données qui nous permettra de tester des requêtes SQL complexes et vérifier que notre base de données fonctionne correctement.
Nous allons créer :
- 5 clients
- 10 produits
- Des commandes et lignes de commande :
- Un client sans commandes
- Un client qui a commandé tous les produits
- Un produit qui n’a pas été commandé
- Un produit qui a été commandé 10 fois
Cette fois-ci, au lieu de créer des données aléatoires à chaque fois, nous allons générer des données aléatoirement une première fois, puis sauvegarder ces données dans un fichier SQL que nous pourrons réutiliser à chaque fois que nous voudrons réinitialiser notre base de données.
Grâce à ces données de tests, nous pourrons vérifier que nos requêtes SQL fonctionnent correctement et que notre base de données est bien structurée.
<?php
require_once 'vendor/autoload.php';
$faker = Faker\Factory::create('fr_FR');
$clients = [];$produits = [];$commandes = [];$commandes_details = [];
//On doit toujours commencer par créer les types d'entités qui n'ont pas de dépendances (ici Clients et Produits)
for ($i = 0; $i < 5; $i++) { $clients[] = [ 'id' => $i + 1, 'nom' => $faker->unique()->name, 'adresse' => $faker->address, ];}//On obtient donc un tableau de clients avec 5 clients d'id 1 à 5
for ($i = 0; $i < 10; $i++) { $produits[] = [ 'id' => $i + 1, 'label' => $faker->unique()->word, 'description' => $faker->sentence, 'prix' => $faker->randomFloat(2, 1, 100), ];}//On obtient donc un tableau de produits avec 10 produits d'id 1 à 10
//On peut maintenant créer les commandes et les lignes de commande
//On commence par récupérer les id des produits pour les utiliser dans les lignes de commande$produitsIds = array_column($produits, 'id');
//On crée les scénarios suivants :
// Client 1 pas de commandes// rien à faire
// Client 2 a commandé tous les produits à travers plusieurs commandes// On va créer 10 commandes pour le client 2, chaque commande contiendra un produit différentfor ($i = 0; $i < 10; $i++) { $commandeId = count($commandes) + 1; //On récupère l'id de la commande en cours (nombre de commandes + 1) $commandes[] = [ 'id' => $commandeId, 'date' => $faker->dateTimeThisYear->format('Y-m-d H:i:s'), 'clientId' => 2, ];
$commandes_details[] = [ 'commandeId' => $commandeId, 'produitId' => $produitsIds[$i], 'quantite' => $faker->numberBetween(1, 5), ];}
// Client 3 a commandé 10 fois un produit// On va créer 10 commandes pour le client 3, chaque commande contiendra le même produit, le produit 1, en quantité 1for ($i = 0; $i < 10; $i++) { $commandeId = count($commandes) + 1; $commandes[] = [ 'id' => $commandeId, 'date' => $faker->dateTimeThisYear->format('Y-m-d H:i:s'), 'clientId' => 3, ];
$commandes_details[] = [ 'commandeId' => $commandeId, 'produitId' => 1, 'quantite' => 1, ];}
// Client 4 a commandé tous les produits à travers une seule commande
//On crée une commande pour le client 4$commandeId = count($commandes) + 1;$commandes[] = [ 'id' => $commandeId, 'date' => $faker->dateTimeThisYear->format('Y-m-d H:i:s'), 'clientId' => 4,];
//On ajoute une ligne de commande pour chaque produitforeach ($produitsIds as $produitId) { $commandes_details[] = [ 'commandeId' => $commandeId, 'produitId' => $produitId, 'quantite' => $faker->numberBetween(1, 5), ];}
// Client 5 a commandé un seul produit à travers une seule commande$commandeId = count($commandes) + 1;$commandes[] = [ 'id' => $commandeId, 'date' => $faker->dateTimeThisYear->format('Y-m-d H:i:s'), 'clientId' => 5,];
$commandes_details[] = [ 'commandeId' => $commandeId, 'produitId' => 1, 'quantite' => 1,];
//On stocke le tout dans un tableau PHP$result = [ 'clients' => $clients, 'produits' => $produits, 'commandes' => $commandes, 'commandes_details' => $commandes_details,];
//Création des requêtes SQL pour insérer les données dans la base de données$sql = '';
foreach ($clients as $client) { $sql .= "INSERT INTO Client (id, nom, adresse) VALUES ({$client['id']}, '{$client['nom']}', '{$client['adresse']}');" . PHP_EOL;}
foreach ($produits as $produit) { $sql .= "INSERT INTO Produit (id, label, description, prix) VALUES ({$produit['id']}, '{$produit['label']}', '{$produit['description']}', {$produit['prix']});" . PHP_EOL;}
foreach ($commandes as $commande) { $sql .= "INSERT INTO Commande (id, date, client_id) VALUES ({$commande['id']}, '{$commande['date']}', {$commande['clientId']});" . PHP_EOL;}
foreach ($commandes_details as $ligneCommande) { $sql .= "INSERT INTO CommandeDetail (commande_id, produit_id, quantite) VALUES ({$ligneCommande['commandeId']}, {$ligneCommande['produitId']}, {$ligneCommande['quantite']});" . PHP_EOL;}
//On écrit les requêtes SQL dans un fichier SQL pour sauvegardefile_put_contents('boutique-data.sql', $sql);
echo 'Fichier SQL généré avec succès !' . PHP_EOL;
// //Optionnellement, on peut sauvegarder les données au format JSON pour sauvegarde// file_put_contents('boutique-data.json', json_encode($result, JSON_PRETTY_PRINT));
Dans un terminal, exécutez le fichier PHP :
php boutique-data.php
Un fichier boutique-data.sql
a été généré à la racine de votre projet.
Ouvrez ce fichier pour vérifier son contenu.
Et voilà ! Vous avez maintenant un jeu de données de test pour votre boutique en ligne.