Blog


Liste des articles

    Construire un menu avec du contenu en base de données avec KnpMenuBundle

    Le , par .

    KNPMenuBundle est un Bundle qui permet de gérer assez facilement les menus d'un site web. Faire un menu statique est très simple et expliqué clairement dans la documentation. Mais parfois, le développeur a besoin de construire un menu (ou un sous-menu) en fonction de contenus en base de données. Ce billet va donc vous expliquer comment faire cela.

    Le contexte

    Nous allons prendre un exemple simple pour illustrer ce billet : j'ai une entité Produit avec les attributs nom et categorie, et une entité Categorie avec les attributs nom et produits. Chaque produit est relié à une catégorie.

    Notre objectif est de construire un menu qui liste les catégories, et envoie l'utilisateur vers une page listant les produits de la catégorie sélectionnée.

    Nous partons du principe que nous avons déjà un contrôleur qui s'occupe de lister les produits d'une catégorie. Sa route s'appelle liste_produits_categorie et elle attend un paramètre id, qui est l'identifiant de la catégorie.

    Création de la classe Builder

    Pour construire notre menu, il nous faut une classe Builder. Voici donc notre classe Builder par défaut :

    use Knp\Menu\FactoryInterface;
    
    class Builder
    {
        public function createMainMenu(FactoryInterface $factory,
                                       array $option)
        {
            $menu = $factory->createItem('root');
    
            $menu->addChild(
                'categorie',
                array('label' => 'Nos produits par catégories')
            );
    
            // D'autres menus ensuite...
    
            return $menu;
        }
    }
    

    Notre objectif maintenant est de pouvoir utiliser le service Doctrine pour pouvoir faire une requête dans notre classe Builder. Pour cela, il va donc falloir transformer notre Builder en service. Ça tombe bien, la procédure est décrite dans la documentation (et en plus, l'utilisation des menus en sera aussi simplifiée).

    Convertir notre classe Builder en service Symfony2

    Premièrement, la documentation nous indique qu'il va falloir récupérer l'objet implémentant FactoryInterface dans le constructeur car ce dernier ne sera plus passé en argument auprès de notre fonction createMainMenu(). Dans notre cas, nous allons nous aussi avoir besoin d'un autre service : l'Entity Manager de Doctrine. Transformons donc notre classe ainsi :

    use Knp\Menu\FactoryInterface;
    use Doctrine\ORM\Entitymanager;
    
    class Builder
    {
        private $factory;
        private $em;
    
        public function __construct(FactoryInterface $factory,
                                    Entitymanager $em)
        {
            $this->factory = $factory;
            $this->em = $em;
        }
    
        public function createMainMenu()
        {
            $menu = $this->factory->createItem('root');
    
            $menu->addChild(
                'categorie',
                array('label' => 'Nos produits par catégories')
            );
    
            // D'autres menus ensuite...
    
            return $menu;
        }
    }
    

    Déclarer les services dans la configuration de l'application

    Il nous faut maintenant déclarer nos services auprès de Symfony2. Cela se fait dans le fichier services.yml de votre bundle, ou bien directement dans le fichier app/config/config.yml.

    services:
        acme_main.menu_builder:
            class:     Acme\MainBundle\Menu\Builder
            arguments: ['@knp_menu.factory', '@doctrine.orm.entity_manager']
    
        acme_main.menu.main:
            class:           Knp\Menu\MenuItem
            factory_service: acme_main.menu_builder
            factory_method:  createMainMenu
            tags:
                - { name: knp_menu.menu, alias: main }
    

    On voit bien ici que notre builder attend deux paramètres : le service Factory de KnpMenu ainsi que le service EntityManager de Doctrine. Notre builder est donc déclaré en tant que service.

    Le deuxième service concerne le menu principal. En effet, on le déclare aussi comme service pour faciliter son utilisation dans les vues. Ce service fait appel à notre service Builder, et on précise la fonction appelée : createMainMenu. De cette manière, vous pouvez créer plusieurs menus au sein de votre classe Builder. Il vous suffit de déclarer deux services Menu, puis d'indiquer la bonne fonction pour l'option factory_method.

    Voilà, tout est prêt maintenant pour construire notre menu en extrayant les informations de la base de données.

    Construction du menu

    Pour cela, rien de plus simple : nous avons l'EntityManager à notre disposition.

    use Knp\Menu\FactoryInterface;
    use Doctrine\ORM\Entitymanager;
    
    class Builder
    {
        private $factory;
        private $em;
    
        public function __construct(FactoryInterface $factory,
                                    Entitymanager $em)
        {
            $this->factory = $factory;
            $this->em = $em;
        }
    
        public function createMainMenu()
        {
            $menu = $this->factory->createItem('root');
    
            $menu->addChild(
                'categorie',
                array('label' => 'Nos produits par catégories')
            );
    
            // Récupération de la liste des catégories.
            $listeCategories = $this->em->getRepository('AcmeMainBundle:Categorie')->find();
    
            // Création des sous-menus.
            foreach ($listeCategories as $categorie)
            {
                $menu['categorie']->addChild(
                    'categorie_' . $categorie->getId(), // Identifiant du menu.
                    array(
                        'label'           => $categorie->getNom();
                        'route'           => 'liste_produits_categorie'
                        'routeParameters' => array('id' => $categorie->getId()),
                    )
                );
            }
    
            // D'autres menus ensuite...
    
            return $menu;
        }
    }
    

    Et voilà donc notre menu construit avec toutes les catégories présentes en base de données. Pour l'utiliser dans vos vues, il suffit simplement d'ajouter :

    {{ knp_menu_render('main') }}
    

    À noter que main représente l'alias que nous avons donné à notre menu dans la configuration des services.

    Catégories : Blog


    Symfony2 avec Oracle DataBase sous Ubuntu

    Le , par .

    Utiliser Symfony2 avec Oracle DataBase est un parcours assez peu documenté. Ce billet de blog tente donc de vous accompagner dans la configuration de Symfony2 pour utiliser Oracle DataBase. Attention, ce billet ne vous indique pas comment installer le serveur Oracle ! Nous partons du principe ici que le serveur de base de données existe déjà. On cherche juste à configurer Symfony2 pour se connecter à ce serveur, sous Ubuntu.

    Tout d'abord, il va falloir utiliser le module PHP oci8, qui n'est pas présent par défaut sous Ubuntu.

    Compilation du module oci8 pour php

    Il va nous falloir télécharger et installer plusieurs outils pour compiler ce module. Executez les commandes suivantes :

    sudo apt-get install build-essential
    sudo apt-get install php5-dev php-pear libaio1
    

    Ensuite, il va nous falloir rajouter des variables d'environnement nécessaire pour l'installation de l'InstantClient. Pour cela, il faut éditer le fichier /etc/environment et ajouter les lignes suivantes :

    LD_LIBRARY_PATH="/usr/local/lib/instantclient_11_2"
    TNS_ADMIN="/usr/local/lib/instantclient_11_2"
    ORACLE_BASE="/usr/local/lib/instantclient_11_2"
    ORACLE_HOME=$ORACLE_BASE
    

    Ensuite, téléchargez le package Basic (le premier dans la liste) et le package SDK (le 5ème). A noter qu'il vous faut un compte sur le site d'Oracle pour pouvoir télécharger les fichiers.
    Une fois téléchargé, retour sur la console, et saisissez les commandes suivantes :

    cd /usr/local/lib
    sudo unzip /chemin/vers/l/archive/instant-client-basic
    sudo unzip /chemin/vers/l/archive/instant-client-sdk
    cd instantclient_11_2
    sudo ln -s libclntsh.so.11.1 libclntsh.so
    sudo pecl install oci8
    

    Pendant la compilation, on vous demandera le chemin vers la bibliothèque InstantClient. Répondez juste :

    instantclient,/usr/local/lib/instantclient_11_2
    

    Le module est maintenant compilé.

    Activer le module dans PHP

    Pour cela, rien de plus simple : il suffit de créer un fichier oci8.ini dans le répertoire /etc/php5/conf.d et d'ajouter le contenu suivant :

    extension=oci8.so
    

    Et bien sûr, n'oubliez pas de redémarrer le serveur Apache :

    sudo service apache2 restart
    

    Configuration de Symfony2

    Ouvrez le fichier de configuration app/config/config.yml ainsi que le fichier app/config/parameter.yml.
    Dans le fichier parameter.yml, renseignez l'adresse et le port (par défaut : 1521) du serveur hôte de la base de données. Renseignez ensuite le nom d'utilisateur, le mot de passe et le nom de la base de données (SID). Changez aussi le driver pdo_mysql par oci8.

    Et voilà, c'est terminé ! Il est cependant possible que vous ayez des erreurs avec les champs date. En effet, Doctrine attend un certain format de date (Y:m:d H:i:s) alors que Oracle, en fonction de sa configuration, peut fournir les dates sous un autre format. Pour régler ce soucis, dans le fichier config.yml, rajoutez à la fin :

    services:
        listener:
            class: Doctrine\DBAL\Event\Listeners\OracleSessionInit 
            tags:
                - { name: doctrine.event_listener, event: postConnect }
    

    C'est un Doctrine Listener inclu dans Doctrine qui devrait résoudre le problème, il n'est pas activé par défaut.

    Catégories : Blog


    Ouverture du blog à d'autres contributeurs

    Le , par .

    Bonjour à tous,

    Vous avez pu vous en rendre compte, ce blog n'est pas aussi actif que je ne le voudrais !

    Nous avons peut-être une solution. Il y a quelques jours un membre me contacte sur le siteduzero avec un article sous le coude, et pas de blog pour le publier. J'ai bien sûr accepté de publier son article (sur Symfony2 et Oracle), vous le verrez demain ici-même.

    L'initiative est très intéressante. Quelqu'un qui a quelque chose à dire sur Symfony2 ne devrait jamais être arrêté faute de lieu pour s'exprimer. C'est pourquoi, si vous vous sentez l'âme d'un auteur d'article de blog, n'hésitez pas à me contacter et nous regarderons ensemble comment publier vos articles ici !

    A vos claviers !

    Catégories : Blog


    Utiliser JsonResponse pour vos retours en Json

    Le , par .

    Dans le cadre d'une API, d'appels en AJAX ou autres, vous avez déjà certainement retourné des données en Json.

    Plutôt que de manuellement encoder en Json et de définir soi-même le type de la réponse, il existe une classe discrète mais bien utile qui fait tout à votre place. Il s'agit de JsonResponse, que je vous invite à consulter.

    Cette classe est tellement pratique que vos retours Json ne se font désormais plus qu'en une seule ligne, voyez par vous-mêmes :

    use Symfony\Component\HttpFoundation\JsonResponse;
    
    public function fooAction()
    {
        $data = $this->getDoctrine()
                     ->getManager()
                     ->getRepository('Bundle:Entity')
                     ->findAll();
    
        return new JsonResponse($data);
    }
    

    Inutile d'utiliser json_encode() sur vos données (ici $data), et inutile également de définir le Content-type adéquat pour la réponse. Bref, du gain de code, donc du bonheur !


    Une checklist pour vos mises en production

    Le , par .

    Il y a quelques jours j'ai ouvert le site Symfony2-checklist.com.

    C'est un site qui contient une checklist de petits points à vérifier impérativement avant toute mise en production. Ce sont des points plus ou moins facile à mettre en oeuvre, mais qu'il faut absolument traiter avant d'ouvrir votre site au monde entier. En bref : à utiliser !

    J'ai voulu ce site communautaire, c'est-à-dire que vous pouvez y apporter votre pierre en un clic : il suffit pour cela d'utiliser le dépôt Github de la checklist. Grâce à Github, vous pouvez facilement corriger une erreur, ajouter un élément dans la liste, et le proposer en retour. Toute modification sur le dépôt Github est publiée sur le site internet dans l'heure suivante. C'est aussi ça l'esprit Symfony2 !

    D'ailleurs si vous parlez une langue qui n'existe pas encore sur le site, vous ferez des heureux en traduisant les points déjà existants de la liste dans la langue que vous maîtrisez. N'hésitez pas !

    J'ouvrirai également bientôt le code source du site. Rien de bien révolutionnaire dedans, mais cela peut servir d'exemple pour certains. C'est en lisant le code des autres qu'on gagne de l'expérience ! Le temps pour moi de nettoyer un peu le code et je vous préviendrai de la publication.

    Catégories : Blog