chance
chance

Reputation: 315

Symfony2 - Variable "form" does not exist when it's being passed in

I'm working on code to send email from a contact form and the form appears correctly until I submit the form then get the following error:

Variable "form" does not exist in AcmeEmailBundle:Default:index.html.twig at line 14

Puzzled to what is causing this as I've dumped the 'form' variable in Twig and it's being passed in, but I'm guessing not during the redirect?

Controller

/**
 * @Route("/", name="contact")
 * @Template("AcmeEmailBundle:Default:index.html.twig")
 */
public function contactAction(Request $request)
{
    $form = $this->createForm(new ContactType());

    if ($request->isMethod('POST')) {
        $form->submit($request);

        if ($form->isValid()) {
            $message = \Swift_Message::newInstance()
                ->setSubject($form->get('subject')->getData())
                ->setFrom($form->get('email')->getData())
                ->setTo('[email protected]')
                ->setBody(
                    $this->renderView(
                        'AcmeEmailBundle:Default:index.html.twig',
                        array(
                            'ip' => $request->getClientIp(),
                            'name' => $form->get('name')->getData(),
                            'message' => $form->get('message')->getData()
                        )
                    )
                );

            $this->get('mailer')->send($message);

            $request->getSession()->getFlashBag()->add('success', 'Your email has been sent! Thanks!');

            return $this->redirect($this->generateUrl('contact'));
        }
    }

    return array(
        'form' => $form->createView()
    );
}

Twig

{% block body %}

{% for label, flashes in app.session.flashbag.all %}
    {% for flash in flashes %}
        <div class="alert alert-{{ label }}">
            {{ flash }}
        </div>
    {% endfor %}
{% endfor %}

<form action="{{ path('contact') }}" method="post" {{ form_enctype(form) }}>
    {{ form_widget(form) }}

    <button type="submit">Send</button>
</form>

{% endblock %}

Form

class ContactType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
    ->add('name', 'text', array(
    'attr' => array(
        'placeholder' => 'What\'s your name?',
        'pattern'     => '.{2,}' //minlength
    )
))
    ->add('email', 'email', array(
        'attr' => array(
            'placeholder' => 'So I can get back to you.'
        )
    ))
    ->add('subject', 'text', array(
        'attr' => array(
            'placeholder' => 'The subject of your message.',
            'pattern'     => '.{3,}' //minlength
        )
    ))
    ->add('message', 'textarea', array(
        'attr' => array(
            'cols' => 90,
            'rows' => 10,
            'placeholder' => 'And your message to me...'
        )
    ));
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $collectionConstraint = new Collection(array(
        'name' => array(
            new NotBlank(array('message' => 'Name should not be blank.')),
            new Length(array('min' => 2))
        ),
        'email' => array(
            new NotBlank(array('message' => 'Email should not be blank.')),
            new Email(array('message' => 'Invalid email address.'))
        ),
        'subject' => array(
            new NotBlank(array('message' => 'Subject should not be blank.')),
            new Length(array('min' => 3))
        ),
        'message' => array(
            new NotBlank(array('message' => 'Message should not be blank.')),
            new Length(array('min' => 5))
        )
    ));

    $resolver->setDefaults(array(
        'constraints' => $collectionConstraint
    ));
}

public function getName()
{
    return 'contact';
}
}

Upvotes: 0

Views: 3307

Answers (2)

sjagr
sjagr

Reputation: 16502

The error message seems pretty self-explanatory. This snippet:

// ...
                $this->renderView(
                    'AcmeEmailBundle:Default:index.html.twig',
                    array(
                        'ip' => $request->getClientIp(),
                        'name' => $form->get('name')->getData(),
                        'message' => $form->get('message')->getData()
                    )
// ...

is rendering the view but not passing form into it. The index.html.twig file tries to access form and throws an error because you haven't sent form to it. I'm wondering why you would send an HTML form in an email... which leads me to think you are using the incorrect Twig file for your SwiftMailer function.

To fix the problem you either have to include form in the renderView function:

// ...
                $this->renderView(
                    'AcmeEmailBundle:Default:index.html.twig',
                    array(
                        'ip' => $request->getClientIp(),
                        'name' => $form->get('name')->getData(),
                        'message' => $form->get('message')->getData(),
                        'form' => $form->createView(),
                    )
// ...

or use the correct template that you're trying to send through the email (this solution seems more appropriate.)

Upvotes: 3

Nicholas Byfleet
Nicholas Byfleet

Reputation: 579

One potential reason that you are receiving this error is that you are not actually passing the form to the view. Where you have:

->setBody(
$this->renderView(
'AcmeEmailBundle:Default:index.html.twig', array(
    'ip' => $request->getClientIp(),
    'name' => $form->get('name')->getData(),
    'message' => $form->get('message')->getData()
))

You need to do something like:

->setBody(
$this->renderView(
'AcmeEmailBundle:Default:index.html.twig', array(
    'ip' => $request->getClientIp(),
    'form' => $form->createView()
))

There are a few other troubling aspects about your code. For instance, it would be a lot better to do something like:

$contact = new Contact(); // Where contact is some kind of Entity
$form = $this->createForm(new ContactType(), $contact);
$form->handleRequest($request);

Then in your mailing process, instead of doing things like:

->setSubject($form->get('subject')->getData())
->setFrom($form->get('email')->getData())

You would do things like:

->setSubject($contact->getSubject())
->setFrom($contact->getEmail())

Another thing that I noticed is that in your controller, if the request method isn't POST you are not returning a valid Response object. Anyway, hope some of that helps.

Edit: As @sjagr points out, annotations take care of this.

Upvotes: 0

Related Questions