In those examples, we assume calling the builder from a form type class definition or a controller, using help of this closure :
$class = function ($object) {
$FQCN = get_class($object);
$class = explode('\\', $FQCN);
return end($class);
};
Types: string
, callable
or Symfony\\Component\\Form\\FormTypeInterface
Default: Symfony\\Component\\Form\\Extension\\Core\\Type\\TextType
(BC)
A string keeps the old behavior, a legacy logic so full BC here.
When it is a callable, it will be passed each entry as first argument and the index as second argument, allowing to use a polymorphic collection :
// given:
abstract class \CoreBundle\Entity\Ticket { ... }
class \AppBundle\Entity\Issue extends \CoreBundle\Entity\Ticket {}
class \AppBundle\Entity\PullRequest extends \CoreBundle\Entity\Ticket {}
class Todo
{
// ...
$tickets;
}
// use:
// TodoFormType::buildForm() with a private EntityManager property
$collection = $this->em->getRepository('CoreBundle\Entity\Ticket')->findAll();
$builder->add('tickets', CollectionType::class, array(
'entry_type_map' => function ($entry) {
if ($entry instanceof \AppBundle\Entity\Issue) {
return 'CoreBundle\Form\Type\\'.ucfirst($entry->getState()).'IssueType';
}
return 'AppBundle\Form\PullRequestType',
},
'data' => $collection,
));
Note
Its usage should deprecate the entry_type
option.
Types: null
, string
, callable
or Symfony\\Component\\PropertyAccessor\\PropertyPath
Default: entry keys or numerical index (BC)
The index name is a string defining the name of the field in the form.
It should be unique for each entry. If generated indexes are not unique, an incrementing numeric index will be used instead.
A string will be converted to PropertyPath
:
$builder->add('tickets', CollectionType::class, array(
'entry_type_map' => function ($entry) {
return 'AppBundle\Form\Type\\'.$class($entry).'Type';
},
'entry_index' => 'ref',
));
Behind the scene, the Symfony\\Component\\Form\\Extension\\Core\\Listener\\ResizeCollectionListListener
will perform (maybe not not exactly in that call but this is the idea of what's happening) :
$builder->add($entry->getRef(), $collection->getTypeforEntry($entry), $options);
for each entry of the collection.
Defined as a callable, it get passed each entry as only argument :
$builder->add('tickets', CollectionType::class, array(
'entry_type_map' => 'AppBundle\Form\Type\TicketType',
'entry_index' => function ($entry) {
return 'ticket_'.$entry->getOptionLabel());
// could return 'ticket_symfony_symfony_pull_14050'
},
));
Tip
By extension this is also the default label when humanized in form theme. So it should stay shorter when intended, unless relying on dynamic entry_options
option to set the label.
Note
Using the second parameter in the callable of entry_type_map
option may be usefull when you define it with the entry_index
option :
$builder->add('tickets', CollectionType::class, array(
'entry_type_map' => function ($entry, $index) {
if (false !== strpos($index, 'pull') {
return 'CoreBundle\Form\Type\PullRequestType';
}
return 'Appbundle\Form\EditIssueType';
},
'entry_index' => function ($entry) {
return $entry->getOptionLabel;
// would return "symfony_symfony_issue_9835"
// and also "symfony_symfony-docs_issue_6144"
},
'data' => array_merge($collection, $docTickets()),
));
It is then possible to directly merge collections of any type easily, since $docTickets
and $collection
may have identic keys the merge will increment the keys. The option entry_index
allow an easier mapping when using allow_add
option.
Types: array
or callable
Default: array()
(BC)
Default array keeps BC.
Can also be a callable which get the entry passed as first argument, the field form type class as second, and the computed name with entry_index
or the original index by default as third.
$builder->add('tickets', CollectionType::class, array(
'entry_type_map' => ChoiceType::class,
'entry_index' => 'optionLabel',
'entry_options' => function ($entry, $type, $index) {
// $type = $collection->getTypeforEntry($entry)
// $index = $entry->getOptionLabel()
$options = array(
'data_class' => $entryClass = get_class($entry),
'label' => 'Tickets:',
);
if ('CoreBundle\Form\Type\IssueType' === $type) {
$options['choices'] = \CoreBundle\Entity\Issue::$states,
'expanded' => true,
$options['choice_attr'] = array('class' => 'option-issue');
if ($entry instanceof \AppBundle\Entity\Issue) {
$options['multiple'] = true;
}
}
if ('AppBundle\Form\Type\PullRequestType' === $type) {
$option['choice_attr'] = array('data-ref' => $index);
}
return $options;
},
));
Note
When this option is a callable, deprecated prototype_data
option or the data
key in prototype_options
option should be defined, so it can be managed when passed to it, otherwise null
case has to be handled in the callable.
Types: null
, string
, array
, callable
or Symfony\\Component\\PropertyAccessor\\PropertyPath
Default: null
(BC)
A string or array define one or more indexes that cannot be removed when using allow_delete
or delete_empty
.
Types: null
, string
, callable
, or Symony\Component\PropertyAccessor\PropertyPath
Default: null
Same as filter_choices
see this issue.
A callable taking each entry as only argument. Or a string or a PropertyPath
instance applied on each entry.
All cases must return a boolean, true
to keep the entry in the collection, false
to discard it.
same as empty_choices
option of ChoiceType
.
Should be deprecated in favor of prototype_options
.
For BC it should be allowed to be a callable or an array so data depends on the form type.
As for allow_add
, allow_delete
, delete_empty
.
Types: array
or callable
Default: value of entry_options
Overrides the name (index) option with prototype_name
value.
Types: string
, array
or callable
Default: __name__
Default use Symfony\Component\Form\Util\StringUtil::fqcnToBlockPrefix()
to prefix default "__name__" when the collection is polymorphic.
When it is a callable it takes the form type FQCN as only argument.
If it is an array, keys must be FQCN and values must be prototype names. A value without index (or with the integer 0
as key) will be used as default for all form types not provided as keys.
Note
Sould deprecate prototype_name
option.
Types: Boolean
, array
or callable
Default: false
When boolean, use the old way.
When using a polymorphic collection pass an array with form types FQCN as keys and boolean as values or a callable which takes the form type FQCN as only argument.