Skip to content

Commit 1df4325

Browse files
authored
Merge pull request #33 from SymfonyCasts/ch4
Add scripts to the 4th chapter
2 parents 2f30c9c + 92f90bb commit 1df4325

File tree

1 file changed

+156
-2
lines changed

1 file changed

+156
-2
lines changed

sfcasts/multiple-submits.md

Lines changed: 156 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,158 @@
1-
# Handling Multiple Submit Buttons
1+
# Multiple Submit Buttons
22

3-
TODO
3+
Alright, we've got our "Create" button working like a charm, but what if we
4+
want a couple of different workflows: "Create and Close" to save the part
5+
and jump back to the list, and "Create and Add Another" to save the part
6+
but stay on the form page for quick data entry.
47

8+
No worries, Symfony is fully capable of handling this. Let's dive into
9+
the second method of adding buttons to a form using the Form type,
10+
and use it to drive our business logic.
11+
12+
## Adding a Second Submit Button Inside the Form Type
13+
14+
First things first, let's tweak the name of our current button in the
15+
`new.html.twig` template to "Create and Close". Now, pop open your Form
16+
type class in `src/Form/StarshipPartType.php`. It's time to drop in a
17+
second button below the fields. Let's add another one using
18+
`->add('createAndAddNew', SubmitType::class)`. This handy
19+
`SubmitType::class` tells Symfony to render it as a `<button type="submit">`.
20+
21+
If you hop over to the browser and refresh, you'll see our two buttons. The
22+
new one doesn't quite look like a button - that's because we've reset
23+
styles. But technically, in the code, it's `<button type="submit">`.
24+
We'll spruce up the styles later.
25+
26+
## Accessing Unmapped Fields in Symfony
27+
28+
For now, in the controller, we're already aware that `form->getData()`
29+
hands us a mapped entity, which in our case is `StarshipPart`. This time,
30+
though, we need to get our hands on an unmapped field - the submit button
31+
we just added. This field doesn't have a matching property on the entity,
32+
which is why we call it "unmapped".
33+
34+
No sweat, we can access any field. Directly below the `addFlash()`, let's
35+
cook up a `$createAndAddNewBtn` variable that equals
36+
`$form->get('createAndAddNew')`. This should match the button name on your
37+
Form type. Let's give it a quick test run first. Down below, I'm going to
38+
write `dd($createAndAddNewBtn)`.
39+
40+
Back to the browser, filling the form notes is optional, so just the name
41+
and price will do. I'm going to hit our "Create and Add New" button now,
42+
and there's our dump. It's a Submit Button with some intriguing fields.
43+
Take a closer look and you'll spot the magical `clicked = true`. Believe it
44+
or not, this little gem is how we can tell which button was actually
45+
clicked, and we can harness this to power different business logic.
46+
47+
## Harnessing Button Clicks to Execute Business Logic
48+
49+
Back to PHPStorm, I'm going to get rid of the `dd()` and give PhpStorm a
50+
little help. To solve the autocomplete, above the button, I'm going to add
51+
`/** @var SubmitButton $createAndAddNewBtn */`. Now, inside your form
52+
submit logic, try typing in `$createAndAddNewBtn->isClicked()`. That's
53+
exactly what we need. Wrap it in an `if` statement, and if the button was
54+
clicked, let's return `$this->redirectToRoute('app_admin_starship_part_new')`.
55+
56+
Now, give the form another whirl. Here's our flash message:
57+
58+
> The part was successfully created
59+
60+
We see it twice because I just resubmitted the form. In the new scenario,
61+
it should be only one message. So we were redirected back to the form page.
62+
You can test out the "Create and Close" button. That should still bring you
63+
back to the part list page.
64+
65+
So, this was a completely valid and super useful way of adding form buttons
66+
inside the Form Type. But if you can avoid cramming buttons in the Form type
67+
and stick to plain HTML buttons, your designer teammates will silently
68+
thank you.
69+
70+
## The Intricacies of Symfony's Form Type: Field Type Guessing
71+
72+
Let's zip back to the Form type for a second. You've probably noticed this
73+
`$builder->add('price', null)`. The second argument to the `add` method
74+
should be the type of the field and for some fields like `price`, `name`,
75+
`notes`, it is `null`. But why `null` instead of a real type like
76+
`IntegerType` in this case, for example?
77+
78+
Well, Symfony has this nifty feature called "field type guessing". When you
79+
set the type to `null`, Symfony will inspect entity properties metadata.
80+
For example, if `price` is an integer property, Symfony will pick `IntegerType`.
81+
If `name` is a string then Symfony will opt for a `TextType`. If we had,
82+
let's say, an `isActive` boolean, then Symfony would select a `CheckboxType`,
83+
and so on.
84+
85+
You can confirm this by peeking at the rendered HTML. Inspect the code for
86+
the `price` field, and you'll see that it's not just `<input type="text">`,
87+
it's `<input type="number">`, which gives us some handy arrows to increase
88+
and decrease the value. This is because the `price` property on the
89+
`StarshipPart` entity is an integer and the Symfony Form Component catches
90+
sight of it. That's why it uses the more optimized field type.
91+
92+
Most of the time, Symfony guesses exactly what you want. But when Symfony
93+
can't guess correctly, or when you want something different, you can always
94+
override the default guessed type by passing the type explicitly.
95+
96+
For example, like this one `IntegerType::class`. If you refresh, nothing will
97+
change, because that's exactly what was set behind the scenes.
98+
99+
## Exploring Symfony's Built-in Form Field Types
100+
101+
But what built-in form field types does Symfony have and where can you find
102+
them? Great question, and I'm glad you asked! Symfony docs will always
103+
be there to help with that. But Symfony also comes with a super nerd-friendly
104+
tool for discovering everything about built-in field types.
105+
106+
In your terminal, run:
107+
108+
```terminal
109+
symfony console debug:form
110+
```
111+
112+
This dumps all available form types, including your own Form Type classes,
113+
which we can see here as a service.
114+
115+
If you want to inspect a specific type, just specify it as an argument to
116+
the command. For example, run:
117+
118+
```terminal
119+
symfony console debug:form TextType
120+
```
121+
122+
And you'll see all options that `TextType` supported, which options are
123+
required and which options come from parent types it extends. Try another one,
124+
for example, run:
125+
126+
```terminal
127+
symfony console debug:form EntityType
128+
```
129+
130+
You'll see that the `class` option is required and MakerBundle already
131+
filled that for us. So smart! Options are set as the third argument
132+
in the array.
133+
134+
And by the way, Symfony doesn't only guess *field types*, it also guesses
135+
*field type options*. For example, if a Doctrine property is `nullable =
136+
true` like for this `notes` field, then Symfony will automatically make it
137+
optional. And the reverse for the other fields, Symfony will automatically
138+
set `required` HTML attribute if field is not nullable.
139+
140+
You can see it in the HTML inspector. For example, we don't see this
141+
`notes` field is required, but if you inspect the `name`, you will see it
142+
has a `required="required"`. And that's why when you hit "Submit" button
143+
with an empty form, you will see these HTML5 validation errors on empty form
144+
submit.
145+
146+
And of course, you can easily override that if needed, too. Options can be
147+
set within an array as the third argument. And if you pass an array and set
148+
`required` to `false`, you will override the default behavior and the
149+
`price` field is not required anymore.
150+
151+
I'm going to revert back this code because we do want the `price` field as
152+
a required field, and we do want it set in the database.
153+
154+
Now, we'll dive much deeper into form field types later in this course.
155+
For now, let's switch gears to something fun and stylish: making our form
156+
look actually nice by applying a built-in Symfony form theme to it.
157+
158+
Catch you in the next chapter!

0 commit comments

Comments
 (0)