Search code examples
phpformsroutessymfonyhandle

Handle form on different route from where it's built Symfony 3


I'm actually creating a website (with symfony 3) where the login form is on the main page (route /). And I would like to handle this form on the /login route.

Unfortunately I don't know how to do that because my form is built in the indexAction() and my loginAction() has no visibility on the $form built in index...

/**
 * @Route("/", name="home")
 */
public function indexAction()
{
    $user = new User();

    $form = $this->createFormBuilder($user)
        ->setAction($this->generateUrl('login'))
        ->setMethod('POST') //btw is this useless ?? Is it POST by default ?
        ->add('Login',   TextType::class)
        ->add('Password',    TextType::class)
        ->add('save', SubmitType::class, array('label' => 'Sign In'))
        ->getForm();

    return $this->render('ShellCodeHomeBundle:Home:index.html.twig', array (
        'login' => '',
        'form_signin' => $form->createView(),
    ));
}

/**
 * @Route("/login", name="login")
 */
public function loginAction(Request $request)
{
    $user = new User();

    //how do I handle the form ????
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {

        $em = $this->getDoctrine()->getManager();
        $user = $form->getData();
        //...
    }

    return $this->render('ShellCodeHomeBundle:Home:index.html.twig', array (
        'login' => $user->getLogin(),
    ));
}

I guess it's useless to tell that, but I'm using twig and I insert the form like this :

<div class="col-lg-12" style="text-align: center;">
    {{ form_start(form_signin) }}
    {{ form_widget(form_signin) }}
    {{ form_end(form_signin) }}
</div>

Hope you will able to help me ! Thanks !


Solution

  • Do not build your form within the controller, that's a bad practice, because you can't reuse this code.

    You should create your form within FormType and define them as a service. That way, you'll be able to reuse this form as often as you need it to.

    Taken from the docs linked below, here's an example for the FormType:

    namespace AppBundle\Form;
    
    use AppBundle\Entity\Post;
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    use Symfony\Component\Form\Extension\Core\Type\TextareaType;
    use Symfony\Component\Form\Extension\Core\Type\EmailType;
    use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
    
    class PostType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('title')
                ->add('summary', TextareaType::class)
                ->add('content', TextareaType::class)
                ->add('authorEmail', EmailType::class)
                ->add('publishedAt', DateTimeType::class)
            ;
        }
    
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => Post::class,
            ));
        }
    }
    

    Then you could use the FormType as in this example:

    use AppBundle\Form\PostType;
    
    // ...
    public function newAction(Request $request)
    {
        $post = new Post();
        $form = $this->createForm(PostType::class, $post);
    
        // ...
    }
    

    For detailed information, check the docs