Adding PHP Function to Symfony ExpressionLanguage, The Simple Way đ
Today I want to share a quick tip for Symfony users âïž. When you use the ExpressionLanguage component you get a context: some variables and some functions.
Those functions are not the same everywhere. For example when using the validation constraint Expression:
#[Assert\Expression(
"is_valid(this.getCategory()) or is_valid(this.getSection())",
message: 'Bad category!',
)]
class BlogPost
{
// ...
}
You get a custom ExpressionLanguage service, defined like this:
// The language itself with a custom provider
->set('validator.expression_language', ExpressionLanguage::class)
->args([service('cache.validator_expression_language')->nullOnInvalid()])
->call('registerProvider', [
service('validator.expression_language_provider')->ignoreOnInvalid(),
])
// The custom provider
->set('validator.expression_language_provider', ExpressionLanguageProvider::class)
This service has a provider attached, itâs the proper way to extend the functionality in ExpressionLanguage. It implements the interface ExpressionFunctionProviderInterface and looks like this:
class ExpressionLanguageProvider implements ExpressionFunctionProviderInterface
{
public function getFunctions(): array
{
return [
new ExpressionFunction('is_valid', function (...$arguments) {
return true; // Redacted for clarity
}, function (array $variables, ...$arguments): bool {
return true; // Redacted for clarity
}),
];
}
}
Itâs great to add custom functions (is_valid here), but what if I just need to add count() support?!
The recommended way is to use this interface like that, with the fromPhp shortcut:
class CustomExpressionLanguageProvider implements ExpressionFunctionProviderInterface
{
public function getFunctions(): array
{
return [
ExpressionFunction::fromPhp('count');
];
}
}
đ€ But wait, canât this be done without PHP code?!
Section intitulée the-del-lazy-del-simple-wayThe lazy simple way
As ExpressionFunction::fromPhp is a static callable, we can call it like a Factory to build the ExpressionFunction we need.
So by leveraging the power of Symfony DIC, we can:
- override the framework ExpressionLanguage used in the Validator component;
- add
ExpressionFunctioninstances on the fly.
All of that with zero line of PHP đ đ
countableExpression:
class: Symfony\Component\ExpressionLanguage\ExpressionFunction
factory: ['Symfony\Component\ExpressionLanguage\ExpressionFunction', 'fromPhp']
arguments: ['count']
validator.expression_language:
class: Symfony\Component\ExpressionLanguage\ExpressionLanguage
calls:
- [addFunction, ['@countableExpression']]
- [registerProvider, ['@validator.expression_language_provider']]
We can add as many functions as needed here without relying on the ExpressionFunctionProviderInterface.
â ïž Doing so, we are now duplicating in our code the validator.expression_language original definition, this could lead to issues if the framework definition is updated. The original version of this article was using decorates but it does not keep the original service the way we need.
Section intitulée use-the-forceUse the force
There were four ways to add this count function in ExpressionLanguage:
- install a bundle;
- create a Provider and set it up in the configuration;
- drop ExpressionLanguage and use plain PHP instead (Callback constraint);
- use the DIC configuration to my advantage.
For my case, I consider the last one the most efficient and simple. What about you? Would you have chosen another?
The DIC configuration is really powerful and if options like factory and decorates are new to you, I strongly recommend taking some time to read about it đ€ you will thank me later.
Cheers đ
Commentaires et discussions
Nos formations sur ce sujet
Notre expertise est aussi disponible sous forme de formations professionnelles !
Symfony avancée
DĂ©couÂvrez les foncÂtionÂnaÂliÂtĂ©s et concepts avanÂcĂ©s de SymfoÂny
Ces clients ont profité de notre expertise
Nous avons construit un extranet afin de de simplifier les tĂąches quotidiennes de gestion, que ce soit pour les utilisateurs (dĂ©partements, associations, mandataires, accueillants et accueillis) et lâĂ©quipe de Cettefamille. Le socle technique utilisĂ© est Symfony, PostgreSQL, Webpack, VanillaJS. Lâemploi de ces technologies modernes permet aujourdâhuiâŠ
Nous avons rĂ©alisĂ© la refonte du site de lâagence Beautiful Monday en utilisant nos compĂ©tences HTML5/CSS3 cĂŽtĂ© front-end, et le framework Symfony2 cĂŽtĂ© back-end. Afin de sâafficher correctement sur nâimporte quel appareil, le site est entiĂšrement responsive. La partie intĂ©gration a Ă©tĂ© effectuĂ©e avec un grand soin, en respectant parfaitement la maquetteâŠ
Ă lâoccasion de la 12e Ă©dition du concours Europan Europe, JoliCode a conçu la plateforme technique du concours. Ce site permet la prĂ©sentation des diffĂ©rents sites pour lesquels il y a un appel Ă projets, et encadre le processus de recueil des projets soumis par des milliers dâarchitectes candidats. Lâapplication gĂšre Ă©galement toute la partie post-concoursâŠ