|
| 1 | +# Handling the Submitted Form in the Controller |
| 2 | + |
| 3 | +Alright, we've built, created, rendered, and styled our form (I swear, I’ve |
| 4 | +done my best so far!). I've given it my all and now our form is ready for |
| 5 | +submission. Now, as any seasoned backend developer will tell you, the real |
| 6 | +fun begins when we start dealing with that submitted data. Let's jump back |
| 7 | +into our controller and make this form functional. |
| 8 | + |
| 9 | +## Updating Controller to Handle Form Data |
| 10 | + |
| 11 | +Open up `src/Controller/AdminController.php`, and in the `newStarshipPart()` |
| 12 | +method, right below the form object, add `$form->handleRequest()`. |
| 13 | + |
| 14 | +To pull this off, we need to pass the current request object to this |
| 15 | +method. You're familiar with this by now. Inject a `$request` from |
| 16 | +HTTP Foundation as a method argument and pass the `$request` to this |
| 17 | +method. You might be wondering what this `handleRequest()` is all about. |
| 18 | +It simply grabs the submitted data from the request, applies that data to |
| 19 | +your form, and now your form contains the user's submitted values. |
| 20 | + |
| 21 | +## Checking Form Submission |
| 22 | + |
| 23 | +Next, we want to know whether the form has actually been submitted or we just |
| 24 | +load the form page. That's a breeze — just write `if ($form->isSubmitted())`. |
| 25 | +Then within that `if`, we can retrieve the submitted data with `$form->getData()`. |
| 26 | + |
| 27 | +Since our form type has a `data_class` option set to `StarshipPart::class`, |
| 28 | +the data you retrieve here isn't a straightforward PHP array. Instead, it's a |
| 29 | +`StarshipPart` entity instance with the fields already filled in for us. |
| 30 | +Skeptical? Go ahead and check it yourself. Let's assign it to a `$part` |
| 31 | +variable and below `dd($part)`. |
| 32 | + |
| 33 | +## Testing Our Form |
| 34 | + |
| 35 | +Back in the browser, I'll quickly fill in the form. Hit create to submit it |
| 36 | +and voila, a shiny new `StarshipPart` object with the data we sent. Notice |
| 37 | +that no ID is set because Doctrine hasn't saved it in the database yet. |
| 38 | +I'll quickly add a PHPDoc above the variable to make PhpStorm's autocomplete |
| 39 | +happier, and delete the `dd()` statement. |
| 40 | + |
| 41 | +## Saving Data with Doctrine's EntityManager |
| 42 | + |
| 43 | +To save the new part, we need Doctrine's `EntityManager`. Inject it with |
| 44 | +`EntityManagerInterface $entityManager` in the method signature. Then, back |
| 45 | +in the `if`, add `$entityManager->persist($part)`, passing the `$part` |
| 46 | +object and next `$entityManager->flush()`. |
| 47 | + |
| 48 | +Back to the browser, I'll set the name to: "Legacy Hyperdrive". |
| 49 | +Give it a fair price, and don’t forget about important note: |
| 50 | + |
| 51 | +> Be careful with high revs! |
| 52 | +
|
| 53 | +Now, hit the submit button again. Did it finally work? Well, at least there are |
| 54 | +no errors. Head to the `$part` page and search for "legacy hyperdrive". |
| 55 | +There it is, your new shiny Starship part, ready for sale. |
| 56 | + |
| 57 | +## Celebrating Success with Flash Messages |
| 58 | + |
| 59 | +Let's celebrate this moment properly. I'm going to add a successful flash |
| 60 | +message. Flash messages are temporary messages stored in the session and |
| 61 | +shown exactly once. They are perfect for things like: |
| 62 | + |
| 63 | +> Your part was created successfully! |
| 64 | +
|
| 65 | +If you peek into `templates/base.html.twig` You'll see we already have code |
| 66 | +that loops over flash messages and renders them with nice styling depending |
| 67 | +on the type: success, warning, error, default. After saving the entity to the |
| 68 | +database, let's write this: `$this->addFlash()` |
| 69 | + |
| 70 | +First argument: the message “type” - it helps to control styling. Write |
| 71 | +`success` here. Second argument: the content of the message. How about |
| 72 | +`sprintf('The part "%s" was created.', $part->getName())`. |
| 73 | + |
| 74 | +## Avoiding Duplication and Redirecting User |
| 75 | + |
| 76 | +To avoid duplicate form submissions when the user refreshes the page - which |
| 77 | +might lead to unwanted parts floating around in space - let's finish the |
| 78 | +process with a redirect. This is a classic best practice for POST forms. |
| 79 | +Let's return `$this->redirectToRoute()`. |
| 80 | + |
| 81 | +We can redirect anywhere, but I'll send users back to the part list for |
| 82 | +convenience. It should be `app_part_index` route name. |
| 83 | + |
| 84 | +## Testing the Overall Flow |
| 85 | + |
| 86 | +Alright, let's create a new part again. How about a quantum reactor for the |
| 87 | +name, set a price, and for notes, I'll say: |
| 88 | + |
| 89 | +> Do not exceed 120% core flux |
| 90 | +
|
| 91 | +OK, submit the form again, and there it is. Our success flash message, |
| 92 | +announcing that the part quantum reactor was successfully created. And if I |
| 93 | +try to refresh the page, the message is gone, so it was shown only once, |
| 94 | +and Chrome does not ask me if I want to resubmit the form again, so it was |
| 95 | +redirected properly too. Sweet! |
| 96 | + |
| 97 | +## Adding a Second Submit Button |
| 98 | + |
| 99 | +Right now we only have one submit button: Create. But imagine this, if |
| 100 | +you're feeling productive, caffeinated, on a roll, and you want to create |
| 101 | +multiple parts quickly, one after the other, you could do this with a few |
| 102 | +extra clicks each time, clicking on the link to return to the form. But |
| 103 | +wouldn't it be so much faster to have a second submit button, that, instead |
| 104 | +of creating and going back to the list, creates and stays on this page with an |
| 105 | +empty form open, so you can immediately create another part? |
| 106 | + |
| 107 | +Well, it might not be much faster, but it still could save someone a few hours |
| 108 | +of their life over the course of many years of adding those parts. |
| 109 | +You might be wondering, is that even possible? Absolutely! And we'll figure out |
| 110 | +how in the next chapter. |
0 commit comments