Simplifiez les paramétrages sur Symfony avec ConfigurationBundle

Nous vous présentons un bundle Symfony open source développé par Sherlockode, permettant aux utilisateurs de gérer la configuration du site, en limitant le recours aux variables d'environnement ou aux paramètres en dur dans des fichiers de configuration.


Commençons par exposer un cas classique sur un projet Symfony. Une application doit envoyer des emails à ses utilisateurs suivant certains événements. Afin de donner un peu de souplesse au système, les développeurs font en sorte de ne pas écrire en dur l'adresse email d'expédition dans le code, mais plutôt en paramètre du chargé d'envoi des emails. Pour satisfaire au système d'injection de dépendance, la valeur injectée est définie dans une variable d'environnement ou dans le fichier parameters.yml, il est donc possible de modifier cette adresse email sans modifier le code.

# parameters.yml
parameters:
    sender_email_address: noreply@example.com

Une problématique récurrente

Posons nous une question simple : qui est le plus susceptible de vouloir modifier l'adresse d'expédition des emails transactionnels ? On peut supposer que cela viendra du marketing, mais probablement pas du développeur ou du responsable de l'hébergement. Malheureusement, avec cette application, seule une personne technique peut accéder à cette configuration et la modifier, ce qui va demander du temps et du budget.

La mise à disposition d'options de configuration est un besoin très courant dès qu'une application grossit, afin de s'affranchir de la dépendance aux développeurs pour le suivi du site au quotidien. Sur un site ecommerce, le nombre de produit à afficher par page ou bien le délai avant de faire une relance pour les paniers abandonnés sont des paramètres sur lesquels les administrateurs veulent avoir la main, le nombre de cas d'usage est quasiment infini.

Une solution technique simple pour centraliser des paramètres est de créer une table dans la base de données avec une colonne permettant d'identifier le paramètre stocké et une colonne avec la valeur en question. Dans notre premier exemple, nous aurions une ligne avec pour clé "sender_email_address" et pour valeur "noreply@example.com". On peut ensuite récupérer la valeur paramétrée en recherchant dans la table la ligne ayant la clé souhaitée.

Les choses commencent à se complexifier si l'on souhaite paramétrer des valeurs non scalaires, comme des tableaux ou des entités. Admettons que l'on souhaite configurer l'article à mettre en avant sur un blog, nous allons donc devoir stocker dans notre table de paramètre l'identifiant de l'entité "article" choisie. Enfin, il faut développer un formulaire spécifique permettant d'afficher la liste des articles publiés, le tout dans une liste déroulante pour que l'administrateur puisse faire son choix.

Lors de l'affichage des pages, il faudra donc récupérer cette valeur à partir de la clé de paramétrage choisie, puis récupérer un objet PHP via un requête Doctrine, introduisant donc plusieurs dépendances dans le code PHP concerné. Ces problématiques se répètent pour chaque paramètre qui serait autre chose d'un simple texte, la base de code devient ainsi rapidement complexe.

Le bundle Symfony développé par Sherlockode permet de répondre exactement à ce besoin et de s'affranchir des problématiques exposées.

Installation

Installez ConfigurationBundle via composer et activez le dans le Kernel.

composer require sherlockode/configuration-bundle
<?php
// app/AppKernel.php

public function registerBundles()
{
   $bundles = [
       // ...
       new Sherlockode\ConfigurationBundle\SherlockodeConfigurationBundle(),
   ];
}

Un fichier de routing fourni avec le bundle permet d’avoir accès à la page d’édition des paramètres qui seront définis dans l’application.

# config/routing.yaml
sherlockode_configuration:
    resource: "@SherlockodeConfigurationBundle/Resources/config/routing.xml"

Définition de paramètres

Vous pouvez ensuite créer votre entité Parameter (voir le readme du projet pour un exemple complet) et écrire la configuration dont vous avez besoin :

sherlockode_configuration:
    entity_class:
        parameter: App\Entity\Parameter
    parameters:
        sender_email_address:
            label: My customer service contact email
            type: simple

C’est tout ! Nous avons maintenant défini le paramètre sender_email_address dont nous avions besoin plus haut, sa valeur peut être modifiée à l’URI /parameter si vous avez importé le fichier de routing plus haut.

L’utilisation du paramètre se fait ensuite via un service de type ParameterManagerInterface permettant de récupérer n’importe quel paramètre.

use Sherlockode\ConfigurationBundle\Manager\ParameterManagerInterface;

function sendEmail(ParameterManagerInterface $parameterManager)
{
    $customerServiceEmail = $parameterManager->get('sender_email_address');
    // send email
}

Admettons que vous souhaitiez utiliser une entité dans le système de paramètre. La mise en avant d’un produit sur un site ecommerce pourrait se faire de cette façon. Nous devons pour cela rajouter la définition correspondante dans la configuration.

sherlockode_configuration:
    entity_class:
        parameter: App\Entity\Parameter
    parameters:
        featured_product:
            label: My featured product
            type: entity
            options:
                class: App/Entity/Product

Le formulaire de gestion de la configuration se met à jour en proposant une liste déroulante des produits et permettant de sélectionner celui qui sera mis en avant. Il peut alors être récupéré facilement :

$product = $parameterManager->get('featured_product');

ConfigurationBundle fournit nativement les types de champs suivants prêts à l'emploi : simple (supporte tous les champs dérivés du type "text"), checkbox, choice, datetime, entity.

Le bundle offre aussi la possibilité de créer vos propres types de paramètres afin de gérer les règles métiers spécifiques que chaque projet pourrait nécessiter. Le code ainsi que la documentation sur les fonctionnalités sont disponibles sur github. N’hésitez pas à contribuer !