Toute application Web dite dynamique nécessite une base de données ainsi que des outils qui permettront de manipuler ces données.
Dans la palette des outils à la disposition des développeurs PHP, on trouve entre autres les DBAL (DataBase Abstraction Layer ou couche d'abstraction de base de données) ou les ORM (Object Relational Mapping ou mapping objet-relationnel).
1. {
Accès aux bases de
données relationnelles
et ORM en PHP
2. { Accès aux bases de données
relationnelles et ORM en PHP
Toute application Web dite dynamique
nécessite une base de données ainsi que des
outils qui permettront de manipuler ces
données.
Dans la palette des outils à la disposition des
développeurs PHP, on trouve entre autres les
DBAL (DataBase Abstraction Layer ou couche
d'abstraction de base de données) ou les ORM
(Object Relational Mapping ou mapping objet-
relationnel).
30/03/2011 Mickaël Perraud 2
3. { Accès aux bases de données
relationnelles et ORM en PHP
3 interventions :
Présentation de différents DBAL
Présentation de 2 ORM :
Propel
Doctrine2
30/03/2011 Mickaël Perraud 3
4. { Accès aux bases de données relationnelles
Contributeur ZF depuis 2007 (Zend_Db, Zend_Barcode)
Responsable documentation française
Donne des webinars sur ZF en partenariat avec Zend
Travaille sur l'aide à la traduction et propose les
versions déconnectées de la documentation PDF / CHM
Vice-trésorier AFUP 2011
@mikaelkael / http://mikaelkael.fr
30/03/2011 Mickaël Perraud 4
5. { Retournons en arrière
On a commencé par tout écrire en dur :
$lien = mysql_connect('localhost', 'mysql_user', 'mysql_password');
if (!$lien) {
die('Impossible de se connecter : ' . mysql_error());
}
$db = mysql_select_db('foo', $lien);
if (!$db) {
die ('Impossible de sélectionner la base de données : ' . mysql_error());
}
$requete = 'SELECT * FROM maTable WHERE id = ' . $_GET['id'];
$resultat = mysql_query($requete);
while($ligne = mysql_fetch_assoc($resultat)) {
echo $ligne['id'].': '.$ligne['valeur'];
}
30/03/2011 Mickaël Perraud 5
6. { Retournons en arrière
Puis on a ”amélioré” :
//config.php
define('DB_HOST', 'localhost');
define('DB_USERNAME', 'mysql_user');
define('DB_PASSWORD', 'mysql_password');
define('DB_DATABASE', 'mysql_base');
//db.php
require_once 'config.php';
$lien = mysql_connect(DB_HOST, DB_USERNAME, DB_PASSWORD);
if (!$lien) {
die('Impossible de se connecter : ' . mysql_error());
}
$db = mysql_select_db(DB_DATABASE, $lien);
if (!$db) {
die ('Impossible de sélectionner la base de données : ' . mysql_error());
}
30/03/2011 Mickaël Perraud 6
7. { Retournons en arrière
Puis les classes sont arrivées :
class BDD {
var $connexion;
function BDD() {
$this->connexion = $this->connecte(DB_TYPE);
}
function connecte($type = 'mysql') {
switch($type) {
case 'mysql':
return mysql_connect(DB_HOST, DB_USERNAME, DB_PASSWORD);
break;
case 'oci8':
//...
30/03/2011 Mickaël Perraud 7
8. { PDO
PDO = PHP Data Object
Ecrit en C
Introduit en PHP 5.0 en 2004
Activé par défaut avec PHP 5.1
Fournit une interface d'abstraction à l'accès
aux données
Plus sécurisé (si bien utilisé)
30/03/2011 Mickaël Perraud 8
10. { PDO : reprenons notre exemple
La connexion :
try {
$dbh = new PDO('mysql:host=localhost;dbname=' . DB_DATABASE, DB_USER, DB_PASSWORD);
echo 'Connected!';
} catch (PDOException $e) {
echo $e->getMessage();
}
En changeant de driver :
try {
$dbh = new PDO('oci:dbname=' . DB_DATABASE, DB_USER, DB_PASSWORD);
echo 'Connected!';
} catch (PDOException $e) {
echo $e->getMessage();
}
Ce qui va suivre est désormais indépendant du driver
30/03/2011 Mickaël Perraud 10
11. { PDO : requêtes préparées
PDO peut être utilisée avec ou sans requêtes
préparées
Pour des raisons de sécurité, préférez les
requêtes préparées :
$stmt = $dbh->prepare('SELECT nom, prenom FROM utilisateurs WHERE id_utilisateur = :id');
$stmt->bindParam('id', $_GET['id'], PDO::PARAM_INT);
$stmt->execute();
$resultat = $stmt->fetchAll();
L'assignation peut être nommée (ci-dessus) ou
numérique
30/03/2011 Mickaël Perraud 11
12. { PDO : lecture des résultats
Il existe plusieurs manières de récupérer les résultats
via PDO :
$resultat = $stmt->fetchAll(PDO::FETCH_...); // Toutes les lignes
//ou
$resultat = $stmt->fetch(PDO::FETCH_...); // Ligne par ligne
Et plusieurs mode de récupération (PDO::FETCH_*) :
PDO::FETCH_ASSOC :
Array
(
[nom] => Perraud
[prenom] => Mickael
)
30/03/2011 Mickaël Perraud 12
14. { PDO : lecture des résultats
Le meilleur pour la fin ? PDO::FETCH_CLASS
Prend un résultat et le retourne sous la forme
d'une classe
On peut instancier la classe directement par
PDO
30/03/2011 Mickaël Perraud 14
15. { PDO::FETCH_CLASS
Notre classe : class Utilisateur {
private $_nom;
private $_prenom;
public function __set($attribut, $valeur)
{
$this->{"set".ucfirst($attribut)} = $valeur;
}
public function setNom($nom)
{
$this->_nom = $nom;
}
public function getNom()
class Utilisateur { {
public $nom; return $this->_nom;
public $prenom; }
} public function setPrenom($prenom)
{
$this->_prenom = $prenom;
}
public function getPrenom()
{
return $this->_prenom;
}
public function __toString()
{
return $this->_prenom . ' ' . $this->_nom;
}
}
30/03/2011 Mickaël Perraud 15
16. { PDO::FETCH_CLASS
Interrogeons la base :
$stmt = $dbh->prepare('SELECT * FROM utilisateurs');
$resultat = $stmt->fetchAll(PDO::FETCH_CLASS, 'Utilisateur');
foreach($resultat as $class) {
echo $class;
// Affiche par exemple : Mickael Perraud
}
30/03/2011 Mickaël Perraud 16
17. { Ce que PDO ne fait pas
Ne fournit pas une abstraction de base de données :
il ne réécrit pas le SQL
Il n'émule pas des fonctionnalités manquantes
30/03/2011 Mickaël Perraud 17
18. { Zend_Db
Composant d'accès aux bases de données de Zend
Framework
Contient différents sous composants :
Zend_Db_Adapter : abstraction de base de données
Zend_Db_Select : abstraction de requête de type
”SELECT”
Zend_Db_Table : ”Table Data Gateway” -
http://martinfowler.com/eaaCatalog/tableDataGateway.html
Zend_Db_Table_Row : ”Row Data Gateway” -
http://martinfowler.com/eaaCatalog/rowDataGateway.html
30/03/2011 Mickaël Perraud 18
19. { Zend_Db_Adapter
Surcharge PDO et certaines extensions
(MySQLi, Oci8, Db2, Sqlsrv) en fournissant une
interface commune
Instanciation via la fabrique de Zend_Db :
$db = Zend_Db::factory('Pdo_Mysql', array('host' => 'localhost',
'username' => 'mysql_user',
'password' => 'mysql_password',
'dbname' => 'mysql_database'));
30/03/2011 Mickaël Perraud 19
21. { Zend_Db : lecture des résultats
Outre fetchAll() ou fetch() de PDO
(renommé en fetchRow()), on dispose de :
fetchAssoc()
fetchCol()
fetchOne()
fetchPairs()
30/03/2011 Mickaël Perraud 21
22. { Zend_Db : autres fonctions
Gestion du schéma :
listTables()
describeTable()
Interface générique de gestion des
transactions (beginTransaction(), commit(),
rollback())
Abstraction de la clause limit()
30/03/2011 Mickaël Perraud 22
23. { Zend_Db_Select
Abstraction DQL : permet de construire des
requêtes de type ”SELECT” en PHP
// Construire cette requête :
// SELECT produit_id, produit_nom, prix
// FROM "produits"
// WHERE (prix > 100.00)
// AND (prix < 500.00)
$prixminimum = 100;
$prixmaximum = 500;
$select = $db->select()
->from('produits',
array('produit_id', 'produit_nom', 'prix'))
->where('prix > ?', $prixminimum)
->where('prix < ?', $prixmaximum);
30/03/2011 Mickaël Perraud 23
24. { DoctrineDBAL
Partie de Doctrine destinée à l'abstraction des bases
de données :
Plusieurs sous-composants :
DoctrineDBALDriver : surcouche de PDO et
quelques drivers (pas de SQL)
DoctrineDBALPlatform : abstraction de la
génération de requêtes et de fonctionnalités (SQL)
DoctrineDBALSchema : abstraction de la gestion du
schéma
DoctrineDBALType : abstraction du typage avec
mapping PHP
30/03/2011 Mickaël Perraud 24
25. { DoctrineDBAL
Connexion :
$connexion = DriverManager::getConnection(array('dbname' => 'mysql_database',
'user' => 'mysql_user',
'password' => 'mysql_password',
'host' => 'localhost',
'driver' => 'pdo_mysql'));
Exécution de requêtes préparées :
$sql = "SELECT * FROM utilisateurs WHERE id = ? AND status = ?";
$stmt = $connexion->prepare($sql);
$stmt->bindValue(1, $id);
$stmt->bindValue(2, $status);
$stmt->execute();
On retrouve une API de récupération de
données très similaire à ce qui précède pour
Zend_Db
30/03/2011 Mickaël Perraud 25