Fix "Array was modified outside object" in ResizeFormListener.

The onSubmit() method of the ResizeFormListener class is assuming the data is an array, and calling unset directly inside a foreach. This works fine in most scenarios, but if data is an instance of IteratorAggregate, it breaks with the following error:

Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener::onSubmit(): ArrayIterator::next(): Array was modified outside object and internal position is no longer valid in ./vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php line 142

This is because the foreach loop is using an Iterator in the background, but the ResizeFormListener has unset the underlying data directly, causing the Iterator and data to be out of sync. When the data is an instance of IteratorAggregate, the loop should use the iterator directly and not rely on foreach.

The onSubmit method has been updated accordingly.
This commit is contained in:
Chekote 2014-02-10 15:46:13 -06:00 committed by Fabien Potencier
parent a1813cb57a
commit e62c0b5a2d
1 changed files with 15 additions and 3 deletions

View File

@ -139,9 +139,21 @@ class ResizeFormListener implements EventSubscriberInterface
// The data mapper only adds, but does not remove items, so do this
// here
if ($this->allowDelete) {
foreach ($data as $name => $child) {
if (!$form->has($name)) {
unset($data[$name]);
if ($data instanceof \IteratorAggregate) {
$iter = $data->getIterator();
while ($iter->valid()) {
$name = $iter->key();
if ($form->has($name)) {
$iter->next();
} else {
$iter->offsetUnset($name);
}
}
} else {
foreach ($data as $name => $child) {
if (!$form->has($name)) {
unset($data[$name]);
}
}
}
}