Chapters
-
Course Code
Subscribe to download the code!Compatible PHP versions: >=5.5.9
Subscribe to download the code!Compatible PHP versions: >=5.5.9
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Process that Form!
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
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:
Show Lines
|
// ... lines 1 - 7 |
use Symfony\Component\HttpFoundation\Request; | |
Show Lines
|
// ... lines 9 - 12 |
class GenusAdminController extends Controller | |
{ | |
Show Lines
|
// ... lines 15 - 31 |
public function newAction(Request $request) | |
{ | |
Show Lines
|
// ... lines 34 - 44 |
} | |
} |
$form->handleRequest()
Next, to actually handle the submit, call $form->handleRequest()
and pass it the
$request
object:
Show Lines
|
// ... lines 1 - 12 |
class GenusAdminController extends Controller | |
{ | |
Show Lines
|
// ... lines 15 - 31 |
public function newAction(Request $request) | |
{ | |
$form = $this->createForm(GenusFormType::class); | |
// only handles data on POST | |
$form->handleRequest($request); | |
Show Lines
|
// ... 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())
:
Show Lines
|
// ... lines 1 - 12 |
class GenusAdminController extends Controller | |
{ | |
Show Lines
|
// ... 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()) { | |
Show Lines
|
// ... line 39 |
} | |
Show Lines
|
// ... 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;
:
Show Lines
|
// ... lines 1 - 12 |
class GenusAdminController extends Controller | |
{ | |
Show Lines
|
// ... 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; | |
} | |
Show Lines
|
// ... 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.
33 Comments
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
on symfony 3.2 works fine
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!
i upgraded symfony to 3.4 that broke everything, so i downgraded back to 3.1. Now everything works.... very weird haha
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!
Checking if form is valid is totally fine, as isValid checks for isSubmitted also :)
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!
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 />
.
.
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!
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.
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!
Hey Victor,
Thanks a lot for your reply. I will do that then.
Thanks again for the good work !
Tom.
You're welcome, and happy learning! ;)
Cheers!
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!
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
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!
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! ;)
I am using php 7.1 :D
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!
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!
Hey Diego,
My version is : Symfony version 3.0.9
Cheers!:D
yooo, you were right ! I upgraded symfony to version 3.4 and its working now.
Tnx a lot !
Cheers ! :)
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...
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!
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
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!
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
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!
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
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!
"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
}
}
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???