Description
Symfony version(s) affected: 3.4.*|4.* (Probably also 2.7+?)
Description
If you enable the option in the framework to throw exceptions on invalid index for the propery accessor:
framework:
property_access:
throw_exception_on_invalid_index: true
(Which I think should be the default behavior by the way, but this is outside the scope of this bug)
When you have a form using a CollectionType
, the PropertyPathMapper
will crash when trying to access invalid indexes when the ResizeFormListener
adds a new field to the form. (Which happens when you add an element to your collection)
How to reproduce
On a Symfony 3.4 standard edition, enable the throw_exception_on_invalid_index
option as mentionned before.
Then use this code in the DefaultController
class DefaultController extends Controller
{
/**
* @Route("/", name="homepage")
*
* @param Request $request
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function indexAction(Request $request)
{
$formBuilder = $this->createFormBuilder(['collection' => ['test']]);
$formBuilder->add(
'collection',
CollectionType::class,
[
'allow_add' => true,
'entry_type' => TextType::class,
]
);
$form = $formBuilder->getForm();
$form->handleRequest($request);
return $this->render(
'default/index.html.twig',
[
'form' => $form->createView(),
]
);
}
}
And this code for the template:
{% extends 'base.html.twig' %}
{% block body %}
{{ form_start(form) }}
{{ form_widget(form) }}
<input type="text" name="form[collection][1]" value="invalid index">
<button type="submit">Submit</button>
{{ form_end(form) }}
{% endblock %}
This adds the element manually because this a the simplest way to test this.
Submit : Crash
Cannot read index "1" while trying to traverse path "[1]". Available indices are "Array
(
[0] => 0
)
".
Possible Solutions
There are many way to tackle this problem :
- Remove the
throw_exception_on_invalid_index
option if it's not meant to be used (I'm against this because I think it should be true by default) - Inject a custom
PropertyAccessor
in thePropertyPathMapper
; notform.property_accessor
. (I find this solution a bit strange) - Make the
form.property_accessor
ignore any settings from theframework.property_accessor.\*
configuration. - Catch the exception properly inside the
PropertyPathMapper
- Create a custom
CollectionPropertyPathMapper
only for theCollectionType
that uses a dedicated property accessor that ignores the global setting. - Create a custom
CollectionPropertyPathMapper
only for theCollectionType
that catches the exception properly. (I'm in favor of this one)