GChart Bundle – un bundle Symfony pour utiliser Google Chart

Je viens de rendre disponible sur github.com GChartBundle, un bundle Symfony (Symfony2 donc…) qui « wrappe » le Google Chart Tool et quelques charts (mais surtout le QrCode) de Google Image Chart API.

Ce que j’ai appris en faisant ce bundle:

La puissance du DIC

La puissance du Dependency Injection Container… ou comment permettre à l’utilisateur de redéfinir des paramètres du Bundle, passer des services aux services que l’on créée…

La puissance des Twig Extensions

… ou comment définir ses propres fonctions Twig, qui elles-même peuvent appeler « render » sur un template.

J’ai passé un peu de temps à trouver comment faire, mais l’idée est d’utiliser la méthode initRunTime() pour garder une référence d’un Twig_Environment:

    //in Twig/TwigExtension.php
    public function initRuntime(\Twig_Environment $environment)
    {
        $this->environment = $environment;
    }

J’aurais pu aussi de la même manière utiliser un template php (en passant 2 resources dans le DIC par exemple…), mais un manque de motivation m’a gagné (je n’utilise pas les templates php de toute façon).

Cette partie (=le « rendering » d’un template dans l’extension Twig) pourrait être plus « propre aussi… Dans une version ultérieure peut-être?

Malheureusement, je n’ai pas de démo live. Mais voici tout de même un démo statique (copier coller du code html généré localement) de ce que génère l’action Demo.

En espérant que ça aide quelqu’un…

jQuery mobile, Symfony2, Doctrine 2 et autres tests…

Bonne année!!

Et oui, après de longs mois de silence, les bonnes résolutions de 2011: comme je suis curieux, j’ai voulu faire quelques tests avec Symfony2 et jQuery mobile.

Et comme ma blonde a une « passion » pour les départements français (donner un numéro de département, et deviner le nom du département – difficile à comprendre quand on n’est pas de France j’imagine), j’ai fait un mini-site qui liste les départements français (liste de tous les départements ou par région).

Testez-le ici.

Mise à jour (2011-01-09)

J’ai aussi réaliser quelque chose de similaire pour les capitales des pays. Voir ici. Cela m’a permis de jouer avec les classes php SimpleXMLElement, DOMDocument et la famille PHP DOM, mais aucune ne m’a complètement convaincue. Voir ici pour des commentaires additionnels.

J’ai utilisé…

  • le framework Symfony2 PR4: j’ai utilisé le fichier tarball pour être rapidement « efficace ». Simple à installer, mais je pense qu’il manque quelques commandes Symfony pour générer des Bundles par exemple (j’ai pas trop chercher, peut-être que ça existe)
  • jQuery mobile 1.0 ALPHA 2:
    • les listView: encore quelques améliorations sont nécessaire (notamment pour les count bubbles des nested list), mais ça promet,
    • les liens (remplacés en call ajax) et le back automatique: cool, mais parfois pas très fluide et très lent, et je pense que c’est encore lent si le lien est dans une liste de 100+ items (DOM trop complexe)
    • parfois lorsque la page se loade sur le iphone, le css ne semble pas appliqué. Le problème se résout lorsqu’on raffraichit la page: problème de latence réseau, problème de webKit, problème de DOM trop long, ou de performance iPhone? Je ne sais pas, mais problème il y a… Pour répliquer à tout coup le problème, allez sur votre iphone à http://departements.fruitsoftware.com/index2.html. Dans la dernière version (http://departements.fruitsoftware.com), j’ai séparé les listes imbriquées en 2 pages: chaque nested list est dans une page séparée.
    • d’une manière générale, il reste encore (un peu (?), beaucoup (?)) de travail à faire. Mais très prometteur et utilisable si on accepte les limitations actuels.
  • une base de donnée mySQL et l’ORM Doctrine 2 avec les docBlock annotations (Doctrine 2: excellent!!). Sauf que je n’ai pas trouvé de façon d’initialiser la connexion à UTF8 via la configuration de Symfony2. Pour m’en sortir, j’ai créé une petite méthode dans l’unique controleur de l’application (probablement une meilleure manière de faire, notamment via les postConnect events de la DBAL de Doctine):
        public function fixUtf8() {
            $conn = $this->get('database_connection');
            $statement = $conn->prepare('SET NAMES \'utf8\';');
            $statement->execute();
        }
    
  • Twig pour les views de Symfony2: je n’ai pas trouvé de limitations pour l’instant, il faut s’habituer je pense à la syntaxe (et à l’IDE qui ne « highlight » pas et ne formate pas correctement – tabs…)

Reste à tester…

  • le HTTP cache de Symfony2: je trouve le principe excellent, je me garde juste ça pour plus tard…
  • comment jQuery mobile se comporte avec Google Analytics, notamment avec le remplacement automatique des liens par des calls Ajax [EDIT] J’ai trouvé ce lien qui semble répondre à cette question: http://www.jongales.com/blog/2011/01/10/google-analytics-and-jquery-mobile/
  • les formulaire jQuery mobile et leur intégration avec Symfony2
  • les formulaires Symfony2 en général
  • PhoneGap (lire cet article)

Quelques remarques

  • s’il vous plait, pas de commentaires sur les régions qui ne sont pas des régions, …. J’ai pris mes données de wikipédia, alors, bon, hein…
  • Le framework Symfony2 semble avoir gagner en robustesse par rapport à la version 1, mais aussi plus exigeant: code plus long à taper. Rien de bien grave là, surtout si on gagne en clarté, performance, fonctionalité, beauté (oui oui, Symfony2, c’est beau!!), règles de l’art…
  • Pour tester: Chrome et firefox l’affaire (en redimensionnant la fenêtre), mais j’ai aussi utilisé le iPhone Simulator qui vient avec xcode (sur Mac uniquement)
  • j’ai utilisé Apache et mySQL installé via macPorts: fini pour moi MAMP, j’ai plus de contrôle avec MacPorts, notamment pour installer des extensions php.

Geolocalisation

Il y a longtemps que je voulais jouer avec la Geolocalisation, j’ai donc monté ce mini-site afin de tester différentes méthodes de géolocalisation:

  • geoIP: librairie PHP
  • Google Maps v3: aucune magie ici (pas de la geolocalisation), mais il y a possibilité d’utiliser les fonctionnalité GPS de l’équipement. Le « sensor » GPS n’est pas utilisé sur mon site, mais google Maps est utilisé de 2 façons:
    • pour ajuster les résultats des autre méthodes de géolocalisation (la « pin » est déplaçable)
    • comme méthode par défaut: un outils de recherche à la google Maps (en extrêmement simple simple simple) est offert
  • Google Gears
  • la geolocalisation des navigateurs « qui ont de l’allure » (firefox, safari) (navigator.geolocation.getCurrentPosition()). Lire https://mozillalabs.com/blog/2008/10/introducing-geode/ pour plus d’info sur l’implémentation dans firefox
  • Google Ajax API: en plus d’avoir accès à pleins de fonctionalités comme Google Maps, Feeds, Search, Earth, google Friends, etc… cette API permet aussi faire de la localisation  (merci à Marc Grabanski)

En plus, j’ai utilisé 2 API « géolocalisées »:

Vous pouvez assayer le tout l’URL suivante: http://geo.fruitsoftware.com/

Amusez-vous!

Symfony, project:deploy et cygwin

Pour tous ceux qui comme moi ne comprenaient pas pourquoi le « sync » de symfony gelait sur leur Windows, avec cygwin, voici l’astuce du jour (trouvé sur le trac de symfony):

Ajouter la ligne suivante dans votre properties.ini (par environnement):

[prod]
host=www.mywebproject.com
port=22
user=USERNAME
dir=/home/path/to/project/on/prod/
parameters="-azvC --force --delete --exclude-from=config/rsync_exclude.txt"

PS.1: j’avais trouvé une autre astuce qui nécessitait de modifier le fichier de la tache projectDeploy de Symfony (en ajoutant un « exec »), mais cette méthode est bien plus propre, merci!

PS.2: j’ai ajouté l’option « v » (=verbose) afin que rsync liste les fichiers qui sont affecté par la synchronisation. C’est à vous de voir!
PS.3: Il m’arrive de devoir changer les permissions des fichiers sur production (plus qu’un simple « symfony project:permissions »), donc histoire à suivre…
PS.4: Suite de l’histoire: Idiot, cygwin utilise les permissions à-la-Unix, il suffisait de mettre les bonnes permissions avec cygwin…

Merci Symfony

Il était une fois…

IL était une fois une équipe qui réalisa un site web pour un client. Tout se passa normalement au cours du développement.
Mais un jour, alors que nous devions mettre sur le serveur du client, nous apprîmes (oui, oui! apprîmes) que:

  • le serveur du client était en fait 2 serveurs,
  • ces 2 serveurs étaient « load-balancés » (pas de » sticky-tcpip » possible)
  • la gestion des sessions PHP était « basique » (file)
  • nous n’avions pas la possibilité de changer la configuration des 2 serveurs (pour utiliser memcached par exemple) ou du « load-balancer »

(je vous passe les détails de mauvaises communications entre les équipes techniques en jeu…)

Horreur!

Qu’allons-nous devenir?

Que faisons-nous?

OMG!

Heureusement…

…tel le petit poucet qui avait pris soin de mettre des pierres dans ses poches, nous avions développé notre site avec le framework Symfony (1.4).

Il est possible de changer très facilement la manière dont sont sauvegardées les sessions PHP avec Symfony, grâce au fichier factories.yml.

Il n’a donc pas fallu plus que 30 minutes pour changer la manière de gérer les sessions!

Merci à…

Notes

  1. Oui, je sais, j’ai mis un « S » majuscule à « Symfony », c’est pour m’habituer.
  2. « … et à la fin, ils firent pleins de projets Symfony. »

Symfony 2.0 – Notes

Some thoughts about Symfony 2. I didn’t play with the sandbox yet, I just read the doc and browse the code (a little bit). So more to come…

routing « inheritence »

One main routing file that can include to other routing files

# hello/config/routing.yml
homepage:
  pattern:  /
  defaults: { _bundle: WebBundle, _controller: Default, _action: index }

hello:
  resource: HelloBundle/Resources/config/routing.yml

Components are actions, yeah!!

Everything is an action, and you can include an action into a template. That’s great, no need to define an action that just include a component (when you need some ajax but the first load is not ajax)

Generating Links

The generate() method takes the route name and an array of values as arguments.

Mmm, I hope there is another way to generate a route, using the controller name and action name (like the old « url_for »…). I think it’s part of the « kill the magic » cleanup…

Assets and links to images, css, js…

<img src="<?php echo $view->assets->getUrl('images/logo.png') ?>" />

You will be able to change the URL root path of your web app without breaking any links. I love it, but HTML integrators will complain… But I like it… and they will (have to?) live with that.

« imports » directive in Configuration file: cleaner configuration files!

#in config_prod.yml
imports:
  - { resource: config.yml }

Symfony, forms and widgets tips

Howto get the user object in a form

Solution to get to user object in an sfForm object: use the 2nd $option parameter while creating the form object and retrieve it.

// In your actions.class.php
$this->form = new myForm(array(), array("currentUser" => $this->getUser()));

// In your form class

// ...
if (!is_object($this->getOption("currentUser")) || !($this->getOption("currentUser") instanceof sfUser))
{
throw new InvalidArgumentException("You must pass a user object as an option to this form!);
}

Source: http://eatmymonkeydust.com/2009/08/symfony-forms-flexible-widgets-based-on-user-credentials/