Je veux créer un formulaire de contact et pouvoir paramétrer qui va
recevoir le message. Pour le moment, je veux être le seul à recevoir ce
message, mais dans le futur, il pourrait y avoir plusieurs
destinataires.
A partir de cette phrase on peut voir immédiatement que l'on veut quelque
chose de très simple, en terme de structure, au niveau de notre fichier de
configuration yaml.
# Pour une adresse de contact
afsy_core:
contact: "mail@exemple.com"
# Pour plusieurs adresses de contact
afsy_core:
contact:
- "mail1@exemple.com"
- "mail2@exemple.com"
La structure a beau être simple, on aura besoin d'utiliser trois concepts
avancés du composant Config :
Prototype
La méthode prototype
permet de gérer un nombre d'éléments
dynamiques. Il va nous servir pour le tableau d'adresses e-mails (de
scalarNode
), mais on peut très bien l'utiliser pour gérer des
éléments structurés (arrayNode
).
Validation
Permet de valider la valeur d'un noeud. Je veux une liste d'adresses
e-mails, je bloque donc la validation si je reçois autre chose.
Normalisation
La normalisation transforme une valeur en une autre. Dans mon code j'attends
un tableau, mais si je reçois une chaîne de caractères, je ne bloque pas, et
je convertis dans le bon format.
Le code
En utilisant ces trois concepts, on va obtenir un code qui va ressembler
plus ou moins à ça :
<?php
namespace Afsy\CoreBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Validator\Validator;
use Symfony\Component\Validator\Constraints\Email;
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('afsy_core');
$rootNode
->children()
->arrayNode('contact')
->beforeNormalization()
->ifString()
->then(function ($value) {
return array($value);
})
->end()
->prototype('scalar')
->validate()
->ifTrue(function ($value) {
return !filter_var($value, FILTER_VALIDATE_EMAIL);
})
->thenInvalid('%s is not a valid address email')
->end()
->end()
->end()
->end();
return $treeBuilder;
}
}
Tester sa configuration
Lorsque l'on commence à avoir une configuration complexe, il devient très
important de tester celle-ci pour être sûr que tout fonctionne comme
prévu.
Dans les différents bundles que j'ai pu regarder, on remarque deux approches
différentes pour tester la configuration d'un bundle :
-
la première consiste à tester les modifications qui sont apportées au
conteneur lorsque l'on exécute l'extension,
-
et la deuxième consiste à fournir un tableau à la configuration pour
voir si il y a des erreurs.
Je vais vous parler de la deuxième méthode car il s'agit, selon moi, de la
plus simple.
Si vous souhaitez plus d'informations sur la première version, n'hésitez pas
à regarder le fichier de test du bundle JMSSecurityExtraBundle.
Pour tester la configuration, j'utilise le composant SymfonyConfigTest crée par Matthias Noback.
Je vais vous montrer comment tester le code que j'utilise plus haut en utilisant ce composant.
<?php
namespace Afsy\CoreBundle\Tests\DependencyInjection;
use Matthias\SymfonyConfigTest\PhpUnit\AbstractConfigurationTestCase;
use Afsy\CoreBundle\DependencyInjection\Configuration;
class ConfigurationTest extends AbstractConfigurationTestCase
{
protected function getConfiguration()
{
return new Configuration();
}
public function testValidateEmailAddress()
{
$this->assertConfigurationIsInvalid(
array(
array(
'contact' => 'not an email address'
)
),
"is not a valid address email"
);
}
public function testNormalization()
{
$this->assertProcessedConfigurationEquals(
array(
array(
'contact' => 'test@exemple.com'
)
),
array(
'contact' => array('test@exemple.com')
)
);
}
public function testPrototype()
{
$this->assertProcessedConfigurationEquals(
array(
array(
'contact' => array('test@exemple.com')
)
),
array(
'contact' => array('test@exemple.com')
)
);
$this->assertProcessedConfigurationEquals(
array(
array(
'contact' => array(
'test@exemple.com',
'test2@exemple.com'
)
)
),
array(
'contact' => array(
'test@exemple.com',
'test2@exemple.com'
)
)
);
}
}
Aller plus loin ?
Si vous souhaitez en savoir plus sur ce composant, il existe de nombreuses
ressources sur Internet en commençant par le livre
« A Year With Symfony »
ou le blog de
Matthias Noback. Vous pouvez également vous inspirer des fichiers de
configuration des bundles existants, par exemple celui de Sonata ou du SecurityBundle
de Symfony2.
Vous pouvez également utiliser ce composant en dehors de Symfony2, comme le
fait Behat, mais je n'ai pas trouvé de code suffisamment simple pour
l'intégrer dans cet article.