Mots-clé : symfony

Symfony 2 : avantages et inconvénients

Après bon nombre de commentaires, voire d’insultes (si si), je résume l’article qui suit :


Vous allez toujours entendre le même discours pour ceux qui commencent avec Symfony et qui n’ont jamais vraiment développé d’autres choses, qui est quelque part logique : Symfony c’est génial, c’est super, c’est la réponse à la vie, l’univers, et au reste, il aurait dû s’appeler « Php – 42 » ou quelque chose comme ça (et si vous ne comprenez pas l’allusion c’est qu’on n’a ni le même background, ni le même humour). C’est, de plus, très souvent le genre de personnes qui n’admettent pas qu’ils n’ont pas d’expérience et cela finit à l’insulte ou au pugilat.

S’ils avaient vraiment pratiqué d’autres choses, il verraient qu’il y a plein d’autres trucs ailleurs, et ils verraient qu’à d’autres endroits il y a des choses mieux.

Ceux qui n’ont pas d’expérience mais l’esprit ouvert me demandent ce qu’il y a comme autres choses à tester, et je leur réponds avec plaisir ! Ceux qui n’ont pas d’expérience et ont besoin de justifier leur existence diront « c’est un gros con il est dépassé il n’y comprend rien ». Je ne donne des cours que pour les premiers. Les autres je les laisse faire alt-tab en permanence entre Facebook et Symfony (et si vous saviez tout ce que je pense quand je parle ainsi…).


Après avoir développé deux applications relativement basiques, voici les inconvénients que j’ai relevé de Symfony :

  • Twig : c’est la seule chose qui semble vraiment pratique, utile et optimisée dans Symfony. A tel point que Zend l’utilisera comme moteur de templates, et Drupal 8 aussi. Un bon point pour Symfony, et le seul. Voici la suite.
  • Symfony prône les bonnes pratiques – ce qui est louable – pourtant j’ai dû faire trois fois du copier coller pour que ça fonctionne… Exemple le plus frappant : la bonne pratique (louable) est de séparer totalement la vue du modèle, et du contrôleur. Mieux : ils ont fait un endroit où on écrit toutes les requêtes complexes, afin de les séparer du modèle : ce sont les Repositories. Problème concret : quand on a un type fichier dans un formulaire qui est envoyé, le type « file » est posté. Si on veut écrire le fichier envoyé, ça passe par un contrôleur, et c’est lui qui est censé l’écrire en base de données ? Non ! Donc c’est côté de la base de données, côté modèle donc. Mais… les entités ne peuvent pas accéder à leur propre repository ! Si vous vous retrouvez dans ce cadre (hypra courant) alors vous allez devoir bidouiller, et créer une fonction statique qui renvoie le manager d’entités et demander à ce dernier de récupérer le repository de la classe en cours. Véridique. Bidouillage, bidouillage, bidouillage. Pourtant, j’insiste : Symfony prône les bonnes pratiques et essaie de faire au mieux, mais il échoue assez… attendez je cherche le qualificatif exact… j’ai trouvé : il échoue lamentablement.
  • Je pensais gagner du temps avec le bundle FOSUser. Faux ! En théorie il est censé simplifier la vie à mort et faire gagner énormément de temps. En pratique, c’est comme Symfony, il va vous falloir entrer dans son coeur, comprendre comment il a été écrit afin de pouvoir vous en servir. Exemple concret là aussi : il n’est fait que pour un seul type d’utilisateurs. Si on en veut plusieurs, il va vous falloir installer un bundle supplémentaire : le PUGXMultiUserBundle. Quelques heures plus tard après l’installation et la configuration, on m’a demandé de créer un rôle modérateur, qui doit pouvoir valider les fiches d’inscription, c’est à dire pouvoir afficher n’importe quelle fiche. Je ne peux même pas vous expliquer comment faire, car j’ai demandé aux experts Symfony – ce sont des personnes qui m’ont sous-traité le second travail que j’ai fait sur Symfony, de le faire eux même parce que je n’en pouvais plus de perdre autant de temps inutilement. J’ai beau chercher, mais un bon développeur Php va perdre beaucoup plus de temps à rechercher tout ça, installer, comprendre le fonctionnement, copier coller puis modifier le code, plutôt que de le faire direct à la main, avec des variables dans $_SERVER pour suivre quelques infos.
  • Symfony et le redimensionnement d’images. Je voulais juste, une fois qu’une image est arrivée en base de données, créer une vignette de cette dernière, afin de pouvoir l’afficher plus rapidement. J’ai donc cherché et voici le résultat – vous noterez bien qu’il est affligeant si on veut simplement redimensionner une image : en théorie  :
    • il faudrait mettre en place un service,
    • à partir de ce service, aller chercher des informations,
    • mettre en place toute une configuration, avec un système de hook (les « écouteurs »)

    … bref, refaire des milliers de choses d’une inutilité absolument affligeante, tout ça pour faire un simple resize. Après avoir passé plusieurs heures à installer le LiipImagineBundle : et m’être aperçu que pour faire un resize, il fallait déclarer vouloir utiliser un service dans ‘app/config/config.yml’, je vois qu’il y a un exemple qui est censé fonctionner sur stackoverflow ici. Et puis là le code qui fonctionne utilise getRequest(). Et le container. Moi j’en avais besoin dans l’entité, car c’est ici qu’on écrit les informations en base de données. Pour pouvoir accéder à un container dans une entité, il faut faire un méga hack, ou pire (lire les deux réponses ici). La seule réponse viable c’et de.. créer un service ! Non mais allô quoi ! Juste pour un crop ! Vraiment on est en plein délire. Hop, top chrono : google =» php imageresize, copier coller, et en moins de 5 minutes, tout fonctionnait. Symfony clame haut et fort qu’il vous fait gagner des heures de boulot ? C’est une blague, une grosse blague ! Posez les pieds sur terre, voici la réalité concrète du terrain : Symfony essaie de pousser encore et encore l’abstraction à son maximum mais on arrive à des non-sens comme celui-là : une entité qui appelle deux services différents, surchargés à mort, des centaines de lignes de code totalement inutiles, juste pour faire un resize. C’est tellement grossier comme problème qu’on en arriverait presque à croire que c’est faux… mais c’est vrai, et les liens que j’ai mis sont bien là pour le prouver.

  • Doctrine est quelque chose… que je ne comprends pas. Il a été crée pour « optimiser » les requêtes. Déjà, rien que d’écrire ça, c’est inévitablement un non sens : on n’optimise pas les requêtes via du Php… À moins que je ne me trompe, on n’a jamais besoin d’optimiser les requêtes à ce niveau ! L’optimisation et la mise en cache doit se faire au niveau du moteur de bases de données. Pourtant, là, on doit écrire du SQL, mais pas vraiment. Olivier arrête de dire n’importe quoi me direz vous. Pourtant ça n’est pas une blague, lisez tout ça ici. Tout y est expliqué : ils ont « surchargé » l’écriture de requêtes, afin de… pouvoir optimiser les requête et mieux faire du cache. Si si. Et ils ont même inventé un concept super novateur, que personne ne connaissait avant (grincement de dents cynique), j’ai nommé : l’hydratation (ou en anglais : « hydration »). Non non, j’insiste, arrêtez de rigoler, c’est pas une blague, ils prennent ça très au sérieux là bas, regardez sur la documentation officielle et cherchez « hydration ». Par contre pour bosser il faut absolument savoir ce que ce mot d’une débilité profonde – au sens informatique – signifie : j’ai mené un entretien d’embauche avec une personne (qui se disait expert), et comme je n’ai pas parlé d’hydratation des données, ça ne lui a pas plu. Bon quand je dis « expert », il faut dire qu’il s’était fait dégager à grands coups de pieds au derrière par sa précédente boîte… j’arrête là je vais être méchant 😉
  • Avec Doctrine, on se prend tout le temps la tête sur les requêtes, ce qui fait qu’au final, comme jamais rien ne fonctionne comme on voudrait avec Doctrine, on se retrouve à vouloir connaitre quelle est la vraie requête faite en base. Voir ici. Réponse officielle : on ne peut pas. On ne peut pas voir les requêtes qui sont envoyées au moteur de base de données. Mais si continuez de lire, arrêtez de pleurer de rire ! Allez vous chercher un mouchoir, essuyez-vous les yeux et revenez.
  • Doctrine est censé simplifier la vie en proposant un modèle d’héritage. Exemple de ce que j’ai réalisé : une personne est la classe de base, et de là descendent les professeurs et les étudiants. Pourtant il est lourd. Très lourd. Très (très³²) lourd. Tellement lourd, que même sur la documentation officielle ils reconnaissent que Doctrine est lourd. La preuve sur la documentation officielle. En fait il est censé simplifier la vie du développeur, mais avec Doctrine il faut une machine énorme pour pouvoir faire tourner la moindre requête un tant soit peu complexe.
  • Pire. Encore bien pire (si c’est possible !). Si, comme moi, vous voulez utiliser des requêtes comprenant des calculs de distance, il vous faudra utiliser des fonctions mathématiques et là, de base, Doctrine ne connait rien, et il vous faudra passer quelques heures à installer un bundle dans votre installation, en modifiant pas mal de fichiers un peu partout. Si, là aussi, essuyez vos larmes de rire et lisez bien ce qui suit, car c’est vrai : il est impossible de faire immédiatement cette requête sous Symfony : "SELECT COS(5) as distance;". Non non ça n’est pas une blague, c’est du sérieux. Voir tout mon article détaillé ici.
  • Symfony est tellement complexe qu’il faut absolument avoir un débogueur intégré tel que xdebug et pouvoir faire du pas à pas dans un environnement tel que PhpStorm qui donne la possibilité de suivre tout, avec la pile d’appel. Rendez vous compte : pour développer un site Web simple, des frameworks comme symfony sont tellement complexes qu’il faut obligatoirement pouvoir faire du pas à pas. Ce sont des experts Symfony qui me l’ont expliqué. Sur le coup j’ai sincèrement (honnêtement, ce n’est pas ironique, c’est véridique) cru que c’était une blague. Php est tellement simple et fluide quand il est bien développé que je n’ai jamais eu à utiliser de débogueur pas à pas en plus de dix ans ! Et ma dernière prestation était en tant qu’expert Web chez Business & Décision, prestation pour la banque, et on n’a jamais eu besoin de faire du pas à pas ! D’ailleurs pourquoi je me justifie ? N’importe quel béotien doit se douter de ça…

Je n’ai pas le temps de lister toutes les autres choses qui m’ont fait perdre un temps fou. J’ai vendu un site que je comptais faire en maximum dix jours, et je l’ai fait en un mois. Symfony était tout bonnement un mauvais choix.

En conclusion :

Symfony est censé faire gagner du temps mais en pratique, on est obligé d’apprendre la globalité de tout le framework et au final on ne gagne absolument pas de temps, et bien pire : si le projet est petit, il faut à tout prix éviter des usines à gaz telles que Symfony.

Pour la petite note, les personnes qui m’ont sous traité le projet – qui tourne bien actuellement – ont été déçues parce que je n’ai pas tenu mes délais, et que mes premières livraisons n’étaient pas de bonne qualité – alors que je « semblais » compétent. Je ne jette pas tout sur Symfony, mais bon sang quelle grossière erreur de ma part ! Pour vous donner une idée de comparaison : j’ai terminé en 3 jours un site qui devrait être mis en ligne incessamment sous peu : un site spécialisé la constatation fiable de sites Web. Il contient :

  • Un formulaire d’inscription contenant tout ce qu’il faut (CSRF protection, re-Captcha etc) ;
  • Un CSS full responsive ;
  • Un blog WordPress (évidemment full responsive) ;
  • Un outil complet de capture d’écran basé sur du Webkit (très gros boulot) ;
  • Du code pour gérer un multi-partenariat en marque blanche ;
  • Du templating Smarty pour modifier l’habillage rapidement ;
  • Une documentation entièrement compatible PhpDocumentor ;
  • Une classe (assez longue) pour le traitement des images (archivage, signature chiffrée etc) ;
  • Un ORM qui :
    • ne fait des requêtes que quand c’est nécessaire,
    • fait des requêtes en SQL pur. Ouf, je respire, des heures entières de gagnées.
    • délègue au maximum à la base de données, ce qui est absolument vital pour avoir une application stable, rapide et pérenne sur le temps.
  • Une classe simple d’envoi de mail, avec la possibilité d’envoyer le texte alternatif (= si jamais le client ne peut pas lire du HTML, on peut préciser le texte). Merci PHPMailer, un outil simple, ultra facile d’utilisation, et utilisé dans ma classe, finit par un code ainsi :
    $mail = new ObjetMail(
        EMAIL_DEFAUT_FROM,
        EMAIL_DEFAUT_FROM_NAME,
        EMAIL_DEFAUT_REPLYTO,
        EMAIL_DEFAUT_REPLYTO_NAME,
        $email,
        'Capture bien prise',
        /*... Texte HTML ...*/,
        /*... Texte alternatif ...*/
    );
    try {
        $mail->send();
        array_push(
            $this->_TabResult,
            $this->trad->get(
                'mail_envoye_en_attente_confirmation'
            )
        );
    } catch (Exception $e) {
        $this->addTabErr(
            $this->trad->get('err_envoi_email')
        );
        $ok = false;
    }
  • Tout est tracé et archivé, aussi bien en base que dans les captures d’écran, et tout est prévu pour une grosse évolution : un compte, ce compte pourra avoir plusieurs emails, plusieurs captures, toutes les connexions – réussies ou échouées – sont déjà tracées, ils pourront avoir une ou plusieurs adresses etc.

Faire la même chose avec Symfony ? Je vous laisse estimer le temps de faire les estimations, le cahier des charges, le devis, le développement, mais attention, grâce à Symfony vous allez gagner énormément de temps : Symfony peut générer le CRUD pour l’administration en ligne de commande, regardez ici. Oulah que de temps gagné ! Sachant que je génère un custom getter-setter en 3 touches avec vim, même s’il y a plusieurs centaines de champs, et plusieurs dizaines de tables, je ferais ça « à la main » au maximum en une journée… enfin bon en comparant avec Symfony je peux dire sans éxagérer : sans Symfony, une journée de perdue, mais dix d’économisées ! Mais pourquoi je continue à essayer de prouver que Symfony ne fait jamais gagner de temps, moi ? Même ces personnes expertes Symfony ont décidé de le laisser tomber et de n’utiliser que Silex pour tous leur nouveaux projets à moins qu’ils n’aient vraiment besoin de choses spécifiques à Symfony… et personnellement je n’arrive pas à voir ce que Symfony a de si spécifique dont on ne peut pas se passer 🙂 … A l’inverse, je vois vraiment toutes les raisons pour lesquelles on peut se passer de Symfony.

PhpStorm, Windows / WAMP et xdebug : howto – la solution

Si jamais vous êtes comme moi, et que vous n’avez pas réussi à faire fonctionner PhpStorm avec xdebug sous Windows avec WAMP, vous avez peut-être le même problème que moi à savoir : le serveur Apache semble mal configuré – ou configurable, et incapable d’utiliser Php correctement avec xdebug.

Je passe toutes les étapes de configuration « classiques », parce qu’elles sont simples et bien documentées – y compris dans PhpStorm. Malgré tout ça, il se peut que cela ne fonctionne pas.

La solution :

Solution PhpStorm RunDebug Configurations pour Windows - WAMP

En fait il faut configurer PhpStorm pour qu’il ne passe pas par Apache, mais qu’il lance le serveur Php intégré (si, Php a un serveur HTTP, cherchez dans la documentation).

Et ainsi, le déboguage en ligne fonctionnera.

C’est grâce à cette vidéo que j’ai eu l’idée d’essayer :

http://www.youtube.com/watch?v=LUTolQw8K9A

Bien sûr, si vous essayez xdebug sous Linux, vous aurez nettement moins de difficultés 🙂.

Symfony: The form’s view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is…

J’ai eu l’erreur qui est le titre de mon post.

Pourtant, j’avais tout fait correctement. J’avais mis en place une collection ManyToMany simple : un partenaire peut être relié à une ou plusieurs personnes et une personne peut être reliée à un ou plusieurs partenaires.

Sur symfony 2.1, tout fonctionnait correctement, et j’ai fait la mise à jour sur symfony 2.3 (pour rester à la pointe 😉 ) mais là une erreur apparaissait :

« The form’s view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is an instance of class HQF\Bundle\PizzasBundle\Entity\Personne. You can avoid this error by setting the « data_class » option to « HQF\Bundle\PizzasBundle\Entity\Personne » or by adding a view transformer that transforms an instance of class HQF\Bundle\PizzasBundle\Entity\Personne to scalar, array or an instance of \ArrayAccess. »

Après un bon moment de recherche, j’ai trouvé ma solution ici.

Dans mon bundle j’avais mon fichier « Bundle/Form/Type/PartenaireType.php » dans lequel j’avais déclaré tout comme il fallait :

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('nom',                    'text');
        $builder->add('site_actif',             'checkbox');
        $builder->add('afficher_img_produits',  'checkbox');
        $builder->add('commande_en_ligne',      'checkbox');
        $builder->add('livraison',              'checkbox');
        $builder->add('livraison_delai',        'integer');
        $builder->add(
            'personnes',
            'collection',
            array(
                'type' => new PersonneType(),
            )
        );
    }

Tout était parfait, et fonctionnait sous Symfony 2.1. Mais lors de la mise à jour, ça ne fonctionnait plus. Il manquait cela : préciser à nouveau que la PersonneType était liée à un type Personne :

'options' => array('data_class' => 'HQF\Bundle\PizzasBundle\Entity\Personne')

Donc dans mon code ça donne ça :

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('nom',                    'text');
        $builder->add('site_actif',             'checkbox');
        $builder->add('afficher_img_produits',  'checkbox');
        $builder->add('commande_en_ligne',      'checkbox');
        $builder->add('livraison',              'checkbox');
        $builder->add('livraison_delai',        'integer');
        $builder->add(
            'personnes',
            'collection',
            array(
                'type' => new PersonneType(),
                'options' => array(
                    'data_class' => 'HQF\Bundle\PizzasBundle\Entity\Personne'
                ),
            )
        );
    }

Un grand merci à Stackoverflow, sinon j’aurais mis bien plus de temps à m’en sortir, je pense !

Symfony: Could not open input file: composer.phar solution

Si jamais vous avez ce problème, une solution qui peut fonctionner est de lancer un shell, et d’aller dans votre répertoire source.
De là, lancez cet ordre :

curl -s http://getcomposer.org/installer | php

Et tout rentrera dans l’ordre !