Installation Add the package via Composer:
composer require sonata-project/form-extensions
Register the bundle in config/app.php (Symfony/Laravel bridge required):
'providers' => [
// ...
SonataProject\Form\Extensions\Provider\SonataFormExtensionsServiceProvider::class,
],
Basic Usage
Extend a Symfony form type (e.g., EntityType) with Sonata’s extensions:
use Sonata\Form\Extensions\Type\CollectionType;
use Sonata\Form\Extensions\Type\ChoiceType;
$builder
->add('tags', CollectionType::class, [
'entry_type' => ChoiceType::class,
'entry_options' => ['choices' => $tagChoices],
]);
First Use Case
Replace nested forms or complex collections with Sonata’s CollectionType for drag-and-drop or inline editing:
$builder->add('items', CollectionType::class, [
'prototype' => true, // Enables inline editing
'allow_add' => true,
'allow_delete' => true,
]);
Dynamic Collections
Use CollectionType for forms with variable-length arrays (e.g., user roles, product options):
$builder->add('roles', CollectionType::class, [
'entry_type' => EntityType::class,
'entry_options' => ['class' => UserRole::class],
'by_reference' => false,
]);
Conditional Fields
Leverage ConditionalFieldExtension to show/hide fields based on parent values:
$builder->add('shipping', TextType::class, [
'conditionally_enabled' => ['field' => 'needs_shipping'],
]);
Grouped Fields
Organize fields into collapsible sections with GroupType:
$builder->add('billing', GroupType::class, [
'fields' => ['address', 'city', 'zip'],
'label' => 'Billing Information',
]);
Symfony\Component\Form\FormFactory via Laravel’s service container:
$formFactory = app(Symfony\Component\Form\FormFactory::class);
$form = $formFactory->createBuilder()->getForm();
sonata_form_field.html.twig):
{% extends 'SonataForm::standard_layout.html.twig' %}
Callback, Expression) for custom logic:
$builder->add('age', IntegerType::class, [
'constraints' => [new Callback([$validator, 'validateAge'])],
]);
Prototype Cloning
prototype: true may duplicate hidden fields in the DOM.prototype_name to scope cloned fields:
'prototype_name' => '__name__', // Unique identifier
By-Reference Pitfalls
by_reference: true can cause detached entities in collections.by_reference: false for detached entities or use ORM\Mapping\ClassMetadata.CSRF in AJAX
_token in AJAX requests or use Symfony\Bridge\Twig\Extension\FormExtension:
{{ form_start(form, {'attr': {'id': 'dynamic-form'}}) }}
dump() to inspect form data:
dd($form->getData());
PRE_SET_DATA/POST_SUBMIT:
$builder->addEventListener(FormEvents::PRE_SET_DATA, function ($event) {
dump($event->getData());
});
Custom Types
Extend AbstractType to create reusable form types:
class CustomCollectionType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('items', CollectionType::class, [
'entry_type' => $options['entry_type'],
]);
}
}
Override Templates
Override Sonata’s Twig templates in resources/views/vendor/sonata_form/:
{# resources/views/vendor/sonata_form/field/collection.html.twig #}
Configuration Quirks
CollectionType) have strict defaults. Override them explicitly:
'allow_add' => true, // Defaults to false
'allow_delete' => true,
How can I help you explore Laravel packages today?