Archives du mot-clé php5

Astuce symfony : générer du cache depuis une task

Dans une tache symfony, il est tout à fait possible de créer un contexte comme si l’on venait d’un appel http.

$configuration = ProjectConfiguration::getApplicationConfiguration($options['application'], $options['env'], false);
$sf_context = sfContext::createInstance($configuration, 'raoul');
sfContext::switchTo('raoul');

Ceci fait, on pourrait imaginer appeler la fonction get_component présente dans PartialHelper.php histoire de générer le cache pour certains composants.

// charge le helper
$configuration->loadHelpers('Partial');
get_component($moduleName, $componentName, $vars); // si le composant utilise du cache, le fichier de cache sera crée

Le probleme est que tous les appels à link_to ou image_tag vont générer des liens invalides. (avec des symfony/symfony dans les urls)

La solution que j’ai trouvée en regardant du coté de sfBrowserBase.class.php consiste à setter le tableau $_SERVER pour simuler complètement la navigation web. Il faut donc insérer les lignes suivantes avant la création du contexte :

unset($_SERVER['argv']);
unset($_SERVER['argc']);
$_SERVER['HTTP_HOST']       = $arguments['host'];
$_SERVER['SCRIPT_NAME']     = $arguments['script_name'];
$_SERVER['SERVER_NAME']     = $_SERVER['HTTP_HOST'];
$_SERVER['SERVER_PORT']     = 80;
$_SERVER['REQUEST_METHOD']  = 'GET';

Bien sur, il faut que votre task prenne host (par exemple ‘localhost’ pour vos test) et script_name (par exemple ‘/monalias/frontend.php’) en arguments.

Cela semble fonctionner dans mon cas. N’hésitez pas si vous avez des retours ou des remarques.

Mise à jour de la liste des contribution à symfony de PMSIpilot

La liste des modestes contributions à symfony a été mise à jour sur pmsipilot.org. On a trouvé deux trois petites choses 😉 et proposé pas mal de patchs.

http://www.pmsipilot.org/2010/03/25/contributions-a-symfony/

Nous utilisons maintenant symfony 1.4 qui propulsera la prochaine version majeure de nos outils de pilotage.

Migration d’un gros projet symfony de la version 1.2 à 1.4

Lors du symfony live 2010 (non, je ne vous ferais pas un compte rendu de symfony live 2010, il y en a de très bien déjà partout sur l’internet) beaucoup de personnes ont interpellées la core team au sujet des problèmes de compatibilité descendante avec symfony.

Récemment, dans ma société, j’ai migré un projet de symfony 1.2 à 1.4. Pas un petit, 220 000 lignes de code (hors symfony, code généré et plugins). A vrai dire, vu comme ça, je me disais que ça marcherait jamais.

J’ai utilisé les documents suivants :

J’ai commencé par mettre à jour lib/vendor/symfony en 1.3 et fait tourner la tache ./symfony project:upgrade1.3.  La plupart des YLM ont été modifiés correctement, tous les héritages des formulaires, la gestion de la disparition du common filter … tout ça a été fait automatiquement pour moi ! project:validate m’a ensuite indiqué la liste des méthodes et fonctions dépréciées. Un peu de surcharge de méthodes, de récupération de vieux helpers, et voila. En quelques heures le projet était d’équerre. Ceci fait, j’ai ensuite migré vers la 1.4.

Le plus pénible à gérer fut la fin de la gestion des tableaux dans les méthodes de sfParameterHolder. project:validate a bien indiqué les classes des contrôleurs à changer mais n’a pas pu chercher dans les autres classes les (maintenant) mauvaises utilisations des tableaux. Pour ça, les tests ont bien aidé, et le reste de l’équipe à résolu quelques occurrence de ce problème les jours suivant.

Pour ma part, des migrations comme ça j’en veux bien tout le temps !

Je travaille avec symfony depuis la version 0.6.3, et je ne l’ai jamais trouvé aussi facile à utiliser.

Au boulot, moi, j’utilise Facebook !

Mais c’est pour améliorer les performances de nos applications grâce à un plugin développé par un de mes brillants collègues : elXHProfPlugin.

Mon équipe l’utilise sans douleurs depuis plusieurs semaines et avec de nombreux gains à la clef. C’est la démocratisation du profiling qui, jusqu’alors, était plus réservé aux CP techniques tant sa mise en place, avec xdebug, était pénible.

Plus d’informations sur le .org de PMSipilot.

Un modeste conteneur de paramètres en PHP5

Voici un code que j’utilise depuis un moment et que je viens d’introduire récemment dans un projet.

L’idée est de proposer à certaine classe de mon projet un conteneur de paramètre flexible et facilement utilisable par les développeurs.

parameters[strtolower($key)] = $value;
  }

  /**
   * teste l'existence d'un parametre
   * @param $key string
   * @return boolean
   */
  public function hasParameter($key)
  {
    if (array_key_exists($key, $this->getParameters()))
    {
      return true;
    }
    else
    {
      return false;
    }
  }

  /**
   * recuperation d'un parametre
   * @param $key string
   * @param $default string
   * @return mixed
   */
  public function getParameter($key, $default = null)
  {
    if ($this->hasParameter($key))
    {
      return $this->parameters[$key];
    }
    elseif (!is_null($default))
    {
      return $default;
    }
    else
    {
      return null;
    }
  }


  /**
   * gere automatique les get et les set
   */
  public function __call($name, $arguments)
  {
    $key = strtolower(substr($name,3));
    $arg = isset($arguments[0]) ? $arguments[0] : null;
    if (substr($name,0,3) === 'has')
    {
      return $this->hasParameter($key, $arg);
    }
    
    if (substr($name,0,3) === 'get')
    {
      return $this->getParameter($key, $arg);
    }

    if (substr($name,0,3) === 'set')
    {
      if (!$arg)
      {
        throw new myException(get_class($this).' un second argument est nécessaire pour une méthode set');
      }
      return $this->setParameter($key,$arg);
    }

    throw new myException('notre __call ne gère que les get ou les set ! méthode indéfinie : '.$name);
  }
}

La méthode __call, ainsi utilisée, permet d’accéder facilement au tableau de paramètres.

Par exemple, dans un script php, on pourra simplement écrire des choses de ce genre :

$param_holder = new ParameterHolder();
$param_holder->setUnParametre('coucou');
$var = $param_holder->getUnParametre();
// ...

Vos classes peuvent également étendre ParametreHolder ou en déclarer un lors de l’appel au constructeur et « attraper » les get* et les set* en utilisant __call. Il est enfin possible de surcharger certains getter ou setter pour faire des traitements spécifiques tout en gardant un comportement générique via __call pour les autres. Voici un petit exemple :

class myClass
{
  private $parameter_holder = null;
  public function __construct()
  {
    $this->parameter_holder = new ParameterHolder();
  }

  public function getRaoul()
  {
   throw new myException('tu tu tut, faut pas fâcher Raoul !');
  }

  public function __call($name, $arguments)
  {
    $this->parameter_holder->__call($name, $arguments);
  }
  
}

En espérant que cela vous soit utile.

Utiliser le système d’évènements de Symfony

Le système d’évènements de Symfony est une avancée particulièrement intéressante dans le framework. Toutefois, la documentation officielle est un peu spartiate sur le domaine. Voici donc un exemple pratique plus didactique pour utiliser les évènements.

Le système d’évènement de Symfony est basé sur le motif de programmation observer qui est un grand classique du genre.

Tout d’abord, il faut enregistrer le listener. On peut le faire à peu près n’importe ou, par exemple dans le preExecute du code d’un contrôleur, ou plus globalement dans le fichier config/ProjectConfiguration.class.php qui va gérer la configuration globale de votre projet.

    
class ProjectConfiguration extends sfProjectConfiguration
{
  public function setup()
  {
    // listener
    if (!sfConfig::get('already_event_connected', false))
    {
      $this->getEventDispatcher()->connect('a.name', 'aclass::dosomething');
      sfConfig::set('already_event_connected', true);
    }
  }
}

Ce code vous assure que le listener sera enregistré une unique fois. En effet, si il est enregistré deux fois, a chaque notification il sera exécuté deux fois ….

Ensuite, n’importe ou dans votre code, vous pouvez « lancer » cet évènement. Par exemple, dans le code d’un contrôleur.

    // notification
    sfContext::getInstance()->getEventDispatcher()->notify(new sfEvent(get_class($this), 'a.name', 
    array(
      'a_var' => $foo,
      'another_var' => $bar,
    )));

La fonction de callback, ici une méthode statique, récupère un objet sfEvent en paramètre. Via ce dernier, on a également accès aux variables passées lors de la notification de l’évènement.

// dans la classe aclass
public static function dosomething (sfEvent $event)
{
  $foo = $event['a_var'];
  $bar = $event['another_var'];
  // code
}

Et voilà, à vous de jouer.

omCrossAppUrlPlugin (liens inter applications dans Symfony) est disponible sur le repository de Symfony

Pour info, j’ai packagé un petit helper Symfony pour le dépot de plugins du projet. Il permet simplement de faire des liens entre applications d’un même projet. Il est compatible Symfony 1.2 uniquement.

Merci de vos retours si vous rencontrez des soucis avec ce helper.

http://www.symfony-project.org/plugins/omCrossAppUrlPlugin