Skip to content

Getting Started With Form Handlers

Iltar van der Berg edited this page Apr 6, 2017 · 6 revisions

Note: If you are familiar with the Symfony form component, these examples will seem very familiar. This is by design, the form handlers are designed to be symmetrical to the form types in the way they are used and configured.

In order to use the form handler, simply create a service that contains your form information. A simple example would be:

<?php
use Hostnet\Component\FormHandler\HandlerConfigInterface;
use Hostnet\Component\FormHandler\HandlerTypeInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouterInterface;

class MyFormHandler implements HandlerTypeInterface
{
    private $router;

    public function __construct(RouterInterface $router)
    {
        $this->router = $router;
    }

    /** {@inheritdoc} */
    public function configure(HandlerConfigInterface $config)
    {
        $config->setType(MyFormType::class);

        $config->onSuccess(function(MyFormData $data, FormInterface $form, Request $request) {
            // do something with the form data, like setting some data in the user
            $data->getUser()->setUsername($data->getUsername());
    
            // ...
            
            return new RedirectResponse($this->router->generate('my-route'));
        });
        // Also a failure branch can be added using:
        // $config->onFailure(/* ... */);
    }
}

Note: Handlers are stateless. Which means that if you need to pass additional data (like the user) to the handler, you need to set this in the data object. For more information see the definition of a Data Transfer Object (DTO).

Then create a service and tag it with form.handler

my_form.handler:
    class: MyFormHandler
    arguments:
        - "@router"
    tags:
        - { name: form.handler }

And in your controller you can use the handler like:

<?php
use Hostnet\Component\FormHandler\HandlerFactoryInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;

class MyController
{
    private $handler_factory;

    public function __construct(HandlerFactoryInterface $handler_factory)
    {
        $this->handler_factory = $handler_factory;
    }

    /**
     * @Route("/your-route", name="route-name")
     * @Template()
    */
    public function formAction(Request $request, MyEntityUser $user)
    {
        $handler = $this->handler_factory->create(MyFormHandler::class);
        $data    = new MyFormData();
        $data->setUser($user);
        
        if (($response = $handler->handle($request, $data)) instanceof RedirectResponse) {
            return $response;
        }
        
        // regular or in-valid flow
        return [
            'form' => $handler->getForm()->createView()
        ];
    }
}

The factory will retrieve the correct handler by the class name. This means that you do not have to inject the service yourself.

Note: You cannot have multiple form handler services that use the same class, since the factory cannot find the correct service for it.

Request flow

The above sequence diagram show the internal flow through the components. It illustrates how the type is used and when each method is used.

Clone this wiki locally