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

mercredi 23 juillet 2008

Mes conventions de codage...

... sont celles des projets sur lesquels je me greffe. C'est en effet pour moi une forme de respect que d'appliquer les standards de codage partagés par une communauté (ou une équipe) de développeurs : ainsi, on maximise les chances de se comprendre et on minimise les coûteuses phases de communication entre geeks introvertis[1] :p

En effet, rien de plus pénible que de reprendre le code de quelqu'un qui a pris des libertés avec des conventions établies à ce niveau, l'apothéose étant obtenue avec ce genre de code :

<?php
  class Ma_superClasse {
 
    function dire_coucou ( $popol) {
  echo 'coucou ' . $popol   . ' !' ;
}
     function DireAuRevoir($Popol )
{ print "Au revoir $Popol !";
     }
  }

Je force bien évidemment ici le trait, mais tout le monde est déjà tombé sur ce genre de code illisible, qui multiplie par 10 votre temps d'intervention sur ce dernier et divise par 1000 votre passion pour la TMA.

Bien entendu, il peut arriver de produire du code sur un projet ne nécessitant l'utilisation d'aucune brique logicielle existante. Auquel cas vous pouvez librement appliquer vos propres standards de codage, l'important étant ici qu'ils soient cohérents et constamment appliqués. S'il peuvent être ceux d'un projet open source existant reconnu, cela augmentera la sympathie potentielle à votre égard de futurs intervenants sur votre code ;)

Je noterai quand même en vrac quelques bonnes pratiques générales globalement reconnues et appréciées :

  • être explicite,
  • indenter son code,
  • documenter son code,
  • à choisir entre les deux, privilégier la lisibilité à la concision,
  • utiliser des noms de variables, de classes, de méthodes, de fonctions et d'arguments parlants,
  • utiliser des noms anglophones,
  • utiliser des motifs de conception connus.

Personnellement, j'ai mes petites préférences et tout comme Oncle Tom - qui m'a gentiment refilé cette chaîne[2] - j'ai tendance à appliquer les standards de codage de symfony, que je trouve homogènes et cohérents. Mais ce sont là bien évidemment essentiellement des questions de goûts et de couleurs.

Notes

[1] Voire les trolls genre les tabulations ça pue, vive l'indentation à trois espaces...

[2] Salopard, ça va se payer ! ;-)

dimanche 20 juillet 2008

Debug PHP facile avec Firefox, Firebug et FirePHP

Tous ceux qui ont déjà eux à batailler avec du code javascript connaissent certainement la fabuleuse extension Firebug pour Firefox. L'outil propose une console permettant d'examiner l'environnement d'exécution javascript mais aussi HTML et CSS de n'importe quelle page web.

FirePHP est une autre extension qui a pour but de proposer le même service mais pour le langage PHP. L'extension repose elle-même sur Firebug et propose, une fois installée, l'affichage dans la console des messages de debug émis depuis vos scripts PHP :

Démo FirePHP

Une fois l'extension Firefox installée, pour pouvoir envoyer un message de log dans la console depuis vos scripts, il faut utiliser une librairie spécifique PHP fournie téléchargeable depuis la page d'accueil du projet FirePHP. Cette librairie très simple est d'ailleurs documentée ici. Une fois l'archive récupérée, décompressez-la et appelez FirePHP de cette façon depuis un script PHP standard :

require_once '/path/to/firephp/lib/FirePHPCore/FirePHP.class.php';
 
$f = FirePHP::getInstance(true);
$f->fb('Hello FirePHP console', FirePHP::INFO);
$f->fb(array('hello' => 'how are you?'));
$f->fb(array('hello' => array('how', 'are', 'you')));
$f->fb(array('foo', 'bar'), 'Results', FirePHP::WARN);
 
$o = new stdClass();
$o->foo = 'foofoo';
$o->bar = 'barbar';
 
$f->fb($o);

Pour envoyer les informations de debug à la console, la librairie PHP envoie les données sérialisées au format JSON dans un entête HTTP personnalisé dédié (X-FirePHP-Data). Ainsi, aucune interférence n'est possible avec vos scripts existants, la seule condition étant bien entendu de ne pas lancer la sortie standard PHP avant que ces entêtes aient été envoyés.

Données JSON passées dans un entête dédié

En bref, un outil génialement simple et efficace.

lundi 30 juin 2008

Symfony 1.1 est dans les bacs

Nous venons de releaser symfony 1.1, le framework qui blanchit les dents et rafraîchit l'haleine.

C'est une étape importante puisque l'architecture même du framework a été entièrement repensée, pour être notamment plus découplée, et favoriser ainsi l'extensibilité et la configurabilité. Voici les autres améliorations phares de cette nouvelle version :

  • Le nouveau framework de formulaires, entièrement orienté objet, permet une réutilisation maximale des éléments et en garantit la sécurité de façon transparente,
  • Le système de gestion de tâches en ligne de commande est une grosse tuerie, il vous permet de créer des scripts en ligne de commande avec gestion de l'aide, des arguments et des options, le tout avec une sortie en couleur au besoin !
  • Le parser YAML a été réécrit from scratch et propose maintenant des messages d'erreurs contextualisés, bien utile à l'heure du débogage,
  • La gestion des formats web permet à votre application de fournir une réponse et un format différents en fonction du type de requête entrante ; concrètement, vous gardez le même contrôleur mais vous proposez des vues adaptées dans le format qui va bien (html, xml, json, etc.) :)
  • La gestion des plugins a été entièrement revue et propose maintenant une totalement API compatible avec le standard PEAR, et gère notamment les dépendances,
  • La couche ORM Propel, toujours en version 1.2, est maintenant proposée sous la forme d'un plugin (activé par défaut), permettant ainsi plus facilement d'utiliser Doctrine ou Propel 1.3 si vous préferez,
  • Le routing a été grandement amélioré tant en performances qu'en extensibilité et souplesse de configuration,
  • La compatibilité avec symfony 1.0 est assurée grâce au plugin sfCompat10, fourni par défaut et activable en une ligne de configuration,
  • Enfin, plus de 8500 tests unitaires et fonctionnels garantissent la stabilité de l'API et préviennent de l'apparition de régressions.

Voila, l'accouchement fut un peu long mais le bébé est là, rose et bien portant. Et il n'attend plus que vous pour jouer avec lui :p

mercredi 25 juin 2008

Symfotaf

Aidez Superdupont à conquérir le web avec symfony! Sensio Labs, la société créatrice du framework symfony dont je vous parle souvent ici et pour laquelle je travaille, cherche à recruter un ou plusieurs développeurs PHP.

Le poste

Le profil du développeur recherché, c'est plutôt quelqu'un (ou quelqu'une, d'ailleurs) :

  • ayant idéalement déjà mis en œuvre le framework symfony sans s'être fait insulter par son client à l'issu du projet,
  • plutôt franchement à l'aise avec les fonctionnalités objets de php5 (y compris ses nombreux exotismes qui nous rendent fous d'amour pour ce merveilleux langage[1]),
  • à l'aise avec les principaux standards du Web comme (X)(HT)ML et CSS,
  • ne citant pas les travaux de Philippe Starck à l'évocation d'un design pattern,
  • curieux, ayant envie d'apprendre et de progresser techniquement,
  • respectueux des bonnes pratiques de développement (ou du moins comprenant l'intérêt de les mettre en oeuvre),
  • autonome, mais prompt à aider les autres s'ils sont en difficultés,
  • qui lit et comprend l'anglais technique (là je viens de faire fuir 24 personnes, j'assume),

Dans les nice-to-have features :

  • la connaissance d'un autre langage de programmation orienté objet est un gros plus (l'équivalent d'un bonus 1D30 + 10, pour donner une idées aux nerds),
  • même chose pour la connaissance de JavaScript et d'un ou plusieurs frameworks dans ce langage,
  • si capacités en gestion de projet, on vous offre un apéritif gratuit offert par la maison,
  • l'acceptation d'une géolocalisation professionnelle sur Clichy (Hauts-de-Seine) est impérative,
  • ah, et primordial également, posséder une importante capacité de résistance aux calembours foireux est fortement recommandé (d'ailleurs, le poste d'émetteur de ces derniers est actuellement occupé).

Fabien P., notre bon patron à tous

Bref, si vous vous reconnaissez complètement (ou fortement, voire partiellement) n'hésitez pas à me contacter, par le biais du formulaire de contact du blog ou, si vous avez peur que je trafique votre CV parce qu'il est mieux que le mien, directement sur celui de SensioLabs.

Post-scriptum

Je tiens à publiquement m'excuser auprès de Dieu, aka Marcel Gotlib, pour avoir détourné l'image de quelques-uns de ses personnages à de pures fins de recrutement éhontées. Pour m'excuser je vais relire l'intégrale de la Rubrique à Brac et m'adresser en consultation au professeur Burp, tiens.

Notes

[1] Ou pas, détester php en sachant expliquer pourquoi est une feature :p

mardi 24 juin 2008

ESC_RAWquerie

Le saviez-vous ? Dans symfony, il est possible de désactiver l'échappement des contenus en passant la constante ESC_RAW en dernier paramètre d'une fonction ou méthode de classe depuis une template :

<?php echo $article->getTitle(ESC_RAW) ?>

Plutôt donc que :

<?php echo $article->getRawValue()->getTitle() ?>

Ou l'infâme :

<?php echo $sf_data->getRaw('article')->getTitle() ?>

Voila, c'est tout, c'était surtout l'occasion de faire en titre le pire jeu de mot de ce blog, et de pousser le billet d'humeur sur la RATP un peu plus bas sur la home.

jeudi 8 mai 2008

No, really, symfony doesn't scale!

Well, err... Really?

mercredi 16 avril 2008

Petit-déjeuner de présentation symfony le 23 avril prochain

Je me permets de relayer cette information qui pourra intéresser une partie du lectorat de ce blog : Sensio Labs organise le mercredi 23 avril un petit-déjeuner de présentation du framework symfony à destination des sociétés de services en informatiques (SSII, agences web, cabinets de conseil, indépendants, etc.) au Centre Etoile Saint-Honoré (Paris).

Fabien Potencier, créateur de symfony et développeur principal y présentera les atouts du framework en entreprise et fera quelques annonces sur les perspectives à venir. Ça sera également l'occasion de rencontrer une grande partie de l'équipe en charge du développement du coeur de symfony, de me serrer la pince et de grapiller quelques croissants gratos ;)

N'hésitez pas à vous inscrire en ligne sur le site de SensioLabs.

- page 1 de 9