Installation
composer require egeloen/ordered-form-bundle
Add to config/bundles.php (Symfony 4+):
return [
// ...
Ivory\OrderedFormBundle\IvoryOrderedFormBundle::class => ['all' => true],
];
Enable in Form Type
Extend your form type with OrderedFormTypeInterface:
use Ivory\OrderedFormBundle\Form\Type\OrderedFormTypeInterface;
class MyFormType extends AbstractType implements OrderedFormTypeInterface
{
public function getOrderedFields()
{
return ['field1', 'field2', 'field3']; // Define order
}
}
First Use Case Use the form in a controller:
$form = $this->createForm(MyFormType::class, $entity);
$form->handleRequest($request);
Field Ordering
Define field order in getOrderedFields():
public function getOrderedFields()
{
return [
'parent_field' => ['child1', 'child2'], // Nested support
'sibling_field1',
'sibling_field2',
];
}
Dynamic Ordering
Override getOrderedFields() to fetch order from DB or config:
public function getOrderedFields()
{
return $this->configManager->getFieldOrder();
}
Integration with Symfony Forms
OrderedFormType as a base for complex forms.FormBuilder for hybrid approaches:
$builder->add('field1', TextType::class);
$builder->add('field2', TextType::class);
Nested Forms
Support nested structures (e.g., Address inside User):
public function getOrderedFields()
{
return [
'name',
'email',
'address' => ['street', 'city', 'zip'], // Nested
];
}
Validation & Submission Handle ordered data in controller:
if ($form->isSubmitted() && $form->isValid()) {
$orderedData = $form->getData();
// Process $orderedData in defined order
}
Field Name Mismatches
getOrderedFields() names exactly match form field names (case-sensitive).dump($form->getConfig()->getAttribute('ordered_fields'));
Circular References
User → Address → User). Use FormEvent listeners to break cycles.Symfony 5+ Deprecations
OrderedFormType in a custom type to avoid deprecation warnings:
class OrderedFormType extends AbstractType
{
public function getParent()
{
return Ivory\OrderedFormBundle\Form\Type\OrderedFormType::class;
}
}
CSRF & Ordering
OrderedFormType's built-in CSRF support:
$builder->add('csrf_token', CsrfTokenType::class);
Inspect Ordered Fields Add this to your form type to log the final order:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
dump($form->getConfig()->getAttribute('ordered_fields'));
});
}
Override Order Dynamically
Use PRE_SUBMIT event to modify order at runtime:
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getData();
$event->getForm()->getConfig()->setAttribute('ordered_fields', ['dynamic_field1', 'dynamic_field2']);
});
Custom Order Providers Create a service to fetch order from external sources (e.g., API):
# config/services.yaml
services:
App\OrderedFieldProvider:
arguments:
$apiClient: '@http_client'
Then inject into your form type:
public function __construct(private OrderedFieldProvider $provider) {}
public function getOrderedFields()
{
return $this->provider->getOrder();
}
Event-Driven Extensions
Listen to OrderedFormEvents::ORDER_CHANGED to react to order modifications:
$dispatcher->addListener(
OrderedFormEvents::ORDER_CHANGED,
function (OrderedFormEvent $event) {
// Log or transform the new order
}
);
Template Overrides
Extend the default Twig template (ordered_form.html.twig) to customize rendering:
{% extends 'ordered_form.html.twig' %}
{% block field_row %}
{{- form_row(form) -}}
{# Custom logic here #}
{% endblock %}
How can I help you explore Laravel packages today?