Skip to content

Commit 94c7d6a

Browse files
atailouloutefabpot
authored andcommitted
[Routing][FrameworkBundle] Allow using env() in route conditions
1 parent 2e588a7 commit 94c7d6a

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ CHANGELOG
99
* added "priority" option to annotated routes
1010
* added argument `$priority` to `RouteCollection::add()`
1111
* deprecated the `RouteCompiler::REGEX_DELIMITER` constant
12+
* added `ExpressionLanguageProvider` to expose extra functions to route conditions
1213

1314
5.0.0
1415
-----
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Matcher;
13+
14+
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
15+
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
16+
use Symfony\Contracts\Service\ServiceProviderInterface;
17+
18+
/**
19+
* Exposes functions defined in the request context to route conditions.
20+
*
21+
* @author Ahmed TAILOULOUTE <ahmed.tailouloute@gmail.com>
22+
*/
23+
class ExpressionLanguageProvider implements ExpressionFunctionProviderInterface
24+
{
25+
private $functions;
26+
27+
public function __construct(ServiceProviderInterface $functions)
28+
{
29+
$this->functions = $functions;
30+
}
31+
32+
/**
33+
* {@inheritdoc}
34+
*/
35+
public function getFunctions()
36+
{
37+
foreach ($this->functions->getProvidedServices() as $function => $type) {
38+
yield new ExpressionFunction(
39+
$function,
40+
static function (...$args) use ($function) {
41+
return sprintf('($context->getParameter(\'_functions\')->get(%s)(%s))', var_export($function, true), implode(', ', $args));
42+
},
43+
function ($values, ...$args) use ($function) {
44+
return $values['context']->getParameter('_functions')->get($function)(...$args);
45+
}
46+
);
47+
}
48+
}
49+
50+
public function get(string $function): callable
51+
{
52+
return $this->functions->get($function);
53+
}
54+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Tests\Matcher;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\DependencyInjection\ServiceLocator;
16+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
17+
use Symfony\Component\Routing\Matcher\ExpressionLanguageProvider;
18+
use Symfony\Component\Routing\RequestContext;
19+
20+
class ExpressionLanguageProviderTest extends TestCase
21+
{
22+
private $context;
23+
private $expressionLanguage;
24+
25+
protected function setUp(): void
26+
{
27+
$functionProvider = new ServiceLocator([
28+
'env' => function () {
29+
// function with one arg
30+
return function (string $arg) {
31+
return [
32+
'APP_ENV' => 'test',
33+
'PHP_VERSION' => '7.2',
34+
][$arg] ?? null;
35+
};
36+
},
37+
'sum' => function () {
38+
// function with multiple args
39+
return function ($a, $b) { return $a + $b; };
40+
},
41+
'foo' => function () {
42+
// function with no arg
43+
return function () { return 'bar'; };
44+
},
45+
]);
46+
47+
$this->context = new RequestContext();
48+
$this->context->setParameter('_functions', $functionProvider);
49+
50+
$this->expressionLanguage = new ExpressionLanguage();
51+
$this->expressionLanguage->registerProvider(new ExpressionLanguageProvider($functionProvider));
52+
}
53+
54+
/**
55+
* @dataProvider compileProvider
56+
*/
57+
public function testCompile(string $expression, string $expected)
58+
{
59+
$this->assertSame($expected, $this->expressionLanguage->compile($expression));
60+
}
61+
62+
public function compileProvider(): iterable
63+
{
64+
return [
65+
['env("APP_ENV")', '($context->getParameter(\'_functions\')->get(\'env\')("APP_ENV"))'],
66+
['sum(1, 2)', '($context->getParameter(\'_functions\')->get(\'sum\')(1, 2))'],
67+
['foo()', '($context->getParameter(\'_functions\')->get(\'foo\')())'],
68+
];
69+
}
70+
71+
/**
72+
* @dataProvider evaluateProvider
73+
*/
74+
public function testEvaluate(string $expression, $expected)
75+
{
76+
$this->assertSame($expected, $this->expressionLanguage->evaluate($expression, ['context' => $this->context]));
77+
}
78+
79+
public function evaluateProvider(): iterable
80+
{
81+
return [
82+
['env("APP_ENV")', 'test'],
83+
['env("PHP_VERSION")', '7.2'],
84+
['env("unknown_env_variable")', null],
85+
['sum(1, 2)', 3],
86+
['foo()', 'bar'],
87+
];
88+
}
89+
}

0 commit comments

Comments
 (0)