Skip to content

Commit 1fb1dda

Browse files
committed
Introduce ExpressionEvaluator
1 parent e73e717 commit 1fb1dda

22 files changed

+418
-31
lines changed

docs/field_types.md

-3
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,6 @@ This feature uses Symfony's expression language, making it versatile and powerfu
329329
The expression will be evaluated with the following context:
330330

331331
- `value`: The value of the row.
332-
- `container`: The Symfony container (only if the `container` option is enabled).
333332

334333
You can also control whether special characters in the output are escaped by setting the `htmlspecialchars` option.
335334
By default, this is enabled, but you can disable it if the output contains HTML elements that should render as HTML.
@@ -361,7 +360,6 @@ sylius_grid:
361360
label: app.ui.most_exensive_order_total
362361
options:
363362
expression: 'container.get("sylius.repository.order").findMostExpensiveOrder(value).getTotal()'
364-
needContainer: true
365363
```
366364
367365
</details>
@@ -389,7 +387,6 @@ return static function (GridConfig $grid): void {
389387
ExpressionField::create(
390388
'most_expensive_order_total',
391389
'container.get("sylius.repository.order").findMostExpensiveOrder(value).getTotal()',
392-
needContainer: true,
393390
)
394391
->setLabel('app.ui.most_exensive_order_total')
395392
)

src/Bundle/Builder/Field/ExpressionField.php

+1-4
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,10 @@ final class ExpressionField
1818
public static function create(
1919
string $name,
2020
string $expression,
21-
bool $needsContainer = false,
2221
bool $htmlspecialchars = true,
23-
): FieldInterface
24-
{
22+
): FieldInterface {
2523
return Field::create($name, 'expression')
2624
->setOption('expression', $expression)
27-
->setOption('needsContainer', $needsContainer)
2825
->setOption('htmlspecialchars', $htmlspecialchars)
2926
;
3027
}

src/Bundle/DependencyInjection/SyliusGridExtension.php

+17
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
use Sylius\Bundle\CurrencyBundle\SyliusCurrencyBundle;
1717
use Sylius\Bundle\GridBundle\Grid\GridInterface;
1818
use Sylius\Bundle\GridBundle\SyliusGridBundle;
19+
use Sylius\Component\Grid\Attribute\AsGridProvider;
20+
use Sylius\Component\Grid\Attribute\AsGridVariables;
1921
use Sylius\Component\Grid\Data\DataProviderInterface;
2022
use Sylius\Component\Grid\Filtering\FilterInterface;
2123
use Symfony\Component\Config\FileLocator;
24+
use Symfony\Component\DependencyInjection\ChildDefinition;
2225
use Symfony\Component\DependencyInjection\ContainerBuilder;
2326
use Symfony\Component\DependencyInjection\Extension\Extension;
2427
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
@@ -67,6 +70,20 @@ public function load(array $configs, ContainerBuilder $container): void
6770
$container->registerForAutoconfiguration(DataProviderInterface::class)
6871
->addTag('sylius.grid_data_provider')
6972
;
73+
74+
$container->registerAttributeForAutoconfiguration(
75+
AsGridVariables::class,
76+
static function (ChildDefinition $definition, AsGridVariables $attribute, \Reflector $reflector): void {
77+
$definition->addTag(AsGridVariables::SERVICE_TAG);
78+
},
79+
);
80+
81+
$container->registerAttributeForAutoconfiguration(
82+
AsGridProvider::class,
83+
static function (ChildDefinition $definition, AsGridProvider $attribute, \Reflector $reflector): void {
84+
$definition->addTag(AsGridProvider::SERVICE_TAG);
85+
},
86+
);
7087
}
7188

7289
public function getConfiguration(array $config, ContainerBuilder $container): Configuration

src/Bundle/Resources/config/services.xml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
1515
<imports>
16+
<import resource="services/expression_language.xml" />
1617
<import resource="services/field_types.xml" />
1718
<import resource="services/filters.xml" />
1819
<import resource="services/templating.xml" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<!--
4+
5+
This file is part of the Sylius package.
6+
7+
(c) Sylius Sp. z o.o.
8+
9+
For the full copyright and license information, please view the LICENSE
10+
file that was distributed with this source code.
11+
12+
-->
13+
14+
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
15+
<services>
16+
<service id="sylius.expression_language.grid.expression_language_factory" class="Sylius\Component\Grid\ExpressionLanguage\ExpressionLanguageFactory">
17+
<argument type="tagged_iterator" tag="sylius.grid.provider" />
18+
</service>
19+
20+
<service id="sylius.expression_language.grid.expression_language" class="Symfony\Component\ExpressionLanguage\ExpressionLanguage">
21+
<factory service="sylius.expression_language.grid.expression_language_factory" />
22+
</service>
23+
24+
<service id="sylius.expression_language.grid.expression_evaluator" class="Sylius\Component\Grid\ExpressionLanguage\ExpressionEvaluator">
25+
<argument type="service" id="sylius.expression_language.grid.expression_language" />
26+
<argument type="service" id="sylius.expression_language.grid.variables_collection" />
27+
</service>
28+
29+
<service id="sylius.expression_language.grid.variables_collection" class="Sylius\Component\Grid\ExpressionLanguage\VariableCollection">
30+
<argument type="tagged_iterator" tag="sylius.grid.variables" />
31+
</service>
32+
</services>
33+
</container>

src/Bundle/Resources/config/services/field_types.xml

+1-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424

2525
<service id="Sylius\Component\Grid\FieldTypes\ExpressionFieldType">
2626
<argument type="service" id="sylius.grid.data_extractor" />
27-
<argument type="service" id="sylius.expression_language" />
28-
<argument type="service" id="service_container" />
27+
<argument type="service" id="sylius.expression_language.grid.expression_evaluator" />
2928
<tag name="sylius.grid_field" type="expression" />
3029
</service>
3130
<service id="sylius.grid_field.expression" alias="Sylius\Component\Grid\FieldTypes\ExpressionFieldType" />

src/Bundle/Tests/Functional/GridUiTest.php

+31
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,27 @@ public function it_filters_books_by_title(): void
101101
$this->assertSame('Book 5', $titles[0]);
102102
}
103103

104+
/** @test */
105+
public function it_shows_books_prices(): void
106+
{
107+
$this->client->request('GET', '/books/');
108+
109+
$prices = $this->getBookPriceFromResponse();
110+
111+
$this->assertEquals([
112+
'42 €',
113+
'10 £',
114+
'42 €',
115+
'10 £',
116+
'42 €',
117+
'42 €',
118+
'42 €',
119+
'10 £',
120+
'42 €',
121+
'42 €',
122+
], $prices);
123+
}
124+
104125
/** @test */
105126
public function it_filters_books_by_title_with_contains(): void
106127
{
@@ -274,6 +295,16 @@ private function getBookAuthorNationalitiesFromResponse(): array
274295
);
275296
}
276297

298+
/** @return string[] */
299+
private function getBookPriceFromResponse(): array
300+
{
301+
return $this->getCrawler()
302+
->filter('[data-test-price]')
303+
->each(
304+
fn (Crawler $node): string => $node->text(),
305+
);
306+
}
307+
277308
/** @return string[] */
278309
private function getAuthorNamesFromResponse(): array
279310
{
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
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+
declare(strict_types=1);
13+
14+
namespace Sylius\Component\Grid\Attribute;
15+
16+
#[\Attribute(\Attribute::TARGET_CLASS)]
17+
final class AsGridProvider
18+
{
19+
public const SERVICE_TAG = 'sylius.grid.provider';
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
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+
declare(strict_types=1);
13+
14+
namespace Sylius\Component\Grid\Attribute;
15+
16+
#[\Attribute(\Attribute::TARGET_CLASS)]
17+
final class AsGridVariables
18+
{
19+
public const SERVICE_TAG = 'sylius.grid.variables';
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
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+
declare(strict_types=1);
13+
14+
namespace Sylius\Component\Grid\ExpressionLanguage;
15+
16+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
17+
18+
/**
19+
* @experimental
20+
*/
21+
final class ExpressionEvaluator implements ExpressionEvaluatorInterface
22+
{
23+
public function __construct(
24+
private ExpressionLanguage $expressionLanguage,
25+
private VariablesCollectionInterface $variablesCollection,
26+
) {
27+
}
28+
29+
public function evaluateExpression(string $expression, array $variables = []): mixed
30+
{
31+
return $this->expressionLanguage->evaluate(
32+
$expression,
33+
array_merge(
34+
$this->variablesCollection->getCollection(),
35+
$variables,
36+
),
37+
);
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
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+
declare(strict_types=1);
13+
14+
namespace Sylius\Component\Grid\ExpressionLanguage;
15+
16+
/**
17+
* @experimental
18+
*/
19+
interface ExpressionEvaluatorInterface
20+
{
21+
public function evaluateExpression(string $expression, array $variables = []): mixed;
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
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+
declare(strict_types=1);
13+
14+
namespace Sylius\Component\Grid\ExpressionLanguage;
15+
16+
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
17+
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
18+
use Webmozart\Assert\Assert;
19+
20+
/**
21+
* @experimental
22+
*/
23+
final class ExpressionLanguageFactory
24+
{
25+
/** @param iterable<int, ExpressionFunctionProviderInterface> $providers */
26+
public function __construct(private $providers)
27+
{
28+
Assert::allIsInstanceOf($this->providers, ExpressionFunctionProviderInterface::class);
29+
}
30+
31+
public function __invoke(): ExpressionLanguage
32+
{
33+
$expressionLanguage = new ExpressionLanguage();
34+
35+
foreach ($this->providers as $provider) {
36+
$expressionLanguage->registerProvider($provider);
37+
}
38+
39+
return $expressionLanguage;
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
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+
declare(strict_types=1);
13+
14+
namespace Sylius\Component\Grid\ExpressionLanguage;
15+
16+
use Webmozart\Assert\Assert;
17+
18+
/**
19+
* @experimental
20+
*/
21+
final class VariableCollection implements VariablesCollectionInterface
22+
{
23+
/** @param iterable<int, VariablesCollectionInterface> $variablesCollection */
24+
public function __construct(private $variablesCollection)
25+
{
26+
Assert::allIsInstanceOf($this->variablesCollection, VariablesCollectionInterface::class);
27+
}
28+
29+
public function getCollection(): array
30+
{
31+
$collections = [];
32+
foreach ($this->variablesCollection as $collection) {
33+
$collections[] = $collection->getCollection();
34+
}
35+
36+
return array_merge(...$collections);
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
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+
declare(strict_types=1);
13+
14+
namespace Sylius\Component\Grid\ExpressionLanguage;
15+
16+
/**
17+
* @experimental
18+
*/
19+
interface VariablesCollectionInterface
20+
{
21+
/**
22+
* @return array<string, mixed>
23+
*/
24+
public function getCollection(): array;
25+
}

0 commit comments

Comments
 (0)