Tutoriaux /

Weborb PHP : Les ValueObjects (Partie 2)

Niveau : Novice

Nous allons dans cet article aborder une des notions les plus importante quand vous faites du Flex connecté à un service AMF, les ValueObjects

Terminologie

Les ValueObjects ne sont pas spécifiques à Flex dans le cadre des échanges AMF, en fait ils existent depuis qu’un client c’est mis à vouloir communiquer avec un serveur. Si vous en discutez avec un développeur C ou Java, il en parlera surement en terme de Data transfer object aka DTO, ou bien encore data access object aka DAO, mais généralement leurs petit nom chez les Flexeurs c’est VO.

A quoi sert un ValueObject ?

Pour ceux qui ne savent pas encore à quoi sert un ValueObject, c’est en fait assez simple. A échangé des données entre un client (flex) et un serveur (weborb, amfphp, blazeds, etc…) en concervant le type (composite), pour ceux qui ne sont pas familier du jargon, si vous envoyer une donnée typé ‘ObjetQuiDechire’ de Flex vers un serveur, le serveur recevra un ‘ObjetQuiDechire’ et saura vous envoyer le même type d’objet sans avoir à taper une seule ligne de code pour traiter les propriétés de cet ‘ObjetQuiDechire’.

Nous avons survolé ensemble dans la première partie de cette série de tutoriaux la façon dont Weborb PHP transmet les informations vers Flex. Nous avons vu les différents types de données supportés. Et l’envois de ces données ne pose généralement pas de problème majeur. Mais comme vous le savez, coté Flex, nos données sont manipulées sous forme de classe, cela garantit la stabilité de l’application et permet d’éviter au maximum l’utilisation de type mutagène (comme les Object) dont le nom des propriétés varies aux grès des fautes de frappe :P . Vous avez surement déjà perdu un temps précieux à essayez de comprendre pourquoi votre id (accidentellement tapé ld – avec un L) vous arrivé toujours à NULL…

Abordons maintenant un cas concret.

Mon premier VO

Dans cette exemple, nous manipulerons un objet contact, voici le code côté Flex :

1
2
3
4
5
6
7
8
9
10
11
package vo
{
	public class ContactVO
	{
		public var id:int;
		public var nom:String;
		public var prenom:String;
		public var dateNaissance:Date;
		public var actif:Boolean;
	}
}

Coté serveur, nous pouvons imaginer que les informations qui concernent les contacts seront stoquées dans une base de données, l’interrogation de la base suivie d’un fetchObject donnera une donnée de ce type :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
// ServiceVO.php
class ServiceVO {
 
	private $CONNECTION_BD;
 
	function __construct(){
		// Connection à la base de données
		// Ici vous instanciez votre $CONNECTION_BD
		// ou vous faites votre mysql_connect()
	}
 
	function getContactVO( $idContact ){
		// Requète
		$query = "SELECT id, nom, prenom, dateNaissance, actif "
			."FROM contact "
			."WHERE id= $idContact";
 
		// Envois
 
		// Retour
		$donneesBD = array(
			"id"=>1,
			"nom"=>"Bouvry",
			"prenom"=>"Stéphane",
			"dateNaissance"=>"2009-07-04",
			"actif"=>true
		);
 
		return $donneesBD;
	}
}
?>

Pour l’instant dans la console Weborb, ça devrait vous donner quelque chose dans ce goût là :

Image 7

Notez que tous les types de données sont conservés à l’exception de la Date, nous verrons cela au moment du Mapping de notre VO, ça va se jouer côté serveur. Mais si vous êtes pressé, utilisez simplement la classe DateTime :

10
11
12
13
14
15
16
		$donneesBD = array(
			"id"=>1,
			"nom"=>"Bouvry",
			"prenom"=>"Stéphane",
			"dateNaissance"=>new DateTime("2009-07-04"),
			"actif"=>true
		);

Attention, si vous êtes sur MAC et que vous utilisez MAMP, vous pouvez oublier la classe DateTime, l’erreur est particulièrement vicieuse car votre script bouzera en silence sans vous avertir des raisons, l’origine de l’erreur laisse une trace dans les logs de MAMP.

Côté flex, la récupération des données est toujours la même :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
 
	<mx:Script>
		<![CDATA[
			import mx.rpc.events.ResultEvent;
			import mx.rpc.events.FaultEvent;
			private function recupererContact() :void {
				serviceVO.getContactVO(1);
			}
 
			private function onResult( result:ResultEvent ) :void {
				trace(result.result);
			}
 
			private function onFault( fault:FaultEvent ) :void {
				trace(fault);
			}
		]]>
	</mx:Script>
 
	<mx:RemoteObject id="serviceVO"
		endpoint="http://localhost:8888/weborb.php"
		destination="ServiceVO"
		source="ServiceVO"
		result="onResult(event)"
		fault="onFault(event)"
	/>
 
	<mx:Button label="Appel méthode" click="recupererContact()" />
</mx:Application>

Si vous placez un point d’arret (breakpoint) dans la méthode onResult, vous devriez obtenir ça :

weborb-php-bp-flex-01

Le trace nous affiche un [object Object]…

Les plus malins vont se dire : « Y’a plus k’a caster » :

13
14
15
16
private function onResult( result:ResultEvent ) :void {
	var typerContact:ContactVO = result.result as ContactVO;
	trace(typerContact);
}

Mais c’est le drame, notre trace nous affiche un NULL sans appel, vous allez devoir mapper

Mappage de VO

Rien à voir avec la patisserie, le mappage, également qualifié « Mapping » va se jouer côté serveur (et un chouilla côté Flex), l’objectif va être de créer une class PHP qui sera (pour le moment) la répique exacte de la classe ContactVO de Flex. Coté PHP, créez un fichier ContactVO.php (forcez vous à utiliser le nom de la classe, ça vous facilitera la vie par la suite) :

1
2
3
4
5
6
7
8
9
<?php
class ContactVO {
	public $id;
	public $nom;
	public $prenom;
	public $dateNaissance;
	public $actif;
}
?>

Dans notre service, nous allons envoyer un ContactVO, donc modifiez le service ainsi (pensez à importer le fichier du VO) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php
// tutorial_vo/ServiceVO.php
require_once 'ContactVO.php';
class ServiceVO {
 
	private $CONNECTION_BD;
 
	function __construct(){
		// Connection à la base de données
		// Ici vous instanciez votre $CONNECTION_BD
		// ou vous faites votre mysql_connect()
	}
 
	function getContactVO( $idContact ){
		// Requète
		$query = "SELECT id, nom, prenom, dateNaissance, actif "
			."FROM contact "
			."WHERE id= $idContact";
 
		// Envois
 
		// Retour
		$donneesBD = array(
			"id"=>1,
			"nom"=>"Bouvry",
			"prenom"=>"Stéphane",
			"dateNaissance"=>new DateTime("2009-07-04"),
			"actif"=>true
		);
 
		// Mapping
		$contact = new ContactVO();
		$contact->id = $donneesBD["id"];
		$contact->nom = $donneesBD["nom"];
		$contact->prenom = $donneesBD["prenom"];
		$contact->dateNaissance = $donneesBD["dateNaissance"];
		$contact->actif = $donneesBD["actif"];
 
		return $contact;
	}
}
?>

Si vous testez à nouveau, la casting ne fonctionne toujours pas, vous devez apporter une dernière modification, cette fois côté Flex. Ajoutez une Metadata RemoteClass à votre VO pour indiquer à la passerelle où se trouve le fichier du VO côté serveur (depuis la racine du dossier /Services) :

1
2
3
4
5
6
7
8
9
10
11
12
13
package vo
{
	[RemoteClass(alias="tutorial_vo.ContactVO")]
	public class ContactVO
	{
		public var id:int;
		public var nom:String;
		public var prenom:String;
		public var dateNaissance:Date;
		public var actif:Boolean;
 
	}
}

En testant le casting côté Flex, vous devriez obtenir un beau ContactVO tout frais.

Résultat du cast de VO

Résultat du cast de VO

Attention, dans le cadre de transmission de VO, un phénomène ésotérique singulier se produit. En effet, à l’arrivé dans Flex, nous avans casté le result pour obtenir un ContactVO. Si vous supprimez l’opération de casting. Le contenu de result devrait redevenir un simple Object. Vous aurez beau importer la classe ContactVO explicitement, ca ne changera rien, il faut au moins une instance de ContactVO pour que l’atterisage des données soit automatiquement typées… Jugez plutôt :

14
15
16
17
// Dans ce cas, le contenu du Result est Object
private function onResult( result:ResultEvent ) :void {
	trace(result);
}

Ensuite même manipe mais en instanciant un ContactVO (peu importe l’endroit dans la vue)

14
15
16
17
18
// la ça marche
private function onResult( result:ResultEvent ) :void {
	var c:ContactVO;
	trace(result);
}

Là aussi…

14
15
16
17
18
// la ca marche aussi
private var c:ContactVO;
private function onResult( result:ResultEvent ) :void {
	trace(result);
}

Et ça fonctionne où que soit votre import (même dans un autre composant dès lors que ce composant est raccordé au fichier principal), et je le rappel : Un simple import ne suffit pas. On peut facilement imaginer que le compilateur n’embarque pas la classe car il estime qu’elle n’est pas utilisée dans l’application, ce qui en soit n’est pas faux, quel interet auriez vous à caster une donnée que vous n’utilisez pas…

Voilà pour l’allez, penchons nous sur l’envois de données typé vers la passerelle Weborb PHP.

Envoyer des VO

Alors là, c’est du finger in the nooze :P , on va ajouter une méthode receptionContactVO à notre service, avec en paramètre un objet typé implicitement de cette manière :

function receptionContactVO( ContactVO $contact ){
	$retour = $contact->nom . " " 
		. $contact->prenom . " né le " 
		. " (id: " .$contact->id 
		." / actif: ".$contact->actif.")";
	return $retour;
}

Coté Flex, en appellant le service, passez directement un ContactVO

private function envoyerContact() :void {
	var c:ContactVO = new ContactVO();
	c.id = 10;
	c.nom = "Barba";
	c.prenom = "Papa";
	c.dateNaissance = new Date();
	c.actif = false;
 
	serviceVO.receptionContactVO(c);
}

Pour la date, vous allez devoir procéder à un traitement préalable. En effet, quand une date en provenance de Flex arrive côté PHP, la passerelle Weborb la transforme en ORBDateTime, (pathWeborb/Weborb/Utils/OrbDateTime.php) .Cette classe fournis par weborb permet justement de traiter les dates. Dans notre exemple, nous destinons la date à une base de donnée où les informations seront enregistrées sous la forme « Y-m-d H:i:s », la classe ORBDateTime fournis pour cela une méthode retournant la date en millisecondes (getTotalMs), cette information va nous permettre via la fonction date d’obtenir une date correctement formatée.

Modifier notre méthode de cette façon :

function receptionContactVO( ContactVO $contact ){
	$retour = $contact->nom . " " 
		. $contact->prenom . " né le " 
		. date("Y-m-d H:i:s", round($contact->dateNaissance->getTotalMs()/1000)) 
		. " (id: " .$contact->id 
		." / actif: ".$contact->actif.")";
	return $retour;
}

Vous pourrez observer que notre Date est correctement formatée

Vous avez maintenant en main les outils nécessaires pour créer des services AMF avec la passerelle Weborb PHP, j’aborderais sous peu une exemple concret pour syntétiser les 2 tutoriaux, vous y trouverez tous les cas abordées ici dans un contexte pratique avec surtout : Amélioration des ValuesObject avec les Intefaces PHP, Héritage de service, Gestion des Données via PDO.

5 commentaires »

  1. Bonjour,

    merci pour ces articles clairs.
    Une petite question: est-il possible d’instancier depuis Flex une classe php avec un argument variable dans le constructeur via WebOrb, soit par exemple:

    function __construct($userId){
    // Classe instanciée pour ce $userId
    }

    Commentaire by iTi — 24 octobre 2009 @ 11:27

  2. Re,

    une autre question, qui pourrait faire l’objet d’une partie 3.
    WebOrb a un mécanisme d’authentification/autorization de ces services. Néanmoins il est difficile de lier ces mécanismes à une base mysql.

    As-tu regardé cela?

    Merci

    Commentaire by iTi — 24 octobre 2009 @ 11:36

  3. Pour ta première question, je n’ai jamais essayé et je dirais a priori non.

    Pour l’autre, je gère moi-même le système d’identification dans une classe mère, ensuite j’étend cette classe dans chaque services pour bénéficier des outils d’authentification dans mes autres services.

    Commentaire by Jacksay — 26 octobre 2009 @ 10:22

  4. Bonjour

    comment creer une requete selection avec php wamp et afficher les donnees dans air
    merci

    Commentaire by ayoub — 13 janvier 2010 @ 6:08

  5. Que tu sois en Flex ou en Air, le fonctionnement est exactement le même que celui décrit dans la série d’articles consacré à Weborb PHP. Tu peut cependant rencontrer des problèmes de sécurité – les fameuses Sandbox Error – mais c’est une simple question de réglage (via les crossdomain.xml)

    Pour interroger ta Base de donnée, tu procèdes de manière classique (mysql_query($requete) ou en utilisant PDO), ensuite tu traites les résultats comme c’est décrit dans l’article (mapping)

    Commentaire by Jacksay — 14 janvier 2010 @ 9:58

Flux RSS des commentaires de cet article. TrackBack URL

Laisser un commentaire