Une couche de persistance légère et transparente

août 29th, 2009 by Tony

Récemment, j’ai relu avec beaucoup d’intérêt certains chapitres de ce livre consacré à la technologie Java :

Java, plus rapide, plus léger

Dans cet ouvrage, les auteurs font le point sur l’état de l’art dans le domaine de la conception logicielle. Le contexte du livre est celui de la technologie Java, mais on peut appliquer les principes développés au cadre de toute technologie orientée objet, il me semble.

Les auteurs ne présentent pas, tel qu’ils le soulignent eux-même, de recettes magiques pour mieux concevoir les logiciels mais invitent à la réflexion sur la conception logicielle en elle-même et notamment sur la tendance à la complexité croissante.

Ce que je retiens de ma lecture : simplicité, légèreté et transparence des briques logicielles sont les objectifs à se fixer si l’on vise le succès d’un projet informatique.

Dans ce qui suit, je présenterais une couche de persistance que j’ai développée récemment dans un projet Flex - Cairngorm - PHP - MySQL, basée sur l’API de réflexion de PHP5.

Concilier le class-mapping et l’object-relational-mapping

 

L’une des difficultés rencontrées lorsque l’on utilise les frameworks, c’est de les rendre compatibles.

Dans les projets Flex de type ERP, j’utilise habituellement le framework plébiscité par Adobe, l’imprononçable Cairngorm.

Le nom fait peur, c’est sûr, mais avec quelques centaines de lignes de code ActionScript3, il fournit un cadre de travail que je trouve, personnellement, robuste, fiable et qui conduit à des projets Flex dans lesquels “on s’y retrouve” (considérations qui n’engagent que moi et qui ne signifie pas que je préfère ce framework à d’autres en toutes circonstances)

Comme vous le faites probablement, j’utilise le class-mapping pour sauvegarder mes objets métiers.

Pour rappel, le class-mapping est une technique qui permet d’échanger des objets typés entre les couches distribuées : la couche client (votre application Flex) envoie un objet de type SocieteVO et la service distant reçoit un objet SocieteVO. Entre les deux, il existe généralement une passerelle qui s’occupe de faire la traduction de type entre les technologies employées.

Par exemple, si votre objet de type SocieteVO contient une propriété de type Number, l’objet équivalent que vous recevrez et que vous manipulerez côté serveur contiendra une propriété de type double si vous utilisez PHP comme technologie et AMFPHP pour passerelle (Number est traduit en double).

On différencie d’ailleurs entre types supportés, interprétés et non-supportés (exemples entre AS3 et PHP : Array est supporté, Number est interprété et BitmapData est non-supporté).

Bref, revenons à nos moutons…je peux donc échanger des objets typés entre ma couche cliente et ma couche serveur sans avoir à me préoccuper de la sérialisation de mes données et de leur transport sur le réseau, et cela est très souple, mais j’aimerais également conserver la souplesse dont je dispose pour sauver mes objets quand j’utilise une librairie d’ORM telle que Doctrine ou Propel dans un projet “full php”.

Et là, il y a un hic, car d’après mes tests en tous cas, on ne peux pas câbler directement au niveau du service distant le class-mapping et l’ORM. J’ai bien trouvé quelques posts sur les blogs du type : Flex + Cairngorm + Hibernate + LCDS…etc. ce qui laisserait penser que tous ceci est possible, mais je n’ai pas trouvé pareilles ressources concernant AMFPHP et Doctrine par exemple. Si vous savez comment faire, un petit commentaire est le bienvenu… :)

L’objectif de la couche que je présente ici est d’ajouter de la persistance aux ValueObjects reçus côté serveur.

Gardant en tête les objectifs de simplicité, légèreté et transparence, j’ai choisi d’utiliser la réflexion, l’une des possibilités préconisées par les auteurs pour atteindre ces mêmes objectifs.

L’API de réflexion de PHP5 est relativement simple à utiliser et pour ma part c’est une possibilité des langages orientés objets que j’apprécie le plus. L’inconvénient d’utiliser la réflexion, c’est ce que cela coûte en performance.

Gardons donc à l’esprit qu’il faut utiliser cette technique dans le cadre d’un développement léger.

Voici donc un premier jet pour une classe introspectant le VO envoyé par le client Flex, détermine son type et la valeur de chacun de ses champs et qui crée la requête SQL appropriée en fonction de l’opération demandée : sélection, insertion, modification ou suppression. Pour ajouter encore un peu de transparence, j’ai utilisé PDO pour l’accès au SGBD.

Le code ne bénéficie pas d’optimisations particulières et n’implémente pas toutes les exigences requises pour une couche de persistance.

Comme pourrait dire Martin Fowler, l’exemple est suffisamment complexe pour ne pas être trivial mais trop simple pour être réel. ;)

Je ne présente ici qu’une seule méthode de la classe en raison de la redondance du code.

Le code complet est disponible ici : SimplePersistanceLayer

class SimplePersistanceLayer
{
 
        // une chaîne Data Source Name pour localiser la base de données
	private $dsn;
        // L'authentification avec le SGBD (ici, MySQL)
	private $user;
	private $password;
        // Une instance de la classe PDO
	private $dbh;
       // Un tableau associatif de correspondance entre un Value Object et une table de base de données
	private $map;
        /**
         * Dans le constructeur, on initialise PDO, et le tableau associatif de correspondance Objet - Relationnel
         **/
	public function __construct() {
 
		$this->dsn = 'mysql:dbname=fpcmanager;host=localhost';
		$this->user = 'root';
		$this->password = 'root';
 
		$this->dbh = new PDO( $this->dsn, $this->user, $this->password);
 
		// Mapping Objet Relationnel
		$this->map = array( "SocieteVo" => "Societe_VO", "StagiaireVo" => "Stagiaire_VO", "FormateurVo" => "Formateur_VO", "StageVo" => "Stage_VO", "SessionVo" => "Session_VO", "ResponsableVo" => "Responsable_VO",
				    "JunctionSessionFormateurVo" => "Junction_Session_Formateur_VO", "JunctionStagiaireSessionVo" => "Junction_Stagiaire_Session_VO", "JunctionSocieteStagiaireVo" => "Junction_Societe_Stagiaire_VO",
				    "JunctionSocieteResponsableVo" => "Junction_Societe_Responsable_VO" );
 
	}
       /**
         * Retourne un tableau de Value Object qui sera interprété comme une ArrayCollection par Flex.
         * Utilise l'API de reflexion de PHP5 pour déterminer le type de l'objet et travailler avec lui.
         * @param un Value Object
         * @return un tableau de Value Object
         **/
         public function findAll( $pVO )
         {
 
                // Tout d'abord, on obtient un ReflectionObject à partir du ValueObject envoyé par Flex.
                // Ce ReflectionObject nous permet de déterminer sur quelle table nous devons sélectionner
                // tous les enregistrements.
		$reflectObj       = new ReflectionObject( $pVO );
		$reflectObjName   = $reflectObj->getName();
		$tableSQL = $this->map[ $reflectObjName ];
 
                // Crée une chaîne SQL
		$query = "SELECT * FROM $tableSQL";
 
                // Exécute la requête, on obtient un pointeur sur une ressource
		$res   = $this->dbh->query( $query );
 
                // Maintenant, l'objectif est de reconstituer un tableau de ValueObject PHP class-mappé
                // à partir de la ressource de base de données.
                $typedVOArr = array();
 
                // On parcourt la ressource comme un tableau d'objets anonymes
                // Et pour chaque objet anonyme obtenu (PDO::FETCH_OBJ) on crée un
                // un objet typé d'échange PHP-Flex.
                while ($obj = $res->fetch(PDO::FETCH_OBJ)) { 
 
                         $reflect = new ReflectionClass( $reflectObjName );
                         $dynamicObject = $reflect->newInstance();
 
                        // Ici, on boucle sur les propriétés de l'objet anonyme et on reconstitue un objet
                        // typé équivalent.
                        foreach( $obj as $property => $value ){
 
                                     $dynamicObject->$property = $value;
 
                         }
 
                       // on ajoute l'objet typé au tableau
                       array_push( $typedVOArr, $dynamicObject );
            }
 
            // Et on retourne le tableau.
            return $typedVOArr;
      }


Voilà, cette petite classe peut être utilisé avec n’importe quel ValueObject “standard” dans un projet Flex - Cairngorm - AMFPHP.

Si vous désirez la compléter, l’optimiser ou proposer d’autres méthodologies pour câbler class-mapping et ORM, n’hésitez-pas à poster un commentaire.

Merci :)


2 Responses to “Une couche de persistance légère et transparente”

  1. LARRY Says:


    PillSpot.org. Canadian Health&Care.Special Internet Prices.Best quality drugs.No prescription online pharmacy. No prescription drugs. Buy drugs online

    Buy:Mega Hoodia.100% Pure Okinawan Coral Calcium.Accutane.Prednisolone.Valtrex.Retin-A.Zyban.Human Growth Hormone.Actos.Prevacid.Arimidex.Petcam (Metacam) Oral Suspension.Lumigan.Synthroid.Nexium.Zovirax….

  2. LEONARD Says:


    Medicamentspot.com. Canadian Health&Care.Special Internet Prices.Best quality drugs.No prescription online pharmacy. Low price drugs. Order drugs online

    Buy:Aricept.Acomplia.Nymphomax.Lipothin.Prozac.Advair.Amoxicillin.Female Cialis.Seroquel.Lasix.Female Pink Viagra.Buspar.Cozaar.Lipitor.Ventolin.Benicar.SleepWell.Zocor.Zetia.Wellbutrin SR….

Leave a Reply