Buy

Hey guys! You're back! Awesome! Because this tutorial is all about forms: the good, the bad, and the ugly.

Quit Hatin' on the Forms

The truth is: the form component is super controversial: some people love it, some people hate it - and a lot of people have trouble learning it. In fact, its documentation on symfony.com is read far more than any other section.

Why? Because honestly, it is complex - too complex sometimes. But you know what? The form component is going to allow you to get a lot of work done really quickly. And when I do see someone suffering with forms, most of the time, it's their fault. They create situations that are far more complicated than they need to be.

So let's not do that - let's enjoy forms, and turn them into a weapon.

Sing Along Code along!

Ok, you guys know the drill: download the course code and unzip it to code along with me. Inside, you'll find the answers to life's questions and a start/ directory that has the same code I have here. Make sure to check out the README for all the setup details.

Once you're ready, start the built-in web server with:

./bin/console server:run

I made a few changes to the site since last time. For example, go to localhost:8000/genus. It looks the same, but see the "Sub Family"? Before, that was a string field on Genus. But now, I've added a SubFamily entity:

40 lines src/AppBundle/Entity/SubFamily.php
... lines 1 - 6
/**
* @ORM\Entity
* @ORM\Table(name="sub_family")
*/
class SubFamily
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string")
*/
private $name;
... lines 24 - 38
}

And created a ManyToOne relation from Genus to SubFamily:

119 lines src/AppBundle/Entity/Genus.php
... lines 1 - 11
class Genus
{
... lines 14 - 25
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\SubFamily")
* @ORM\JoinColumn(nullable=false)
*/
private $subFamily;
... lines 31 - 117
}

So every Genus belongs to one SubFamily.

I also started a new admin section - see it at /admin/genus. But, it needs some work - like the ability to add a new genus. That'll be our job. And the code will live in the new GenusAdminController.

Creating a new Form

To create a form, you'll add a class where you'll describe what the form looks like.

Tip

Actually, you can build a form directly in the controller if you want to.

In PhpStorm, select anywhere in your bundle and press command+N, or right click and select "New". Find "Form" and call it GenusFormType:

21 lines src/AppBundle/Form/GenusFormType.php
... lines 1 - 2
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class GenusFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
}
public function configureOptions(OptionsResolver $resolver)
{
}
}

Cool! This just gave us a basic skeleton and put the class in a Form directory. Sensible! These classes are called "form types"... which is the worst name that we could come up with when the system was created. Sorry. Really, these classes are "form recipes".

Here's how it works: in buildForm(): start adding fields: $builder->add() and then name to create a "name" field:

25 lines src/AppBundle/Form/GenusFormType.php
... lines 1 - 8
class GenusFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
... lines 15 - 16
;
}
... lines 19 - 23
}

Keep going: add('speciesCount') and add('funFact'):

25 lines src/AppBundle/Form/GenusFormType.php
... lines 1 - 12
$builder
->add('name')
->add('speciesCount')
->add('funFact')
;
... lines 18 - 25

Right now, those field names can be anything - you'll see why in a second.

And that's it! The form is built after writing about 4 lines of code! Let's go render it!

Leave a comment!

  • 2016-07-12 叶朱丽

    Hi Ryan!
    Now I see why....
    Thanks a lot for your explanation!

  • 2016-07-12 weaverryan

    Hi Giulietta!

    Actually, this error is ok! When we create the form in this tutorial, the URL is actually /admin/genus/new. When you go to /genus/new, you're executing a different controller - and this controller (at this point in the tutorial) is old and outdated (I actually forgot it was there - you should ignore it). I think the missing "New" button is the same problem - try going to /admin/genus (instead of /genus) - and you should see that button. The idea is that we have a public "frontend" for our site (e.g. /genus) and an admin section (e.g. /admin/genus).

    Cheers!

  • 2016-07-09 叶朱丽

    Hi!
    I keep on getting this error when trying to access the /genus/new page:

    Type error: Argument 1 passed to AppBundle\Entity\Genus::setSubFamily() must be an instance of AppBundle\Entity\SubFamily, string given, called in C:\xampp\htdocs\symf3\finish\src\AppBundle\Controller\GenusController.php on line 23

    I have tried to solve the problem, but I am afraid this goes beyond my knowledge :(

    Also, I don't see the 'New' blue button anywhere (tried with both the 'start' and the 'finish' files provided).

    Am I missing something?

    Thanks a lot!

    Giulietta

  • 2016-06-15 JLChafardet

    weaverryan Glad to have been of help

  • 2016-06-15 weaverryan

    Awesome, thank you for checking! I'll push the fix now :)

  • 2016-06-15 JLChafardet

    Fixed indeed.

    below is diff of what it had, and what it has now.

    diff file: http://pastie.org/private/jmts...

    as you requested, and I said, created a new branch (as youll see in my terminal) reset --hard to the initial point (as i did a git commit with the error)
    changed parameters.yml to a new database (aqua_note_2)

    console doctrine:database:create
    console doctrine:migrations:migrate
    console doctrine:fixtures:load

    here is the whole output:

    Terminal output text: http://goo.gl/9yzKky
    Terminal output images:
    part 1: http://goo.gl/UzoRmw
    part 2: http://goo.gl/qt51c4
    Browser output (without the non existing methods ofc basic starting point)
    genus list: http://goo.gl/Oe9qOZ
    genus detail: http://goo.gl/KTbWex
    admin area: http://goo.gl/PeD5a9

  • 2016-06-15 JLChafardet

    weaverryan going to create a git branch for that point, and attempt your suggestion and let you know the results in a minute.

    --update--

    fixed, check latest message above this one.

  • 2016-06-15 weaverryan

    Hey JLChafardet!

    Since you're able to get this migrations bug, and I can't repeat it, would you be willing to test out a fix for me?

    Here's what you would do:

    1) Replace your Version20160207092254.php file with this one: https://gist.github.com/weaver...

    2) Drop everything and reload the fixtures from scratch:


    bin/console doctrine:database:drop --force
    bin/console doctrine:database:create

    ./bin/console doctrine:migrations:migrate

    If this works, then I'll push that fix up for everyone :).

    Thanks!

  • 2016-06-15 JLChafardet

    found a workarround.

    console doctrine:migrations:status

    this gave me the next in line migration version. which was 20160207092254

    checked in phpstorm which was the next in line, which was 20160412160008

    opened Version20160412160008.php got the version number(without Version) and performed:

    console doctrine:migrations:execute 20160412160008

    that worked.

    then did

    doctrine:migrations:execute 20160412165619

    which is the latest version

    then loaded the fixtures and bam, worked.

  • 2016-06-15 JLChafardet

    weaverryan need a hand here! your code is giving me a plethora of errors.

    http://goo.gl/ipSR6s <- take a peak