PhpMyObject manuel
Date de publication : 29/07/2007 , Date de mise à jour : 29/12/2007
Par
Nicolas BOITEUX
PMO est une API développée en PHP. Un Object relational Mapping (ORM) qui transforme les résultats de requêtes SQL en objets. PMO est basé en parti sur le motif de conception Active record. PMO gère les relations 1:1, 1:n, n:m.
I. Introduction
II. Pourquoi utiliser PMO ?
III. Fonctionnement global
IV. Le controlleur PMO_MyController
V. Les objets PMO_MyObject
VI. Les objets PMO_MyTable
VI. Les maps PMO_MyMap
VIII. Le class loader
IX. Les Exceptions
X. Exemples
XI. Exemple de controleurs
XII. Remerciements
I. Introduction
Source wikipedia: "En génie logiciel, le patron de conception (design pattern) active record est une approche pour lire les données d'une base de données. Les attributs d'une table ou d'une vue sont encapsulés dans une classe. Ainsi l'objet, instance de la classe, est lié à un tuple de la base. Après l'instanciation d'un objet, un nouveau tuple est ajouté à la base au moment de l'enregistrement. Chaque objet récupère ses données depuis la base; quand un objet est mis à jour, le tuple auquel il est lié l'est aussi. La classe implémente des accesseurs pour chaque attribut."
Ce manuel décrit la version 0.12. Il va vous apprendre à utiliser PMO et à développer plus simplement et plus rapidement vos applications PHP.
II. Pourquoi utiliser PMO ?
Voici les raisons pour lesquelles PMO est succeptible de vous intérresser:
- pour faire de l'orienté objet
- pour ne pas recoder 50 fois les mêmes classes
- pour manipuler votre base de donnée en 3 lignes
- pour rendre réutilisable ces classes
- pour encapsuler la gestion des données dans des classes dédiées à cela
Voici les raisons pour lesquelles PMO est succeptible de vous intérresser par rapport aux autres ORM PHP:
- il est simple
- il ne remplace pas SQL
- il découvre automatiquement les schémas de la base (pas de fichiers XML à manipuler)
- il utilise des interfaces,
- il est conçu à partir d'une architecture logiciel (UML)
- il implémente des classes de stockage
- il permet de faire du relationnel
- il permet d'utiliser vos propres classes
III. Fonctionnement global
PMO traite le résultat du SGBD de la façon suivante: Il transforme chaque ligne résultat de la requête SQL en objets.
exemple avec une table utilisateur contenant 10 utilisateurs |
SELECT * from utilisateur;
va renvoyer 10 objets utilisateur.
|
exemple avec une table utilisateur contenant 10 utilisateurs, une table ville contenant 5 villes |
SELECT * from utilisateur, ville WHERE utilisateur. id_ville= ville. id_ville;
va renvoyer 10 objets utilisateur, et 5 objets ville
|
IV. Le controlleur PMO_MyController
L'objet PMO_MyController sert à executer une requête SQL.
Executer une requête SQL |
$controller = New PMO_MyController();
$ map = $controller ->query (" SELECT * FROM utilisateur , ville ; " );
while ($ result = $map ->fetch ()){
echo $result [ ' ville ' ] ->nom ;
echo $result [ ' utilisateur ' ] ->nom ;
}
|
V. Les objets PMO_MyObject
PMO crée des objets de type PMO_MyObject.
PMO_MyObject possède trois propriétés:
- object_id : identifiant unique de l'objet (obsolète)
- object_table : une référence qui pointe vers un objet PMO_MyTable décrivant le schéma de la table dont découle l'objet
- object_attribute : un tableau indexé contenant vos données, nom de colonne => valeur
PMO_MyObject possède plusieurs méthodes:
- ::factory(nomdetable) : sert à créer un objet PMO_MyObject vide conforme au schéma de la table pour insertion
- ::override(nomdetable) : sert à créer un objet PMO_MyObject vide conforme au schéma de la table pour update (par défaut tout les attributs sont à blanc - !attention aux pertes de données!)
- load() : charge un objet depuis la base de données (les champs équivalents à la clef primaire doivent être renseignés)
- delete() : supprimer l'objet de la base de données ce qui correspond à 1 ligne dans une table
- commit() : écrire ou mettre à jour l'objet de la base de donnée ce qui correspond à 1 ligne dans une table
- toXml() : renvoit l'objet sous la forme d'un fichier XML
- getTable() : renvoit la référence de l'objet PMO_MyTable duquel il découle.
- getRelated() : renvoit une map contenant tous les objets liés 1:n à cet objet.
Afficher la valeur de l'attribut |
echo $objet ->attribut ;
exemple:
echo $utilisateur ->login ;
|
Modifier la valeur de l'attribut |
$objet ->attribut = $ valeur ;
Exemple:
$utilisateur ->login = " newlogin " ;
|
Charger un objet depuis la BDD |
$objet ->load ();
Exemple pour l' utilisateur 1:
/** creation d ' un objet équivalent à la table utilisateur * /
$ utilisateur = PMO_MyObject: : factory(' utilisateur ' );
$utilisateur ->user_id = 1 ;
$utilisateur ->load ();
|
Enregistrer un objet en BDD |
$objet ->commit ();
exemple:
$utilisateur ->commit ();
|
Supprimer un objet de la BDD |
$objet ->delete ();
exemple:
$utilisateur ->delete ();
|
Récupérer un objet au format XML |
$objet ->toXml ($ encoding );
exemple:
$utilisateur ->toXml (" ISO - 8859 - 1 " );
|
VI. Les objets PMO_MyTable
Un objet PMO_MyTable décrit le schéma d'une table de la base de donnée.
- table_name : nom de la table
- table_pk : array contenant le nom de toutes les clefs primaires
- table_attribute : un tableau indexé d'attributs contenant le nom de la colonne / Null/ type / default / extra => valeur
Retrouver l'objet table lié à un objet PMO_MyObject |
$ objetable = $objet ->getTable ()
exemple:
$ tableutilisateur = $utilisateur ->getTable ();
|
Modifier le nom d'une colonne |
Editez la variable table_alias du cache de la table
exemple pour que customer_id devienne toto:
protected $ table_alias = Array (
' customer_id ' = > ' toto '
);
|
Utiliser votre propre classe implémentant PMO_MyObject pour cette table |
Editez la variable table_classname du cache de la table
exemple:
protected $ table_classname = " newclassname " ;
|
Les objets PMO_MyTable sont écrit en cache à la première execution de votre script dans le répertoire cache/
VI. Les maps PMO_MyMap
PMO référence les objets PMO_MyObject dans un objet PMO_MyMap qui possèdent des méthodes pour retrouver ces objets.
La structure de la propriété map |
PMO_MyMap -|
|-- row --|
|--> référence PMO_MyObject
|
Exemple avec une table utilisateur et ville |
SELECT * from utilisateur,ville WHERE utilisateur.id_ville=ville.id_ville;
qui renverait deux lignes serait représenté comme ça:
PMO_MyMap -|
|-- row 0 --|
|--> référence PMO_MyObject utilisateur
|--> référence PMO_MyObject ville
|-- row 1 --|
|--> référence PMO_MyObject utilisateur
|--> référence PMO_MyObject ville
|
Chaque Row permet d'identifier les relations entre les objets. Ainsi on sait que les objets du row 0 sont liés ensemble.
PMO_MyMap contient une propriété : un array indexé
Les méthodes de PMO_MyMap:
- getObjectByValue(nom de la table de l'objet, nom de l'attribut, valeur de l'attribut): permet de retrouver un objet dans la map grace à la valeur d'un de ses attributs.
- getMapByTable(nom de la table): permet de renvoyer une nouvelle sous map MyMap qui ne contient que des objets de la table passé en paramètre. C'est une forme de filtre.
- getMapByValue(nom de la table de l'objet, nom de l'attribut, valeur de l'attribut): permet de renvoyer une nouvelle map qui ne contient que les lignes de résultats contenant l'objet que l'on passe en paramètre.
- getMap(): retourne la propriété map
Récupérer ligne par ligne la map |
$ result = $map ->fetch ();
exemple:
while ($ result = $map ->fetch ()){
echo($result [ ' utilisateur ' ] ->login );
}
|
Retrouver un objet |
$ object = $map ->getObjectByValue (" nomdetable " , " nomdecolonne " , " valeur " );
exemple:
$ object = $map ->getObjectByValue (" utilisateur " , " login " , " toto " );
|
Créer une autre map ne contenant que des objets provenant d'une table x |
$ newmap = $map ->getMapByTable (" nomdelatable " )
exemple:
$ newmap = $map ->getMapByTable (" utilisateur " );
|
Créer une map ne contenant que des objets relatifs à un objet dont la colonne x à cette valeur |
$ newmap = $map ->getMapByValue (" nomdetable " , " nomdecolonne " , " valeur " );
exemple:
$ newmap = $map ->getMapByValue (" utilisateur " , " login " , " toto " );
|
Créer une map ne contenant que des objets relatifs à un objet dont ses n primary key ont ces valeurs |
$ newmap = $map ->getMapByObjectByValue ($ PMO_MyObject );
exemple:
$user ->user_id = 1 ;
$user ->user_departement_id = 1 ;
$ newmap = $map ->getMapByObjectByValue ($ user );
|
Créer une map ne contenant que des objets relatifs à un objet PMO_MyObject |
$ newmap = $map ->getMapRelated ($ PMO_object );
exemple:
$film ->titre = ' tarzan ' ;
$ newmap = $map -> getMapRelated($ film );
while ($ result = $newmap ->fetch ())
echo $result [ ' salle ' ] ->numero ;
echo $result [ ' cinema ' ] ->nom ;
|
VIII. Le class loader
Le class loader permet d'utiliser vos propres objets héritant de PMO_MyObject, pour cela vous devez créer une class dans le répertoire class_loader/. Le nom du fichier doit être class_xxxxx.php
exemple de class utilisateur implémentant une méthode helloworld() |
class utilisateur extends PMO_MyObject{
public function helloworld(){
echo(' this class is instanciate when a database table user exist ' );
}
}
|
Il faut ensuite éditer la classe PMO_MyTable_xxx.php se trouvant dans le répertoire cache/ qui décrit la structure de votre table. Cette classe est crée automatiquement par PMO dans ce répertoire lors de la première execution d'un SELECT par le controlleur.
exemple de modification de PMO_MyTable_xxx.php |
Editez cette ligne:
protected $ table_classname = " utilisateur " ;
|
Par défaut $table_classname vaut NULL ce qui signifie que vous utilisez pour toutes vos tables, l'objet générique PMO_MyObject
appel de la méthode helloword |
L' objet peut être ensuite utilisé de cette façon:
$object = PMO_MyObject::factory( ' utilisateur' );
$object->helloworld();
|
IX. Les Exceptions
Pmo permet d'utiliser les exceptions pour les opérations sur les objets.
exemple de gestion exception |
try {
$object ->commit ()
} catch (Exception $ e ){
die($e ->getMessage ());
}
|
exemple de gestion exception |
try {
$user ->loginz = " toto " ;
} catch (Exception $ e ){
die($e ->getMessage ());
}
|
X. Exemples
Pour les exemples, j'utiliserais une table employe, mais ça fonctionne pareil avec n'importe laquelle de vos tables
Dézippez l'archive de PhpMyObject, et configurez le fichier config.php pour que PMO puisse intérroger votre base de donnée.
|
/** mysql / sqlite / oracle / pgsql */
$driverz = "sqlite";
/** if you use sqlite */
$dsn = 'sqlite:c:/test/test.db';
$hostz = 'localhost';
$userz = 'votrelogin';
$passz = 'votrepass';
$basez = 'votrebase';
|
Affichage du nom des 20 premiers employés de la table employe.
require_once(" core / PMO_MyController . php " );
$controler = new PMO_MyController();
$ map = $controler ->query (" SELECT * FROM employe limit 20 ; " );
while ($ result = $map ->fetch ()){
echo($result [ ' employe ' ] ->nom );
}
|
Affichage du nom des 20 premiers employés de la table employe et du numéro de leur place de parking.
require_once(" core / PMO_MyController . php " );
$controler = new PMO_MyController();
$ map = $controler ->query (" SELECT * FROM employe , parking WHERE employe . id_employe = parking . id_employe limit 20 ; " );
while ($ result = $map ->fetch ()){
echo($result [ ' employe ' ] ->nom );
echo($result [ ' parking ' ] ->numero_place );
}
|
Modification du nom de l'employe dupont en durand
require_once(" core / PMO_MyController . php " );
$controler = new PMO_MyController();
$ map = $controler ->query (" SELECT * FROM employe ; " );
$ employe = $map ->getObjectByValue (" employe " , " nom " , " dupont " );
$employe ->nom = " durand " ;
$employe ->commit ();
|
Autre exemple si vous connaissez déjà toutes les informations de Durand, il est inutile d'utiliser le controller.
Attention aux pertes de données, override() initialise à blanc toutes les colonnes qui n'ont pas été paramêtrées.
require_once(" core / PMO_MyController . php " );
$ employe = PMO_MyObject: : override(" employe " );
$employe ->id = " 250 " ;
$employe ->nom = " durand " ;
$employe ->commit ();
|
Création d'un objet employe qui a pour nom de Masson
require_once(" core / PMO_MyController . php " );
$ employe = PMO_MyObject: : factory(" employe " );
$employe ->nom = " Masson " ;
$employe ->commit ();
|
Affichage de tous les noms d'un film dans lequel a joué un acteur Dupont. Pour l'exemple, nous ne préciserons pas ce critère directement
dans la requête SQL, mais nous utiliserons les relations PMO entre objets.
require_once(" core / PMO_MyController . php " );
$controler = new PMO_MyController();
$ map = $controler ->query (" SELECT * FROM film , actor WHERE film . actor_id = actor . actor_id ; " );
$ actor = $map ->getObjectByValue (" actor " , " nom " , " dupont " );
$ mapoffilm = $actor ->getRelated (' film ' );
while ($ result = $mapoffilm ->fetch ()){
echo($result [ ' film ' ] ->nom_film );
}
|
XI. Exemple de controleurs
exemple d'un controleur développé avec PMO |
require_once(" core / PMO_MyController . php " );
class gestionutilisateur(){
public function getUser(PMO_MyObject $ user ){
$user ->load ();
return $ user ;
}
public addUser(PMO_MyObject $ user ){
$user ->commit ();
}
public createUser(){
return PMO_MyObject: : factory(" utilisateur " );
}
public removeUser(PMO_Object $ user ){
$user ->delete ();
}
public printUser(PMO_Object $ user ){
echo($user ->user_id );
echo($user ->name );
echo($user ->login );
}
public checkPass(PMO_Object $ user , $ password ){
if ($user ->pass = = sha1($ password ))
return TRUE ;
return FALSE ;
}
}
|
exemple d'un code impératif utilisant PMO |
require_once(" core / PMO_MyController . php " );
$controler = new PMO_MyController();
$ map = $controler ->query (" SELECT * FROM user , ville where user_id = " $ userid
AND ville. id_ville= user. id_ville; " ) ;
while ( $ result = $map ->fetchMap ( ) ) {
$ utilisateur = $ result [ ' user ' ] ;
$ ville = $ result [ ' ville ' ] ;
echo ( " Nom: " . $utilisateur ->nom ) ;
echo ( " Ville: " $ville ->nom_ville ) ;
}
|
XII. Remerciements
Remerciements à Etanne pour la correction du manuel.
Les sources présentées sur cette page sont libres de droits
et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation
constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ©
29/07/2007 Nicolas BOITEUX. Aucune reproduction, même partielle, ne peut être
faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc.
sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à
trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.