Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Process that Form!

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Inspect the HTML and check out the <form> element. Notice: this does not have an action attribute. This means that the form will submit right back to the same route and controller that renders it. You can totally change this, but we won't.

In other words, our single action method will be responsible for rendering the form and processing it when the request method is POST.

Before we do any processing, we need the request. Type-hint it as an argument:

... lines 1 - 7
use Symfony\Component\HttpFoundation\Request;
... lines 9 - 12
class GenusAdminController extends Controller
{
... lines 15 - 31
public function newAction(Request $request)
{
... lines 34 - 44
}
}

$form->handleRequest()

Next, to actually handle the submit, call $form->handleRequest() and pass it the $request object:

... lines 1 - 12
class GenusAdminController extends Controller
{
... lines 15 - 31
public function newAction(Request $request)
{
$form = $this->createForm(GenusFormType::class);
// only handles data on POST
$form->handleRequest($request);
... lines 38 - 44
}
}

This is really cool: the $form knows what fields it has on it. So $form->handleRequest() goes out and grabs the post data off of the $request object for those specific fields and processes them.

The confusing thing is that this only does this for POST requests. If this is a GET request - like the user simply navigated to the form - the handleRequest() method does nothing and our form renders just like it did before.

Tip

You can configure the form to submit on GET requests if you want. This is useful for search forms

But if the form was just submitted, then we'll want to do something with that information, like save a new Genus to the database. Add an if statement: if ($form->isSubmitted() && $form->isValid()):

... lines 1 - 12
class GenusAdminController extends Controller
{
... lines 15 - 31
public function newAction(Request $request)
{
$form = $this->createForm(GenusFormType::class);
// only handles data on POST
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
... line 39
}
... lines 41 - 44
}
}

In other words, if this is a POST request and if the form passed all validation. We'll add validation soon.

Fetching $form->getData()

If we get inside this if statement, life is good. For now, just dump the submitted data: dump($form->getData()) and then die;:

... lines 1 - 12
class GenusAdminController extends Controller
{
... lines 15 - 31
public function newAction(Request $request)
{
$form = $this->createForm(GenusFormType::class);
// only handles data on POST
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
dump($form->getData());die;
}
... lines 41 - 44
}
}

OK, let's see what this dumps out!

Fill out the form with very realistic data and submit. Check that out! It dumps and associative array with the three fields we added to the form. That's so simple! We added 3 fields to the form, rendered them in a template, and got those three values as an associative array.

Now, it would be very, very easy to use that associative array to create a new Genus object, populate it with the data, and save it via Doctrine.

But, it would be awesomesauce if the form framework could do our job for us. I mean, use the data to automatically create the Genus object, populate it, and return that to us. Let's do that.

Leave a comment!

33
Login or Register to join the conversation
Tom Avatar

Im getting a weird error in a file I haven't even touched...

Warning: count(): Parameter must be an array or an object that implements Countable

in vendor\symfony\symfony\src\Symfony\Component\Validator\Validator\RecursiveContextualValidator.php at line 712

what???

Reply
Kirill Avatar

It is cause of php version >=7.2 that returns count(null) as exception. If you develop this one on php version >= 7.1.4 is will be all ok

Reply
Pupinia Avatar

on symfony 3.2 works fine

Reply

Hey Cryptoblob,

It sounds like a BC breaks in a your current PHP version. SO, I think you just need to upgrade dependencies, probably Symfony validator at least. I think if you run this code on a lower PHP version - it should work without this warning, but would be better to upgrade that dependency. I bet this problem was already fixed in a newer version.

Cheers!

Reply
Tom Avatar

i upgraded symfony to 3.4 that broke everything, so i downgraded back to 3.1. Now everything works.... very weird haha

Reply

Hey Cryptoblob,

Yeah, sometimes upgrade to a new minor version is not simple, but Symfony do their best to make it smooth. You can take a look at UPGRADE-3.*.md files here: https://github.com/symfony/... . So, if you want to upgrade from Symfony 3.1 to 3.4 - take a look at UPGRADE-3.2.md, UPGRADE-3.3.md and UPGRADE-3.4.md files. They contain some instuctions you have to do in order to upgrade Symfony packages. Though, if there're other dependencies in your project, you need to look at their changelogs to know what exactly actions they require from you.

I hope this helps!

Cheers!

Reply
Default user avatar
Default user avatar 3amprogrammer | posted 5 years ago

Checking if form is valid is totally fine, as isValid checks for isSubmitted also :)

Reply

Definitely! I also leave off isSubmitted() in practice - it's nice to show to beginners at first, but I'm too lazy to include it after ;).

Thanks for the note!

Reply
Default user avatar
Default user avatar Terry Caliendo | weaverryan | posted 5 years ago | edited

But according to the docs it looks like in future versions isValid() will throw an exception if its not submitted, so it will cause issues upon upgrade, won't it?:
http://api.symfony.com/3.3/Symfony/Component/Form/FormInterface.html#method_isValid
<br />If the form is not submitted, this method always returns false (but will throw an exception in 4.0).<br />
.
.

Reply

Hey Terry,

Thanks for this notice! You're totally right now. You came across an old comment which was left more than year ago, but now situation is changed.

Cheers!

Reply
Default user avatar

Hey,

I'm new with Symfony. I was just wondering... Should i start directly to learn Symfony4 or should i come back a little and go with Symfony 3 since there are so much more tutorial about it ?

Thanks a lot, i really enjoy your tutorials.

Cheers from France.

Reply

Hey Tom,

Welcome! And that's a good question! Well, you definitely need to start with Symfony Flex, and the only tutorials about it is in Symfony 4 track. So I'd say you better start with Symfony 4. Then, when you finish all the Symfony 4 courses, you can start watching Symfony 3 related courses because we have a lot of topics covered there. But now, since you already know how to use Symfony Flex, instead of doing it in Symfony 3 way you should use Flex.

Cheers!

Reply
Default user avatar

Hey Victor,

Thanks a lot for your reply. I will do that then.

Thanks again for the good work !

Tom.

Reply

You're welcome, and happy learning! ;)

Cheers!

Reply
weaverryan Avatar weaverryan | SFCASTS | posted 5 years ago | edited

Yo there!

Ah, you're really close! There is one... maybe two problems :)

1) Remove $form->handleRequest(). That's redundant: you're actually submitting your form two times - once with submit() and again with handleRequest, but with empty data. When you call handleRequest(), it finds the fields on the POST data, and then it calls submit() internally. So, remove that line!

2) I believe for the myDate value, you will need something different. When you use submit, you should submit the data in the format that would normally come from the web. So, it would actually be:


$form->submit(['myDate' => [
    'year' => 2017,
    'month' => 11,
    'day' => 20
]]);

It needs this format because, by default, the DateType field renders as 3 select elements, calls year, month & day. If you set the widget option on that field to single_text, then it would render as a single input text. So, you would submit text:


$form->submit(['myDate' => '2017-11-20']);

I hope that helps! Cheers!

Reply
Default user avatar

Hi guys,

I have problem rendering form after i added Request object as argument in newAction method.
It seems that adding Request and $form->handleRequest($request) is valid just after i submit form.
And i can not find solution in downloaded script because there is no proper code according to this part of course.
Do you know how can i solve this issue ?

Cheers ! :D

Reply

Hey Eddy!

Ah, I just saw your other note about this and asked you to make a comment. I see you already did - excellent!

I'm not sure I fully understand the problem yet. You said:

> It seems that adding Request and $form->handleRequest($request) is valid just after i submit form.

Can you explain that in more detail? Do you get an error when you render (don't submit) the form? Or do you not have an error, but a difference problem?

Let us know - sorry I couldn't quite understand the issue yet - but we'll get to the bottom of it!

Cheers!

Reply
Default user avatar

Heya,

I got an answer which was resolution for my issue.
Problem was that i passed Symfony\Component\BrowserKit instead \Symfony\Component\HttpFoundation\Request as param to my method in controller which was wrong.
Now i have another problem, after i submit form, which might be related to php version.

Warning: count(): Parameter must be an array or an object that implements Countable
vendor/symfony/symfony/src/Symfony/Component/Form/Form.php at line 716

So, if some of you have resolution for this as well , i would be really really nice :D :D
TNX! ;)

Reply
Default user avatar

I am using php 7.1 :D

Reply

Hey Eddy!

Bah, nice find with the BrowserKit Request! Indeed, everything would blow up immediately when you added that!

About your new error.... hmm, tricky! It *might* be a PHP error - it's certainly "weird" enough. The error comes from here: https://github.com/symfony/... - and I don't see any change to this line in newer versions of Symfony (so, if it were a PHP bug, we would have fixed it by now!).

Can you post your form and controller data? And also, a screenshot of the stacktrace? The error is odd, because that line of code checks to make sure the value is an array or Countable!

Cheers!

Reply
Default user avatar

Hey,

Here is my part of code
https://gist.github.com/edd...
Maybe this can help. :)

Cheers!

Reply

Hey @Eddy

Your form looks good to me, so I believe this is an incompatability with an older Symfony version and PHP7
Can you tell me which Symfony version are you using?
Maybe if you upgrade to a newer version it will be fixed

Cheers!

Reply
Default user avatar

Hey Diego,

My version is : Symfony version 3.0.9
Cheers!:D

Reply
Default user avatar

yooo, you were right ! I upgraded symfony to version 3.4 and its working now.
Tnx a lot !
Cheers ! :)

1 Reply
Richard Avatar
Richard Avatar Richard | posted 5 years ago

I need some clarification about you saying it only handles POST data. This code of mine populates the form object from a GET query just fine. What am I mixing up? ie when I render the form it still contains the submitted values (this is a search dialog). https://gist.github.com/ril...

Reply

Hey Richard

That's because you explicitly specified to use "GET" method on your form, by default it uses "POST", and you should use it too, because it's more secure, and it's an standard when you are creating records on your system

Cheers!

Reply

Hello,

let me say your tutorials are really awesome!

I have a question for you. when I try to dump the data with

dump($form->getData());

it get this warning:

The CSRF token is invalid. Please try to resubmit the form.

I double checked the code but the error remains the same. can you please help me?

thank you!

carlo

Reply

Hey chieroz ,

How does your form look like? Probably, you forget to render a SCRF hidden field. Actually, you don't need to render it manually, Symfony does it behind the scene when {{ form_end(form) }} is called. Do you have a `form_end` call on your page? If so, just open this form page in your browser to regenerate SCRF token and submit this form again.

Cheers!

Reply

hello Victor,

I checked the source of the page and I confirm my form has the hidden field with the token.

when I submit the form and I check in the profiler the POST parameters, the _token value is the same as the value I saw in the form, but I still get the error message about the CSRF token.

thank you for your help.

carlo

Reply

Hey Carlos!

Hmm - this doesn't sound good at all :). Victor was right - basically the only way you can mess this up is by forgetting to render the field (which you haven't done!). I've only seen CSRF tokens fail one other time ever, and it was when someone had misconfigured their session storage (which is not something you normally need to configure at all). CSRF tokens work via your session - so this is possibly the problem.

Here's how you can see if your session is working.

1) Find your favorite controller and add the following:


$this->get('session')->set('testing_value', 'yay');

2) Go to the URL that executes this controller

3) Update the code in your controller


// $this->get('session')->set('testing_value', 'yay');
dump($this->get('session')->get('testing_value'));die;

4) Go back to that URL. Were we able to load the value from the session?

Cheers!

Reply

Hello Ryan,

I followed your advice I was NOT able to retrieve the value from the session.

I checked ALL the differences between my code and your code and I found this difference in config.yml:

YOURS
session:
handler_id: ~

MINE
session:
handler_id: session.handler.native_file

I updated my config.yml and BOOM: problem solved.

I am using a standard Debian Jessie VM in Vagrant, I don't know why the standard setup doesn't work.

thank you for your help!

Carlo

Reply

Hey Carlo!

Good catch! BTW, you should move the session save path to a directory that is not shared between host and guest machines in case you want to use "handler_id: session.handler.native_file". For more information please check this issue.

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*", // v3.1.4
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.4
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "knplabs/knp-markdown-bundle": "^1.4", // 1.4.2
        "doctrine/doctrine-migrations-bundle": "^1.1" // 1.1.1
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.7
        "symfony/phpunit-bridge": "^3.0", // v3.1.3
        "nelmio/alice": "^2.1", // 2.1.4
        "doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
    }
}
userVoice