Installation:
composer require aygon/form-handler-bundle
Enable the bundle in config/bundles.php:
Aygon\FormHandlerBundle\AygonFormHandlerBundle::class => ['all' => true],
First Use Case: Extend a Symfony form type to use the handler:
use Aygon\FormHandlerBundle\Form\Handler\HandlerInterface;
use Aygon\FormHandlerBundle\Form\Handler\HandlerTrait;
class MyFormType extends AbstractType
{
use HandlerTrait;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->setHandler($builder->getData(), $options['handler']);
// ... form fields
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'handler' => null, // Inject your handler class
]);
}
}
Create a Handler:
Implement HandlerInterface or extend AbstractHandler:
use Aygon\FormHandlerBundle\Form\Handler\AbstractHandler;
class MyFormHandler extends AbstractHandler
{
public function handle($data)
{
// Process form data (e.g., save to DB, trigger events)
return true; // Return false to re-render form with errors
}
}
Use in Controller:
$form = $this->createForm(MyFormType::class, $entity, [
'handler' => new MyFormHandler(),
]);
Decoupled Logic:
UserRegistrationHandler for user creation, NewsletterHandler for subscriptions.Reusable Handlers:
EntityHandler for CRUD):
abstract class EntityHandler extends AbstractHandler
{
protected $entityManager;
public function __construct(EntityManagerInterface $em)
{
$this->entityManager = $em;
}
public function handle($entity)
{
$this->entityManager->persist($entity);
$this->entityManager->flush();
}
}
Validation Integration:
public function handle($data)
{
$errors = $this->validator->validate($data);
if (count($errors) > 0) {
return false; // Form will re-render with validation errors
}
// Proceed with logic
}
Event Dispatching:
public function handle($data)
{
$event = new FormSubmittedEvent($data);
$this->eventDispatcher->dispatch($event, FormEvents::SUBMITTED);
}
Dependency Injection:
Inject services (e.g., EntityManager, Mailer) into handlers via constructor:
class ContactHandler extends AbstractHandler
{
private $mailer;
public function __construct(\Swift_Mailer $mailer)
{
$this->mailer = $mailer;
}
}
Form Events:
Attach handlers to form events (e.g., PRE_SUBMIT, POST_SUBMIT) for granular control:
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getData();
// Pre-process data
});
Dynamic Handlers: Use factory services to instantiate handlers dynamically:
# config/services.yaml
services:
App\Form\HandlerFactory:
arguments:
- '@service_container'
Handler Lifecycle:
Form Data vs. Entity:
PRE_SUBMIT) and bound entities (on POST_SUBMIT).Error Handling:
false from handle() to re-render the form. Use $form->addError() for form-wide errors:
if (!$this->handle($data)) {
$form->addError(new FormError('An error occurred.'));
}
Symfony 2.1 Constraint:
Log Handler Output: Temporarily log handler results to debug:
public function handle($data)
{
$this->logger->debug('Handler data:', ['data' => $data]);
// ...
}
Form Dump: Use Symfony’s form dumper to inspect submitted data:
$form->submit($data);
dump($form->getData());
Custom Handlers:
Extend AbstractHandler to add shared functionality (e.g., logging, notifications):
abstract class LoggableHandler extends AbstractHandler
{
protected function logAction($action, $data)
{
$this->logger->info(sprintf('%s: %s', $action, json_encode($data)));
}
}
Handler Decorators: Decorate handlers to add cross-cutting concerns (e.g., audit logging):
class AuditHandlerDecorator implements HandlerInterface
{
private $handler;
private $auditService;
public function __construct(HandlerInterface $handler, AuditService $audit)
{
$this->handler = $handler;
$this->auditService = $audit;
}
public function handle($data)
{
$this->auditService->log('form_submitted', $data);
return $this->handler->handle($data);
}
}
Configuration: Override default handler options in form types:
$resolver->setDefaults([
'handler' => new MyHandler(),
'handler_options' => ['key' => 'value'], // Pass to handler
]);
Testing: Mock handlers in unit tests:
$handler = $this->createMock(HandlerInterface::class);
$handler->method('handle')->willReturn(true);
$form = $this->createForm(MyFormType::class, [], ['handler' => $handler]);
How can I help you explore Laravel packages today?