Aller au contenu

UGA - MIASHS - S7 - BDD - Pierre Blarre

Données factices avec Faker

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 :

Fenêtre de terminal
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 :

Fenêtre de terminal
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 :

faker-tests.php
<?php
require_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 :

Fenêtre de terminal
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 :

faker-tests.php
<?php
require_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 :

Fenêtre de terminal
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 :

faker-tests.php
<?php
require_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 :

Fenêtre de terminal
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 :

.env
DB_DRIVER=mysql
DB_HOST=localhost
DB_PORT=3306
DB_NAME=[YOUR_DB_NAME]
DB_USER=[YOUR_DB_USERNAME]
DB_PASS=[YOUR_DB_PASSWORD]
DBML_FILE=boutique-schema.dbml
SVG_FILE=boutique-erd.svg
DDL_FILE=boutique-schema.sql
FAKER_FILE=boutique-data.php
DML_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 :

Fenêtre de terminal
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 :

Fenêtre de terminal
.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 :

.env.example
DB_DRIVER=mysql
DB_HOST=localhost
DB_PORT=3306
DB_NAME=[YOUR_DB_NAME]
DB_USER=[YOUR_DB_USERNAME]
DB_PASS=[YOUR_DB_PASSWORD]
DBML_FILE=boutique-schema.dbml
SVG_FILE=boutique-erd.svg
DDL_FILE=boutique-schema.sql
FAKER_FILE=boutique-data.php
DML_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.

faker-tests-db.php
<?php
require_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 Client
for ($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 array
foreach ($clients as $client) {
echo $client['nom'] . ' - ' . $client['adresse'] . PHP_EOL;
}
$pdo = null; // Close the connection
?>

Dans un terminal, exécutez le fichier PHP :

Fenêtre de terminal
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.

boutique-data.php
<?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érent
for ($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é 1
for ($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 produit
foreach ($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 sauvegarde
file_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 :

Fenêtre de terminal
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.