Skip to content

Commit 191b495

Browse files
author
hamza
committed
fix #17993 - Deprecated callable strings
ext
1 parent d479934 commit 191b495

File tree

5 files changed

+186
-0
lines changed

5 files changed

+186
-0
lines changed

UPGRADE-3.1.md

+19
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,25 @@ Form
1919
* Support for data objects that implements both `Traversable` and `ArrayAccess`
2020
in `ResizeFormListener::preSubmit` method has been deprecated and will be
2121
removed in Symfony 4.0.
22+
23+
* Using callable strings as choice options in ChoiceType has been deprecated
24+
in favor of `PropertyPath` in Symfony 4.0 use a "\Closure" instead.
25+
26+
Before:
27+
28+
```php
29+
'choice_value' => new PropertyPath('range'),
30+
'choice_label' => 'strtoupper',
31+
```
32+
33+
After:
34+
35+
```php
36+
'choice_value' => 'range',
37+
'choice_label' => function ($choice) {
38+
return strtoupper($choice);
39+
},
40+
```
2241

2342
FrameworkBundle
2443
---------------

UPGRADE-4.0.md

+20
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,26 @@ Form
1616

1717
* Support for data objects that implements both `Traversable` and
1818
`ArrayAccess` in `ResizeFormListener::preSubmit` method has been removed.
19+
20+
* Using callable strings as choice options in ChoiceType is not supported
21+
anymore in favor of passing PropertyPath instances.
22+
23+
Before:
24+
25+
```php
26+
'choice_value' => new PropertyPath('range'),
27+
'choice_label' => 'strtoupper',
28+
```
29+
30+
After:
31+
32+
```php
33+
'choice_value' => 'range',
34+
'choice_label' => function ($choice) {
35+
return strtoupper($choice);
36+
},
37+
```
38+
1939

2040
FrameworkBundle
2141
---------------

src/Symfony/Component/Form/CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ CHANGELOG
77
* deprecated the "choices_as_values" option of ChoiceType
88
* deprecated support for data objects that implements both `Traversable` and
99
`ArrayAccess` in `ResizeFormListener::preSubmit` method
10+
11+
* Using callable strings as choice options in `ChoiceType` has been deprecated
12+
and will be used as `PropertyPath` instead of callable in Symfony 4.0.
1013

1114
3.0.0
1215
-----

src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php

+14
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ public function createListFromChoices($choices, $value = null)
8686
{
8787
if (is_string($value) && !is_callable($value)) {
8888
$value = new PropertyPath($value);
89+
} elseif (is_string($value) && is_callable($value)) {
90+
@trigger_error('Passing callable strings is deprecated since version 3.1 and PropertyAccessDecorator will treat them as property paths in 4.0. You should use a "\Closure" instead.', E_USER_DEPRECATED);
8991
}
9092

9193
if ($value instanceof PropertyPath) {
@@ -117,6 +119,8 @@ public function createListFromLoader(ChoiceLoaderInterface $loader, $value = nul
117119
{
118120
if (is_string($value) && !is_callable($value)) {
119121
$value = new PropertyPath($value);
122+
} elseif (is_string($value) && is_callable($value)) {
123+
@trigger_error('Passing callable strings is deprecated since version 3.1 and PropertyAccessDecorator will treat them as property paths in 4.0. You should use a "\Closure" instead.', E_USER_DEPRECATED);
120124
}
121125

122126
if ($value instanceof PropertyPath) {
@@ -153,6 +157,8 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null,
153157

154158
if (is_string($label) && !is_callable($label)) {
155159
$label = new PropertyPath($label);
160+
} elseif (is_string($label) && is_callable($label)) {
161+
@trigger_error('Passing callable strings is deprecated since version 3.1 and PropertyAccessDecorator will treat them as property paths in 4.0. You should use a "\Closure" instead.', E_USER_DEPRECATED);
156162
}
157163

158164
if ($label instanceof PropertyPath) {
@@ -163,6 +169,8 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null,
163169

164170
if (is_string($preferredChoices) && !is_callable($preferredChoices)) {
165171
$preferredChoices = new PropertyPath($preferredChoices);
172+
} elseif (is_string($preferredChoices) && is_callable($preferredChoices)) {
173+
@trigger_error('Passing callable strings is deprecated since version 3.1 and PropertyAccessDecorator will treat them as property paths in 4.0. You should use a "\Closure" instead.', E_USER_DEPRECATED);
166174
}
167175

168176
if ($preferredChoices instanceof PropertyPath) {
@@ -178,6 +186,8 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null,
178186

179187
if (is_string($index) && !is_callable($index)) {
180188
$index = new PropertyPath($index);
189+
} elseif (is_string($index) && is_callable($index)) {
190+
@trigger_error('Passing callable strings is deprecated since version 3.1 and PropertyAccessDecorator will treat them as property paths in 4.0. You should use a "\Closure" instead.', E_USER_DEPRECATED);
181191
}
182192

183193
if ($index instanceof PropertyPath) {
@@ -188,6 +198,8 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null,
188198

189199
if (is_string($groupBy) && !is_callable($groupBy)) {
190200
$groupBy = new PropertyPath($groupBy);
201+
} elseif (is_string($groupBy) && is_callable($groupBy)) {
202+
@trigger_error('Passing callable strings is deprecated since version 3.1 and PropertyAccessDecorator will treat them as property paths in 4.0. You should use a "\Closure" instead.', E_USER_DEPRECATED);
191203
}
192204

193205
if ($groupBy instanceof PropertyPath) {
@@ -202,6 +214,8 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null,
202214

203215
if (is_string($attr) && !is_callable($attr)) {
204216
$attr = new PropertyPath($attr);
217+
} elseif (is_string($attr) && is_callable($attr)) {
218+
@trigger_error('Passing callable strings is deprecated since version 3.1 and PropertyAccessDecorator will treat them as property paths in 4.0. You should use a "\Closure" instead.', E_USER_DEPRECATED);
205219
}
206220

207221
if ($attr instanceof PropertyPath) {

src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php

+130
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,21 @@ public function testCreateFromChoicesPropertyPathInstance()
6363
$this->assertSame(array('value'), $this->factory->createListFromChoices($choices, new PropertyPath('property')));
6464
}
6565

66+
/**
67+
* @group legacy
68+
*/
69+
public function testCreateFromChoicesPropertyPathWithCallableString()
70+
{
71+
$choices = array('foo' => 'bar');
72+
73+
$this->decoratedFactory->expects($this->once())
74+
->method('createListFromChoices')
75+
->with($choices, 'end')
76+
->willReturn('RESULT');
77+
78+
$this->assertSame('RESULT', $this->factory->createListFromChoices($choices, 'end'));
79+
}
80+
6681
public function testCreateFromLoaderPropertyPath()
6782
{
6883
$loader = $this->getMock('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface');
@@ -77,6 +92,21 @@ public function testCreateFromLoaderPropertyPath()
7792
$this->assertSame('value', $this->factory->createListFromLoader($loader, 'property'));
7893
}
7994

95+
/**
96+
* @group legacy
97+
*/
98+
public function testCreateFromLoaderPropertyPathWithCallableString()
99+
{
100+
$loader = $this->getMock('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface');
101+
102+
$this->decoratedFactory->expects($this->once())
103+
->method('createListFromLoader')
104+
->with($loader, 'end')
105+
->willReturn('RESULT');
106+
107+
$this->assertSame('RESULT', $this->factory->createListFromLoader($loader, 'end'));
108+
}
109+
80110
// https://github.com/symfony/symfony/issues/5494
81111
public function testCreateFromChoicesAssumeNullIfValuePropertyPathUnreadable()
82112
{
@@ -138,6 +168,24 @@ public function testCreateViewPreferredChoicesAsPropertyPath()
138168
));
139169
}
140170

171+
/**
172+
* @group legacy
173+
*/
174+
public function testCreateViewPreferredChoicesAsPropertyPathWithCallableString()
175+
{
176+
$list = $this->getMock('Symfony\Component\Form\ChoiceList\ChoiceListInterface');
177+
178+
$this->decoratedFactory->expects($this->once())
179+
->method('createView')
180+
->with($list, 'end')
181+
->willReturn('RESULT');
182+
183+
$this->assertSame('RESULT',$this->factory->createView(
184+
$list,
185+
'end'
186+
));
187+
}
188+
141189
public function testCreateViewPreferredChoicesAsPropertyPathInstance()
142190
{
143191
$list = $this->getMock('Symfony\Component\Form\ChoiceList\ChoiceListInterface');
@@ -191,6 +239,25 @@ public function testCreateViewLabelsAsPropertyPath()
191239
));
192240
}
193241

242+
/**
243+
* @group legacy
244+
*/
245+
public function testCreateViewLabelsAsPropertyPathWithCallableString()
246+
{
247+
$list = $this->getMock('Symfony\Component\Form\ChoiceList\ChoiceListInterface');
248+
249+
$this->decoratedFactory->expects($this->once())
250+
->method('createView')
251+
->with($list, null, 'end')
252+
->willReturn('RESULT');
253+
254+
$this->assertSame('RESULT', $this->factory->createView(
255+
$list,
256+
null, // preferred choices
257+
'end'
258+
));
259+
}
260+
194261
public function testCreateViewLabelsAsPropertyPathInstance()
195262
{
196263
$list = $this->getMock('Symfony\Component\Form\ChoiceList\ChoiceListInterface');
@@ -228,6 +295,26 @@ public function testCreateViewIndicesAsPropertyPath()
228295
));
229296
}
230297

298+
/**
299+
* @group legacy
300+
*/
301+
public function testCreateViewIndicesAsPropertyPathWithCallableString()
302+
{
303+
$list = $this->getMock('Symfony\Component\Form\ChoiceList\ChoiceListInterface');
304+
305+
$this->decoratedFactory->expects($this->once())
306+
->method('createView')
307+
->with($list, null, null, 'end')
308+
->willReturn('RESULT');
309+
310+
$this->assertSame('RESULT', $this->factory->createView(
311+
$list,
312+
null, // preferred choices
313+
null, // label
314+
'end'
315+
));
316+
}
317+
231318
public function testCreateViewIndicesAsPropertyPathInstance()
232319
{
233320
$list = $this->getMock('Symfony\Component\Form\ChoiceList\ChoiceListInterface');
@@ -267,6 +354,27 @@ public function testCreateViewGroupsAsPropertyPath()
267354
));
268355
}
269356

357+
/**
358+
* @group legacy
359+
*/
360+
public function testCreateViewGroupsAsPropertyPathWithCallableString()
361+
{
362+
$list = $this->getMock('Symfony\Component\Form\ChoiceList\ChoiceListInterface');
363+
364+
$this->decoratedFactory->expects($this->once())
365+
->method('createView')
366+
->with($list, null, null, null, 'end')
367+
->willReturn('RESULT');
368+
369+
$this->assertSame('RESULT', $this->factory->createView(
370+
$list,
371+
null, // preferred choices
372+
null, // label
373+
null, // index
374+
'end'
375+
));
376+
}
377+
270378
public function testCreateViewGroupsAsPropertyPathInstance()
271379
{
272380
$list = $this->getMock('Symfony\Component\Form\ChoiceList\ChoiceListInterface');
@@ -329,6 +437,28 @@ public function testCreateViewAttrAsPropertyPath()
329437
));
330438
}
331439

440+
/**
441+
* @group legacy
442+
*/
443+
public function testCreateViewAttrAsPropertyPathWithCallableString()
444+
{
445+
$list = $this->getMock('Symfony\Component\Form\ChoiceList\ChoiceListInterface');
446+
447+
$this->decoratedFactory->expects($this->once())
448+
->method('createView')
449+
->with($list, null, null, null, null, 'end')
450+
->willReturn('RESULT');
451+
452+
$this->assertSame('RESULT', $this->factory->createView(
453+
$list,
454+
null, // preferred choices
455+
null, // label
456+
null, // inde
457+
null, // groups
458+
'end'
459+
));
460+
}
461+
332462
public function testCreateViewAttrAsPropertyPathInstance()
333463
{
334464
$list = $this->getMock('Symfony\Component\Form\ChoiceList\ChoiceListInterface');

0 commit comments

Comments
 (0)