Documentation et exemples d'utilisation de la classe PHP pour MariaDB/MySQL
v2.0 - Avec gestion d'erreurs, pagination, Query Builder avancé
La classe permet de gérer plusieurs serveurs MySQL/MariaDB. Utilisez addServer() pour configurer chaque connexion.
| Paramètre | Type | Requis | Description |
|---|---|---|---|
$name |
string | Oui | Nom identifiant du serveur |
$host |
string | Oui | Adresse du serveur (ex: localhost) |
$database |
string | Oui | Nom de la base de données |
$user |
string | Oui | Nom d'utilisateur |
$password |
string | Oui | Mot de passe |
$port |
int | Non | Port (défaut: 3306) |
$options |
array | Non | Options PDO supplémentaires |
require_once 'MySQL.php';
// Configuration du serveur principal (local)
MySQL::addServer(
'default', // Nom du serveur
'localhost', // Hôte
'ma_base', // Base de données
'root', // Utilisateur
'mon_password', // Mot de passe
3306 // Port
);
// Configuration d'un second serveur (distant)
MySQL::addServer(
'remote',
'192.168.1.100',
'base_distante',
'admin',
'password_secure',
3306
);
// Activer le mode debug (affiche les détails des erreurs SQL)
MySQL::setDebug(true);
// Basculer entre les serveurs
MySQL::use('default');
$users = MySQL::select("SELECT * FROM users");
MySQL::use('remote');
$products = MySQL::select("SELECT * FROM products");
La classe utilise une exception personnalisée MySQLException avec des types d'erreur spécifiques et un système de logging automatique.
MySQLException, log d'erreurs, et mode debug.
| Type | Description |
|---|---|
SERVER_NOT_FOUND |
Serveur non configuré |
CONNECTION_FAILED |
Échec de connexion à la base |
SQL_ERROR |
Erreur d'exécution SQL |
EMPTY_DATA |
Données vides pour INSERT/UPDATE |
MISSING_WHERE |
Clause WHERE manquante pour DELETE |
TRANSACTION_ROLLBACK |
Transaction annulée |
try {
$user = MySQL::selectOne(
"SELECT * FROM userss WHERE id = ?", // ⚠️ 'userss' n'existe pas
[42]
);
} catch (MySQLException $e) {
// Informations de base
echo "Message: " . $e->getMessage() . "<br>";
echo "Type: " . $e->getErrorType() . "<br>";
echo "Code: " . $e->getCode() . "<br>";
// Vérifier le type d'erreur
if ($e->isConnectionError()) {
echo "Problème de connexion au serveur !";
} elseif ($e->isSqlError()) {
echo "Erreur dans la requête SQL.";
}
// Récupérer tous les détails sous forme de tableau
$details = $e->toArray();
print_r($details);
}
// Toutes les erreurs SQL sont automatiquement loguées
// Récupérer le log complet
$errors = MySQL::getErrorLog();
foreach ($errors as $error) {
echo "[{$error['timestamp']}] Erreur SQL : " . $error['error'] . "<br>";
echo "Requête : " . $error['query'] . "<br>";
echo "Serveur : " . $error['server'] . "<br>";
echo "Temps : " . round($error['time'] * 1000, 2) . " ms<br><br>";
}
// Récupérer la dernière erreur
$lastError = MySQL::getLastError();
if ($lastError) {
echo "Dernière erreur : " . $lastError['error'];
}
// Vider le log
MySQL::clearErrorLog();
// Activer le mode debug (affiche la requête dans le message d'erreur)
MySQL::setDebug(true);
try {
MySQL::select("SELECT * FROM table_inexistante");
} catch (MySQLException $e) {
// En mode debug, le message contient la requête complète
echo $e->getMessage();
// "Erreur SQL [42S02]: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.table_inexistante' doesn't exist
// Requête: SELECT * FROM table_inexistante"
}
// En production, désactiver le debug pour ne pas exposer les requêtes
MySQL::setDebug(false);
// Le message sera simplement : "Erreur d'exécution de la requête SQL."
try {
MySQL::addServer('bad', 'wrong.host', 'db', 'user', 'pass');
MySQL::use('bad');
MySQL::select("SELECT 1");
} catch (MySQLException $e) {
if ($e->isConnectionError()) {
echo "Impossible de se connecter au serveur. Vérifiez la configuration.";
// Logger l'erreur, envoyer une alerte, etc.
}
}
Exécute une requête SELECT et retourne toutes les lignes sous forme de tableau associatif.
// Récupérer tous les utilisateurs
$users = MySQL::select("SELECT * FROM users");
foreach ($users as $user) {
echo $user['name'] . " - " . $user['email'] . "<br>";
}
// Avec des paramètres (requête préparée)
$activeUsers = MySQL::select(
"SELECT * FROM users WHERE status = ? AND created_at > ?",
['active', '2024-01-01']
);
// Avec LIKE
$search = '%john%';
$results = MySQL::select(
"SELECT * FROM users WHERE name LIKE ?",
[$search]
);
// Récupérer un utilisateur spécifique
$user = MySQL::selectOne(
"SELECT * FROM users WHERE id = ?",
[42]
);
if ($user) {
echo "Nom : " . $user['name'];
} else {
echo "Utilisateur non trouvé";
}
// Compter le nombre d'utilisateurs
$count = MySQL::selectValue("SELECT COUNT(*) FROM users");
// Somme des ventes
$total = MySQL::selectValue(
"SELECT SUM(amount) FROM orders WHERE status = ?",
['completed']
);
count() pour compter les enregistrements.
// Compter tous les utilisateurs
$total = MySQL::count('users');
// Compter avec condition
$activeCount = MySQL::count('users', 'status = ?', ['active']);
// Compter les valeurs distinctes
$uniqueCities = MySQL::count('users', null, [], 'DISTINCT city');
$newId = MySQL::insert('users', [
'name' => 'Jean Dupont',
'email' => 'jean@example.com',
'status' => 'active',
]);
echo "Nouvel ID : " . $newId;
// Gestion de l'erreur si données vides
try {
MySQL::insert('users', []); // ⚠️ Lance une MySQLException
} catch (MySQLException $e) {
echo "Erreur : " . $e->getMessage(); // "Aucune donnée à insérer."
}
$users = [
['name' => 'Alice', 'email' => 'alice@example.com'],
['name' => 'Bob', 'email' => 'bob@example.com'],
['name' => 'Charlie', 'email' => 'charlie@example.com'],
];
$inserted = MySQL::insertBatch('users', $users);
echo "{$inserted} utilisateurs insérés";
$affected = MySQL::update(
'users',
['name' => 'Jean Martin', 'email' => 'jean.m@example.com'],
'id = ?',
[42]
);
// Erreur si données vides
try {
MySQL::update('users', [], 'id = 1', []);
} catch (MySQLException $e) {
echo $e->getMessage(); // "Aucune donnée à mettre à jour."
}
$deleted = MySQL::delete(
'users',
'id = ?',
[42]
);
// ⚠️ WHERE obligatoire
try {
MySQL::delete('users', '', []); // Lance une exception
} catch (MySQLException $e) {
echo $e->getMessage(); // "Clause WHERE requise pour la suppression."
}
// Requête complexe avec JOIN
$results = MySQL::raw("
SELECT u.*, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.status = ?
GROUP BY u.id
HAVING order_count > ?
ORDER BY order_count DESC
LIMIT ?
", ['active', 5, 10])->fetchAll();
// CREATE TABLE
MySQL::raw("
CREATE TABLE IF NOT EXISTS logs (
id INT AUTO_INCREMENT PRIMARY KEY,
message TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
");
La méthode query() permet de construire des requêtes complexes avec JOIN, GROUP BY, HAVING, ORDER BY et LIMIT sans écrire de SQL brut.
| Option | Type | Description |
|---|---|---|
columns |
string|array | Colonnes à sélectionner (défaut: *) |
join |
string|array | Clauses JOIN |
where |
string | Clause WHERE |
whereParams |
array | Paramètres du WHERE |
groupBy |
string|array | GROUP BY |
having |
string | Clause HAVING |
havingParams |
array | Paramètres du HAVING |
orderBy |
string|array | ORDER BY |
limit |
int | LIMIT |
offset |
int | OFFSET |
// INNER JOIN simple
$usersWithOrders = MySQL::query('users', [
'columns' => ['users.id', 'users.name', 'orders.total'],
'join' => 'INNER JOIN orders ON users.id = orders.user_id',
'where' => 'users.status = ?',
'whereParams' => ['active'],
]);
// Multiple JOINs
$results = MySQL::query('orders', [
'columns' => [
'orders.id',
'users.name as user_name',
'products.name as product_name',
'order_items.quantity'
],
'join' => [
'INNER JOIN users ON orders.user_id = users.id',
'INNER JOIN order_items ON orders.id = order_items.order_id',
'INNER JOIN products ON order_items.product_id = products.id',
],
'where' => 'orders.status = ?',
'whereParams' => ['completed'],
]);
// LEFT JOIN avec alias
$users = MySQL::query('users', [
'columns' => [
'users.*',
'COUNT(orders.id) as order_count'
],
'join' => 'LEFT JOIN orders ON users.id = orders.user_id',
'groupBy' => 'users.id',
]);
// GROUP BY simple
$byStatus = MySQL::query('users', [
'columns' => ['status', 'COUNT(*) as count'],
'groupBy' => 'status',
]);
// GROUP BY avec HAVING
$popularProducts = MySQL::query('order_items', [
'columns' => [
'product_id',
'SUM(quantity) as total_sold',
'AVG(price) as avg_price'
],
'groupBy' => 'product_id',
'having' => 'total_sold > ?',
'havingParams' => [100],
'orderBy' => 'total_sold DESC',
'limit' => 10,
]);
// GROUP BY multiple colonnes
$monthlySales = MySQL::query('orders', [
'columns' => [
'YEAR(created_at) as year',
'MONTH(created_at) as month',
'COUNT(*) as order_count',
'SUM(total) as revenue'
],
'where' => 'status = ?',
'whereParams' => ['completed'],
'groupBy' => ['YEAR(created_at)', 'MONTH(created_at)'],
'having' => 'revenue > ?',
'havingParams' => [1000],
'orderBy' => ['year DESC', 'month DESC'],
]);
// ORDER BY simple
$sorted = MySQL::query('products', [
'orderBy' => 'price ASC',
'limit' => 20,
]);
// ORDER BY multiple
$users = MySQL::query('users', [
'where' => 'status = ?',
'whereParams' => ['active'],
'orderBy' => ['created_at DESC', 'name ASC'],
'limit' => 50,
'offset' => 100, // Page 3 avec 50 éléments par page
]);
// Combiné : JOIN + WHERE + GROUP BY + HAVING + ORDER BY + LIMIT
$topCustomers = MySQL::query('users', [
'columns' => [
'users.id',
'users.name',
'users.email',
'COUNT(orders.id) as total_orders',
'SUM(orders.total) as total_spent'
],
'join' => 'INNER JOIN orders ON users.id = orders.user_id',
'where' => 'orders.status = ? AND orders.created_at >= ?',
'whereParams' => ['completed', '2024-01-01'],
'groupBy' => 'users.id',
'having' => 'total_spent >= ?',
'havingParams' => [500],
'orderBy' => 'total_spent DESC',
'limit' => 10,
]);
Deux méthodes de pagination : paginate() pour les requêtes SQL brutes et paginateQuery() pour le Query Builder.
[
'data' => [], // Les résultats de la page
'pagination' => [
'total' => 150, // Nombre total d'enregistrements
'per_page' => 20, // Éléments par page
'current_page' => 2, // Page actuelle
'last_page' => 8, // Dernière page
'from' => 21, // Premier élément
'to' => 40, // Dernier élément
'has_more' => true, // Il y a une page suivante
'has_previous' => true, // Il y a une page précédente
]
]
// Pagination simple
$result = MySQL::paginate(
"SELECT * FROM users WHERE status = ? ORDER BY created_at DESC",
['active'],
2, // Page 2
20 // 20 éléments par page
);
// Afficher les résultats
foreach ($result['data'] as $user) {
echo $user['name'] . "<br>";
}
// Informations de pagination
$pagination = $result['pagination'];
echo "Page {$pagination['current_page']} / {$pagination['last_page']}<br>";
echo "Total : {$pagination['total']} utilisateurs<br>";
// Liens de navigation
if ($pagination['has_previous']) {
echo "<a href='?page=" . ($pagination['current_page'] - 1) . "'>← Précédent</a> ";
}
if ($pagination['has_more']) {
echo "<a href='?page=" . ($pagination['current_page'] + 1) . "'>Suivant →</a>";
}
// Pour les requêtes complexes avec GROUP BY, fournir une requête de comptage
$result = MySQL::paginate(
"SELECT category_id, COUNT(*) as count FROM products GROUP BY category_id",
[],
1,
10,
"SELECT COUNT(DISTINCT category_id) FROM products" // Requête de comptage
);
// Pagination avec le Query Builder
$result = MySQL::paginateQuery(
'products',
3, // Page 3
15, // 15 par page
[
'where' => 'status = ? AND stock > ?',
'whereParams' => ['active', 0],
'orderBy' => 'created_at DESC',
]
);
// Avec JOIN
$result = MySQL::paginateQuery(
'orders',
1,
10,
[
'columns' => ['orders.*', 'users.name as user_name'],
'join' => 'INNER JOIN users ON orders.user_id = users.id',
'where' => 'orders.status = ?',
'whereParams' => ['pending'],
'orderBy' => 'orders.created_at DESC',
]
);
// Affichage complet
$products = $result['data'];
$p = $result['pagination'];
echo "<table>";
foreach ($products as $product) {
echo "<tr><td>" . $product['name'] . "</td></tr>";
}
echo "</table>";
echo "<p>Affichage {$p['from']} - {$p['to']} sur {$p['total']}</p>";
// Numéros de page
echo "<div class='pagination'>";
for ($i = 1; $i <= $p['last_page']; $i++) {
if ($i == $p['current_page']) {
echo "<strong>{$i}</strong> ";
} else {
echo "<a href='?page={$i}'>{$i}</a> ";
}
}
echo "</div>";
// Fonction helper pour générer la pagination HTML
function renderPagination($pagination, $urlPattern = '?page=%d') {
$html = "<div class='pagination'>";
// Bouton Précédent
if ($pagination['has_previous']) {
$url = sprintf($urlPattern, $pagination['current_page'] - 1);
$html .= "<a href='{$url}' class='prev'>← Précédent</a>";
}
// Pages
$start = max(1, $pagination['current_page'] - 2);
$end = min($pagination['last_page'], $pagination['current_page'] + 2);
for ($i = $start; $i <= $end; $i++) {
if ($i == $pagination['current_page']) {
$html .= "<span class='current'>{$i}</span>";
} else {
$url = sprintf($urlPattern, $i);
$html .= "<a href='{$url}'>{$i}</a>";
}
}
// Bouton Suivant
if ($pagination['has_more']) {
$url = sprintf($urlPattern, $pagination['current_page'] + 1);
$html .= "<a href='{$url}' class='next'>Suivant →</a>";
}
$html .= "</div>";
return $html;
}
// Utilisation
echo renderPagination($result['pagination']);
Les transactions permettent d'exécuter plusieurs opérations de manière atomique.
try {
MySQL::transaction(function() {
$orderId = MySQL::insert('orders', [
'user_id' => 42,
'total' => 299.99,
]);
foreach ($cartItems as $item) {
MySQL::insert('order_items', [
'order_id' => $orderId,
'product_id' => $item['id'],
'quantity' => $item['qty'],
]);
}
});
} catch (MySQLException $e) {
echo "Échec : " . $e->getMessage();
}
// Afficher les statistiques
$stats = MySQL::getStats();
echo "Requêtes : " . $stats['queries'] . "<br>";
echo "Temps : " . round($stats['time'] * 1000, 2) . " ms";
// Vérifier l'état de la connexion
if (MySQL::isConnected()) {
echo "Connecté au serveur : " . MySQL::current();
}
Exemple complet combinant toutes les fonctionnalités pour un système de gestion de commandes avec pagination et statistiques.
require_once 'MySQL.php';
// Configuration
MySQL::addServer('default', 'localhost', 'shop', 'root', 'password');
MySQL::setDebug(true);
// ========== CRUD COMMANDES ==========
// Créer une commande avec transaction
function createOrder($userId, $items) {
return MySQL::transaction(function() use ($userId, $items) {
$total = array_sum(array_column($items, 'subtotal'));
$orderId = MySQL::insert('orders', [
'user_id' => $userId,
'total' => $total,
'status' => 'pending',
]);
foreach ($items as $item) {
MySQL::insert('order_items', [
'order_id' => $orderId,
'product_id' => $item['product_id'],
'quantity' => $item['quantity'],
'price' => $item['price'],
]);
}
return $orderId;
});
}
// Lister les commandes avec pagination et JOIN
function getOrders($page = 1, $status = null) {
$options = [
'columns' => [
'orders.id',
'orders.total',
'orders.status',
'orders.created_at',
'users.name as user_name',
'users.email',
],
'join' => 'INNER JOIN users ON orders.user_id = users.id',
'orderBy' => 'orders.created_at DESC',
];
if ($status) {
$options['where'] = 'orders.status = ?';
$options['whereParams'] = [$status];
}
return MySQL::paginateQuery('orders', $page, 20, $options);
}
// Statistiques par catégorie
function getCategoryStats() {
return MySQL::query('products', [
'columns' => [
'categories.name as category',
'COUNT(products.id) as product_count',
'AVG(products.price) as avg_price',
'MIN(products.price) as min_price',
'MAX(products.price) as max_price',
],
'join' => 'INNER JOIN categories ON products.category_id = categories.id',
'groupBy' => 'categories.id',
'having' => 'product_count >= ?',
'havingParams' => [5],
'orderBy' => 'avg_price DESC',
]);
}
// ========== UTILISATION ==========
// Créer une commande
try {
$orderId = createOrder(42, [
['product_id' => 1, 'quantity' => 2, 'price' => 29.99, 'subtotal' => 59.98],
['product_id' => 3, 'quantity' => 1, 'price' => 99.99, 'subtotal' => 99.99],
]);
echo "Commande #{$orderId} créée !";
} catch (MySQLException $e) {
echo "Erreur : " . $e->getMessage();
}
// Lister les commandes (page 1)
$orders = getOrders(1, 'completed');
foreach ($orders['data'] as $order) {
echo "Commande #{$order['id']} - {$order['user_name']} - {$order['total']}€<br>";
}
// Stats
$stats = getCategoryStats();
foreach ($stats as $stat) {
echo "{$stat['category']}: {$stat['product_count']} produits, moyenne {$stat['avg_price']}€<br>";
}
// Afficher les performances
$perf = MySQL::getStats();
echo "Requêtes SQL : {$perf['queries']} en " . round($perf['time']*1000,2) . "ms";
| Méthode | Description | Retour |
|---|---|---|
addServer() |
Configure un serveur MySQL | void |
setDebug() |
Active/désactive le mode debug | void |
use() |
Sélectionne le serveur actif | void |
current() |
Nom du serveur actif | string |
isConnected() |
Vérifie la connexion | bool |
select() |
SELECT multiple lignes | array |
selectOne() |
SELECT une ligne | array|null |
selectValue() |
SELECT une valeur | mixed |
count() |
Compter les enregistrements | int |
insert() |
INSERT une ligne | int (ID) |
insertBatch() |
INSERT multiple lignes | int (count) |
update() |
UPDATE des lignes | int (affected) |
delete() |
DELETE des lignes | int (deleted) |
raw() |
Requête SQL brute | PDOStatement |
query() |
Query Builder (JOIN, GROUP BY, etc.) | array |
paginate() |
Pagination d'une requête SQL | array |
paginateQuery() |
Pagination avec Query Builder | array |
transaction() |
Exécute dans une transaction | mixed |
getStats() |
Statistiques de performance | array |
getErrorLog() |
Log des erreurs SQL | array |
getLastError() |
Dernière erreur | array|null |
clearErrorLog() |
Vide le log | void |