Installation:
composer require braunstetter/valid-form-event
Add the bundle to config/bundles.php (Symfony) or register it in config/app.php (Laravel via Symfony bridge):
Braunstetter\ValidFormEventBundle\ValidFormEventBundle::class => ['all' => true],
First Use Case:
App\Form\MyFlexibleFormType).Braunstetter\ValidFormEventBundle\Form\ValidFormTypeInterface or use the trait ValidFormTypeTrait:
use Braunstetter\ValidFormEventBundle\Form\ValidFormTypeTrait;
class MyFlexibleFormType extends AbstractType
{
use ValidFormTypeTrait;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('field1')
->add('field2')
->addEventListener(ValidFormEvents::VALID, [$this, 'onValidForm']);
}
public function onValidForm(ValidFormEvent $event)
{
$data = $event->getData();
// Your logic here (e.g., upload image, process data)
}
}
Register the Form:
// In your controller or service
$form = $this->createForm(MyFlexibleFormType::class, $entity);
Conditional Logic in Forms:
ValidFormEvents::VALID to trigger logic only when the entire form passes validation.public function onValidForm(ValidFormEvent $event)
{
$data = $event->getData();
if ($data->getAction() === 'publish') {
$this->publishService->publish($data);
}
}
Nested Forms:
VALID event propagates correctly.ValidFormTypeTrait in child forms to inherit validation checks:
class ChildFormType extends AbstractType
{
use ValidFormTypeTrait;
// ...
}
Event Propagation:
$event->stopPropagation();
Data Access:
$event->getData() or form fields via $event->getForm():
$form = $event->getForm();
$fieldValue = $form->get('field1')->getData();
Laravel-Specific:
FormComponent via spatie/laravel-symfony-support or symfony/form directly in Laravel 9+.config/app.php:
'providers' => [
Braunstetter\ValidFormEventBundle\ValidFormEventBundle::class,
],
Dependency Injection:
public function __construct(private UploadService $uploadService) {}
public function onValidForm(ValidFormEvent $event)
{
$this->uploadService->upload($event->getData()->getImage());
}
Validation Groups:
$builder->addEventListener(ValidFormEvents::VALID, [$this, 'onValidForm'], 10);
Event Order:
VALID event fires after all validation constraints are checked. Logic here runs only if the form is entirely valid.PRE_SUBMIT or SUBMIT events unless intentional.Circular Dependencies:
ValidFormTypeTrait is used consistently to avoid infinite loops.Laravel-Specific Quirks:
Illuminate\Http\Request) may not directly support Symfony’s FormEvent. Use a bridge or wrap logic in a service layer.Data Mutability:
ValidFormEvent provides a clone of the form data. Modify data cautiously to avoid unintended side effects:
$dataClone = $event->getData(); // Clone, not reference
Check Event Firing:
VALID event is triggered by adding a dump() or logger:
public function onValidForm(ValidFormEvent $event)
{
\Log::debug('Form valid!', ['data' => $event->getData()]);
}
Validation Errors:
$event->getForm()->getErrors().Priority Conflicts:
10, 20) to control execution order:
$builder->addEventListener(ValidFormEvents::VALID, [$this, 'onValidForm'], 20);
Custom Events:
PARTIALLY_VALID) by subclassing ValidFormEvent.Form Modifiers:
public function onValidForm(ValidFormEvent $event)
{
if ($event->getData()->isPremium()) {
$event->getForm()->add('premiumField');
}
}
Testing:
ValidFormEvent in tests:$event = $this->createMock(ValidFormEvent::class);
$event->method('getData')->willReturn($data);
$this->formType->onValidForm($event);
Performance:
public function onValidForm(ValidFormEvent $event)
{
dispatch(new ProcessDataJob($event->getData()));
}
How can I help you explore Laravel packages today?