Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Form Handler Laravel Package

digivia/form-handler

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require digivia/form-handler
    

    Ensure your project uses Symfony 5.4+ and PHP 8.

  2. Enable the Bundle: Register Digivia\FormHandler\DigiviaFormHandlerBundle in config/bundles.php (Symfony 5.1+). For older Symfony versions, add it to AppKernel.php.

  3. First Use Case: Create a form handler class (e.g., src/Form/Handler/ContactFormHandler.php):

    namespace App\Form\Handler;
    
    use Digivia\FormHandler\FormHandlerInterface;
    use Symfony\Component\Form\FormInterface;
    
    class ContactFormHandler implements FormHandlerInterface
    {
        public function handle(FormInterface $form): void
        {
            $data = $form->getData();
            // Process form data (e.g., save to DB, send email)
        }
    }
    
  4. Controller Integration: Inject the handler into your controller and delegate form processing:

    use App\Form\Handler\ContactFormHandler;
    use Digivia\FormHandler\FormHandlerInterface;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    
    class ContactController
    {
        public function submit(Request $request, FormHandlerInterface $handler): Response
        {
            $form = $this->createForm(ContactType::class);
            $form->handleRequest($request);
    
            if ($form->isSubmitted() && $form->isValid()) {
                $handler->handle($form); // Delegate logic
                return new Response('Success!');
            }
            return $this->render('contact/form.html.twig', ['form' => $form->createView()]);
        }
    }
    

Implementation Patterns

Core Workflows

  1. Separation of Concerns:

    • Controllers: Handle HTTP requests/responses and form instantiation.
    • Handlers: Contain business logic (e.g., validation, persistence, notifications).
    • Example:
      // Controller (thin)
      public function submit(Request $request, UserRegistrationHandler $handler): Response
      {
          $form = $this->createForm(UserRegistrationType::class);
          $form->handleRequest($request);
      
          if ($form->isSubmitted() && $form->isValid()) {
              $handler->handle($form); // Pure logic
          }
          // ...
      }
      
  2. Reusable Handlers:

    • Create base handlers for common operations (e.g., EmailNotificationHandler, DatabaseSaverHandler).
    • Extend or compose them for specific use cases:
      class OrderConfirmationHandler implements FormHandlerInterface
      {
          private EmailNotificationHandler $emailHandler;
          private DatabaseSaverHandler $dbHandler;
      
          public function __construct(EmailNotificationHandler $emailHandler, DatabaseSaverHandler $dbHandler)
          {
              $this->emailHandler = $emailHandler;
              $this->dbHandler = $dbHandler;
          }
      
          public function handle(FormInterface $form): void
          {
              $this->dbHandler->save($form->getData());
              $this->emailHandler->sendConfirmation($form->getData());
          }
      }
      
  3. Dependency Injection:

    • Use Symfony’s DI to inject services (e.g., EntityManager, Mailer) into handlers:
      class UserProfileHandler implements FormHandlerInterface
      {
          public function __construct(private EntityManagerInterface $em) {}
      
          public function handle(FormInterface $form): void
          {
              $user = $form->getData();
              $this->em->persist($user);
              $this->em->flush();
          }
      }
      
  4. Form Events:

    • Trigger custom events in handlers for cross-cutting concerns (e.g., logging, analytics):
      use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
      
      class AnalyticsHandler implements FormHandlerInterface
      {
          public function __construct(private EventDispatcherInterface $dispatcher) {}
      
          public function handle(FormInterface $form): void
          {
              $this->dispatcher->dispatch(new FormSubmittedEvent($form->getData()));
          }
      }
      
  5. Validation:

    • Use Symfony’s validator directly in handlers or leverage form validation:
      class SubscriptionHandler implements FormHandlerInterface
      {
          public function __construct(private ValidatorInterface $validator) {}
      
          public function handle(FormInterface $form): void
          {
              $errors = $this->validator->validate($form->getData());
              if (count($errors) > 0) {
                  throw new \RuntimeException('Validation failed');
              }
              // Proceed
          }
      }
      

Gotchas and Tips

Pitfalls

  1. Handler Lifecycle:

    • Handlers are stateless by design. Avoid storing instance-specific data unless managed externally (e.g., via services).
    • Example of anti-pattern:
      // ❌ Avoid: Storing data in handler instance
      class BadHandler implements FormHandlerInterface {
          private $counter = 0;
          public function handle(FormInterface $form): void {
              $this->counter++; // Unpredictable behavior!
          }
      }
      
  2. Form Submission Check:

    • Always verify $form->isSubmitted() && $form->isValid() in controllers before calling handlers. Skipping this may lead to unintended handler execution (e.g., on page load).
    • Example:
      // ❌ Risky: Handler called even if form isn't submitted
      $handler->handle($form); // May fail or cause side effects
      
  3. Circular Dependencies:

    • Handlers should not depend on controllers or other handlers directly. Use Symfony’s DI to resolve dependencies.
    • Example of anti-pattern:
      // ❌ Circular dependency
      class HandlerA implements FormHandlerInterface {
          public function __construct(private HandlerB $handlerB) {}
      }
      class HandlerB implements FormHandlerInterface {
          public function __construct(private HandlerA $handlerA) {} // ❌
      }
      
  4. Error Handling:

    • Handlers should not throw exceptions for business logic errors (e.g., validation failures). Return results or use Symfony’s error handling (e.g., Problem details).
    • Example:
      // ✅ Preferred: Return boolean or result object
      public function handle(FormInterface $form): bool {
          if (!$this->isValid($form->getData())) {
              return false;
          }
          // ...
          return true;
      }
      
  5. Symfony 6+ Compatibility:

    • The package is last updated for Symfony 5.4/6. Test thoroughly with Symfony 6+ due to potential API changes (e.g., AppKernel deprecation).
    • For Symfony 6, ensure config/bundles.php is used instead of AppKernel.php.

Debugging Tips

  1. Handler Execution:

    • Add debug logs to trace handler calls:
      use Psr\Log\LoggerInterface;
      
      class DebugHandler implements FormHandlerInterface {
          public function __construct(private LoggerInterface $logger) {}
      
          public function handle(FormInterface $form): void {
              $this->logger->info('Handler called with data:', ['data' => $form->getData()]);
          }
      }
      
  2. Form Data Inspection:

    • Dump form data in handlers to verify payloads:
      use Symfony\Component\VarDumper\VarDumper;
      
      public function handle(FormInterface $form): void {
          VarDumper::dump($form->getData());
      }
      
  3. Dependency Injection Issues:

    • Use Symfony’s debug:container command to inspect service availability:
      php bin/console debug:container Digivia\FormHandler
      

Extension Points

  1. Custom Handler Interfaces:

    • Extend FormHandlerInterface for domain-specific contracts:
      interface OrderHandlerInterface extends FormHandlerInterface {
          public function handle(Order $order): void;
      }
      
  2. Middleware for Handlers:

    • Create a decorator or interceptor to add pre/post-processing logic:
      class LoggingHandlerDecorator implements FormHandlerInterface {
          public function __construct(private FormHandlerInterface $handler, private LoggerInterface $logger) {}
      
          public function handle(FormInterface $form): void {
              $this->logger->info('Before handler');
              $this->handler->handle($form);
              $this->logger->info('After handler');
          }
      }
      
  3. Event-Driven Handlers:

    • Dispatch events before/after handler execution using Symfony’s EventDispatcher:
      class EventDispatchingHandler implements FormHandlerInterface {
          public function __construct(private EventDispatcherInterface $dispatcher, private FormHandlerInterface $handler) {}
      
          public function handle(FormInterface $form): void {
              $this->dispatcher->dispatch(new FormHandlingEvent($form, FormHandlingEvent::PRE_HANDLE));
              $this->handler->handle($form);
              $this->dispatcher->dispatch(new FormHandlingEvent($form, FormHandlingEvent::POST_HANDLE));
          }
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
besmartand-pro/php-quality-config
sentix/ai-chatbot
codifyo/ts-generator-bundle
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor