Chapters
-
Course Code
Subscribe to download the code!Compatible PHP versions: >=5.3.3
Subscribe to download the code!Compatible PHP versions: >=5.3.3
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Using an External Form Type Class
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
Using an External Form Type Class¶
We built our form right inside the controller, which was really simple. But, it makes our controller a bit ugly and if we needed to re-use this form somewhere else, that wouldn’t be possible.
For those reasons, the code to create a form usually lives in its own class. Create a new Form directory and a new file called RegisterFormType. Create the class, give it a namespace and make it extend a class called AbstractType:
// src/Yoda/UserBundle/Form/RegisterFormType.php
namespace Yoda\UserBundle\Form;
use Symfony\Component\Form\AbstractType;
class RegisterFormType extends AbstractType
{
}
We need to add a few methods to this class. The first, and least important is getName(). Add this, and just return a string that’s unique among your forms. It’s used as part of the name attribute on your rendered form:
// src/Yoda/UserBundle/Form/RegisterFormType.php
// ...
public function getName()
{
return 'user_register';
}
The really important method is buildForm(). I’m going to use my IDE to create this method for me. If you create your’s manually, just don’t forget the use statement for the FormBuilderInterface.
The buildForm method is where we build our form! Genius! Copy the code from our controller that adds the fields and put that here:
// src/Yoda/UserBundle/Form/RegisterFormType.php
use Symfony\Component\Form\FormBuilderInterface;
// ...
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username', 'text')
->add('email', 'email')
->add('plainPassword', 'repeated', array(
'type' => 'password'
)
);
}
Finally, create a setDefaultOptions function and set the data_class option on it:
// src/Yoda/UserBundle/Form/RegisterFormType.php
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
// ...
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Yoda\UserBundle\Entity\User',
));
}
That’s it! This class is now a recipe for exactly how the form should look.
Using the Form Class¶
Remove the builder code in our controller. Instead, replace it with a call to createForm and pass it an instance of the new RegisterFormType:
// src/Yoda/UserBundle/Controller/RegisterController.php
use Yoda\UserBundle\Form\RegisterFormType;
// ...
public function registerAction(Request $request)
{
$defaultUser = new User();
$defaultUser->setUsername('Foo');
$form = $this->createForm(new RegisterFormType(), $defaultUser);
// ...
}
Refresh! We’ve conquered forms!
Forms: From Space¶
Some quick review. A form is something you build, giving it the fields and field types you need. At first, a form just returns an associative array, but we can change that with the data_class option to return a populated object. Forms can also be built right inside the controller or in an external class.
Got it? Great! Let’s move on to validation.
16 Comments
Hi Diego!
Yes, very good catch! And actually, I don't believe we have a a non-deprecated way to handle this yet. It's something we're working on :). For now, don't worry about it.
Cheers!
Thanks for your fast answer, and one more thing, I think the comment's counter of the page is broken or something, it says 0 comments.
You're right - I've got a bug in the system - on my list to fix it!
Cheers!
Hi there!
Sorry for asking this dumb question here, but I couldn't find in documentation the list of options to pass to
[FormBuilderInterface] $builder->add() method (third parameter)
Thanks for your time :)
Hey!
Every field type has different options (though many options - like label - are used by every field type). Just find the field your working with and all the types are doc'ed :) http://symfony.com/doc/curr...
Cheers!
Oh yeah I found that and it is very useful but my real problem is since I'm working with field validations, I found that you can add constraints directly in FormType, just like this:
$builder->add('plainPassword', 'repeated', array(
'constraints' => array(
new Assert\Regex(array(
'pattern' => '/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).*$/'
))));
So I've been searching where can I check all this options but I just can't find it.
Sometimes I find kind of lost in the documentation hehehe
Thanks for your fast answer ;]
Ok, so *most* options are included in the docs :). If you want to look in the source code to find the available options, the trick is that every field type is backed by a class. For example, "date" is DateType, and you can look on that class for the options (there is also a hierarchy, so all fields extend from FormType and get *its* options too).
Now, constraints is special - it's added to *all* fields via a "plugin" of sorts, called a "form type extension". To see where these options come from, the class is called FormTypeValidatorExtension. If you look up how form type extensions work and what they do, it'll help make more sense. So it's a powerful bit of functionality that provides these options, but this should get you started.
Cheers!
Great!
thanks for your time bro
Hi , the second argument is $defaultUser not $user...
public function registerAction(Request $request)
{
$defaultUser = new User();
$defaultUser->setUsername('Foo');
$form = $this->createForm(new RegisterFormType(), $user);
// ...
}
Good catch! I just fixed this at sha: https://github.com/knpunive...
Thanks Marco!
hello, there are something about buildForm that i don't understand, buildForm return nothing, how do it work plz ?
thanks
Hey there!
Sorry for the late reply! You're right that buildForm returns nothing :). But that's ok! It's purpose is to modify the `$builder` variable that is passed in. So basically:
1) Symfony creates this `$builder` variable
2) Symfony calls buildForm() and passes you this variable
3) You modify this by adding fields with add()
4) Symfony uses the modified `$builder` to build your form
Does that make sense?
Cheers!
I encountered another problem,
when i submit, it displays :
The CSRF token is invalid. Please try to resubmit the form.
but if in the getName, it return "form" replace the "user_register",
there is not this problem !
like this
class RegisterFormType extends AbstractType
{
public function getName()
{
return "form";
}
...
}
could you help me plz ? merci !
Hmm, that is very strange! You should not need to change from "user_register" to "form" - in fact the getName() method is not very important.
I think there could be another problem. What does your Twig template look like? The CSRF token is a hidden input field, and if you forget to render it, you will get this error message. Make sure you have form_rest(form) in your Twig template (or in newer versions of Symfony, you can use form_end(form) - look at the *last* code block on this page: https://knpuniversity.com/s...
Ultimately, if you view the HTML source of your page, you should see name="_token" field. If you don't see that, the CSRF token is not rendering, which will cause you this problem :).
Cheers!
Hey there!
If someone is going thru this tutorial but using symfony 3, you will find a little problem with "createForm" method, it now takes the class name (RegisterFormType::class) instead of the object itself
"Houston: no signs of life"
Start the conversation!
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=5.3.3",
"symfony/symfony": "~2.4", // v2.4.2
"doctrine/orm": "~2.2,>=2.2.3", // v2.4.2
"doctrine/doctrine-bundle": "~1.2", // v1.2.0
"twig/extensions": "~1.0", // v1.0.1
"symfony/assetic-bundle": "~2.3", // v2.3.0
"symfony/swiftmailer-bundle": "~2.3", // v2.3.5
"symfony/monolog-bundle": "~2.4", // v2.5.0
"sensio/distribution-bundle": "~2.3", // v2.3.4
"sensio/framework-extra-bundle": "~3.0", // v3.0.0
"sensio/generator-bundle": "~2.3", // v2.3.4
"incenteev/composer-parameter-handler": "~2.0", // v2.1.0
"doctrine/doctrine-fixtures-bundle": "~2.2.0", // v2.2.0
"ircmaxell/password-compat": "~1.0.3", // 1.0.3
"phpunit/phpunit": "~4.1" // 4.1.0
}
}
Hi, I've following this videos and I found em great, but just one thing, "OptionsResolverInterface" is deprecated in 2.6 version. Would be nice to read a post or watch an update of how to fix it.
Cheers!