Starting Form Handling0:06
All right, so congratulations, you've made it to a new chapter. New chapter, new shirt. We're now gonna move on to form handling. And you know what? I just have a feeling that this video, specifically this one right here that you're watching for many of you, is gonna be the one that unlocks so many doors. It'll be the one where you figure out, okay, I kind of get what's going on here.
It'll be the one where you figure out, okay, I kind of get what's going on here. I understand how I can receive data from the user, how I can submit the form, how I can do something with that data, and how I can then redirect when I'm done. So without further ado, let's get going. Alright, so let's begin within our routes file. And the very first thing I wanna do is rename this view welcome, not really appropriate anymore. Instead, for this video, we're gonna build kind of a,
Creating Ideas View0:47
welcome, not really appropriate anymore. Instead, for this video, we're gonna build kind of a, a digital notebook, so to speak, a way to record and save ideas for later. So let's rename this to ideas for now. And you'll see, because I'm using PB Storm, it will actually update the view name automatically, but likely on your end, you may have to do that manually. Okay, so now we know when the user visits the homepage, we're gonna load a view called ideas
Styling with Tailwind1:09
Okay, so now we know when the user visits the homepage, we're gonna load a view called ideas that in its current state, is an empty uh, layout. Okay? So we know we're gonna have some kind of form that will ultimately have a text area, right? So if I were to view this in the browser though, well we just got an empty text area, an Unile text area. And so here's the deal. I don't wanna make you watch me write a bunch of CSS by hand, so I'm gonna pull in a CSS framework called Tailwind,
write a bunch of CSS by hand, so I'm gonna pull in a CSS framework called Tailwind, but it's really important for me. Let's zoom in. It's really important for me to note. If you don't like Tailwind, if you don't know what it is, it doesn't matter. It's not gonna block you. You can skip over it entirely. The only reason I'm pulling it in is just so our form looks a tiny bit prettier. But yeah, if you wanna skip over that,
so our form looks a tiny bit prettier. But yeah, if you wanna skip over that, if you're working along, go right ahead. Okay, so let's do this. So I will visit the Tailwind CSS website and specifically I will go to their paid section, but don't worry, I'm not promoting their paid tool. We're gonna use some of the free components they offer. So let's look for forms and they should have some basic form
So let's look for forms and they should have some basic form layouts that we can reach for. And yeah, we're gonna keep this crazy simple. I just want something like this, just a, a simple heading a text area and then a label below it. All right, so let's go to the code and you'll see this is a free sample and I'm gonna grab this right here and close it out. Okay, so now back to my editor.
and I'm gonna grab this right here and close it out. Okay, so now back to my editor. Let's now replace this text area with our tailwind snippet. Okay, so we have a label, a wrapper for our text area and then a note below. But yeah, right now we haven't installed tailwind. So if I were to come back and refresh, yeah, I mean this is fine, but it's not using tailwinds. So what we'll do is later I'll show you the formal way for how to pull this into your project.
So what we'll do is later I'll show you the formal way for how to pull this into your project. But for now, let's just reference it from A CDN, which is almost exclusively used for demos and things like this. So I will paste it in here and you can see I'm referencing it on a CDN. If you wanna do the same, you can pause and copy this or just Google tailwind, CDN, and you'll find this very link.
or just Google tailwind, CDN, and you'll find this very link. Okay, so now that's it. If I were to come back and give it a refresh there, there we go. We can see it's taking effect, but of course, because I have a light background, you can't even see the text area there, so that's okay though. I'm gonna use a dark background.
there, so that's okay though. I'm gonna use a dark background. We'll do a class of background of gray. And again, all of these are provided through tailwinds. So why don't we do something like 700 if I come back and give it a refresh. I think that looks good. Okay, so now very quickly, let's add some padding, uh, represented by P six all around. And then finally, maybe I will set a maximum width of like Excel and then I'll set the margins to auto.
And then finally, maybe I will set a maximum width of like Excel and then I'll set the margins to auto. So yeah, this is utility-based CSS. If you're unfamiliar with this, I would highly recommend taking a look. Uh, I really love it, but otherwise, if you're just not interested, that's okay too. Skip over this part entirely. So anyways, now if I come back and refresh, we have a, a nice sleep presented form.
So anyways, now if I come back and refresh, we have a, a nice sleep presented form. Okay, so now we can return to our ideas view and substitute this, we'll say new idea. And then let's update the labels four attribute, which of course points to the inputs id. And then we'll also update the name attribute as well. Let's do all three of those and change it to idea. Finally, for our little blurb here, we'll say, have an idea you want to save
Finally, for our little blurb here, we'll say, have an idea you want to save for later, something like that. And that gives us this. Great, looks good to me. Okay, so now how should this work? Well, ideally the user enters an idea into the text area, they click a button, and then that should post to our server. Alright, let's do that. Now let's add the button
Alright, let's do that. Now let's add the button and we don't have one, so why don't we grab that from the tailwind site. Let's return and let's see, do we have anything? Hmm, yeah, why don't we grab this guy right here. So I'll come back and go to the code, go to the bottom, and wow, that's here. There we go. So let's grab this, and I think we're done there.
There we go. So let's grab this, and I think we're done there. So we'll switch back and I will paste it in at the bottom. We don't need a cancel button, we just need a basically a footer with a button, with a type of submit that will say, save. Pretty cool. So come back, refresh. And there we go. And in this case, I don't think we need to align to the right, so why don't we get rid of this entirely and it'll align to the start.
Submitting a POST Form5:36
to the right, so why don't we get rid of this entirely and it'll align to the start. Cool. Alright, so now I'm gonna type something in, I click save, but of course, by default, a form is just gonna make a get request to the current page. And that's specifically why you see that the page reloaded and it's sent through the, um, the idea name. We don't want that. Instead, we're gonna make a post request. So the method is post,
we're gonna make a post request. So the method is post, and of course action is gonna be the endpoint, uh, the URI, uh, that we are posting to. Let's stick with ideas. Okay? So now if we did nothing else, if I come back and I try this again, we're gonna get a 4 0 4. And can you guess why? Can you pause and guess why, why are we getting a 4 0 4? And of course the answer is
Can you pause and guess why, why are we getting a 4 0 4? And of course the answer is because we haven't registered a route that responds to that. So now you might be thinking though, well wait a minute, Jeff. Yes, we did. We have a route that loads the ideas view, right? We have a get route that responds to the homepage. We are, or we're not yet listening to a post request to the ideas page.
We are, or we're not yet listening to a post request to the ideas page. So let's create another one. I'll copy this and say, now listen for a post request, not a get request, two ideas. And then here I'm gonna use that dd uh, function that we learned about in the blade directives lesson. We can also use it as a global helper. So I can say hello. I call these sanity checks. It's, it's a way to say, all right,
I call these sanity checks. It's, it's a way to say, all right, are we even hitting this line before I proceed? Are we getting to this point? So let's add an idea, submit it, and now we get a four 19. And this can be a little confusing at first page expired. What did we, did we not fill it out quickly enough? Let's do it really fast this time, try it again and no, we're gonna get the exact same thing.
CSRF Protection Explained7:23
Let's do it really fast this time, try it again and no, we're gonna get the exact same thing. And that's not what it means. Uh, so what's happening here is Laravel provides some automatic protection out of the box against what's known as, uh, a cross site request, forgery attack. Now, you don't necessarily need to know too much about what that is, but it's helpful. So if you want, let's, let me give you the 32nd illustration, cross site request forgery.
So if you want, let's, let me give you the 32nd illustration, cross site request forgery. This is an attack where a user is tricked or coerced into making a request to an entirely different server, an entirely different domain than the one they're currently on. And here's the most bare bones example. Imagine you're on my website and when you submit some kind of random form,
Imagine you're on my website and when you submit some kind of random form, some unassuming form on my website, it's actually making a post request to laas.com to log you out. Well, if we don't protect against things like this on the laas end, we just receive the incoming request, we see the cookie and we sign you out. So think about that. You would have a way on this website over here to submit a form
So think about that. You would have a way on this website over here to submit a form that then logs you out on an entirely different website over here. And this is the most basic example you can imagine far more dangerous, um, examples like transferring money potentially if you have the worst bank ever, you know, um, um, grabbing data, changing data, uh, deleting an account, things like that, right? So here's the way we solve against that.
things like that, right? So here's the way we solve against that. We have these tokens and we call them CSRF tokens. They are generated on the server, um, that we're trying to protect against. So in this case, project test will generate its own token and this is happening for you automatically, by the way. Next, we will add that token to our form, and when the form is submitted, we will compare the token that was generated in the form to the token
and when the form is submitted, we will compare the token that was generated in the form to the token that we have on the server side and see if they match up. And if they did, well then that means we're safe, right? That means this form is being submitted, uh, against the current sites because the tokens match up. If we're over on the malicious side over here, we don't have access to that CSRF token, so we are unable to complete the attack. That's what's going on here.
to complete the attack. That's what's going on here. And in this case, because we didn't include the token in our form, this is why they don't match up. So we see a four 19. Okay? So let's fix that. And like everything in Laravel, it's super simple. Let's go back to our view. And at the top I'm gonna add a new blade directive called CSRF. That's it. We're done. Our protection is now in place.
called CSRF. That's it. We're done. Our protection is now in place. Alright, so let's give it another shot back to our editor. And real quick, let's open up dev tools and let's go to our form right here. And there we go. So that CSRF directive is basically a wrapper that creates this input right here. It has a name of token and this value is our CSRF token. Again, when we submit the form,
It has a name of token and this value is our CSRF token. Again, when we submit the form, it will be included with the request. We then compare that value against the token that was generated server side and as long as they match, we're good to go. Cool. So let's get going. Now I submit the form, I hit save and we get hello, it works. Our sanity check is in place.
Saving Ideas in Session10:37
and we get hello, it works. Our sanity check is in place. We have now uh, passed the CSRF protection check and we are now moving on to the point where we can process the request data. Alright, so next, how do we access that request data? Well, we can do it in a couple ways. We have a request helper method we could use and I could say, give me all of the request data and yeah, if you ever wanna see, well,
and I could say, give me all of the request data and yeah, if you ever wanna see, well, what is all of the request data? Once again, reach for your handy dandy DD where you gotta get that shirt, right? Come back, give it a refresh. And there we go. So we have our idea, and then of course we have the token that was included with the form submission, but this is the thing we care about.
with the form submission, but this is the thing we care about. All right, let's give it another shot. We'll say what's an idea? Um, every developer, we need to launch a new podcast. So we do this and sure enough we have sent that to the server, we can now fetch that idea and persist it in any way. Uh, we want to, for now, we haven't yet, uh, discussed databases,
Uh, we want to, for now, we haven't yet, uh, discussed databases, so we're just gonna store it in a session that is unique to the user's current browser. So I'll show you how to do that. Let's grab the idea from the request. And I can do it by saying request idea. And this is one way to do it. Another option is to use what's known as a Laravel facade. If I type requests.
Another option is to use what's known as a Laravel facade. If I type requests. And there's gonna be a bunch here and you wanna make sure you grab the right one. So if you wanna use the facade approach, look for the one that includes the word facade, illuminate support, facades request. And then I could say, um, get, uh, get the input for ideal and this would be the exact same thing. And of course you can import this at the top.
and this would be the exact same thing. And of course you can import this at the top. Another option just to confuse you a little bit, and I'm only telling you this because you're gonna see it in the wild. So if you're a little confused, it's important to know upfront. Another option is you might see the request, um, declared as a parameter here and it'll be this one right here, illuminate
as a parameter here and it'll be this one right here, illuminate HTTP request, not the facade. So you might see this as well. And yeah, in these cases you might say, uh, request get me the input for idea. Or you might even see it used like this. So all of this is, is meant not to confuse you, but just to show you, sometimes there's more than one way to do things.
but just to show you, sometimes there's more than one way to do things. And in the wild, if you're looking at source code, I don't want you to feel super confused for now, we're gonna keep it very simple and we're gonna use that helper function called request. So I can say idea is request idea, okay, what's an easy way to persist something? Let's use the session so I can say session. And once again, we have a little helper
Let's use the session so I can say session. And once again, we have a little helper function here called session. We're going to push something to the session and we're gonna give this a unique name. In this case ideas. AI is helping me out. I think that looks good. Two ideas. We're gonna push a new item and you can think of this as an array. Let's push idea. Alright,
and you can think of this as an array. Let's push idea. Alright, so this is done. And think about what's happening. When the user visits the homepage, we load a view the user types in an idea that they have when they submit the form, that then takes 'em to this point here we fetch their idea and we push it into the session that has this name of ideas. What do we do now though?
and we push it into the session that has this name of ideas. What do we do now though? If we don't do anything, we're just gonna get a white screen, aren't we? Let's give it a shot. Uh, launch a podcast save. And yeah, we, we handled those steps but then we didn't do anything. So we just see a white screen here. What we should do is redirect somewhere. Where should we redirect?
What we should do is redirect somewhere. Where should we redirect? Well, hmm, let's just redirect back to this page. So why don't we say return a redirect to where, back to the homepage. And that's it. It's complete. When you post here, grab the idea, push it into this array called ideas, and then redirect back to the homepage. So now we can see when we load the homepage, we should grab
and then redirect back to the homepage. So now we can see when we load the homepage, we should grab or fetch the ideas or get the ideas from the session if there are any. So let's give that a shot session, get ideas and we're gonna save that. Alright? So once again, sanity check. Do we have anything here? And think about it. We should at this point. So if I come back, refresh, sure enough, ideas is an array that contains one item.
We should at this point. So if I come back, refresh, sure enough, ideas is an array that contains one item. However, in some cases there won't be any at all, in which case null will be returned. So in these situations you might wanna set a default. If there are no ideas in the session, then let's start. Let's, uh, let's initialize things with an empty array. Alright, so now I'm gonna pass those ideas to our view and we've learned how to do that just like this. Cool. So let's make pint happy,
and we've learned how to do that just like this. Cool. So let's make pint happy, let's load our view. And then yeah, maybe right down here at the bottom we will say your ideas and we're just gonna loop over that array and display each idea below something like this. We'll say, we'll for each ideas as idea, then within a list item, echo that idea. All right, let's give it a shot. Let's come back.
then within a list item, echo that idea. All right, let's give it a shot. Let's come back. And there we go. It doesn't look very great. We'll fix that in just a minute, but sure enough, this is working. Okay, so very quickly, why don't we say MT six and then we'll just set the, the color here, even though I should probably do it set wide. Yeah, something like that. Let's say, uh, font bold. Yeah, and then maybe, uh, a little margin there.
Yeah, something like that. Let's say, uh, font bold. Yeah, and then maybe, uh, a little margin there. And then on each of these we'll say tech small. Good enough for me. Uh, no issue there. So this looks good. Can I add a new idea? Sure. Um, start a new branch of lar cast.com. Save it. And there we go. We pushed to the session. We redirected when we redirect on the homepage, we fetch, uh, the array of ideas from the session. We pass it to the view, the view receives it,
uh, the array of ideas from the session. We pass it to the view, the view receives it, it loops over the ideas and it renders each one within a list item. So cool. So now let's do this. Um, let's go back here and temporarily I'm gonna add a route, uh, that will just delete all of the items from the session. Um, in the next episode I'll show you how to formally submit a delete request to do that.
Um, in the next episode I'll show you how to formally submit a delete request to do that. But for now I'm just gonna say delete ideas. And all we would do in this particular case is say session forget ideas and then let's redirect, uh, back to the homepage. Now again, I just wanna reiterate, this is kind of sloppy. We shouldn't do this. We are doing something destructive as part of a get request. This isn't restful, it's only temporary for now
as part of a get request. This isn't restful, it's only temporary for now until we talk about delete requests. But yeah, it's just a way to reset things very quickly for us. Alright, so now if I were to come back, I can go to delete ideas. There, there we go. We emptied our bucket so to speak, but now notice even though we don't have ideas, I still see the heading, which is a little confusing.
but now notice even though we don't have ideas, I still see the heading, which is a little confusing. So let's do this. Let's wrap it and say, well only on the condition that we have some ideas. So we check the count. If there are some then render this HTML block. Otherwise, ah, we don't need to see that at all. All right, let's add an idea. Once again, launch a podcast, make a new Laravel course profit.
Once again, launch a podcast, make a new Laravel course profit. You get the idea. We are now recording our ideas and if I refresh, it's still gonna work because they are linked to our current session. And real quick, if it helps you, uh, if sessions are somewhat new, I like to think of sessions, sort of like a notepad that is unique to each user. Each user gets their own notepad where we can record stuff, we can store stuff for later,
Each user gets their own notepad where we can record stuff, we can store stuff for later, but they are temporary, which means if I were to open this page in Firefox, well I'm not gonna see any ideas because we have a new session in that case. So yeah, just keep in mind for long-term persistence, we actually would want to reach for something like a database and I promise I'll show you how to do
for something like a database and I promise I'll show you how to do that in the next chapter. Alright, so we're about done here. Um, it's really important to me that you know exactly what's going on here. So if at any point if you didn't understand this, if CSRF went right over your head, that's okay. If there's something weird here, uh, let's go to the routes file.
If there's something weird here, uh, let's go to the routes file. If you didn't get this, if the request stuff was confusing, now is the opportunity to ask a question, uh, below the video@layercast.com and we will get you patched up. We will make sure you understand every piece of this before we move on to the next lesson. And in fact, in the next lesson, I wanna return to this and figure out maybe a cleaner way
And in fact, in the next lesson, I wanna return to this and figure out maybe a cleaner way that we can wipe all of our ideas. I'll see you then.
