bug #15623 Fix the retrieval of the value with property path when using a loader (stof)
This PR was merged into the 2.7 branch.
Discussion
----------
Fix the retrieval of the value with property path when using a loader
| Q | A
| ------------- | ---
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | n/a
| License | MIT
| Doc PR | n/a
the ChoiceType is transforming the form data to its value in case of non-expanded fields.
When creating the choice list from choices, this works fine when using a property path for the choice_value, because it has a safeguard against values which are not object or arrays (a typical case being ``null`` because nothing is selected yet).
However, when loading from a ChoiceLoader, the generated closure was missing the same safeguard, breaking the usage of ChoiceLoader with property path.
This went unnoticed because the only usage of choice_loader in core is for the doctrine type, and this one uses its own logic to get the choice value
I added test on the PropertyAccessDecorator directly, to have fast tests. We could imagine adding tests in the ChoiceTypeTest using a ChoiceLoader too, matching all existing tests for other ways to specify arguments, but I'm not sure it is worth it.
Commits
-------
5df64dc
Fix the retrieval of the value with property path when using a loader
This commit is contained in:
commit
c9927bf277
@ -141,7 +141,13 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface
|
|||||||
if ($value instanceof PropertyPath) {
|
if ($value instanceof PropertyPath) {
|
||||||
$accessor = $this->propertyAccessor;
|
$accessor = $this->propertyAccessor;
|
||||||
$value = function ($choice) use ($accessor, $value) {
|
$value = function ($choice) use ($accessor, $value) {
|
||||||
|
// The callable may be invoked with a non-object/array value
|
||||||
|
// when such values are passed to
|
||||||
|
// ChoiceListInterface::getValuesForChoices(). Handle this case
|
||||||
|
// so that the call to getValue() doesn't break.
|
||||||
|
if (is_object($choice) || is_array($choice)) {
|
||||||
return $accessor->getValue($choice, $value);
|
return $accessor->getValue($choice, $value);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +93,36 @@ class PropertyAccessDecoratorTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertSame('value', $this->factory->createListFromLoader($loader, 'property'));
|
$this->assertSame('value', $this->factory->createListFromLoader($loader, 'property'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/symfony/symfony/issues/5494
|
||||||
|
public function testCreateFromChoicesAssumeNullIfValuePropertyPathUnreadable()
|
||||||
|
{
|
||||||
|
$choices = array(null);
|
||||||
|
|
||||||
|
$this->decoratedFactory->expects($this->once())
|
||||||
|
->method('createListFromChoices')
|
||||||
|
->with($choices, $this->isInstanceOf('\Closure'))
|
||||||
|
->will($this->returnCallback(function ($choices, $callback) {
|
||||||
|
return array_map($callback, $choices);
|
||||||
|
}));
|
||||||
|
|
||||||
|
$this->assertSame(array(null), $this->factory->createListFromChoices($choices, 'property'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/symfony/symfony/issues/5494
|
||||||
|
public function testCreateFromChoiceLoaderAssumeNullIfValuePropertyPathUnreadable()
|
||||||
|
{
|
||||||
|
$loader = $this->getMock('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface');
|
||||||
|
|
||||||
|
$this->decoratedFactory->expects($this->once())
|
||||||
|
->method('createListFromLoader')
|
||||||
|
->with($loader, $this->isInstanceOf('\Closure'))
|
||||||
|
->will($this->returnCallback(function ($loader, $callback) {
|
||||||
|
return $callback(null);
|
||||||
|
}));
|
||||||
|
|
||||||
|
$this->assertNull($this->factory->createListFromLoader($loader, 'property'));
|
||||||
|
}
|
||||||
|
|
||||||
public function testCreateFromLoaderPropertyPathInstance()
|
public function testCreateFromLoaderPropertyPathInstance()
|
||||||
{
|
{
|
||||||
$loader = $this->getMock('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface');
|
$loader = $this->getMock('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface');
|
||||||
|
Reference in New Issue
Block a user