Ayant passé toute la semaine dernière à essayer de comprendre pourquoi est-ce que mon application Flex ne communiquait pas avec mon serveur AMF fourni par le module Zend_Amf, je pense avoir mis le doigt dessus.

Un collègue m'a fourni exemple simpliste d'une application Flex "Hello World" qui fonctionnait chez lui en local. Une fois envoyé, j'ai installé WAMP 2.x et lancé l'application qui marcha.

Voulant fusionner mon application avec la sienne, j'ai supprimé tous les dossiers/fichiers inutiles de sa distribution du Zend Framework. Bien évidemment, j'en avais trop supprimé donc j'ai tout remplacé par ma distribution (1.8.1) et là, plus rien ne fonctionnait.

Dans la précipitation, j'ai remis les portions de code initiales dans mon fichier MXML en pensant que c'était mon code qui merdouillait mais même après avoir tout restauré, rien ne fonctionnait... Flex ne communiquait pas avec mon serveur.

J'ai alors comparé ma version du Zend Framework et la sienne et là, j'ai compris que cela venait de là...

Procédure

Une nouvelle version du Zend Framework est sortie il y a quelques jours en version 1.8.2 (changelog) mais qui n'a apparemment pas encore réglé ce soucis.
J'ai alors téléchargé toute les versions depuis la 1.7.7 pour faire des tests sur une machine virtuelle.

J'ai donc sur ma machine virtuelle, une version 5.2.3 de PHP (5.2.9-2 en local) et une arborescence qui me permet de changer aisément de version du Zend Framework via un système de liens symboliques. Faisons un tour des fichiers sources :

Serveur Zend_Amf

<?php  
set_include_path(  
    'library'
    . PATH_SEPARATOR . get_include_path()
);

// Inclusion du serveur
require_once 'Zend/Amf/Server.php';  
require_once 'Zend/Version.php';


// Inclusion des services
require_once 'services/Test_Amf.php';  
require_once 'services/Hello_Service.php';

// Création d'un object Zend_Amf_Server
$server = new Zend_Amf_Server();

// Assignation des services
$server->setClass('Test_Amf');
$server->setClass('Hello_Service');

// Env' de dev
$server->setProduction(false);

// Réponse serveur
echo $server->handle() . Zend_Version::VERSION;  

Si je vais sur ma page de serveur, j'obtiens donc ceci :

Zend Amf Endpoint  
1.7.7  

Comme nous le voyons, j'ai assigné deux services qui sont respectivement HelloService.php et TestAmf.php :

Hello_Service

<?php  
class Hello_Service  
{
    public function __construct()
    {
    }

    public function getHelloWorld()
    {
        return 'Hey, you requested a Hello from ' . __CLASS__ . '.php class!';
    }
}

Test_Amf

<?php  
class Test_Amf  
{

    /**
     *    @return string
     */
    public function helloWorld() {
        // var_dump('foobar');
        return 'Hey, you requested a Hello from ' . __CLASS__ . '.php class!';
    }
}

Fichier source de l'application Flex

Mon fichier testamf.mxml_ sera compilé autant que fois qu'il y a de version avec son fichier service-config.xml associé qui pointera sur les différentes versions des serveurs AMF.

<mx:application xmlns:mx="http://www.adobe.com/2006/mxml">  
    <mx:remoteobject fault="faultHandler(event)" destination="zend" showbusycursor="true" id="myRemote" result="resultHandler(event)">
    </mx:remoteobject>
    <mx:script>

    </mx:script>
    <mx:panel paddingbottom="20" title="Test Zend_Amf" paddingleft="20" paddingtop="20" height="100%" width="100%" paddingright="20" id="main">
        <mx:text text="Current AMF Endpoint : " id="endpt_text"></mx:text>
        <mx:grid>
            <mx:gridrow>
                <mx:griditem>
                    <mx:button click="getHelloWorld()" label="Say hello from Hello_Service"></mx:button>
                </mx:griditem>
                <mx:griditem>
                    <mx:button click="helloWorld()" label="Say hello from Test_Amf"></mx:button>
                </mx:griditem>
                <mx:griditem>
                    <mx:button click="{grid.removeAllChildren();}" label="Clear"></mx:button>
                </mx:griditem>
            </mx:gridrow>
        </mx:grid>
        <mx:grid id="grid"></mx:grid>
    </mx:panel>
</mx:application>  

Et voici donc le fichier de service associé :

<services-config>  
    <services>
        <service messagetypes="flex.messaging.messages.RemotingMessage" id="zend-service" class="flex.messaging.services.RemotingService">
            <destination id="zend">
                <channels>
                    <channel ref="zend-endpoint"></channel>
                </channels>
                <properties>
                    <source>*</source>
                </properties>
            </destination>
        </service>
    </services>
    <channels>
        <channel-definition id="zend-endpoint" class="mx.messaging.channels.AMFChannel">
            <endpoint uri="http://php-lyon.sqli.com/php-flex/current/1.7.7/" class="flex.messaging.endpoints.AMFEndpoint"></endpoint>
        </channel-definition>
    </channels>
</services-config>  

Pour chaque version, je changeais l'URI du endpoint. Cela aurait très bien pu être fait dynamiquement en Flex mais n'étant pas un pro-Flex, je n'ai pas trop voulu perdre de temps dessus.

Résultats

Une fois l'ensemble mis en place, j'ai procédé à tester chacune des applications en vérifiant rigoureusement les versions du ZendAmfServer associé. Voici les captures d'écran des résultats :

zend_amf_177

zend_amf_178

zend_amf_182

J'ai volontairement mis 3 captures différentes, celle qui fonctionne (1.7.7) et dans celles qui ne fonctionnent pas : j'ai mis de la branche 1.7.* et la toute dernière version (1.8.2).

Pour finir...

N'étant pas expérimenté en Flex et AMF, je découvre un peu cette nouvelle technologie qui est de plus en plus demandée. Aussi, j'espère avoir un retour intéressant de Romain qui peut-être pourra m'éclairer sur ces tests. Si vous avez réussi à développer une application viable avec d'autres versions que la 1.7.7 du Zend Framework, je vous serais reconnaissant de me faire partager vos retours d'expérience.

Merci.


Joris Berthelot