Soutenez-nous
 

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');

			/** user_id correspond à la clef primaire*/
			$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");
			
			// nous récupérons la map de film lié à l'acteur sélectionné ci-dessus			
			$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(){
					
					/** récupère un utilisateur dans SGBD */
					public function getUser(PMO_MyObject $user){
						/** charge les données à partir du sgbd */
						$user->load();
						
						/** retourne l'objet user */
						return $user;
					}
						
					/** ajoute un utilisateur en base */
					public addUser(PMO_MyObject $user){
						/** ecrit les données de l'objet dans la table utilisateur */
						$user->commit();
					}
					
					
					/** creer un objet utilisateur */
					public createUser(){
						return PMO_MyObject::factory("utilisateur");
					}
					
					/** supprime un utilisateur */
					public removeUser(PMO_Object $user){
						/** supprime les données relative à l'objet dans la table utilisateur */
						$user->delete();
					}

					/** affiche les données utilisateurs */
					public printUser(PMO_Object $user){
						echo($user->user_id);
						echo($user->name);
						echo($user->login);
					}
			
					/** controle le mot de passe de l'utilisateur */
					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");		
			
			/** instancie le controlleur */
			$controler = new PMO_MyController();

			/** cree une map d'objets */
			$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.



Valid XHTML 1.1!Valid CSS!

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

 
 
 
 
Partenaires

PlanetHoster
Ikoula