Utilisation de sfUser et de ses « namespace »(s)

Récemment j’ai du développer un outil permettant de créer des tournois, cet outil a la particularité d’être accessible par les personnes connectés ou non. Je devais conserver d’une page à l’autre les informations saisies par mon utilisateur, pour quelqu’un de connecté on peut toujours passer par la base de donnée mais pour les autres on doit jouer avec la classe sfUser.

Le scénario est le suivant :
– Etape 1 : je saisis des informations dans un formulaire
– Etape 2 : je saisis de nouvelles informations en fonction des précédentes

En réalité il y a bien plus d’étapes que cela mais ce scénario me permet de poser les bases de mon article.

Pour rester dans la simplicité voici le schéma que nous allons utiliser :

ModelA:
  columns:
    id:         { type: integer(4), autoincrement: true, unsigned: true, primary: true }
    title:      { type: string(255), notnull: true }
    body:       { type: clob, notnull: true }
 
ModelB:
  columns:
    id:         { type: integer(4), autoincrement: true, unsigned: true, primary: true }
    title:      { type: string(255), notnull: true }
    body:       { type: clob, notnull: true }

Tout d’abord j’ai un formulaire lié à un modèle, je dois conserver cet objet dans ma session pour me permettre d’y accéder lors des étapes suivantes. Voilà comment j’ai procédé au niveau de ma class myUser :

<?php
 
class myUser extends sfBasicSecurityUser
{
  const
  MY_NAMESPACE = 'mynamespace';
 
  /**
   * __call
   *
   * @param string $method
   * @param Array $arguments
   */
  public function __call($method, $arguments)
  {
 
    switch (true)
    {
      case (('set' === $prefix = substr($method, 0, 3))
          && (Doctrine_Core::isValidModelClass($class = substr($method, 3)))) :
        $this->_set($class, $arguments[0]);
        break;
 
      case (('getInstance' === $prefix = substr($method, 0, 11))
          && (Doctrine_Core::isValidModelClass($class = substr($method, 11)))) :
        return $this->getModelInstance($class);
        break;
 
      default:
        return parent::__call($method, $arguments);
        break;
    }
 
  }
 
  /**
   * Model storage
   *
   * @param string $class
   * @param Doctrine_Record $argument
   */
  public function _set($class, $argument)
  {
    if (!$argument instanceof $class)
    {
      throw new Exception(sprintf('You must specify a valid %s', $class));
    }
 
    $this->setAttribute($class, $argument, self::MY_NAMESPACE);
  }
 
  /**
   * Return model
   *
   * @param string $modelName
   * @return Doctrine_Record
   */
  protected function getModelInstance($modelName)
  {
    return $this->getAttribute($modelName, array(), self::MY_NAMESPACE);
  }
}

Ayant surchargé ma méthode __call(), je peux désormais appeler les méthodes suivantes :

$this->getUser()->setModelA(new ModelA());
$this->getUser()->getInstanceModelA();

Pour être sûr de ne passer que des objets définis au niveau de mon schéma j’utilise la méthode « Doctrine_Core::isValidModelClass », ce code me permet également de ne conserver qu’une seule fois un objet au niveau de mon objet myUser. De plus, je regroupe toutes ces données dans un « namespace » ce qui me permettra de les effacer très simplement par exemple si mon utilisateur souhaite retourner sur la première étape.

// apps/MON_APPS/modules/MON_MODULE/actions/action.class.php
  public function executeStep1(sfWebRequest $request)
  {
    $this->getUser()->cleanMyNameSpace();
  }
 
// apps/MON_APPS/lin/myUser.class.php
  /**
   * Clean Mynamespace
   *
   * @param $exception Valeur à ne pas enlever
   * @return void
   */
  public function cleanMyNameSpace()
  {
    $this->getAttributeHolder()->removeNamespace(self::MY_NAMESPACE);
  }

Ce code m’a permis de conserver une flexibilité lorsque je passe d’une étape à l’autre, en effet, j’aurai pu choisir de passer simplement les attributs que je souhaite conserver. Depuis la mise en production les paramètres nécessaires d’une étape à l’autre ont changé en conservant un objet entier je n’ai pas eu à m’en soucier, de plus je ne suis pas obligé de stocker ces objets en base de donnée.

Partagez cet article