30
{ Accès aux bases de données relationnelles et ORM en PHP

Présentation de DBAL en PHP

Embed Size (px)

DESCRIPTION

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).

Citation preview

Page 1: Présentation de DBAL en PHP

{

Accès aux bases de

données relationnelles

et ORM en PHP

Page 2: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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).

Page 3: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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 :

PropelDoctrine2

Page 4: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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

Page 5: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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'];}

Page 6: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 6

{ Retournons en arrière

Puis on a ”amélioré” :

//config.phpdefine('DB_HOST', 'localhost');define('DB_USERNAME', 'mysql_user');define('DB_PASSWORD', 'mysql_password');define('DB_DATABASE', 'mysql_base');

//db.phprequire_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());}

Page 7: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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': //...

Page 8: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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é)

Page 9: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 9

{ PDO : quelles bases de données ?

Demandez à phpinfo() :

Demandez à PDO :print_r(PDO::getAvailableDrivers());

/*Array( [0] => sqlite [1] => dblib [2] => mysql [3] => oci [4] => odbc [5] => pgsql [6] => sqlite2) */

Page 10: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 10

{ PDO : reprenons notre exemple

La connexion :

En changeant de driver :

Ce qui va suivre est désormais indépendant du driver

try { $dbh = new PDO('mysql:host=localhost;dbname=' . DB_DATABASE, DB_USER, DB_PASSWORD); echo 'Connected!';} catch (PDOException $e) { echo $e->getMessage();}

try { $dbh = new PDO('oci:dbname=' . DB_DATABASE, DB_USER, DB_PASSWORD); echo 'Connected!';} catch (PDOException $e) { echo $e->getMessage();}

Page 11: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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 :

L'assignation peut être nommée (ci-dessus) ou numérique

$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();

Page 12: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 12

{ PDO : lecture des résultats

Il existe plusieurs manières de récupérer les résultats via PDO :

Et plusieurs mode de récupération (PDO::FETCH_*) :

PDO::FETCH_ASSOC :

$resultat = $stmt->fetchAll(PDO::FETCH_...); // Toutes les lignes//ou $resultat = $stmt->fetch(PDO::FETCH_...); // Ligne par ligne

Array( [nom] => Perraud [prenom] => Mickael)

Page 13: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 13

{ PDO : lecture des résultats

Et plusieurs mode de récupération (PDO::FETCH_*) :

PDO::FETCH_NUM :

PDO::FETCH_BOTH (par défaut) :

PDO::FETCH_OBJ :

Array( [0] => Perraud [1] => Mickael)

Array( [nom] => Perraud [0] => Perraud [prenom] => Mickael [1] => Mickael)

object(stdClass)#1 (2) { ["nom"]=> string(7) "Perraud" ["prenom"]=> string(7) "Mickael"}

Page 14: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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

Page 15: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 15

{ PDO::FETCH_CLASS

Notre classe :

class Utilisateur { public $nom; public $prenom;}

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() { return $this->_nom; } public function setPrenom($prenom) { $this->_prenom = $prenom; } public function getPrenom() { return $this->_prenom; } public function __toString() { return $this->_prenom . ' ' . $this->_nom; }}

Page 16: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 16

{ PDO::FETCH_CLASS

$stmt = $dbh->prepare('SELECT * FROM utilisateurs');$resultat = $stmt->fetchAll(PDO::FETCH_CLASS, 'Utilisateur');

foreach($resultat as $class) { echo $class; // Affiche par exemple : Mickael Perraud}

Interrogeons la base :

Page 17: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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

Page 18: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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

Page 19: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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'));

Page 20: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 20

{ Zend_Db_Adapter

Exécution de requêtes préparées :

Abstraction DML (”INSERT”, ”UPDATE”, ”DELETE”) :

$stmt = $db->query('SELECT * FROM utilisateurs WHERE id_utilisateur = ?', array($_GET['id']));

$id = $db->insert('utilisateurs', array('nom' => 'Doe', 'prenom' => 'John'));

$db->update('utilisateurs', array('nom' => 'Doe', 'prenom' => 'Jane'), array('id_utilisateur = ?' => 2));

$db->delete('utilisateurs', array('id_utilisateur = ?' => 2));

Page 21: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 21

{ Zend_Db : lecture des résultats

Outre fetchAll() ou fetch() de PDO (renommé en fetchRow()), on dispose de :

fetchAssoc()

fetchCol()

fetchOne()

fetchPairs()

Page 22: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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()

Page 23: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 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);

Page 24: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 24

{ Doctrine\DBAL

Partie de Doctrine destinée à l'abstraction des bases de données :

Plusieurs sous-composants :

Doctrine\DBAL\Driver : surcouche de PDO et quelques drivers (pas de SQL)

Doctrine\DBAL\Platform : abstraction de la génération de requêtes et de fonctionnalités (SQL)

Doctrine\DBAL\Schema : abstraction de la gestion du schéma

Doctrine\DBAL\Type : abstraction du typage avec mapping PHP

Page 25: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 25

{ Doctrine\DBAL

Connexion :

Exécution de requêtes préparées :

On retrouve une API de récupération de données très similaire à ce qui précède pour Zend_Db

$connexion = DriverManager::getConnection(array('dbname' => 'mysql_database', 'user' => 'mysql_user', 'password' => 'mysql_password', 'host' => 'localhost', 'driver' => 'pdo_mysql'));

$sql = "SELECT * FROM utilisateurs WHERE id = ? AND status = ?";$stmt = $connexion->prepare($sql);$stmt->bindValue(1, $id);$stmt->bindValue(2, $status);$stmt->execute();

Page 26: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 26

{ Doctrine\DBAL : transation

Transaction imbriquées :// $connexion instanceof Doctrine\DBAL\Connection$connexion->beginTransaction(); // 0 => 1, transaction "réelle" démarréetry {

//...

// nested transaction block, this might be in some other API/library code that is // unaware of the outer transaction. $connexion->beginTransaction(); // 1 => 2 try { //...

$connexion->commit(); // 2 => 1 } catch (Exception $e) { $connexion->rollback(); // 2 => 1, transaction marquée pour annulation throw $e; }

//...

$connexion->commit(); // 1 => 0, transaction "réelle" confirmée} catch (Exception $e) { $connexion->rollback(); // 1 => 0, transaction "réelle" annulée throw $e;}

Page 27: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 27

{ Doctrine\DBAL : schéma manager

listDatabases()

listSequences()

listTables()

listTableColumns()

listTableDetails()

listTableForeignKeys()

listTableIndexes()

listViews()

createSchema()

Page 28: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 28

{ Doctrine\DBAL : schéma génération

Création table utilisateur :$schema = new \Doctrine\DBAL\Schema\Schema();$maTable = $schema->createTable("utilisateurs");$maTable->addColumn("id_utilisateur", "integer", array("unsigned" => true));$maTable->addColumn("nom", "string", array("length" => 50));$maTable->addColumn("prenom", "string", array("length" => 50));$maTable->setPrimaryKey(array("id_utilisateur"));$schema->createSequence("utilisateurs_seq");

$myForeign = $schema->createTable("commentaires");$myForeign->addColumn("id_commentaire", "integer");$myForeign->addColumn("utilisateur_id", "integer");$myForeign->addForeignKeyConstraint($myTable,

array("utilisateur_id"), array("id_utilisateur"), array("onUpdate" => "CASCADE"));

// Récupérer les requêtes pour générer le schéma$queries = $schema->toSql($myPlatform);// Récupérer les requêtes pour effacer le schéma$dropSchema = $schema->toDropSql($myPlatform);

Page 29: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 29

{ Ceux qu'il ne faut pas oublier

ADOdb : 5.11 (PHP 5)

PEAR::MDB2 : 2.5.0 en beta (PHP 5.3+)

Page 30: Présentation de DBAL en PHP

30/03/2011 Mickaël Perraud 30

{ Zend\Db 2.0

Zend\Db\Adapter : ajout plugin (pre- post-connect), suppression du SQL pur

Zend\Db\Query : abstraction DML, DQL, ainsi que DDL (”alter”, ”create”, ”drop”) et DCL (”commit”, ”rollback”, ”savepoint”), supporte ANSI ainsi que les dialectes des SGBD

Zend\Db\ResultSet : modélisation des résultats

Zend\Db\Metadata : gestion du schéma

http://framework.zend.com/wiki/display/ZFDEV2/Zend+Db+2.0+Requirements