Skip to content

Commit 84925de

Browse files
committed
fix
1 parent dfbe8ea commit 84925de

File tree

9 files changed

+155
-78
lines changed

9 files changed

+155
-78
lines changed

phpstan-baseline.neon

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
parameters:
2+
ignoreErrors:
3+
-
4+
message: "#^Dead catch \\- Throwable is never thrown in the try block\\.$#"
5+
count: 1
6+
path: src/Component/FieldTypes/CallableFieldType.php

phpstan.neon

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
includes:
2+
- phpstan-baseline.neon
3+
24
- vendor/phpstan/phpstan-webmozart-assert/extension.neon
35
- vendor/phpstan/phpstan-phpunit/extension.neon
46

src/Bundle/Renderer/TwigGridRenderer.php

+19-5
Original file line numberDiff line numberDiff line change
@@ -37,32 +37,42 @@ final class TwigGridRenderer implements GridRendererInterface
3737

3838
private FormTypeRegistryInterface $formTypeRegistry;
3939

40-
private OptionsParserInterface $optionsParser;
41-
4240
private string $defaultTemplate;
4341

4442
private array $actionTemplates;
4543

4644
private array $filterTemplates;
4745

46+
private ?OptionsParserInterface $optionsParser;
47+
4848
public function __construct(
4949
Environment $twig,
5050
ServiceRegistryInterface $fieldsRegistry,
5151
FormFactoryInterface $formFactory,
5252
FormTypeRegistryInterface $formTypeRegistry,
53-
OptionsParserInterface $optionsParser,
5453
string $defaultTemplate,
5554
array $actionTemplates = [],
5655
array $filterTemplates = [],
56+
?OptionsParserInterface $optionsParser = null,
5757
) {
5858
$this->twig = $twig;
5959
$this->fieldsRegistry = $fieldsRegistry;
6060
$this->formFactory = $formFactory;
6161
$this->formTypeRegistry = $formTypeRegistry;
62-
$this->optionsParser = $optionsParser;
6362
$this->defaultTemplate = $defaultTemplate;
6463
$this->actionTemplates = $actionTemplates;
6564
$this->filterTemplates = $filterTemplates;
65+
$this->optionsParser = $optionsParser;
66+
67+
if (null === $optionsParser) {
68+
trigger_deprecation(
69+
'sylius/grid-bundle',
70+
'1.14',
71+
'Not passing an instance of "%s" as the eighth constructor argument of "%s" is deprecated.',
72+
OptionsParserInterface::class,
73+
self::class,
74+
);
75+
}
6676
}
6777

6878
public function render(GridViewInterface $gridView, ?string $template = null)
@@ -77,7 +87,11 @@ public function renderField(GridViewInterface $gridView, Field $field, $data)
7787
$resolver = new OptionsResolver();
7888
$fieldType->configureOptions($resolver);
7989

80-
$options = $resolver->resolve($this->optionsParser->parseOptions($field->getOptions()));
90+
$options = $field->getOptions();
91+
if (null !== $this->optionsParser) {
92+
$options = $this->optionsParser->parseOptions($options);
93+
}
94+
$options = $resolver->resolve($options);
8195

8296
return $fieldType->render($field, $data, $options);
8397
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020
<argument type="service" id="sylius.registry.grid_field" />
2121
<argument type="service" id="form.factory" />
2222
<argument type="service" id="sylius.form_registry.grid_filter" />
23-
<argument type="service" id="sylius.grid.options_parser" />
2423
<argument>@SyliusGrid/_grid.html.twig</argument>
2524
<argument>%sylius.grid.templates.action%</argument>
2625
<argument>%sylius.grid.templates.filter%</argument>
26+
<argument type="service" id="sylius.grid.options_parser" />
2727
</service>
2828
<service id="Sylius\Bundle\GridBundle\Renderer\TwigGridRenderer" alias="sylius.grid.renderer.twig" />
2929

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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\Bundle\GridBundle\Tests\Unit\Parser;
15+
16+
use PHPUnit\Framework\TestCase;
17+
use Sylius\Bundle\GridBundle\Parser\OptionsParser;
18+
use Sylius\Bundle\GridBundle\Parser\OptionsParserInterface;
19+
20+
final class OptionsParserTest extends TestCase
21+
{
22+
public function testItImplementsOptionsParserInterface(): void
23+
{
24+
$this->assertInstanceOf(OptionsParserInterface::class, new OptionsParser());
25+
}
26+
27+
public function testItParserOptionsWithCallable(): void
28+
{
29+
$options = (new OptionsParser())->parseOptions([
30+
'type' => 'callable',
31+
'option' => [
32+
'callable' => 'callable:strtoupper',
33+
],
34+
'label' => 'app.ui.id',
35+
]);
36+
37+
$this->assertArrayHasKey('type', $options);
38+
$this->assertArrayHasKey('option', $options);
39+
$this->assertArrayHasKey('label', $options);
40+
41+
$this->assertIsCallable($options['option']['callable'] ?? null);
42+
}
43+
44+
public function testItFailsWhileParsingOptionsWithInvalidCallable(): void
45+
{
46+
$this->expectException(\RuntimeException::class);
47+
48+
$options = (new OptionsParser())->parseOptions([
49+
'type' => 'callable',
50+
'option' => [
51+
'callable' => 'callable:foobar',
52+
],
53+
'label' => 'app.ui.id',
54+
]);
55+
}
56+
}

src/Bundle/spec/Parser/OptionsParserSpec.php

-70
This file was deleted.

src/Bundle/spec/Renderer/TwigGridRendererSpec.php

+45-1
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ function let(
5151
$fieldsRegistry,
5252
$formFactory,
5353
$formTypeRegistry,
54-
$optionsParser,
5554
'"@SyliusGrid/default"',
5655
$actionTemplates,
5756
$filterTemplates,
57+
$optionsParser,
5858
);
5959
}
6060

@@ -116,6 +116,50 @@ function it_renders_a_field_with_data_via_appropriate_field_type(
116116
$this->renderField($gridView, $field, 'Value')->shouldReturn('<strong>Value</strong>');
117117
}
118118

119+
function it_renders_a_field_with_data_via_appropriate_field_type_when_no_option_parser_is_provided(
120+
Environment $twig,
121+
ServiceRegistryInterface $fieldsRegistry,
122+
FormFactoryInterface $formFactory,
123+
FormTypeRegistryInterface $formTypeRegistry,
124+
GridViewInterface $gridView,
125+
Field $field,
126+
FieldTypeInterface $fieldType,
127+
): void {
128+
$actionTemplates = [
129+
'link' => '@SyliusGrid/Action/_link.html.twig',
130+
'form' => '@SyliusGrid/Action/_form.html.twig',
131+
];
132+
$filterTemplates = [
133+
StringFilter::NAME => '@SyliusGrid/Filter/_string.html.twig',
134+
];
135+
136+
$this->beConstructedWith(
137+
$twig,
138+
$fieldsRegistry,
139+
$formFactory,
140+
$formTypeRegistry,
141+
'"@SyliusGrid/default"',
142+
$actionTemplates,
143+
$filterTemplates,
144+
null,
145+
);
146+
147+
$field->getType()->willReturn('string');
148+
$fieldsRegistry->get('string')->willReturn($fieldType);
149+
$fieldType->configureOptions(Argument::type(OptionsResolver::class))
150+
->will(function ($args) {
151+
$args[0]->setRequired('foo');
152+
})
153+
;
154+
155+
$field->getOptions()->willReturn([
156+
'foo' => 'bar',
157+
]);
158+
$fieldType->render($field, 'Value', ['foo' => 'bar'])->willReturn('<strong>Value</strong>');
159+
160+
$this->renderField($gridView, $field, 'Value')->shouldReturn('<strong>Value</strong>');
161+
}
162+
119163
function it_throws_an_exception_if_template_is_not_configured_for_given_action_type(
120164
GridViewInterface $gridView,
121165
Action $action,

src/Component/FieldTypes/CallableFieldType.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,13 @@ public function __construct(private DataExtractorInterface $dataExtractor)
2626
public function render(Field $field, $data, array $options): string
2727
{
2828
$value = $this->dataExtractor->get($field, $data);
29-
$value = (string) call_user_func($options['callable'], $value);
29+
$value = call_user_func($options['callable'], $value);
30+
31+
try {
32+
$value = (string) $value;
33+
} catch (\Throwable $e) {
34+
throw new \RuntimeException(\sprintf('The callback for field "%s" returned a value that could not be converted to string.', $field->getName()));
35+
}
3036

3137
if ($options['htmlspecialchars']) {
3238
$value = htmlspecialchars($value);

src/Component/spec/FieldTypes/CallableFieldTypeSpec.php

+19
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,25 @@ function it_uses_data_extractor_to_obtain_data_and_passes_it_to_a_static_callabl
7878
])->shouldReturn('bar');
7979
}
8080

81+
function it_throws_an_exception_when_a_callable_return_value_cannot_be_casted_to_string(
82+
DataExtractorInterface $dataExtractor,
83+
Field $field,
84+
): void {
85+
$field->getName()->willReturn('id');
86+
$dataExtractor->get($field, ['foo' => 'bar'])->willReturn('BAR');
87+
88+
$this
89+
->shouldThrow(\RuntimeException::class)
90+
->during('render', [
91+
$field,
92+
['foo' => 'bar'],
93+
[
94+
'callable' => fn () => new \stdclass(),
95+
'htmlspecialchars' => true,
96+
],
97+
]);
98+
}
99+
81100
static function callable(mixed $value): string
82101
{
83102
return strtolower($value);

0 commit comments

Comments
 (0)