Catégorie : développement

Tout ce qui concerne le développement en général, que ce soit des choses générales, ou des choses bien précises. Cela va de la gestion de projet à la recherche du fonctionnement de pointeurs en C.

Php : comment dériver la classe Exception et lui passer un tableau de chaines

Dans la plupart de mes pages, j’ai besoin, lorsqu’il y a une erreur, de mettre un message explicite qui est souvent long. Qui dit long dit plusieurs lignes. Ou bien j’ai envie de stopper l’exécution en cours et d’afficher plusieurs messages. L’idée de base est de lever une exception, mais une exception qui reçoit plusieurs chaînes de caractères comme message d’erreur. Alors j’ai fait ma propre classe en m’inspirant de l’aide sur les exceptions de php.net.

On peut lever une exception de cette façon :

throw new ExceptionErr(
  array(
    "Nous vous avons envoyé la liste récemment.",
    "Afin de garantir une qualité de service ".
    "pour tout le monde, ",
    "nous ne pouvons ré-envoyer la liste que dans ".
    $delai
  ) 
);

Vous pouvez la récupérer ou simplement lire le code. En espérant que cela serve à d’autres personnes :

<?
/**
 * fichier exception_err.php
 *
 * Historique :
 * 21/09/2011 : Olivier Pons
 *              Création
 * @author Olivier Pons
 * @version 1.0
 * @since 1.0
 * @copyright Olivier Pons
 * @package Classes_Base
 */

/**
 * Includes
 */

/**
 * Classe Exception qu'on peut
 * lever en lui passant un tableau
 * en paramètre.
 *
 * @author Olivier Pons
 * @version 1.0
 * @since 1.0
 * @copyright Olivier Pons
 * @package Classes_Base
 *
 */
class ExceptionErr extends Exception
{
  /** 
   * @var array le tableau contenant les lignes d'erreur
   */
  private $TabErr;
  
  /** 
   * Lit le tableau contenant les lignes d'erreur
   * @return array le tableau contenant les lignes d'erreur
   */
  public function getTabErr()
  {
    if (!isset($this->TabErr)) {
      throw new Exception('TabErr : pas initialise');
    }   
    return $this->TabErr;
  }

  /** 
   * Surcharge de la représentation de l'objet sous forme de
   * chaine
   *
   * @return string Représentation de l'objet sous forme de
   *   chaine.
   */
  public function __toString() {
      return __CLASS__ .
        ": [{".$this->code."}]: {".$this->message."} ".
        "- {".var_export($this->TabErr,true)."}\n";
  }

  /** 
   * Constructeur surchargé de la classe "Exception" de base.
   *
   * @param array $tab_err
   *   Tableau contenant les chaines à mettre à la suite dans
   *   un tableau d'erreur (voir les classes qui utilisent
   *   cette classe pour comprendre)
   * @param integer $code
   *   Numéro de code d'erreur
   * @param Exception $previous
   *   Exception précédente
   *
   * @return void
   */
  public function __construct(
    $messages, $code = 0,
    Exception $previous = null) 
  {
      if (!is_array($messages)) {
        throw new Exception("Messages : array attendu");
      }   
      if (count($messages)==0) {
        throw new Exception("Messages : tableau vide");
      }   
      list($message)=each($messages);
      parent::__construct($message, $code, $previous);
      $this->TabErr = $messages;
  }
}

?>

ExtJs, DataGrid, Store et événements : mémo pour le déboguage

Voici un petit mémo simple : si vous essayez de comprendre dans quel ordre se font les événements, je vous conseille de lire la page ici.

Parmi tout ce qui est expliqué, voici ce que j’utilise le plus souvent : une fonction de trace des événements.
Faites comme moi : un bon copier-coller des familles, et vous aurez dans votre console tous les événements concernant l’objet que vous voulez :

function captureEvents(observable) {
    Ext.util.Observable.capture(
        observable,
        function(eventName) {
            console.info(eventName);
        },
        this
    );		
}
 
Ext.onReady(function(){
    var grid = new Ext.grid.GridPanel({
        ... 
    });
 
    captureEvents(grid);
});

Exemple concret : j’avais un problème, lorsque je créais un nouvel enregistrement dans une DataGrid, j’avais beau essayer de le sélectionner, rien n’y faisait. J’ai cherché pendant des heures, j’ai essayé d’éliminer au fur et à mesure des choses, jusqu’à ce que je mette en place ce code, et là, magie, dans la console :

>beforeload
>datachanged
>load
>read
>add
>datachanged
>beforesync
>write
>datachanged

J’ai vu qu’en fait après l’événement d’ajout « add » sur lequel je comptais pour sélectionner l’élément en cours, il y avait… une mise à jour (« beforesync », « write », « datachanged ») !
En fait ça a fait tilt : j’avais activé la synchronisation automatique des données, et donc juste après l’insertion, le store tentait de se synchroniser, donc la sélection était inévitablement dé-sélectionnée.

Ici aussi, comme dans la plupart de mes articles techniques, j’espère avoir aidé la communauté et avoir évité à d’autre personnes de perdre des heures inutiles, comme celles que j’ai passées !

Php : comment faire un trim() sur tout un array()

C’est simple, et voici comment faire en trois lignes (si vous enlevez mes commentaires) : je crée une fonction anonyme qui est appelée en boucle par array_walk() et qui fait un ‘trim’ sur l’élément en cours :

/* Pas très propre, mais rapide et qui reste
 * compréhensible : je crée une fonction anonyme qui
 * est appelée en boucle par array_walk() et qui fait
 * un 'trim' sur l'élément en cours :
 */
array_walk($tab,
  create_function('&$item,$key', '$item = trim($item);')
);

Trello : encore une innovation géniale de Joel Spolsky

Voilà l’idée derrière la chose : pour tous les projets, on a juste des idées. Ces idées, ils proposent de les matérialiser sous forme de « cartes ». Et de faire des tas de cartes. Après, on organise ces cartes, et quand on clique sur ces cartes, on a évidemment plein de détails : qui l’a créée, des commentaires, des modifications, etc.

Il s’appelle Trello.

Bref c’est un outil très novateur, et qui de côté tout ce qui est priorité (enfin il ne le met pas de côté, disons qu’il le cache : c’est en réalité dans l’organisation des cartes qu’on peut gérer les priorités).

Vos projets deviennent plus lisibles et ça ressemble beaucoup aux post-it qu’on a tendance à coller un peu partout quand on veut faire des choses.

Et si vous voulez, carrément, avoir une idée concrète de comment se gère un projet ainsi, vous pouvez le voir avec Trello dans Trello

Trello

Le plus impressionnant, c’est que tout est sur le Web, et que ça tourne parfaitement, et que tout se synchronise automatiquement ! Exemple concret : vous ouvrez votre tableau sur lequel il y a vos cartes, et un collaborateur aux Etats Unis ouvre le même tableau, et lorsqu’il applique des modifications, elles se répercutent automatiquement sur votre tableau, en temps réel ! Par contre, ne me demandez pas d’entrer dans les détails : si jamais deux personnes travaillent sur la même carte au même moment, je ne sais pas du tout ce qu’il se passe.

Vraiment une bonne idée, que je suis en train de tester, et tout se passe de manière naturelle. Joel Spolky est vraiment toujours très novateur !

Php et utf-8 : comment lire correctement un fichier texte

Si vous essayez de lire un fichier en utf8 mais que vous avez des problèmes, voici une solution toute simple qui pourra vous aider : essayez de rajouter l’option « u » lorsque vous ouvrez le fichier. Mon code ne fonctionnait pas correctement jusqu’à ce que je trouve cette astuce :

$handle = @fopen('wfrench-1.2.3/dico', 'ru');
if ($handle!==false) {
  while (($buffer = fgets($handle, 4096)) !== false) {
    array_push( $mots, $buffer);
  }
  if (!feof($handle)) {
    fclose($handle);
    throw new Exception("Erreur: fgets() a échoué");
  }
  fclose($handle);
}
else {
  throw new Exception("Erreur: fopen() a échoué\n");
}

Trackmania 2 / ManiaScript, ManiaPlanet et Labyrinthes : génération automatique

Vous avez peut-être vu que j’avais écrit un générateur de labyrinthes en C, qui créait en bout de course un fichier Autohotkey (là aussi je vous laisse vous renseigner). Ce fichier Autohotkey lançait Trackmania United Forever et automatisait la pose de blocs, et au final il y avait une course dans… un labyrinthe de blocs de course. J’avais donc modifié Trackmania afin d’en faire un outil pour jouer dans des labyrinthes !

Trackmania 2 est sorti, en version bêta, avec achat pour 0.01 € de moins.
Comme c’était une offre extraordinaire, j’ai sauté sur l’occasion.

Et dans Trackmania 2, ils ont fait très fort (même si ça n’est pas encore 100 % terminé, c’est déjà très abouti) : dans leur éditeur de maps, ils ont fait un langage de programmation qui leur est propre, une sorte de fils caché entre le JavaScript et XML, avec quelques attouchements de C et de « principes objet ».
Je trouve que ça n’est pas très lisible, et encore moins maintenable, mais bon, c’est pour un jeu, alors il faut pas en demander trop, surtout quand on voit qu’on n’est pas que joueur, mais qu’on peut être acteur !
Ce pseudo-langage de programmation s’appelle «ManiaScript».

Je me suis dit : je vais refaire mon générateur de labyrinthes, mais pour «ManiaScript».
J’ai donc commencé à préparer le terrain en «ManiaScript» : j’ai préparé des routines de poses de blocs, des routines pour poser les montées, etc. J’en ai profité pour faire une petite copie d’écran que je vous livre avec plaisir (cliquez dessus pour agrandir) :

Image Trackmania de Labyrinthes

Puis j’en ai profité pour me repencher sur mon ancien générateur, et je me suis dit : je vais le reprendre, afin de lui faire générer des scripts «ManiaScript».

C’est ce que j’ai fait, et au bout de deux soirées passées à tout ré-analyser ce que j’avais fait (même si je mets des tonnes de commentaires, mon générateur est en C pur, donc c’est très dur (pour moi en tous les cas) de me replonger dans le bain), j’ai enfin pu recompiler et générer quelque chose. J’en ai donc fait une copie d’écran que je vous livre avec plaisir (cliquez dessus pour agrandir) :

Image Trackmania de Labyrinthes

Et puis j’ai repassé toute une soirée à réussir à lier les deux. Le plus gros problème vient du fait que je prends les repères mathématiques «classiques» c’est à dire en vertical, Y, à l’horizontal X, et en profondeur Z. Dans Trackmania, le Y et Z sont inversés. Bonjour le casse tête mais je n’étais pas à ça près. J’ai donc réussi : j’ai fait une copie d’écran que je vous livre avec un bien plus grand plaisir que les deux précédents (cliquez dessus pour agrandir) :

Image Trackmania de Labyrinthes

La pose des montées se fait avant la pose des blocs principaux. C’est assez marrant à voir, et comme je suis gentil, je vous ai même fait une copie d’écran (cliquez dessus pour agrandir) :
Image Trackmania de Labyrinthes

Ensuite, j’ai voulu tester les limites de ma machine, et j’ai crée le plus grand labyrinthe possible pour Trackmania 2, et à mon grand plaisir, le jeu n’a pas explosé, comme il le faisait pour Trackmania United. Mattez moi ça (cliquez dessus pour agrandir) :
Image Trackmania de Labyrinthes

Trackmania 2 a une nouveauté extraordinaire : ils précalculent les ombres avec un réalisme époustouflant, et j’ai donc demandé de précalculer avec le maximum de précision (il y a six niveaux, et le plus détaillé prend plusieurs heures de calcul), et voilà ce que ça a donné (cliquez dessus pour agrandir) :
Image Trackmania de Labyrinthes

Ensuite, je me suis dit que les labyrinthes c’est bien joli, mais uniquement des blocs carrés, c’est pas très marrant. Donc j’ai décidé d’améliorer le tout, et j’ai trouvé un truc : après que le labyrinthe ait été posé par le script, j’ai imaginé rajouter en «ManiaScript» du code qui « décore » le labyrinthe. Par exemple, pour les tournants, j’ai mis des blocs de type « route », et j’ai ajouté un bloc « carré » pour terminer tous les cul-de-sac (cliquez dessus pour agrandir) :
Image Trackmania de Labyrinthes

Et puis je me suis aperçu que les blocs avaient la possibilité d’avoir des néons incrustés, et que les tournants étaient éclairés, j’ai essayé de voir ce que ça donnait en mode nuit, et c’est vraiment beau (cliquez dessus pour agrandir) :
Image Trackmania de Labyrinthes

J’ai recalculé le même labyrinthe afin que vous puissiez comparer avec et sans les améliorations (cliquez dessus pour agrandir) :
Image Trackmania de Labyrinthes
Image Trackmania de Labyrinthes

Et le même labyrinthe en mode nuit (cliquez dessus pour agrandir) :
Image Trackmania de Labyrinthes

Ensuite, j’ai trouvé d’autres types de blocs dont j’ai pu me servir pour améliorer encore le rendu, et faire des tunnels. Le rendu de nuit des tunnels est encore plus joli (cliquez dessus pour agrandir) :
Image Trackmania de Labyrinthes

Et puis les dernières captures, qui concernent le seul circuit que j’ai entièrement validé, sur douze étages (cliquez dessus pour agrandir) :
Image Trackmania de Labyrinthes

Et comble de joie, le dernier étage a en plus le tout dernier type de tunnels que j’avais implémenté, mais il ne sort que très rarement sur les labyrinthes qui ne sont pas très larges (celui ci fait 4×4) (cliquez dessus pour agrandir) :
Image Trackmania de Labyrinthes

Nouvelle version de Smarty – 3.1 : les avantages

J’ai récemment mis à jour quelques-uns de mes sites avec la nouvelle version de Smarty, la version 3.1.
Plusieurs choses sont maintenant possibles et c’est très appréciable.
La plus importante c’est le fait que Smarty détecte maintenant de manière très intelligente si les accolades {} sont pour lui ou pas.
Il est donc tout à fait possible de coder du JavaScript et de mettre du CSS sans utiliser {literal}{/literal}.

Pour toutes les personnes qui utilisent Smarty, ils réaliseront rapidement à quel point c’est pratique.

De plus les warnings sont à « on » par défaut, c’est à dire que si les variables n’existent pas, on a le warning classique Php. On aime ou on aime pas, mais maintenant il faut souvent utiliser {if isset($mavariable)}{/if}.

Enfin, l’autre différence majeure que j’ai noté, c’est la rapidité : c’est tout simplement incomparablement plus rapide. Vraiment. Surtout pour les tableaux et autres, c’est impressionnant. A vous de voir.

Smarty 3.1 et les plugins : comment faire / howto

Sur la toute dernière version de Smarty (3.1), voici comment créer un plugin personnalisé.
Pour résumer, l’un de mes sites n’était pas assez optimisé.
Le code qui sortait était :

<body class="sbody">
    <div>
....
    </div>
....
</body>

J’ai donc ajouté le filtre d’optimisation qui supprime les espaces en début :

$this->smarty->loadFilter('output', 'trimwhitespace');

Le code de sortie est devenu :

<body class="sbody"><img src="/title.jpg" /><div>....</div>....</body>

Tout mise en une ligne, super !
Le seul problème, c’est que ça ne fonctionnait pas avec le code JavaScript, il faut en effet les retours à la ligne.
J’ai donc crée mon plugin qui ne fait que supprimer les espaces en début de ligne, et remplacer de « retour + line feed » (deux octets) de fin de ligne par un seul octet « retour ».

Voici le code, je vous laisse comprendre, c’est extrêmement simple :

/* Déclarer un plugin "block".
 * Block = il faut un début et une fin.
 * Ici : {triml} {/triml}
 */
$this->smarty->registerPlugin('block',
  'triml', array($this,'smarty_block_trim_l'));

Après avoir déclaré le plugin, il faut faire la fonction adéquate :

/**
 * Fonction de plugin smarty pour supprimer tous les espaces
 * en début de ligne entre les blocs {triml}{/triml}
 * "triml" = trimleft
 * Voir le constructeur et chercher $this->smarty->registerPlugin()
 *
 * @param array $params les paramètres qu'on passe à {strip_nl}
 * @param variant $content Le contenu qu'il y a dans le bloc
 * @param variant $template Le nom du template
 * @param variant &$repeat
 *
 * @return int Description retour
 */
public function smarty_block_trim_l(
  array $params, $content, $template, &$repeat)
{
  $content = preg_replace('/\n[\s]+/', "\n", $content);
  return $content;
}

Et voilà maintenant, vous pourrez aussi optimiser votre site comme un professionnel.
Bien évidemment le gain le plus gros est dans la compression (voir mod_deflate)

Php / optimisation / compilation et le projet du compilateur FaceBook

Saviez vous que Facebook a eu une idée assez intéressante ?
Ils ont crée un outil qui transforme le code Php en code C++ et qu’on peut donc compiler.
D’ailleurs la plupart des choses de FaceBook tournent via cet outil, pour accélérer et optimiser au maximum leur site.
Il est ainsi possible de pousser la performance Php à l’extrême.

Pour ceux qui veulent rendre leur site encore plus rapide, voici le lien :

https://github.com/facebook/hiphop-php

Gimp, scripting et Python-fu : exemple par la transformation d’une image PNG en image transparente

J’ai été plus loin dans l’automatisation de Gimp.

J’ai voulu reprendre mes deux articles qui parlaient de Script-fu : le premier pour débuter ici, et le second qui passe à peine à la vitesse supérieure, qui explique l’assignation des variables ici.

Mais comme je suis un grand fan de Python et que tout a été fait pour pousser Python en avant dans Gimp, j’en ai profité.
Trois heures de travail avant d’y arriver.

Première chose à savoir :

On parle de script Python, mais ce sont des plugins.
Donc, lorsqu’on les installe, il faut les mettre dans le répertoire ~/.gimp/plug-ins/ et non pas ~/.gimp/scripts/.

Deuxième chose :

Ils doivent être exécutables. Donc :

chmod +x ~/.gimp/plug-ins/monscript.py

Troisième chose :

Enfin, allez chercher des exemples ici : http://registry.gimp.org/

Vous les installez et vous les lancez à partir de là vous avez tout ce qu’il vous faut.
Si vous avez lu ces trois informations avant de vous lancez dans l’aventure je vous aurais probablement fait gagner au moins une demi-journée.

Enfin, pour que la ligne de commande fonctionne sur les dernières versions de Gimp (2.6.8) à l’heure de l’écriture de cet article, il y a plein d’articles obsolètes sur le net. Je vais encore vous faire gagner des heures de recherche :

Voici un exemple complet d’un lancement en ligne de commande qui fonctionne :

gimp -i --batch '(python-fu-batch-to-transparent-indexed RUN-NONINTERACTIVE "/home/olivier/Bureau/france.php.png" "/home/olivier/Bureau/france.2.php.png")' -b '(gimp-quit 0)'

Et voici mon plugin tout simple que j’ai codé en 15 minutes, mais avant d’arriver là j’ai cherché pendant six heures…

Cliquez ici pour le télécharger.

Ce plugin transforme une image PNG en la même image, mais en transparente et en couleurs indexée.
Il n’est pas 100% terminé, car la couleur de transparence est codée en dur, mais il fonctionne très bien pour peu que votre couleur soit le blanc 🙂

Pour ce qui est de la méthode, je me suis très fortement inspiré de ce site.

Si je vous ai aidé n’hésitez pas à me laisser un message !