Prendre un Café

L'espace d'expression de Nicolas Perriault

Aller au contenu | Aller au menu | Aller à la recherche

Dev

Développement PHP, actionScript2, Ruby, XHTML, CSS, javascript, etc.

Fil des billets - Fil des commentaires

mardi 2 juin 2009

Utiliser les fonctions GeoIP de PHP sous Ubuntu

Mon Dieu, les billets techniques refleuriraient-ils au printemps ? Si vous désirez récupérer des informations géographiques à partir de l’adresse IP (ou du hostname) d’un utilisateur, vous pouvez utiliser les fonctions fournies par l’extension PECL GeoIP.

Voici la procédure d’installation sur une Ubuntu 8.04:

$ sudo -s
# apt-get install build-essential php5-dev php5-cli libgeoip-dev libgeoip1 php-pear
# pecl install geoip

Si toiut s’est bien passé :

# echo "extension=geoip.so" >> /etc/php5/cli/php.ini

Si vous utilisez Apache comme serveur :

# echo "extension=geoip.so" >> /etc/php5/apache2/php.ini

Il faut également installer la base GeoIPCity de Maxmind :

# wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
# gunzip GeoLiteCity.dat.gz
# mv GeoLiteCity.dat /usr/share/GeoIP/GeoIPCity.dat

Vous pouvez maintenant tester l’extension avec une ligne du genre[1] :

$ echo "<?php var_dump(geoip_record_by_name('209.202.168.**'));"|php

Ça donne ici :

array(11) {  ["continent_code"]=>
  string(2) "NA"
  ["country_code"]=>
  string(2) "US"
  ["country_code3"]=>
  string(3) "USA"
  ["country_name"]=>
  string(13) "United States"
  ["region"]=>
  string(2) "NC"
  ["city"]=>
  string(4) "Cary"
  ["postal_code"]=>
  string(5) "27511"
  ["latitude"]=>
  float(35.7********)
  ["longitude"]=>
  float(-78.7*******)
  ["dma_code"]=>
  int(560)
  ["area_code"]=>
  int(919)
}

Enjoy.

Notes

[1] J’ai volontairement masqué certaines informations pour d’évidentes raisons de confidentialité.

jeudi 4 décembre 2008

Fayotage

[13:13:07] Glooze: hey, doctrine + sf, ca roxxe quand même :p
[13:13:29] NiKo: génial, tu peux faire un billet pour le dire steup ? :D
[13:13:48] Glooze: dès que j’aurai trouvé un pdf de la doc !
[13:13:54] NiKo: un pdf oO
[13:14:05] NiKo: tu connais pomme P -> PDF
[13:14:13] Glooze: Ouais mais non
[13:14:29] Glooze: j’suis pas sous mac tout le temps (notamment mon portable il est sous ubuntu)
[13:14:32] NiKo: ahhh ok môssieur veut un beau livre relié cuir, bien sûr
[13:14:39] NiKo: ben sous ubuntu c’est natif
[13:14:43] NiKo: imprimer -> pdf
[13:14:47] NiKo: depuis firefox
[13:14:50] Glooze: et pis surtout une doc sur 8 pages, ça me fait aller sur chaque et imprimer
[13:14:51] Glooze: :o
[13:14:59] Glooze: Alors une doc plus grosse :p
[13:15:30] NiKo: si tu fais pas de billet, je faillote sur mon blog en faisant un gros copier coller de cette discussion
[13:15:32] NiKo: </menace>
[13:15:36] Glooze: Y a eu des tas de changements (en mieux d’ailleurs) pour la 1.2, donc mon definitive guide (acheté môssieur) il est plus trop utile :p
[13:15:44] Glooze: Mais vas-y, faillote !
[13:15:47] NiKo: ça marche

lundi 1 décembre 2008

Meet Joe Beet

Sorry for the lame title of this blog post, but I’m happy enough to announce the immediate availability of both symfony 1.2 and Jobeet, the new symfony advent calendar!

Jobeet It is a set of 24 tutorials, published day-by-day between December 1st and Christmas. Each tutorial is meant to last one hour, and will be the occasion to see the ongoing development of a web application with symfony, from A to Z.

So don’t hesitate to start reading day one of this great tutorial :-)

Edit: I forgot to mention the simultaneous release of the symfony and Doctrine book :)

vendredi 31 octobre 2008

Let's Play with Symfony 1.2 and Doctrine

It’s been quite a long time I didn’t give a go to Doctrine, so as it’s gonna be bundled by default in with the upcoming 1.2 release of symfony, I thought it was a good occasion to play with it.

So let’s checkout the 1.2 SVN branch of symfony and create a test project with a main application[1]:

$ mkdir sf12test && cd sf12test
$ mkdir -p lib/vendor
$ svn co http://svn.symfony-project.com/branches/1.2 lib/vendor/symfony
$ php lib/vendor/symfony/data/bin/symfony generate:project sf12test
$ ln -s ../lib/vendor/symfony/data/web/sf web/sf
$ ./symfony generate:app main

Create a webserver vhost pointing to the web folder of the project directory. I’ve already explained plenty of times how to achieve this step.

Now, let’s enable the sfDoctrinePlugin and disable the Propel one by editing the setup() method of the config/ProjectConfiguration.class.php file:

public function setup()
  {
    $this->disablePlugins('sfPropelPlugin');
    $this->enablePlugins('sfDoctrinePlugin');
  }

You can list the available tasks running this simple command:

$ ./symfony list doctrine

Managing the Database Schema

First, configure your config/databases.yml file to set the database connection parameters. If you want to quick test Doctrine, use a local SQLite db, like this:

all:
  doctrine:
    class:    sfDoctrineDatabase
    param:
      dsn:    sqlite://<?php echo dirname(__FILE__).'/../data/data.db' ?>

We’re going to make a very simple weblog application, so let’s configure our database schema. We can do it in YAML[2], so fire up your favorite editor/IDE and edit a brand new config/doctrine/schema.yml:

BlogPost:
  actAs:
    Sluggable:
      fields:       [title]
    Timestampable:
  columns:
    title:          string(255)
    body:           clob
    author:         string(255)
 
BlogComment:
  actAs:            [Timestampable]
  columns:
    blog_post_id:   integer
    author:         string(255)
    email:          string(255)
    content:        clob
  relations:
    BlogPost:
      class:        BlogPost
      local:        blog_post_id
      foreign:      id
      foreignType:  many
      type:         one

Note that Doctrine offers several pretty cool features including native behaviors (timestampable and slugable are used here).

Now, create a data/fixtures folder and put a data.yml file in, containing some test data in YAML format:

BlogPost:
  p1:
    title: My first post
    body: |
      This is cool.
    author: NiKo
    created_at: "<?php echo date('Y-m-d H:i:s', time() - 86400) ?>"
  p2:
    title: My second post
    body: |
      This is still cool.
    author: NiKo
    created_at: "<?php echo date('Y-m-d H:i:s', time() - 7200) ?>"
  p3:
    title: Third post
    body: |
      Is this one cool?
    author: Roger Hanin
    created_at: "<?php echo date('Y-m-d H:i:s') ?>"
 
BlogComment:
  c1:
    BlogPost: p3
    author: John
    email: john@doe.com
    content: Hey, you're right there.
    created_at: "<?php echo date('Y-m-d H:i:s', time() - 86400) ?>"
  c2:
    BlogPost: p3
    author: Paul
    email: paul@doe.com
    content: Nope, he's not.
    created_at: "<?php echo date('Y-m-d H:i:s') ?>"

Okay, now run the command below to generate the needed files, create the database and fill it with the data fixtures:

$ ./symfony doctrine:build-all-load

We can run several DQL queries in command line to check if everything is fine. DQL is very powerful, and compatible with a lot of RDBMS. You’ll find more information on DQL on the doctrine website.

For example, to find all blog posts:

$ ./symfony doctrine:dql "From BlogPost p"
found 3 results
-
  id: '21'
  title: 'My first post'
  body: "This is cool.\n"
  author: NiKo
  slug: my-first-post
  created_at: '2008-10-29 15:14:25'
  updated_at: '2008-10-30 15:14:25'
-
  id: '22'
  title: 'My second post'
  body: "This is still cool.\n"
  author: NiKo
  slug: my-second-post
  created_at: '2008-10-30 13:14:25'
  updated_at: '2008-10-30 15:14:25'
-
  id: '23'
  title: 'Third post'
  body: "Is this one cool?\n"
  author: 'Roger Hanin'
  slug: third-post
  created_at: '2008-10-30 15:14:25'
  updated_at: '2008-10-30 15:14:25'

Another example, to find informations about the blog post with slug third-post and its associated comments:

$ ./symfony doctrine:dql "Select p.title, p.author, c.author, c.content From BlogPost p, p.BlogComment c Where p.slug = 'third-post' Group by c.id"
found 3 results
-
  id: '23'
  title: 'Third post'
  author: 'Roger Hanin'
  BlogComment: [{ id: '15', author: John, content: 'Hey, you''re right there.' }, { id: '16', author: Paul, content: 'Nope, he''s not.' }]

Put the Query Logic in the Model

The Model part of any MVC architecture must contains the business data and associated logic. In other words, these data and logic should never be handled anywhere else, to decouple your components at max. So we’ll add some query methods in the lib/model/doctrine/BlogPostTable.class.php file, which represents our blog_post table and available operations on it:

<?php
class BlogPostTable extends Doctrine_Table
{
  public function getAll()
  {
    return Doctrine_Query::create()->
      select('p.title, p.slug, p.body, p.author, p.created_at, count(c.id) numcomments')->
      from('BlogPost p, p.BlogComment c')->
      orderBy('p.created_at DESC')->
      groupBy('p.id')->
      execute();
  }
 
  public function getOneBySlug($slug)
  {
    $posts = Doctrine_Query::create()->
      from('BlogPost p')->
      leftJoin('p.BlogComment c')->
      where('p.slug = ?')->
      orderBy('c.created_at ASC')->
      limit(1)->
      execute(array($slug));
 
    return isset($posts[0]) ? $posts[0] : null;
  }
}

A Weblog is About Web Interface, uh?

Okay, let’s add pretty controllers and templates to give some life to our blog. First, generate a post module in the main app:

$ ./symfony generate:module main post

Then, edit the apps/main/modules/post/actions/actions.class.php file:

<?php
class postActions extends sfActions
{
  public function executeIndex($request)
  {
    $this->posts = Doctrine::getTable('BlogPost')->getAll();
  }
  
  public function executeShow($request)
  {
    $this->post = Doctrine::getTable('BlogPost')->getOneBySlug($slug = $request->getParameter('slug'));
    $this->forward404Unless($this->post, 'No post with slug=' . $slug);
    $this->comments = $this->post->getBlogComment();
  }
}

We should have display templates too. The first one will show the posts list, in apps/main/modules/post/templates/indexSuccess.php:

<?php foreach ($posts as $post): ?>
  <?php include_partial('post/post', array('post' => $post, 'numComments' => $post->getNumcomments())) ?>
  <hr/>
<?php endforeach; ?>

Note that we must create the _post partial template, in apps/main/modules/post/templates/_post.php:

<h2><?php echo link_to($post->getTitle(), 'post/show?slug='.$post->getSlug()) ?></h2>
<p>
  <small>Posted by <?php echo $post->getAuthor() ?> on <?php echo $post->getCreatedAt() ?>
  <?php if (isset($numComments)): ?>
    - <?php echo $numComments ?> comments
  <?php endif; ?>
  </small>
</p>
<?php echo $post->getBody(ESC_RAW) ?>

The other main template will display one post and its comments, in apps/main/modules/post/templates/showSuccess.php:

<?php include_partial('post/post', array('post' => $post)) ?>
 
<h2>Comments</h2>
<?php if (!count($comments)): ?>
  <p>No comment yet.</p>
<?php else: ?>
<?php foreach ($comments as $comment): ?>
  <p><small>By <?php echo $comment->getAuthor() ?> on <?php echo $comment->getCreatedAt() ?></small></p>
  <blockquote><?php echo $comment->getContent() ?></blockquote>
<?php endforeach; ?>
<?php endif; ?>

That’s it. A rough but functional weblog if you lauch your browser to yourhost/main_dev.php/post/index:

step2.png

And if you click a post title:

step1.png

Good News, the Forms Framework Works with Doctrine Too

Symfony 1.1 introduced the new forms framework, and good news, Doctrine can take part of it. So maybe you’ve already noticed it, we have form classes generated already, in the lib/form/doctrine folder of the project.

So let’s add a neat commenting system to our blog, by first editing the lib/form/doctrine/BlogCommentForm.class.php file:

<?php
class BlogCommentForm extends BaseBlogCommentForm
{
  public function configure()
  {
    unset($this['id'], $this['created_at'], $this['updated_at']);
    
    $this->widgetSchema['blog_post_id'] = new sfWidgetFormInputHidden();
    
    $this->validatorSchema['author']  = new sfValidatorString(array('min_length' => 3));
    $this->validatorSchema['email']   = new sfValidatorEmail();
    $this->validatorSchema['content'] = new sfValidatorString(array('min_length' => 5));
  }
}

Now, use the form in the executeShow() method of our controller:

<?php
// ...
  public function executeShow($request)
  {
    $this->post = Doctrine::getTable('BlogPost')->getOneBySlug($slug = $request->getParameter('slug'));
    $this->forward404Unless($this->post, 'No post with slug=' . $slug);
    $this->comments = $this->post->getBlogComment();
    
    $comment = new BlogComment();
    $comment->setBlogPost($this->post);
    $this->form = new BlogCommentForm($comment);
    
    if ($request->isMethod('post') && $this->form->bindAndSave($request->getParameter('blog_comment')))
    {
      $this->redirect('post/show?slug='.$this->post->getSlug());
    }
  }

And in the showSuccess.php template, we’ll append the form display:

<h3>Add a comment</h3>
 
<?php echo $form->renderFormTag(url_for('post/show?slug='.$post->getSlug())) ?>
  <table>
    <?php echo $form ?>
    <tr>
      <td></td><td><input type="submit"/></td>
    </tr>
  </table>
</form>

We’ve now a pretty commeting system added to our blog, thanks to all the goodness provided by symfony and Doctrine:

step3.png

Conclusion

The time when everyone choosed Propel because it was more stable than Doctrine seems to be over. Doctrine is robust, and performs quite well on my box. Furthermore, it handles complex relationships and dynamic object hydratation natively and better than Propel. Doctrine is also very well integrated into symfony, certainly because Jonathan Wage - the Doctrine lead developer - now works for Sensio, creator and main sponsor of symfony.

Notes

[1] Note that Windows users should replace calls to ./symfony by php symfony.

[2] If you hate YAML, you can still write Doctrine table definition classes in raw PHP by hand

jeudi 30 octobre 2008

Utiliser Memcached avec PHP sous Mac OS X

Ayant récemment eu besoin de travailler sur une application utilisant memcached, j’ai du l’installer sur ma machine perso tournant sous Mac OS X. Pour mémoire, memcached est un système de stockage distribué de paires clé/valeur en mémoire vive, très rapide et performant. Cela peut s’avérer un outil de choix pour faire monter en charge une architecture, par exemple en ajoutant des frontaux web et en utilisant memcached comme espace partagé de stockage des données de session utilisateur. On peut également imaginer d’y stocker les résultats de traitements complexes, des templates compilés, des jeux de résultats SQL, etc.

J’ai trouvé un excellent tutoriel d’installation de memcache pour OS X pour cela, que je vous invite à suivre pour mettre en œuvre les exemples ci-après. Une fois l’installation effectuée, vous pouvez lancer le démon memcached avec cette ligne de commande :

$ sudo memcached -d -u nobody -m 128 127.0.0.1 -p 11211

Notez que cette dernière ligne de commande lance le démon memcached sous l’utlisateur nobody, en local sur le port 11211 et alloue 128 Mo de mémoire vive au service de stockage.

Exemple d’utilisation en PHP

Le tutoriel couvre également l’installation de l’extension PECL memcache, fournissant une API particulièrement simple et efficace à PHP pour utiliser le service.

Exemple d’utilisation basique :

<?php
$m = new Memcache;
$m->connect('localhost', 11211) or die ("Could not connect");
$m->set('toto', 'tata');
echo $m->get('toto'); // tata 

Pour utiliser memcached comme système de stockage des sessions, PHP dispose d’un gestionnaire de sessions memcache qu’il suffit d’activer par configuration dans votre fichier php.ini. Il suffit de remplacer la valeur :

session.save_handler = files

Par ces deux lignes, en adaptant au besoin les valeurs de connexion au démon :

session.save_handler = memcache
session.save_path="tcp://127.0.0.1:11211?persistent=1&weight=1&timeout=1&retry_interval=15"

Attention cependant, en cas de coupure du service memcached, toutes les données de sessions actives seront perdues.

lundi 22 septembre 2008

Eclipse PDT, Subclipse et Subversion 1.5.2 sont dans un bateau

Le package complet pour la version stable d’Eclipse PDT fournit Subclipse[1] en version 1.2 par défaut.

Cette version de Subclipse est incapable de gérer la dernière version du client Subversion, la 1.5.2. La moindre tentative d’update devrait vous afficher ce message laconique : The version of this client is too old[2].

Et bien entendu, il est au premier abord impossible de désinstaller le plugin Subclipse en version 1.2 fournit par PDT.

Aussi, voici l’astuce permettant de mettre à jour votre version de Subclipse au sein de votre environnement Exclipse/PDT :

  • Dans le menu Software updates, choisissez Manage configuration
  • Dépliez l’arborescence des dépendances pour le module PDT, et sélectionnez Subclipse
  • Cliquez sur Disable, puis relancez Eclipse
  • Dans Software Updates, choisissez Find and Install et ajoutez un nouveau dépôt distant[3], et renseignez le comme ci-dessous :
    • Name : Subclipse 1.4.x
    • URL : http://subclipse.tigris.org/update_1.4.x
  • Sélectionnez ce dépôt, puis lancer la recherche de packages
  • Sélectionnez les modules Subclipse et SVNKit
  • Redémarrez Eclipse

Après ces manipulations, vos devriez retrouver vos fonctionnalités préférées.

Notes

[1] Subclipse est un plugin intégrant Subversion à Eclipse

[2] Et c’est pas la première fois que ça arrive

[3] Chez Eclipse, on appelle ça un Update site

mercredi 17 septembre 2008

Request For Comments: sending emails in symfony 1.2

There should be a standard way for sending emails in upcoming symfony 1.2, and I’m in charge of implementing it, using the excellent SwiftMailer library. So I’ve created a dedicated RFC page on the symfony wiki just to get your opinions on the Right Way It Should Be Done®.

If you’re interested, there’s also a dedicated thread on the devs mailing list.

Edit: Swift integration didn’t make it for symfony 1.2, and here are my main reasons:

  • I didn’t get enough time
  • Swift is strangely coded from an architecture point of view: you must override the SMTP connection class to be able to send a mail using PHP mail() native function ; so it’s hard to extend or tweak it easily
  • I didn’t get enough time
  • Swift looked like a dead project at the time symfony 1.2 was released
  • I didn’t get enough time

To be honnest I’d like to see it integrated for symfony 1.3, but maybe with another lib… Stay tuned.

vendredi 25 juillet 2008

Partager la session utilisateur entre Flash/Flex et symfony avec AmfPHP

Pour les besoins d'un projet récent, j'ai eu besoin de valider la possibilité de gérer l'authentification et l'accès à la session symfony (côté serveur) depuis une interface générée par Adobe Flex (en Flash, donc côté client).

Pour cela, j'ai utilisé la librairie AmfPHP en version 1.9beta2, certes pas très récente mais suffisament fonctionnelle pour satisfaire à ce besoin précis. Voyons comment ça se passe concrètement. L'avantage de la démonstration ci-dessous est qu'elle ne nécessite pas d'installer Flex puisque AmfPHP fournit un navigateur de services (browser) qui nous suffira pour valider notre concept.

Installation du plugin sfGuard

Je pars du principe que tout le monde a une installation de symfony 1.1 nanti d'une application main, ainsi qu'un projet et un virtual host apache fonctionnels pointant sur local.mademo.org. Si ce n'est pas le cas, voila de quoi vous mettre à jour.

On commence par installer le plugin sfGuard, qui se chargera de la persistance des droits et permissions utilisateurs en base de données, et fournira les utilitaires d'authentification et de manipulation de la session côté serveur :

$ ./symfony plugin:install sfGuardPlugin
$ ./symfony propel-build-all
$ ./symfony cc

On charge quelques données de test dans notre base de données nouvellement mise à jour :

$ mkdir data/fixtures 
$ cp plugins/sfGuardPlugin/data/fixtures.yml.sample data/fixtures/fixtures.yml
$ ./symfony propel:data-load main

Ce jeu de données de test nous fournit par défaut un compte admin (mot de passe admin) qui nous servira à tester notre service d'authentification.

Ensuite, il nous faut modifier notre classe apps/main/lib/myUser.php gérant la session utilisateur afin qu'elle étende désormais la classe sfGuardSecurityUser, fournie par le plugin sfGuard :

<?php
// Fichier apps/main/lib/myUser.php
class myUser extends sfGuardSecurityUser
{
}

Installation et configuration d'AmfPHP

Nous allons installer la librairie AmfPHP dans le sous-répertoire web/ de notre projet[1], et aménager quelque peu notre arborescence pour accueillir les services AmfPHP :

$ cd /path/to/project
$ svn export https://amfphp.svn.sourceforge.net/svnroot/amfphp/tags/1.9beta2 web/amfphp
$ mkdir lib/amfphp-services
$ mv web/amfphp/services/amfphp lib/amfphp-services/

Ceci fait, nous allons éditer plusieurs fichiers d'amfphp afin de l'adapter à notre environnement symfony. Tout d'abord, commençons par éditer la valeur de la variable $servicesPath dans le fichier web/amfphp/globals.php :

<?php
// ...
$servicesPath = dirname(__FILE__).'/../../lib/amfphp-services/';

Enfin, il nous faut "patcher"[2] le fichier web/amfphp/core/amf/app/Filters.php, qui initialise la session PHP sans définir le nom de la session. Ici, nous utiliserons le nom de la session symfony par défaut, "symfony" (ligne 105 du fichier) :

102     //Fix for godaddy not allowing ini_get
103     $sessionName = "PHPSESSID";
104   }
105   session_name('symfony');
106   session_start();
107   $session_id = session_id();

Création d'un service permettant le partage de la session utilisateur

Voila, nous pouvons maintenant créer un service de gestion de l'authentification, que nous nommerons pompeusement UserSessionService et que nous enregistrerons dans le fichier lib/amfphp-services/UserSessionService.php :

<?php
require_once dirname(__FILE__).'/../../config/ProjectConfiguration.class.php';
 
/**
 * This class tests the symfony session within an AmfPHP context
 *
 */
class UserSessionService
{
  /**
   * Symfony context
   * @var sfContext
   */
  protected $context = null;
  
  /**
   * Symfony session
   * @var sfGuardSecurityUser
   */
  protected $user = null;
  
  /**
   * Public constructor
   *
   */
  public function __construct()
  {
    $configuration = ProjectConfiguration::getApplicationConfiguration('main', 'dev', true);
    $this->context = sfContext::createInstance($configuration);
    $this->user = $this->context->getUser();
  }
  
  /**
   * Checks wheter user is authenticated or not
   *
   * @return boolean
   */
  public function isAuthenticated()
  {
    return $this->getUser()->isAuthenticated();
  }
  
  /**
   * Authenticates user
   *
   * @param  string  $username
   * @param  string  $password
   * @return boolean True if user has been successfully authenticated
   */
  public function login($username, $password)
  {
    if ($this->isAuthenticated())
    {
      return true;
    }
    
    $user = sfGuardUserPeer::retrieveByUsername($username);
    
    if (!is_null($user) && $user->checkPassword($password))
    {
      $this->getUser()->signIn($user);
      return true;
    }
    
    return false;
  }
  
  /**
   * Signs out a user 
   *
   */
  public function logout()
  {
    return $this->getUser()->signOut();
  }
  
  /**
   * Retrieves the current symfony context
   *
   * @return sfContext
   */
  protected function getContext()
  {
    return $this->context;
  }
  
  /**
   * Retrieves the current symfony user session
   *
   * @return sfGuardSecurityUser
   */
  protected function getUser()
  {
    return $this->user;
  }
}

Pour tester notre service, utilisons le navigateur de service proposé par AmfPHP. Pour cela, il faut lancer un navigateur sur http://local.mademo.org/amfphp/browser/index.html :

Naviagateur de services AmfPHP

Via cette interface, elle même réalisée en Flex, on peut tester les méthodes publiques définies dans notre service, manipuler les arguments, et constater que nous arrivons à nous authentifier et que nous accédons bien à la même session utilisateur que dans symfony : login, logout et test du statut d'authentification.

En conclusion

On pourrait aller beaucoup plus loin dans cet exemple, en proposant par exemple une classe proxy en ActionScript 3 représentant un utilisateur du système (dans notre cas, une instance de la classe sfGuardUser), cette dernière reproduisant tout ou partie de ses méthodes et propriétés, et donc d'utiliser l'ORM Propel directement depuis Flash... Je vous laisse faire vos tests si le coeur vous en dit.

D'autre part, même si la librairie AmfPHP semble un peu passée au niveau architecture, elle reste néanmoins très efficace pour publier des services PHP dans Flash au travers du protocole AMF. J'ai eu vent d'autres librairies comme WebORB ou SabreAMF, mais je ne sais pas vraiment ce qu'elles valent... Des avis dans l'assistance ?

Notes

[1] Du coup, on expose certains scripts AmfPHP, mais la librairie n'est malheureusement que prévue pour fonctionner en ce sens...

[2] Oui, c'est terriblement crade, je ne comprend d'ailleurs pas qu'AmfPHP n'aie pas prévu ce cas de figure...

- page 1 de 9