Transcript for:

how exactly do you choose a first programming language to learn why PHP and not Ruby or JavaScript or python I mean how can you be expected to make such a large decision without having the expertise to differentiate between all of the available choices it's a good question now we could look at usage stats or developer happiness reviews but the truth is it largely depends on your environment there's no one correct answer just as there's no correct spoken language to learn it just depends now if you're hoping to turn at a WordPress or a larable shop then you're surely going to want PHP on the other hand you might have a friend who works at Shopify who has offered to show you the ropes in that case you'll likely be working with Ruby and that's cool too the point is it doesn't really matter right now you're interested in the fundamentals of programming and whether you choose PHP or Ruby or something else doesn't really matter you'll be happy to hear that these Concepts cross over and once you've learned one language the next one is significantly easier to pick up so with that in mind let's learn some PHP oh hi there I didn't see you walk in nice to meet you my name's Jeffrey and yeah little looks like I will be your teacher for this semester's PHP for beginners class and I hope you're excited because I'm not going to sugarcoat it you have a long road ahead there's a lot to learn not what you want to hear at the very beginning but it but it's true uh maybe at some point you saw a listing that says become a programmer with this twoe boot camp but I don't know what they're smoking it doesn't work that way it's a long track but trust me if this is the job and if this is the career for you I think you're going to enjoy every step of the process okay so let's talk about this course I've made for you um it has been meticulously designed specifically for where you are in your journey right now and sometimes at the beginning you are overwhelmed with options they'll say hey install a code editor and then you check and there's 12 different choices well which one do I pick uh maybe you want to learn a language well which one there's there's 10 different ones to pick you know so you are constantly inundated with choices that you are not yet qualified to make and that's where I step in for each step of this process I will show you choices and then I will recommend one or two maybe this editor maybe install PHP in that way uh when you're working with the language itself maybe take this approach instead of that approach and I think it'll really help you and trust me I only wish someone had been available 15 years ago or so when I was first learning it would have been a massive help to me and you get this all for free you don't have to pay a penny for it so I hope you're excited I'm done talking let's get to work okay so before we can dig in and have some fun of course the first step is to create the world so to speak and that means installing all of the tooling necessary to start building PHP applications so let's go the first prerequisite is a good code editor and maybe you already have the step complete uh I'm assuming you might have a little HTML and CSS experience but maybe that's about it uh but nonetheless I would recommend using PHP storm which is what I will use in this series or Visual Studio code or Sublime Text all three are fantastic choices or again if you really like what you're currently using then stick with it no problem there at all next up you'll need access to a suitable terminal and Lily Mac and windows ship with these out of the box so for example I'm on a Mac if I were to search for terminal and this is how mine looks and yeah we're not going to spend too much time in the terminal but if you can change directories if you can list files if you can run a couple commands you'll be in good shape I'll show you one right now if I want to change directories I can use CD and on my Mac I'm going to go to my desktop so I can do this right here and there we go if I want to list the files I can use LS and in this case I don't have any files uh on my desktop and later you'll learn how to run commands like PHP and my SQL okay but otherwise you can also install dedicated tools that some people prefer for example I use one called warp and here's what that looks like a little bit cleaner but still effectively the same thing it just has a few bells and whistles you might also consider a tool like iterm or again on Windows uh Windows terminal should do the trick for you okay so on that note the next step is to of course install PHP in MySQL and I'll warn you this can be a little frustrating because there's so many different ways you could do it developers have all sorts of opinions about what that correct way is so what I'm going to do is show you a handful of those options and then I will recommend one or two all right so let's start with the Mac on the Mac I'm a big fan of a tool called Homebrew here's instructions for how to install it and then once it's available you can install PHP by saying Brew install PHP let me show you real quick I'm going to copy this right here or click on the clipboard switch to the terminal that you picked in the last window again I'm using one called warp and I will command V and run that command and yeah that's now doing its thing so let's give it just a minute okay and that's complete and then finally notice we need to run these two commands so I will copy them and paste it in so why don't we test it out by running the command brew and there we go let's now search for PHP Brew search PHP and here's everything that pops up and yeah notice how we can install the latest version of PHP like I've already done but if for some reason you also need an older version that's an option as well so in your case you would say Brew install PHP and notice at the time of this recording we're grabbing 8.1.4 all right that took a few minutes but it looks like it's done and let's try it out PHP DV for version and sure enough I get 8.1.4 okay let's try it again but this time for MySQL which will be our database and I'll talk to you more about that in future episodes through install MySQL okay and that's finally done as well let's test it out there we go so yeah if you're on a Mac or even actually home brew is a nice and easy way to get these things installed on your machine but what about Windows well for Windows a very popular tool these days is called laragon just visit leon. org visit the download page and you will want this version right here and that'll get you up and running it's a full UI it's the full thing it's the full deal otherwise if you're familiar with WSL and WSL 2 you might consider that h maybe the the entry point is a bit higher depending upon where you are and you're learning uh I would base your usage of this on if you know what it is if you identify with this and you think oh that's exactly uh what I need then that's the way to go otherwise if this looks like gibberish maybe skip over it of course there's dedicated tooling like Docker and there's wrappers around Docker again it's a little advance for where we currently are you might consider a long-standing uh tool called zamp and there's also one called M uh M works for Windows and Mac these are these are traditional local environment ecosystem so to speak and they include everything you need to get up and running so yeah whether you install it manually with home brew uh whether you pull in largon or zamp or M it doesn't exactly matter so your job right now is to pick one of these again I would recommend home Pro and Lon if you're on Windows pick one of these run through the entire inst ation process and see if you can get it to work okay and then the final piece of the puzzle for now is to choose some kind of UI for interacting with your mySQL database now of course you could do it directly from the terminal and some people do but you know what I think you'll be a little more comfortable if you choose one of these dedicated apps the one I like and what we will be using in this series is called table plus and there is a download for mac and windows and it looks like Linux is an option as well otherwise if you want something webbased and and much more traditional PHP my admin is actually what I originally got set up with uh maybe 15 years ago or so you can try out the demo if you want it's an option um if you need it it's entirely free but you know what I would recommend just stick with table plus and you'll feel right at home okay so think about it at this point you should have something like PHP storm or Visual Studio code or Sublime Text installed on your machine a code editor uh you should have PHP and MySQL installed you should have a database goey like table plus installed you should have chosen a terminal whether it's the one that your OS provides or iterm or warp it doesn't really matter just pick one so now all of the tooling is available we don't quite know what to do with that tooling but it's now on our machine so that's the topic of the next lesson let's put it all together and uh figure out what comes out on the other side I'll see you then okay so our tools are now in place which means the next baby step is a little one let's just see if we can get something in the browser all right let's get going all right so I hope you're working along if so open up the terminal that you set up in the last episode and I'd like to create a directory for our first website but real quick and this will apply across the board for this series the way you go about creating a new site will slightly depend upon how you installed uh your environment how you installed PHP in your server so for example if you went with Homebrew like I demonstrated in the last video you can store your website directories anywhere you want on the other hand if you went with something like M have a look at the documentation I think they will give you a specific directory where you should create your new website folders so again just look at the documentation for whatever um installation path you chose and then follow that in my case I used home Bru so I can put my websites anywhere I want in that case I will go to my home directory and on the Mac I can CD to uh that home directory by using Tilda slash for Windows I believe it'll be something like CD to cql in and then maybe users your name and desktop I think that's right okay let's make a directory for all of our websites I can use this command mkd IR make directory and we'll call it websites uh whatever you want some people call it code it doesn't matter okay now I can CD to that directory change directory to websites okay so now yeah we can name this first project anything we want I will just call it demo so once again make directory called demo and we'll CD into that new folder okay I think we're ready to get started open up the editor that you chose in the last episode and then in my case I can choose open here but for you it might be file and open directory something like that okay and if I open my home directory sure enough I can see that website's folder at the top and demo is the one I want to open okay I'm excited so let me click up here on the top left and I only want to see my project files and we're all set so let's rightclick and choose new file and to begin I'm going to call it index.html not PHP this is a simple static HTML file now most editors will include any number of Snippets for common tasks in my case I want some basic boilerplate for an HTML file and this is what it gives me but let's keep it super simple I'm going to get rid of these two meta tags and keep it like this all right now actually a quick note if what I've just done here this HTML uh looks foreign to you you may not be ready for this particular series I would hit the pause button and research something like HTML for dummies go through that get a little comfortable learn a bit of CSS and then you're ready for this course okay so yeah let's just say H1 a heading one and we'll say hello world every series has to begin with a simple hello world okay so now I want to view it in the browser so it may turn out that your editor has some kind of functionality for viewing the results in line like you see here but why don't we just load it directly in a browser so that we're all on the same page so to do that I will return to the terminal and let's run PHP DH this brings up the help for PHP and have a look right here- s runs with a built-in web server it sounds like this is what we want but real quick once again a discrepancy if you went with something like M they will include a server for you you probably have Apache or engine X and they will have instructions for how to preview your website in the browser otherwise you'll need to boot one up yourself and that's what I need to do here so I can say PHP Das s and let's go with Local Host and a port how about 8888 all right we have a development server running and in fact I should be able to command click on this URL to access it otherwise just copy it and paste it into a browser all right congratulations you've now booted up a server and we're displaying a static piece of HTML great but I want you to notice that it automatically worked and part of that is because I named the file index so for example if I were to rename this file and on PHP storm I can go to refactor rename or there's always a shortcut and yeah if I changed it to anything else well keep in mind as soon as I return to the browser and refresh it won't be able to find that so yeah you'll often find that index is an important file name okay but now I want this to be dynamic I'm assuming you already have a little experience building a static website at least the basics to instead make it dynamic I'm going to switch to PHP so once again I will rename this file to index.php now again notice if I don't change anything at all because I'm running php's built-in web server it'll still work just like the previous example but now we have the full power of PHP at our fingertips so let's have a look here let's clear out this H1 tag and let's open up our first PHP block we do that by typing less than sign question mark PHP and then a space and then another question mark and a greater than sign and I'll warn you it's really confusing the first time you do it maybe the first 10 times you do it you'll have to look at the keyboard to make sure you're hitting the right keys but I promise after a while you won't even think about it okay so now we're basically designating that whatever occurs between or inside this PHP block should be treated as not HTML but PHP so for example if we just did something like this and I once again wrote hello world this is not going to work and in fact if you have a good editor it'll let you know hm there's something going on here switch back to the browser reload it and we get a parse error so notice we're trying to interpret this PHP but it has no clue what this is because it's not HTML we have to write using the PHP language so I'll show you the easiest way to Simply print a string we can do that that by saying Echo and then within quotes your string hello world and then at the very end add a semicolon and in fact I just used the word string which can be a little confusing at first whenever you hear that word all I mean is basic text a string of characters that mean exactly what you read here they are not special symbols or identifiers that the language will understand it's literally text okay all right so think about what's going on here when the page loads we display a heading level one tag and as its text content we open up a PHP block and we Echo out the string hello world and yeah I know Echo can be a little confusing think of it just like print this text onto the page and in fact print is something that we could use here and it's mostly the same as Echo there's some slight differences but but still stick with Echo most people do all right so if we switch back give it a refresh we get the exact same thing as our static version but again I hope you're excited by definition we are now building our first Dynamic website that uses PHP and we'll keep taking this further and further so to finish up today's learning I want you to play around with echoing Different Strings Hello Universe um hello Town whatever you want practice inserting that text uh in other areas of the document maybe add a paragraph tag where you Echo out some gibberish string uh the entire point is to become comfortable with writing this awkward sequence of characters you'll get it all right at this point you've learned how to successfully Echo out a hello world string but yeah what we've done here well right now you'd be forgiven for thinking but why what's better about this versus what had at the beginning where we simply wrote hello world as the content of the H1 tag and of course you're right uh at the moment we're just getting used to PHP we're shaking hands and if you think about it we've already learned a handful of important things first we can open a PHP tag like this and then we close it at the bottom anything between that opening and closing tag will be interpreted as not HTML but PHP so we've also learned that when we work with PHP we can mix it within any HTML document and that's somewhat unique to PHP next we've learned that if we want to prepare a string and display it on the page we can use Echo and then we place the string within quotes now those quotes could be double quotes or they could be single quotes we can talk about the differences later but then lastly we've learned that we end a command with a semicolon think of this almost like a period for writing English when you finish your thought or when you finish the sentence you conclude it with probably a period or something like that some kind of punctuation well within PHP we complete a sentence uh so to speak with a semicolon all right but now in this episode let's talk about how we can combine things or concatenate would be the proper term for example what if instead of world we wanted it to be somewhat Dynamic maybe it could be Universe maybe it could be town maybe it could be folks you know whatever you want so let's remove that and yeah in many languages we use the plus symbol we would do things like this hello plus world but yeah you'll notice in PHP it doesn't like that wrong string concatenation operator in PHP we use the period so yeah this is the term we use concatenation we are going to concatenate hello with World okay let's leave it like that and see what we get in the browser so I'll switch to the terminal if your server isn't still running let's boot it up like we did in the last episode and then view it in the browser and yeah we get the exact same thing but now we have a new piece of syntax that we can work with the concatenation operator so now we can swap this out on the Fly universe and we get Hello Universe maybe hello everybody switch back and that works as well okay cool next let's make the greeting itself Dynamic uh maybe instead of hello it's hi or what's up or anything else you can think of all right let's do it a little bit differently though this time we're going to create our first variable we create a variable by using the dollar sign and then any number of characters so if I really wanted to what we have here could be a variable name it's not a very good one but it would work but in our case I did say the word greeting right so I think that's a good name for the variable dollar sign greeting equals what well in our case why don't we make it equal to hello so I will say hello okay and I think I'm done but what do I put at the end again what is the punctuation for a piece of logic once again it's a semicolon and again in your head just think of it sort of like a period I am finished with this piece of logic so I conclude it with a semicolon okay so now I have a variable called greeting that is equal to the string hello but if I switch back to the browser there is no difference here because I haven't used that variable anywhere okay let's swap it out so now let's select everything here and I will replace it with our variable name and let's see what we get there it'll be close but not quite yeah notice I get hello everybody as one long string or as one long word and that would make sense if you think about it right now I say Echo out greeting and then no space and then everybody immediately after it so we could do this in a couple ways of course of course I could just do a space right here and yeah that would work um but maybe everybody will be dynamic as well or that will become a variable so another option would be to concatenate a space and then concatenate the rest of the string so now I'm echoing out whatever greeting happens to be and then a space and then everybody switch back give it a refresh and yeah we get the exact same thing so now you've learned about variables but you know what when I originally learned this I I think my first thought was once again but why why create the variable why is that better than echoing out the hello string like we had in the last video and the answer is sometimes the variable will point to things that you don't have control over it might uh refer to something the user types in it might refer to something that comes from the database it might refer to something that you're going to manipulate in some way um maybe the user provides a string of characters and then you change the capitalization or you tweak them or you do something um that you couldn't do manually or statically that is the reason for a variable and trust me if that's confusing it won't be confusing in a week or so all right so now to finish up as it turns out there's actually a couple different ways we could write this and I think you'll find this is true for programming in general often for any given task there's there's a handful of ways you could approach it and often each of those ways will generate the exact same thing in the browser so there's no difference for the end user but for you the programmer you could write it in a number of ways for example instead of using concatenation like we've done here another option is to store the whole thing within double quotes like this greeting space everybody okay now if I come back and refresh yeah once again to the end user there's no difference but for you the programmer you've changed the code slightly and this is referred to as refact fact in that is when we tweak the code without actually changing the end result for the user we've tweaked it to be uh more accommodating to what you consider uh to be clean or attractive or appropriate or efficient or or fill in the blank all right so now we've learned something new here we've learned that even if we have a string we could store and evaluate a variable within it but now here's the catch if we instead use single quotes did you notice how my syntax highlighting change that was a little hint now we don't get what greeting evaluates to we get the text itself okay so now we can see there is a difference between using single quotes versus double quotes and that difference is if you want to nest and evaluate a variable within a string you have to use double quotes switch back refresh and now it works all right good job onward to the next lesson okay welcome back so now that you're a bit more comfortable with variables I think the next topic we should tackle is conditionals let's get going and I have an example for you and what I'd like to do here is dynamically render a message that indicates whether or not you've read a particular book so let me grab one real quick all right here's the closest one what do we have here we have dark matter really good book I highly recommend it okay so when we're done if you've read the book it should say something like you have read Dark Matter okay so let's boot up our server but this time rather than manually writing it out most terminals allow you to press up to cycle through your previous commands and I'll do that this time all right then I can command click on the URL all right and sure enough as you'd expect we get our static message but now real quick let's write a little CSS so I will rightclick choose inspect and I'm going to select the body tag here and even if you're not comfortable with CSS just come along for the ride I'm going to set a display of grid on the body and then I'm going to use this place items property to put everything in the center but right now the body is only as tall as its content which isn't very tall at all so let's set the height of the body to 100% of the viewports height and what this will do is perfect perfectly Center it on the page all right so I'll bring that back or I can press shift command C and then one last thing let's set the margins to zero okay and then actually one more font family let's set it to uh Sans serif all right that's all the CSS we're going to write here so I will select that switch back to PHP storm and then in my head tag I'll do it inline here and we'll say on the body tag apply these Styles and now if we switch back and give it fresh yeah it just looks a little cleaner to my eyes okay so now we want to make this Dynamic so how would we do that well let's begin by opening PHP text so hm I think the first thing we should do is turn the name of the book into a variable so let's do that now we'll call it name equals a string and then again we conclude it with a semicolon now let's reference that variable clear this out open PHP Echo the name and then close PHP okay come back give it a refresh and yeah we get the exact same thing very cool okay so now the next thing we need to do is indicate in some way uh whether or not the user has read Dark Matter so again in in many cases this will come from a database you'll have a database of the user and the books they've read have they read it have they not or sometimes you'll make an API call think of that as sort of like an external surface that has all of this data uh but yeah right now in our learning why don't we just hardcode this so has dark matter been red I'll call it red and what would I say here yes or no well we could do something like this but generally we use what's known as a Boolean think of a Boolean as simply true or false has it been read true or false in our case why don't we say true okay so now think about it we should check whether the book has been read and if so we write you have read the book and if it has not been read maybe we write you have not read Dark Matter okay so let's see how we might do that and if you want pause the video and see if you can figure that out on your own all right great job if you figure that out but if not no worries I wouldn't blame you because we haven't yet reviewed what's known as a conditional so think of a conditional as a way to create a branch in your logic or or put more simply think of it as a way to ask a question and usually it starts with the keyword if if such and such turns out to be the case then I want to do this but if it's not the case then I want to do something else so maybe you're going to lunch maybe you're going to Subway if Subway is open then let's go in and eat but if Subway is not open let's go somewhere else right it's a simp simple question and we can write that with PHP by saying if and then open parentheses and yeah real quick notice how when I did that my editor automatically added a closing parenthesis most editors will do that these days all right next ask your question here and then open a curly brace and once again my editor adds the closing curly brace so think of everything that occurs between these curly braces uh as the logic for what should happen if this question returns true if this question has a positive uh response but in our case yeah we can't we can't use basic English here we have to speak in terms of the language so in our case I really just want to say well if the book has been read then prepare a message so let's clear this out and I'm just going to say if red or in other words if the value for this variable is true then create a message and maybe this message will say well exactly what we have here you have read name just like that okay so now if I come down here I'm going to replace all of this with an opening PHP tag that Echoes the message itself okay but now before we review this in the browser it's going to work so spoiler alert it works uh but yeah did you notice how there's a little squiggly underneath message variable message is probably undefined so again when you use a good code editor it's almost like a robotic assistant that will give you little pieces of advice for example what if red was set to false well think about it what do you think would happen and if you're working along pause the video and um ask yourself that what would happen here H all right let's come back give it a refresh aha we get a warning undefined variable message but now you might be thinking wait wait wait a minute wait wait wait wait wait wait we created our message variable right here so why on Earth is it saying undefined when I have proof that we defined it right here okay and this is what being a programmer is you need to go through it line by line to make sure you understand what's happening so let's do it together we start by creating a name that evaluates to Dark Matter fine then we have another variable called red that is set to false and then we say well if red is true or positive then keyword there then create a message variable okay so let's say that again if red is true only on that condition do we create a variable called message but now red is set to false which means this condition this question fails if red no it hasn't been read so don't do anything here that's what's happening at no point in this logic do we create the message variable which is why PHP is squawking at you okay so why don't we do this instead I'm going to say else and then once again between these braces is the logic that should happen if the book has not been read and in that case why don't we duplicate this message variable and say you have not read the name of the book okay so now the message that we display to the user is dynamic so if I come back and give it refresh you have not read dark matter but if we toggle this to True come back refresh you have read Dark Matter pretty cool all right so let's finish up by making just a couple small tweaks or a couple small refactors first up right down here where we Echo out the message um no problem whatsoever but as you can imagine in PHP echoing the value of a variable is really really common so with that in mind there is a shorthand version and it looks like this okay so let's talk about it actually real quick let me prove it to you refresh and now we have you have read Dark Matter two times um so notice less than question equals that is identical to opening PHP and calling Echo it's the exact same thing so if it feels weird to you and you don't want to use it all right it's fine no problem uh but I will tell you most people will reach for this and then also notice how I was able to a the semicolon and that's because immediately after we Echo the variable we instantly close PHP so in those situations the semicolon is optional keep it if you want and it might be a good idea right now just to get you in the habit of always concluding a statement so to speak with a but do know if you ever see it being omitted that's why okay so from now on whenever I need to Echo out a variable I will almost always reach for this uh particular syntax and in fact I'll remove the semicolon all right last Little Thing Before I Let You Go notice we have one more squiggly line here condition is always true because red is evaluated at this point all right so think about what's happening here it's helping you out it's saying hey you're asking this question if the user has read the book but because you set this variable to true that means 100% of the time the answer to that question is going to be yes or true or in other words if the answer is always yes then this logic here where we proceed if the answer is not yes will never fire it's Superfluous why does it exist delete it and then once again if the answer is always yes then why are you asking the question you could remove that as well and in our little example here this is a little more appropriate but yeah remember in real life the answer to that question will be dynamic maybe you've read the book but John hasn't read the book maybe you didn't read it last week but this week you did in those cases you won't know the answer to that question and that is why uh the conditional here would be appropriate okay just some things to to think about all right you're making really good progress I know we're starting to creep in slightly more complex logic so keep playing around with this and when you're ready move on to the next episode all right so check this out at this point you should be pretty comfortable with creating variables for for primitive strings and numbers right uh name equals John Doe age equals 25 but now what about when the variable should should contain so to speak um a collection of things like a list of your favorite books how exactly would we do that I'll show you how all right so let's say you want a section of your website for recommended books so maybe you'd have an unordered list and just for fun I've chosen three different books from three different decades that I would actually recommend and I'll show you these so we have um from Philip dick Do Androids Dream of Electric Sheep this is what spawns Blade Runner it's very interesting makes you I think uh next this was uh well Stephen King the langers this was originally a short story in one of his um compilation books I don't remember which one it was but then they extracted it into its own release super super good uh imagine waking up in a plane and 90% of the people on the plane have disappeared but the plane didn't land they try to figure out what happened there and then finally of course from this decade is hail Mary which is one of the best books I've read in many many years okay so let's say we have those three books uh do Android stream of Electric Sheep next up we have the langers and then finally Hail Mary okay so now our job is to make this Dynamic remember in real life things like this will often be stored within uh a database here's John's recommendations or here's Sarah's recommendations all of those are stored in a database so yeah how would we do this well once again we could open up PHP directly within our body tag and yeah what would be a good variable name for our list of books well I said books right so why don't we call it books but yet at this point we've learned that we can do things like this but I instead wanted to represent many book names so what do we reach for in that case and the answer is an array so think of an array as the programming equivalent of a folder it's a way to take a a group group of things or a list of things and put them together in a folder and then if you want to move all of those things from one place to to another place you just pick up the folder and you carry it right the same basic principle is true for arrays I create an array using this uh notation Open Bracket closed bracket now I can store each of these titles as strings there's one next the lingers and then finally Hail Mary all right cool so now I have a single variable that represents a list of recommended books the next step is to Loop over that list and for each item display a list item that includes the name of the book so here's how we do that in PHP let's do this open up PHP and I will say for each books as and now when I'm looping over this array how do I want to represent or refer to each item within that array well how about name or book anything you want singular is fine and then just like with conditionals in the last episode we open up braces okay and I'll close PHP at the bottom so now the way this works is for however many items we have in this array I will trigger all of the logic that is contained between these braces so if you want to pause and think to yourself well how many times will I let's do this Echo uh a list item that says hello okay so if I were to run this in the browser pause for a second and think how many hellos will I see okay well as you can imagine we will see three hell let's come back give it a refresh and sure enough I get three because there's three items here if I were to add another one here then of course we would Loop over it four times and we'll have four hellos all right so let's bring this back and now let's replace uh the text here with the name of the book so I'll show you a couple ways to do this we could once again use concatenation so in this case I'm saying okay I want to render a list item and then the name of the book and then a closing list item and that should in fact do the trick pretty cool um but of course as we learned an episode or two ago we could also just inline all of this I could say Echo open a list item then do the name of the book and then close it all in one go come back refresh and very good but now a quick little note I don't know if we covered this but imagine for whatever reason you need to add that little trademark symbol at the end of the book name or something like that but notice how my editor immediately starts complaining at me and that's because now it's trying to find a variable called book TM and of course that doesn't exist so yeah of course the issue is I want that TM to occur immediately after the name of the book so I could add a space here but in this situation I don't want that I don't want a space between it so what do we do in situations like this uh well of course you could reach for concatenation or uh you'll often see this in the wild you can wrap the name of the variable within braces and that sort of silos the variable nope this is the thing that I want you to render and then everything after it uh will not be included as part of that variable name so this would be a way that we could solve it all right just a little aside but something you should be aware of for now I'll bring it back to book looks good okay so for little examples like this what we've come up with is perfectly fine but yeah as you can imagine in some situations your list item will contain its own set of HTML maybe it houses a div with headings and a sublist and anchor tags and things like that and I think what you'll find is when you start trying to render all of that as part of an echo string you know as you can imagine here very quickly it starts to get super messy so for this reason there is a shorthand for loops and I'll show you how it looks let's start from scratch open up phtp and yeah for each books as book but this time instead of opening up a curly brace we're going to use an alternative syntax sort of a shorthand that you will mostly see when working with views or or or HTML as you see here and that shorthand or alternative syntax is a okay so let's close PHP so that that I can return to HTML hello there and then we need some way to delineate where the end of the 4 each should occur so at the very bottom I will open up PHP again and write end for each all right so if we switch back we should once again get three hello theirs and we do okay so I think you'll find whenever you need to build up complex HTML fragments this alternative syntax for for each is 100% the way to go and yeah it's not limited to for each you can also use it for conditionals it's the exact same uh syntax okay so now let's just update this by opening PHP echoing out the book name and if I switch back and refresh we're good to go here but also don't forget you learned about short Echo tags right so you could instead just say equal book and then close it out and that would work as well and once again this is the approach that I would usually take so give it a refresh and we still get the same thing all right so you're making pretty good progress now you've now learned that a variable can house so to speak a collection of things and that's specifically what an array is for it's for containing a collection of things uh maybe that collection could be names a collection of names it could be a collection of numbers it could be a collection or list if you prefer a list of usernames a list of book names a list of of popular tweets anything like that could go in a primitive array and then you use the for each syntax to Loop over each item within that array and proceed however you need to all right welcome back let's keep focusing on arrays so you now know how to define an array which is good and you can Loop over them but yeah what about situations where you need to interact with individual items within that array for example if I want to grab this value here from the books array uh how do I do that what is the appropriate syntax and actually it's not too hard within a paragraph tag I want to Echo out this item here so I know I'm working with the books array and if I count one two yeah it's almost like I want to do something like this go into the books array and give me the item and actually that's not too far off we can use brackets here like this but it's not going to give you the result you might expect let's have a look refresh and yeah I get project Hail Mary instead of one two the langers so I asked for the langers but you gave me the third item instead which is really confusing Until you realize that for most programming languages if you're working with a list it will be zerob based which effectively means the very first item will have an index of zero and then you count up from there so in this case it would be 0 1 2 so now we can see when I said books two think of that as give me the second index uh effectively from the books array all right 0 1 2 project Hail Mary and sure enough that's what we get so in our case if we actually want the langle ear well zero one so I would update this like so and that works and of course if I want the very first item again that would be an index of zero and that's how I would grab it all right very cool but now let's take it even further most of the time you will require more data than simply the title of the book right uh for example who is the author of the book is there a description of the book what about the category is it horror or sci-fi you know things like that but how do I represent that data that Associated data when all I have here is a string you know well think about it like this first item of any array in this case I have a string but it doesn't have to be a string if I wanted it to it could be um excuse me it could be an integer it could be a number it could be a Boolean or it could even be another array and what's cool about this is now I have a sort of container or a folder for information specifically about a single book for example the name of the book do Android's Dream of Electric Sheep uh the author of the book is philli K dick and then a URL to where we can purchase the book and yeah this is definitely an improvement so now if you add more books just add more arrays and we'll do one more project Hail Mary is written by Andy Weir and then once again some kind of URL to buy the book but there is one issue here if I come back to this code 6 months from now I may not remember what that URL is for is it a URL to purchase the book is it a URL to download the PDF after you purchased it is it a URL to the author's website you know you just don't know and it would be nice if there was a way to associate a key with each value here and in PHP we can do that it's called an associative array kind of a fancy term but it just literally means associating a key with a value like a key value pair so let's do this one what would be a good key for this well it's the name of the book right so let's call it name and I create the association by making an arrow so I have a fancy font that makes this arrow look pretty yours may not do that but it doesn't matter all I'm typing here is the equal sign and then a greater than sign so let's do another one Well author right so author arrow and then this could be purchase URL yeah the the way I think of it is this key points to that value this key points to that value and this key points to that value and one less little thing here notice how I made that U Capital this is a basic convention uh for many languages if you have more than one word make the first letter of the new word capital okay so again you might see some people do this that's fine as well conventions can be followed or ignored you know it's up to you and we'll talk about that more in the future okay so now let's this one too here's the name here's the author and here is the purchase URL okay I'm liking this so now check this out if I want to Loop over it like we did in the last episode well once again PHP for each books as book and I'm going to use the alternative syntax and for each now in the last episode we echoed out the book itself right but that's not going to work and already you can see my editor is is kicking up a fuss and we'll see that in the browser too yeah so what's happening here is when we Loop over the books array each item now within that Loop is not a string it's an array itself so we're basically saying ah print the array to the screen and PHP is going huh I don't I don't know what you want me to do here so it sounds like we actually want to print the name uh within that array okay so you'll remember at the beginning of the video we learned that we could access items within an array array by using numbers but when you're working with an associative array you can instead use the key itself sort of like an identifier so in this case let's replace it with name and now we will get exactly what we had before all right very cool so let's think about it let's extend it now maybe I don't just want the name of the book I also want a link to where you can purchase the book so let's add an anchor tag and yeah we kind of want something like this all right come back give it a refresh and ideally each of those books will link to a unique URL to where you can buy the book and we already have the purchase URL so let's reference that book purchase URL okay and if I come back give it a refresh yeah look in the bottom left portion of the screen and it is working okay so you're making really good progress and you're starting to learn how you can construct slightly more complex data sets and and trust me you can take this even further once you learn a bit more okay but I think we're going to call it a day here uh a quick note before I let you go if you're watching this at lc.com if you look below the description of every video there will be a short 5 to 10 minutes max uh homework that I would encourage you to work through just to make sure that what you watched here is being committed to memory and if you're instead watching uh something like YouTube go to PHP for beginners. comom find the episode number and then you also can work through the homework okay so onward to the next video I hope you're excited I'll see you later okay welcome back and congratulations for making it this far trust me I know it's not easy especially the first time around okay so now in this video this should be fun I get to introduce you to functions which you can sort of think of as verbs of the programming World functions are respons I for doing things let me give you a couple examples so have a look at our books array once again and you'll see that I've added just a couple things first up the homework from the last episode requested that you add a release year to each book and then we display it right down here within our Loop so I've done that next up I've added a third book here called The Martian that is also by Andy we and yeah the reason why I'm doubling up on authors here is because we're not just going to discuss functions in this video but you will also learn about filtering so yeah imagine this will ultimately be some kind of Book Repository that you maintain and in real life there are hundreds or thousands of books that you want to present to the user in this case I'm hard coding it so we'll keep it very simple but yeah one of the things a user will instantly need to do is filter the books according to maybe the release year or the author so it would be nice if I could say well just give me only the books that were written WR by Andy wear because that's all I'm interested in uh right now okay so how exactly would we do it all right I'll give you a couple ideas let's scroll down here here's our Loop and yeah notice we're saying all right for each book says book and then display a list item but maybe we could also say well if the book was written by Andy Weir only on that condition should I render a list item otherwise skip it okay okay here's what we could do open up PHP and we could say if the book's author and I'm going to add a little typo here but just come along for the ride if it equals Andy Weir and let's use the alternative syntax only on that condition should we render a list item and then I will close this out at the bottom just like that so yeah you might think this would work but if we have a look in the browser and we give it a refresh uh-uh we still get all of the items which is weird because we know that do Android stream of Electric Sheep was not written by Andy wear so so what exactly is going on here and the issue is this equal sign all right so here's the deal when we use a single equal sign like I've done here we are literally assigning a value so this effectively says all right for this book's author key make it equal to or assign it to Andy Weir so for example let me show you something if we also included the author at the very end so we'll say Echo out the book's author like this and if I switch back and refresh yeah notice that now every book is written by Andy Weir which of course we know is incorrect and yeah the reason is because we are assigning a value rather than checking for a quality think of it like this Loop over all of the books and for each one set the book's author equal to Andy Weir and then render the list item that's what's happening here but in our heads we thought we were checking for equality we thought we were saying well if the books author is Andy we only on that condition do we proceed okay so how do we check for equality we use and it's a little weird but we use three equal signs and once again my font will make it look a little fancier just make sure you type that equal sign three times and you're good to go so now watch what happens if I come back and give it a refresh we only show and render the books that were written by Andy wear and in this case we ignored uh do Android stream of Electric Sheep because it wasn't written by Andy so yeah a single equal sign when you want to assign a value triple equal when you want to check equality okay so I'm feeling a little better this does work but yeah we are hardcoding the author's name which isn't overly practical but yeah it works instead though it would be nice if I could create a fun function that filtered the books automatically and yet don't forget functions are like the verbs of the programming World their job is to be called they then do something and then often they return a result okay here's how we Define a function and I'll do it right down here we start with the keyword function and then we give it a name and just like defining a variable you can name it anything you want and our case I want to filter by the author so let's be a little on the nose filter by author then we open and close a parenthesis and then we add our braces okay so we're starting to see a pattern here remember how we added braces when defining a conditional and we learned that if that condition was truy if it evaluated to something that is positive basically only on that condition would we execute the logic within the braces and the exact same thing is true for a function this logic within here will only be executed when I actively call that function and here's how we call a function reference its name filter by author and then you can see my editors helping me here open and close parenthesis and then we end our statement this is my way of saying call the function that is named filter by author okay so let's give this a shot let's play around for just a moment and we'll say maybe right down here let's open a paragraph tag and to start let's Echo out whatever is returned from that function call and yeah take a moment and ask yourself what you think we're going to see here let's have a look in the browser give it a refresh and I don't see anything but if you think about it that makes perfect sense we're calling this function here the function doesn't do anything at all and it doesn't return anything at all so of course we don't Echo anything at all that makes sense okay so now let's have it return something gibberish return and notice I use this keyword here return and I can return an object an array a string a Boolean a number whatever I want let's just say gibberish and if I come back and refresh aha it works all right so I know I'm literally returning gibberish here but this is actually pretty cool because now within this function I can do anything I want I could have conditionals I could have loops I could even interact with Services outside of my application and the coolest part is I get to uh isolate and Abstract all of that often confusing logic behind a simple function with a readable name that describes what all of that code is doing so that is sort of what we're doing here we're just taking confusing logic and tucking it behind a function with a nice and readable name that describes what all of that logic is doing okay so now think about it filter by author well that probably should receive something it should receive all of the books here and it should then fill filter them and return only the books that were written by in this case Andy Weir okay we have our work cutout for us how do we do that well the first thing I said is that the function needs to receive the books so we can specify that a function requires a certain type of data by declaring it within the parenthesis here in this case I need some books to filter okay so now if I come back to the browser and I give it a refresh immediately I get an error too few arguments to function filter by author okay so PHP looked at this and it saw okay you had this function here and it requires some books to work off of but then you called the function and you never passed through the books and that is an error so we see it in the browser here okay let's pass through the books come back and give it a refresh and now again we haven't changed the logic but we have removed the error okay so now I can work off of books and that's going to be equivalent to what we see here so yeah if we wanted to we could say I'm going to show you the long form way and then I will show you a short form so let's get rid of this conditional because we will no longer take that approach and we'll clean this up for this video the code we will write will be a little naive maybe a little unsophisticated and then in the next video I will show you a dedicated array filter function that will make the code a lot more but yeah this is a good first step so you might think to yourself all right I have a list of books and I want to return a new list of books that were only written by Andy Weir okay so we might say well create a new array called filtered books then we could say Loop over the books that you gave us we know how to do that and then check the author of the book all right well if that book's author is triple equal and a weir in that case add that book to our new uh array we can add or append to an array using this syntax here so notice the brackets here append this book as a new item within this array okay but now what if the author of the book is not Andy Weir well in that case we don't do anything at all we just continue on to the next item of the loop so when we're done if we did this correctly filtered books should now be an array that contains two items all right so at the bottom let's return our new array and yeah I'm excited let's try this out so right down here where we Loop over all of the books let's change it let's now Loop over only the books by Andy so I could say filter by author and in this case PHP storm autocompletes for me but yeah again notice how we call the function we send through the data it requires that triggers this function here which means the logic between the braces runs and in this case it builds up an array and it returns that array so now we are looping over what was returned from this function call all right let's give this a run back to Firefox give it a refresh and congratulations it took a little work but now we are successfully filtering an array according to the author so now to finish up last little thing I don't see any re into to hardcode the author's name why don't we make that a parameter as well so now we could say all right we're going to filter by author but which author well you have to give us that information so we'll do that here author is now a variable could be Andy we or it could be uh the author of any book in our database okay so all we have to do is swap out the hardcoded string with our parameter like this okay so now notice we made a change and my editor picks up on it and it says hey you forgot to provide the author let's do it now once again Andy Weir and this is a nice little refactor hopefully everything still works and it does but now notice that I've introduced a little more flexibility and that's a lot of what programming is introducing flexibility where things can adapt to to different environments and and different situations so now if I want to filter by Philip K dick let's copy all of that bring it down with any luck we should now have an array with only a single item and we Loop over it how cool is that okay but like I said we still have a little more work to do here this is a little unsophisticated I think we can do better in the next episode we'll talk about dedicated PHP functions I'll see you then hey there everybody welcome back and you know what I hope you're excited because trigger warning I'm going to push you just a little beyond your comfort zone in this video we will talk about Lambda functions and refactoring and why and when you might want to make a function you have a little more generic and a little more flexible so let's get started and see what we can come up with so we will once again work with our books list and yeah here's that filter by author function that we worked on in the last episode and yeah it gets the job done but it's not the most flexible thing in the world and here's what I mean what if you later decide that you also need to filter according to the release year how exactly do you do it when author is right there in the name well I'll tell you what a lot of newcomers do is they will reach for duplication so they add a second function all right let's filter by the year and then they substitute where they need to so check if the release year is now equal to not author but the year and I haven't checked this but I'm pretty sure that would work but once again hopefully you can see this is not very practical what about in the future when you need to filter according to 10 different parameters does that mean you're going to have 10 different filter functions of course not we don't want to do that so instead it sounds like we need to make things just a little more generic and flexible how exactly do we do that well I'll show you how to get there in a few steps all right let's get going first upep notice how we are looping over our books and originally you learned that you reference a variable name like books but then in the last episode we swapped that out with this function call but remember it's still the same thing I'm not saying Loop over the function I'm saying Loop over whatever is returned from the function which itself is an array so it's still the same thing but yet there's nothing ke keeping you from swapping this out like this maybe this is filtered books and now I will extract a variable and yeah this is actually the the jargon that we would generally use uh extract variable and that means exactly what you just saw we take a bit of logic and we extract it into a variable and then we substitute the variable wherever that logic used to be exactly like this and yeah this is still going to work exactly the way it did before okay cool that's step one here's step two now what you see here is what's known as a named function yeah a named function is nothing more than a function that has a name teacher of the year over here but yeah as it turns out there's nothing that requires that functions be named so for example if I were to delete that well my editor is squawking here but not because the syntax is invalid let's have a look expression is not used anywhere yes so my editor is saying okay you created this function good deal but you never used it so you might want to have a look notice it didn't say invalid because it's not invalid all right interesting so now we know we can create named functions or Anonymous functions so your next question is well what do you do with an anonymous function and the answer is well you could assign it to a variable or you could even pass it to other functions kind of interesting okay let's review that variable option filter by author all right very interesting so now I have a variable that is equal to a function call and notice because I have an assignment here an expression that means I need to conclude it with a semicolon which is a little bit different okay but now if I scroll down I'm trying to use that function but my editor is complaining undefined and that makes sense I don't have a named function anymore I have a variable name that points to a function that is not a named function so let's swap this out with the variable name like so and now this should do the trick so yeah what we have here is what's known technically to use jargon uh as a Lambda function but yeah for now just think of it as an anonymous function that would be fine come back to Firefox cross your fingers refresh the page and yeah it still works okay so now I think we have the tools and the knowledge we need to move on to our refactor all right so let's bring this back to a named function I'll undo this a few steps and yeah let's think about it if I want this to be more generic it sounds like I can't have any reference to the author because I could be filtering by a category or a release here instead so why don't we just call it filter next though maybe I'm filtering books but maybe I could also be filtering a different array entirely why don't we make this more generic and as a result more flexible so I'm going to change this to how about uh items some people go with data some people just write array it doesn't really matter I just want a generic term that could represent any collection of items so I will stick with that now I have to update the names and then next I can't say filtered books because it may not be books so let's select that and actually real quick notice how I was able to create multiple cursors here almost all editors have support for this this at this point just Google your editor's name followed by multic cursor or multiple cursors okay that allows me to quickly update things like this how about filtered uh items okay what else needs to be updated well the book name that will simply be item and then the last thing we should update is this right here I can no longer assume that we are filtering by the author and I can't assume that I have access to an author variable okay so how would we do that well it sounds like when I call the function I need to give it a key like a author and then also a value so this is sort of how I want to use the function I want to give it my array I want to give it my key and then I want to give it the value that the key should match okay let's update our function uh signature key valume all right now we can update this key volume and yeah with any luck if we update this I think this should probably still do the trick let's give it a test come back to Firefox give it a refresh and good I didn't make a mistake and now the cool thing is this is quite a bit more flexible what if I want the author to be Andy wear I just update the argument here refresh that works what if we instead want to filter according to the release year that would be uh 2011 I think I have one yeah the Martian that works as well uh what about 1968 last example and you get the idea okay cool this is definitely an improvement but I think we can still take it a little further the comparison we have here is one of equality give me all of the books that were released in the year 1968 but yeah once again it's not the most flexible thing in the world because what if I instead wanted to say uh give me all of the books that were released after the year 2000 well with our current implementation that's impossible it just won't work so how can we make this more flexible well when we started refactoring this function we took some of the specifics and we pulled them out of the function and instead we passed them in when we called the function so would there be a way to effectively say this right here this check I want to be in charge of that check I will pass it in when I call the function and if that sounds confusing just come along for the ride and I think it'll make sense okay so let's try a refactor and I'm going to start by writing the code that I wish would work so we learned about Anonymous functions what if I could just say well I'm going to pass an anonymous function or a Lambda and this function needs to accept the current book and now if we scroll up we just want to reproduce what we have have here okay so maybe return look at the book's release year and tell me if it equals 1968 all right and this is actually pretty interesting so think about it now I'm saying ideally here's how I want it to work I'd like to call a function named filter I want to give it an array and then I also want to pass a function where I can be in charge of how this comparison is made and in this case I'm doing equality but yeah like we said earlier I just as easily say greater than equal 2000 and now on the Fly I've changed this comparison give me the books where the release year is greater than or equal to 2000 yeah so notice what we did there we took this rigid logic that forced uh a an Ane equality check and we pulled it out of the function so that we can be in control of it and that's pretty cool okay but now of course it doesn't work and my editor is complaining non stop now let's make it work so we scroll up and we're going to update our function signature and that's the term we use the signature is the parameters of the function and we'll say give me some items and then give me some kind of function that I can call so yeah we could write it out some people will do things like this or you will often see FN which is short for function and I'm going to stick with this approach because if we do once we start start learning about Arrow functions in the future you'll feel a little more at home okay so let's figure this out we decided that this check here is now being declared when we invoke the filter function so let's swap that out with our function call but now H we said right down here that we need to receive the book right so that means when I call the function I need to pass the book or in this case the generic item name okay and I think that looks right come back and refresh and it works so you know what I think this is really cool because now we have full control over the comparison and here's what I mean if I later decide that no no no no I want books that were released before the year 2000 now I have a way to do that really easily or I could say give me the books that were written by this author or some other author once again now I have a place to do that which is pretty cool okay so now I want to finish up with one final refactor and I know what you're thinking uh-uh this is enough Jeff we can be done for the day uh but no one final thing so what we've done here is great and you should pat yourself on the back but as it turns out PHP provides built-in functions for working with arrays so if I got rid of this and replaced it with php's version which is called array filter well as it turns out the signature for that function is very similar to what we have have here and that means if I come back and refresh I still get the same thing but now I get to use what PHP provides out of the box which is really cool so now let's just finish up by saying how about book's author once again is Andy Weir and that all works like it did before pretty cool okay I think it's time to move onward to the next episode but yeah once again if you need to watch this video twice ask comments work through the homework and then when you feel comfortable only then can you move on bye all right so before we move on to the technical check-in in the next episode yeah let's take five minutes or so to talk about code organization and why often you might want to separate your PHP logic from the HTML itself let's have a look so what we have right now is a single HTML file with all of our PHP logic nested inside it including any data or filtering or functions or Loops as you see here and yeah at least to some extent it's kind of a feature the the ability to combine PHP and HTML within a single file is really powerful but also as as you might be able to imagine there's also the potential that this file grows and turns into a monstrosity that's incredibly difficult to reason about so even at this early stage it's very important that you're always thinking about uh readability and code organization so I'll tell you what a lot of PHP developers will do is they will separate the logic itself the the PHP code that gathers the data and they will split that from the HTML that displays the data to the user so I'll show you what we could do here what if we took everything here so I'm going to select all of this PHP here and I'm going to cut it and as a first step just the very first step why don't we get it out of the body tag why don't we put it at the very top of the document like this okay so yeah it's a simple and subtle enough change but notice how now we are being crystal clear that our PHP logic is entirely separate from the core HTML itself okay but what about this that's PHP do we have to figure out where that goes and the answer is no we don't have to take it that far if we look at what this is doing we are looping over an array and we are building up some HTML that's exactly what this is for but notice how it's effectively um dumb actually that's the word we often use in the programming Community you will often hear people say that the template or the view and by the way for now just think of it as the HTML just another word for the HTML uh they will often say it should be dumb and what they mean by that is uh it probably shouldn't be doing any complex logic it shouldn't be interacting with external services or the database uh maybe ideally but remember for any given guideline you can break it whenever you decide that it's appropriate to break that guideline but yeah just as a general rule of thumb we would like our templates to to mostly be kind of dumb and that is the official uh jargon we're going to use in this series okay so this looks good uh it's a good first step but but as you can imagine when your application grows this section at the top of your doc type is also going to grow and grow and grow and it's going to get a little messy so the next step would be to split this logic into its own file so with that in mind what if we had one file for the PHP logic and then another file for again what we might call the view or the template or the HTML portion what what the user sees all right let's do this I'm going to create a brand new file here and we can name this anything we want but I do want it to be clear that it is a template that is connected to index so I might say index. template.php we might say index.html PHP we might say index. viw I'm going to go with this view term because a as you learn more and you start digging into Frameworks you will see that word often and it's probably a good idea if we understand what it means earlier than later all right so I'm going to copy everything and move it over but now I'm going to get rid of all of this PHP logic at the top the only thing within this file is our core HTML and then whatever uh data we need to Echo or Loop over okay now we can switch back to index.php and I will do the opposite I'm going to get rid of all the HTML there and leave only the PHP logic itself okay but next notice if I scroll to the bottom my editor is saying ah this is redundant and this is a it's an optional rule but almost everyone follows it if you have a file that exclusively contains PHP you can omit the the closing portion of the PHP tag and then further I wouldn't indent this I would do something like this and then add a space at the top okay so now we have two files one file that declares the data and again this would be the file that might interact with your datab base this might be the file that calls some kind of API to give me I don't know the the top 20 books uh from Amazon if I if I know how to make that request I would do it within this file once I have compiled all of that data I would then load the view that displays that data okay so notice we have a separation there but now if I come back to the browser and I reload of course I get a blank page and that's because at the moment uh the application doesn't know anything about out this view just because you create it doesn't mean it's magically referenced anywhere so let's do this I'm going to go back to index.php and I I need a way to say load my view or load the HTML and we can do that at the bottom by saying uh either require or include let's do require and I'm going to give it the name of the file index. view.php okay so think about what happens when we load this file it creates an array of book it creates a filtered books variable and then it requires our view or the HTML and yeah when we say require just think load load the view now what's cool is the view will have access to all of the data that was defined in this file which means even though I didn't create filtered books in this file it's still going to work even though you see a squiggly line here hold that thought if I come back to Firefox yeah now that is working so what's going on with the squiggly line here your probably only going to see this if you're working along in PHP storm and uh I think it's confusing and I'm surprised they do this but PHP storm will not follow uh requires and includes when when tracking variables or something like that but we can solve it pretty easily by opening up settings and I'm sorry I'll do it manually let's go to phb storm preferences editor inspections and these are all the the inspections that PHP storm will do for for any language or for any tool the one we care about is within the PHP section all the way down to uh undefined symbols and then undefined variable because that was the error that we were seeing I'm going to turn on this right here search for variable definitions outside the current file so let's turn that on as I've done apply it and that Squigly line should go away if I return to the view and it does yeah kind of a weird one but if you're using Visual Studio code or Sublime Text I bet you won't see that at all either way though it's still going to work there's no problem there at all cool all right so think about what we accomplish in this episode and by the way this is like Bedrock stuff it's incredibly important what we're covering in this video we've learned that it's key to separate your PHP logic from the the layer that renders it for the user and that second layer could be called the HTML you could call it the view you could call it the template they're often used interchangeably I typically use the word view which is why we named the file index. view.php and now notice how much easier it is to reason about if I need to adjust the PHP logic I go into index.php and I make my change if I instead need to tweak the presentation for example uh I don't want to use an unordered list I want to switch over to divs or a definition list or something well I know that I will make that change within the view layer and this this also is much easier to reason about it has access to some data and it's again effectively dumb it Loops over it and it renders it for the user pretty cool all right so in section two we're going to crank it up a notch I will add some new Concepts we will introduce the database we'll figure out how routing works it should be lots of fun but first first before we get there let's do a quick technical check-in just think of it like a chapter review to make sure that everything I covered was actually committed to memory and then take the quiz and once you Ace that quiz only then can you move on to section two okay so let's do our review and first up if I want to Define a variable I always begin with a dollar sign so let's create a variable for a business name done notice the name is a string so we surround it in quotes and then we conclude the statement with a semicolon let's make another variable for the cost of L cast which is $15 a month now as you can imagine sometimes we need to gather and group all of these attributes so in those situations we can switch over to an array business equals an array the name of the business is lass and the cost of the business once again is $15 now I can access each of those values by doing this business bracket the name of the key next let's move on to conditionals maybe if the monthly cost is too high we don't want to proceed we could say if business cost is greater than how about $99 in that case yeah let's leave the store Echo not interested easy all right let's do another one what what about the categories that are offered as part of the business for laracast that would be things like uh testing PHP training JavaScript training Etc next we want to Loop over them all right that's easy too let's use for each for each business categories as category then once again render it however you need to in this case we'll do an echo echo the category to the page but yeah in real life you might want to render it as part of a list item or at the very least add a break finally we reviewed functions maybe we need to offer users a way to sign up for our site well in those cases very likely we'd have a function called register maybe that function accepts a user and now yeah you can proceed however is appropriate so I'll tell you in real life this will consist of things like create the user record in the database uh maybe sign them in and that would involve something called sessions that we haven't yet reviewed uh maybe you want to send them a welcome email send a welcome email maybe you also need to redirect the user so they just signed up let's send them to their dashboard so redirect to their new dashboard you get the idea and in fact this is often the sorts of things that you'll be doing uh in real life okay so that's function finally we learned about requires and includes and the importance of separating our logic from the template or the view so in this case I have a variable called business and a function called register let's now require our view index. view.php and that required file will have access to both of these okay so let's come back and yeah very quickly let's Echo the business's name and then let's also include a list of categories that the business provides all right easy enough we could say for each business categories and we'll call it category and then I will use the short alternative syntax like so and yeah then within a list item we can Echo the category itself okay let's have a look in the browser and yes sure enough we have our business name as well well as an unordered list of categories and yeah that'll do it for our Rapid Fire review of everything we covered in this chapter so now your job before you move on to section two is to take the quiz and make sure that all of this junk was actually committed to memory uh quick note you will find a link to the quiz in the description below the video on the larest website uh you do have to be signed in you don't have to be a subscriber but it'd be great if you were but yeah just as as long as you're signed in even as a guest you can access access the quiz and uh put your skills to the test I'll see you in the next video all right welcome back and congratulations you've now reached section two of PHP for beginners so yes section one was all about the initial fundamentals and granted I get it there's plenty of things we haven't yet reviewed like classes and objects and objectoriented programming but yeah at least the initial fundamentals I hope should now be part of your skill sets so now section two is all about figuring out at least initially what it looks like to build a website or an application using PHP and MySQL so let's get started now to make things a little easier on the eye and also so that we have something to work with I think we should start with an existing HTML uh boilerplate or skeleton so with that in mind I'm going to grab a component from Tailwind ui.com uh whether you're familiar with this or not you don't need to worry there there's no prerequisite here all I'm doing is browsing their components to find a pretty stacked uh HTML skeleton so notice if you're following along yeah I just want something like this uh an initial bit of practical HTML that we can experiment with and you'll see this happens to be one of their free uh components so I will click on this here and now if I switch back to my editor let's go into my view and within the body tag I'm going to paste all of that in like that okay so now we have some markup to work with we have a bunch of CSS utility classes here and again if you're not familiar with any of this trust me don't be afraid you don't need to worry about it you're not going to be tested on it it's just a quick way to have something pretty in the browser okay so now the the only remaining step before we check it out in the browser is to follow the instructions here and then import the Tailwind uh CSS so notice we need to add these classes to our HTML tag so I will do that now class and paste that in and then on the body tag we need a class of H full that stands for height full or height is 100% okay that's it and then let's import the CSS and ironically we do that that via a script tag uh CDN Tailwind css.com all right so yeah let's give it a shot I come back to Firefox we give it a refresh and yeah you see what I mean now we have something pretty attractive to work with and more importantly our template has a number of sections so to speak so we have a navigation area we have a header area we have a main content section so this will very closely resemble the the sorts of websites that you actually build on your own time okay let's get back to work all right so let's see and yeah again don't spend too much mental energy trying to figure out what's going on here unless you want to the important bits are that we have a navigation section and I will hide that with command minus we have a header section which corresponds to what you see here and then at the very bottom we have a main content section so notice we have little notes replace with your content all right hello welcome to the homepage okay come back to Firefox give it a refresh and yeah this is what you'd expect okay but now I want to of course have links so if we go up to the navigation section let's see um we have a dashboard team projects calendar and reports so we have a look of course that corresponds here okay why don't we change dashboard to home and that will take us to well slth homepage so if I come back and refresh sure enough that has been updated let's do the same thing for a couple others so we'll say how about uh we have one for home one for about us and that will link to how about slab and then we'll come back to that in a moment and then I'll have another one that ideally would link to slash Conta all right let's have a look come back to Firefox and give it a refresh and there we go okay so the next step is let's create an about page so how do we do that well let's see we have index.php and I've removed all the variables from the previous episodes but but in real life you probably have some some data Gathering to do at the moment it just requires a view so why don't we do the same thing for about about.php will load a view called about . view.php and to do that at least initially I'm going to duplicate index. view.php and we'll call it about. view.php all right and yeah as I'm doing this hopefully alarm bells are going off in your head because think about it what about when we have 20 different pages am I duplicating this massive HTML 20 different times Well if I did I'd end up with a sort of n plus1 problem where let's say you need to change or tweak the navigation bar or import a script well think about it you'd have to do it for however many pages are in your size which clearly is not something we want but yeah baby steps so I'm going to go down to the bottom here H yeah we'll say now you are on the about page okay so let's have a look here okay so yeah we're on the homepage let's try clicking on abouts and mhm the address Spar updates but notice it still says welcome to the homepage which is weird that doesn't seem right so whenever you're in doubt of course just click that refresh button a bunch of times and cross your fingers but no dice it doesn't make a difference okay well if we have a look it is about.php so yeah let's give that a shot come back about.php aha it works okay so now we're starting to learn something about how uh php's built-in server works and it looks like if we request something that it can't match or identify it'll defer to the default and remember index.php that file name is always the default okay but yeah it would be nice if I could just do slab I don't always want to add the extension here well I'll show you how to get around that but for now it's a little bit just a little bit above our pay grade but I promise I'll show you how to do that in a handful of episodes so for now let's stick with the full file name so with that in mind I'm going to go back to index.php I'm sorry our view and here's our navigation bar and yeah it sounds like I need to update this to slab about.php and whenever we do create a contact uh file that would be contact.php okay and now notice I have to do the exact same thing for the about page so update that yeah so clearly imagine making a change like this across 20 different views it would be a nightmare right and we can't allow it so I'm only duplicating myself once before we solve this problem okay so come back to Firefox give it a refresh and now if I click on about it takes me to slab about.php and we do see the corresponding page if I want to go back that works as well so let's finish up by doing one more for contact so I'll duplicate this again contact.php we'll do the same thing for contact . view we will begrudgingly duplicate that HTML just for a few moments and then down here at the bottom where are we contact us and then did I update the view no got to do that here all right so yeah let's cross our fingers here's the homepage and pay attention to the copy here the about page and the contact page so now we can even uh update the headers so let's do this in index.php and yeah notice to go through all of this HTML it's just a SLO it's a nightmare I can't even find it where's the header there we go all right so this is our homepage I'll do the same thing for about search for header all right maybe about us and then to contact contact us okay give it a refresh and now it's a little bit more clear home about contact but also notice real quick that the the little pill background remains on the home section and that's because those Styles have been hardcoded so yeah if we were to inspect this let's have a look where's our navigation area all right so notice hm what are we doing here so yeah first step we have Aria current that's for accessibility it's a way to signal to screen readers what the current page is and notice that the styling is a little bit different so we have background gray and then 900 is basically how gray is it so you'll see yep there's a background but none of these other ones have a background so yeah yet again this would be a situation if you were building a static HTML site where you would just have to deal with all of this crap you know you'd have to um manually update every file and say okay now here uh is this the only difference yeah I think so so now this would be for about and and then this one would be uh text Gray 300 and then hover is gray 700 I think that's right come back to about and now we can see that uh move around and in fact I'm sorry I spelled gray wrong there we go and then we do the same thing for contact so yeah kill me this is just kind of a painful thing to do here we'll update this now move it down to the contact Styles and then update this once again to text Gray is 300 and then hover when you hover over it it becomes a darker gray that's basically What's Happening Here refresh yes notice Tailwind gives me a way to to quickly style things without updating a dedicated CSS file so if you're interested definitely check it out but if you're not interested you don't need to worry about any of this stuff okay so home about contact yeah it works but I promise you there's a better way to organize and structure these things so I will show you that in the next episode okay welcome back let's get started cleaning things up so as you know when you're building a simple static website you sort of have no choice but to accept the duplication right I mean maybe there's uh some kind of fancy JavaScript uh templating option you could reach for but yeah if we're only talking about HTML and CSS duplication is just part of the deal but now we're using a dynamic language which means we don't have to go along with that anymore we can remove it entirely and I'll show you how in this episode but before we get to that let's first organize our files just a bit already it's getting a little confusing and now imagine that we had 20 or 30 additional files all dumped within the same directory yeah we don't want that so instead I'm going to create a new directory and this will be exclusively for our views okay so now let's grab each of these and I will command click them and drag them into the views directory okay now of course I need to update these files to point to the Views directory and then the file and I will update all of these one more and yeah already that's just a little bit cleaner than what we had before okay so now let's go into our views directory and yeah you'll remember in the last episode we begrudgingly duplicated all of this HTML for every single view yeah clearly we don't want that we need to fix that so here's what I'm thinking let's add a new directory within the views folder called partials and yeah you can think of a partial as a partial piece of HTML okay how can we divide this up well hm maybe we could start with with the navigation area so notice if I select all of that yeah it is a massive piece of HTML it just keeps going and going let's cut that and I'm going to create a new file in the partials directory called nav PHP and I'll paste that in all right and now if we switch back and visit that about page well the navigation area is gone and that would make sense all we've done so far is created a file but we haven't yet used it so I can do that now and you've already learned about requires and includes it's the same thing PHP require partials snav PHP okay cross your fingers come back and refresh and it's back okay so now we were able to take all the duplication for the navigation area and extract it and that's a programming keyword to extract code into its own file so now I'm going to do the exact same thing for every file select all of it and replace it once again with a require to partials snav PHP and I'm going to copy that so that I don't have to write it again now to the contact page and the exact same thing select it all and replace it cool so now this should work for every single file but notice that now if I need to for example add an additional navigation link like this testing we'll notice I only have to do it in a single place whereas in the last episode uh I would have had to update the navigation HTML for every single file of course that's the benefit to this approach Okay cool so now yeah let's let's go back what else can we do here H well what about starting at the doc type and grabbing everything leading up to the navigation area that's sort of like the header or the head section all right let's do that so add a new one headp HP and I will paste that in and now I can update to this so at the top require partials SL head and then we will fix the indentation shortly let's also do one for the footer or the foot if you want footer.php paste that in all right switch back and then we can substitute that yes so notice how requires are literally you can almost think of it as paste paste the contents of this file directly here that's that's an easy way to think of it okay so now let's unindent this and uh yeah if we switch back to index.php everything seems to be working great but now notice for this file we've removed so much duplication we can do a little bit more like for the head section but but already I think this is looking pretty good okay so now I should be able to select all of this and then update our other views and the only thing I have to tweak is the header everything else should be the same all right so cross your fingers refresh home about contact yeah we're 95% of the way there but notice how the logic for the currently active navigation link is now locked to the about page so we can fix this pretty easily but I'm going to punt on it for this episode just so just so we don't get off track okay so the only remaining step is why don't we also extract to the banner okay create a new file banner. PHP and I will paste that in but again notice now we are extracting a partial that hardcodes the current page so file that one away okay let's come back and replace it with our new partial and then I'm going to do the exact same thing for the other pages so that and that okay so yeah now have a look at how our uh views look my about view requires a head requires a navigation area requires a banner and then the main section is always going to be pretty much unique to every page so I can keep this here and then we close out our site and then we do the exact same thing for contact and index so this is homepage this would be about yeah all of that duplication has now been destroyed which is really good but now we've introduced a new problem notice how the text of the banner is hardcoded to about for every single page and of course we don't want that okay so it sounds like we need to make a portion of a partial Dynamic how exactly do we do that I'll give you some ideas okay let's close the views directory and yeah let's introduce a brand new term I want you to think of these three files sort of like controllers and that's an official programming term so just as view is sort of a a do Ed term in the community controller is as well you can think of a controller as being responsible for uh accepting an incoming request and providing a response and when I use that word request I just mean a visit to the about page that is a user's request to visit the about page we then accept that request and we provide a response and that response consists of what you see within this view okay so I'm introducing Concepts that are maybe a little bit above our pay grade but are going to uh pay dividends down the line once you are introduced the Frameworks where you see these exact same Concepts again okay so and if you want we could even create a controller directory but let's hold off on that just for now okay so why don't we give a name for this page this is home or actually you know what let's call it heading okay and then for the contact page The Heading is contact and then finally for the about page The Heading is about us and maybe for contact it's contact us okay so now remember that any variable we Define in our controller will be accessible within the corresponding View and partials okay let's give it a shot I will go into banner and let's change about to heading all right so once again cross those fingers refresh home about contact everything seems to be working which is great okay so to wrap up think about everything we did in this episode we started by creating a dedicated folder for our views directory within those views we extracted a number of partials to remove duplication notice when I visit the index page how much easier this is to understands if I don't need to work with the navigation area I shouldn't have to consume that massive block of HTML and on the other hand if I do need to work with the navigation area I can go directly to that partial and make my change so all of this becomes significantly easier to to work with all right so you're making really good progress as always let's move onward to the next episode all right welcome back let's Dive Right In so you'll remember in the last episode we punted on this section right here notice how if I click on the contact page it still looks like the about page is selected even though that's not correct okay I'm going to show you how to solve this in a few steps we can begin by visiting the navigation partial and yeah here's our nav links and specifically notice these two right here a dark gray color and white text and sure enough we see it right there for the about link okay so now it makes perfect sense it's always showing up as the about page because we've hardcoded it into the HTML okay so it sounds like we need to instead apply that conditionally all right so we need a way to say well if the current page is home then apply these active Styles so I'll show you how to do that to begin I'm going to visit how about uh index.php and I want to show you something first up within this file I can Echo gibberish and just to show you if if I switch back and visit the homepage we'll see it at the top however if I instead Echo something that is not a string like how about an array we're going to see a warning notice array to string conversion all right so when we use Echo PHP is expecting us to provide a string and that's good to know but yeah what about situations where I instead want to dump an array or an object well in those cases we can use a function called VAR uncore dump or or variable dump okay if I come back and give it a refresh there we go so now I can see this variable is an array that contains one item where that item's value is this gibberish text here okay so now I want to show you something else PHP also uh includes and this is a new term uh what's known as a super Global so these are variables that are accessible uh from any script or from any file uh you could use it to grab information about a get request or a post request and if you don't know what those are you will soon but we can also ask for information about the server so let's have a look here and notice I use dollar signore server and then we dump that okay so that's going to be an array but it's a little difficult to parse here so we have a couple options but what I like to do is to wrap it within HTML pre- tags and that will preserve the formatting so check this out why don't we Echo out an opening pre- tag and then we dump it and then we Echo a closing pre- tag all right so if we switch back and give it a refresh yeah notice it's that much easier to take in which is great so we dump the contents of this array and then we see the rest of our view but also one thing that you often want to do is dump your variable and then kill the execution or die and I use that word die because it's actually a programming term it's the exact term in fact that we would use to kill the execution so notice if I call die here nothing after that function call will be executed so if I come back and refresh we dump our variable and then there's nothing else at the bottom of the page and as it turns out this is something that you're going to do all the time basically every time that you quickly want to inspect a particular variable so if I want to do this all the time it's a shame that I would constantly have to uh Echo this opening preag then dump the variable then close it then call die well maybe we should reach for a function and remember functions just do things they are the verbs of the programming world so why don't we wrap all of this within a function called uh how about d d dump and die and then I will paste all of that in but of course now I don't always want to dump the server super Global I want to dump whatever value you pass in okay and then I will replace that here okay so now have a look if I refresh we don't see anything because I didn't call this function but now I will D and dump the contents of this super Global come back refresh and now we get exactly what we had before but that logic is now nicely wrapped within a brand new function so if I instead one want to die and dump whatever this heading variable is come back refresh and it works pretty cool okay so let's bring this back and actually inspect our super Global here and uh specifically I want to point your attention to this key here request URI and notice the value is uh forward slash which always refers to the homepage so basically everything after the domain name so I think what we can do is inspect the request URI to figure out what the current page is let's give it a shot let's Echo the server request your and yeah if we come back and refresh at the very top sure enough I can now detect what the current page is if I switch over to about let's do the same thing here we'll do it right there and now we should see slab. PHP okay interesting so now let's take it a little further I'm going to get rid of all that and switch over to our navigation partial and yeah maybe we could conditionally apply this open up PHP if and let's close that PHP uh if we look into the server super Global and specifically at the request URI if that equals forward slash or the homepage only on that condition should we Echo out the following classes and what was it background of gray 900 and text white I think yeah I think that's right okay so we can definitely clean this up a little more but but baby steps if I come back and give it a refresh sure enough I now see the appropriate Styles and if I instead switch to contact notice we no longer see it on the homepage so it is in fact Dynamic okay but I think we also need to have an else condition yeah so notice right now we might be applying a class of text White as well as text Gray so it sounds like we would need to say well if it's the current page then use these classes otherwise else uh Echo that class and yeah I want you to notice this will work but already it's really really messy okay so here's here's what I want to show you I want to show you a slightly different way that we could format things and to illustrate this I will return to index.php and I'll paste this logic in here and reformat all right and this is what we just wrote so if a condition is truthy then Echo this string otherwise Echo that string so as it turns out for situations like this we could alternatively reach for the turnar operator which is just a different way that we could structure things so if I were to rewrite this it would look like the following Echo and then our condition so I will copy that here then a question mark and that's sort of like asking a question is it Tru the if so I want to Echo these classes and if it's not truy I want to Echo that so yeah this form and this form are effectively and functionally identical it's just a different way to write the exact same thing we ask our question if it's truy then do this if it's not truy then do that okay so I showed you this because we could rewrite this and save a few keystrokes let's return to our navigation area and I'm going to change this let's remove all of this and we'll say all right Echo and then we ask our question is the request your I slash question mark is it then do these classes if it's not then do those classes and yeah this should do the exact same thing come back and refresh and notice I still see uh those active Styles all right and of course I don't have to write Echo here I could use the short PHP TX like so and even in this case the semicolon is optional so that cleans it up just a little bit but I think we could take it a little further in just a moment for now though let's copy all of this and repeat it and the only thing I'm going to change is which URI I'm looking for so for this link I would want to check well are we on the about page only on that condition do we apply those Styles and then we'll do the same thing for the contact page like so so if we did everything correctly cross your fingers I think this should work refresh and keep an eye on that black background we have home about contact congratulations it works but yeah even with our refactor to the turn are operator it's a little little cumbersome to write so I wonder if we could make it uh even cleaner H let's see let's go into index. phtp and I will add a new function maybe this function will tell me if the URL or URI will use URL in this case if the URL is a particular uh value so this will return a Boolean true or false and we know how to determine that because it's this right here so I will copy that switch back and paste it in and then we'll just replace the value with this variable and return the result okay so now we have a useful function that tells me if this URL is the homepage or the about page let's see if we can use it now I will go into nav and let's replace all of this by saying well if the URL is the homepage only on that condition do we apply these classes so yeah no notice it's a very small Improvement you might even call it I don't know a micro Improvement but I promise you so much of your programming career will consist of small little improvements like this where you take something that's a little cumbersome or a little vague or confusing and you wrap it up in such a way that it's not confusing and then you do that over and over you rinse and repeat and uh congratulations you're a programmer okay so I'm going to use this and if I come back and refresh ooh I don't see anything but what about on the homepage refresh I do but not on about and not on contact and if you think about it that makes perfect sense we only defined this function within index.php okay so now we're in this weird boat where I have to copy these functions for each page and immediately this feels wrong so if I do it again it's going to solve the problem problem but yeah we don't want to do that I don't want to duplicate functions across every file so once again this is an example of extraction we're going to extract these functions into their own file just like we extracted these view partials into their own file so why don't we call it create a new file and how about functions.php and I'll paste it in now I can manage and Define them in a single location so that means back to index.php I can delete those and the same for contact and the same for about but now of course I have to require that functions file so I will do that at the top functions.php and yeah it's true I would have to do this for every view but I'll show you how to get around that in an episod or to I promise and then we'll do it right here as well and yeah if we did everything correctly that problem should now be solved and it is great cool so yeah now we have Dynamic active navigation styling for each page which is pretty cool all right as always onward to the next episode welcome back okay hey uh I've been doing some thinking and you know what you're ready it's time to Crank It Up A Notch and figure out how we can build a custom router from scratch and granted it's not going to be the most complex or sophisticated router in the world uh but you know what it'll be entirely practical for where you are right now in your learning and you know what you may not even know what a router is and if that's the case no worries at all I'm going to explain every step of the process and watch this maybe two times because I really do think you're going to learn a lot in this video let's get going now as always we will tackle this in a series of steps so up until this point we had a direct mapping between a file path in the address bar and the corresponding controller so for example if I visit contact well we have contact.php and sure enough we have a corresponding contact.php controller okay but I want to change all of that instead I want a single point of entry where I can then be responsible for mapping whatever is in the URI to the corresponding controller okay so I want to be in charge of that okay so the first step is to create a new directory specifically for our controllers like so and I will grab about contact and index.php and drag them into there okay now we'll close that up we'll have again a single point of entry that is responsible for handling the current route so for example if I say hello there and switch back give it a refresh sure enough we are loading this page and even if we have something like this in the address bar notice that it still defers to that index.php file okay well next up we learned in the last episode how to die and dump the current server super globble so let's import functions.php and try that out again DD server all right come back give it a refresh and yeah once again we have the request URI so notice if I change this to contact yep we have a match there but we also have to be a little careful for example what if there happens to be something in the query string you've probably seen this before something like that where we have a question mark at the end of the path uh and then a series of key value pairs okay well now notice request URI is not contact anymore it is the full path including the query string so we need to account for that okay but yeah we could start by saying okay well the current URI is server request URI and then we could we could start in a very basic way I could say well if the URI equals forward slash then maybe we're on the homepage so we would require controllers SL index.php but now before we run this in the browser I do want you to notice something this file requires functions.php and then it potentially includes controllers index and that file also includes the functions file and we can't do that so in fact if I come back to the browser and we give this a refresh we get a fatal error notice cannot redeclare DD and again that's because we required the file two times so we effectively declared that function two times okay so now we have the ability to remove this from all of our controllers and I told you in the last episode we would solve that little issue and now we have great so if I come back and give it a refresh everything is working we've handled the first use case okay let's do another one how about well else if the URI is slab then we will require controllers slab. PHP okay but now real quick before we run this you may remember in our our navigation bar we are still linking to those full file names let's tweak it now we no longer do PHP in the address bar so I will delete all of those at once okay so now we can say if you visit SL about then let's load the corresponding controller cross your fingers refresh the homepage works I click on about oh and we have that same problem maybe I didn't oh I missed one there we go sorry about that I thought got that anyway we give it a refresh and now it works okay so you can see uh how we might begin building the most basic form of a router and yeah just to be uh comprehensive we'll do the last one if it happens to be SL contact then I will load the contact controller yeah so clearly what we have here isn't the final product but we will slowly get there uh through baby steps so again home about contact I think we're in good shape here but yeah now what about the query string maybe when you visit the contact page you could include a name or something like that well now at the moment we don't see anything and that's something we have to address what if the user visits a URI that you don't have a corresponding controller for what do we do in those situations and we'll solve all of that uh in this video but yeah in this case what is the problem well URI I is no longer SLC contact it's this full thing here and just to make sure we're all on the same page I'll prove it to you come back give it a refresh and now this is what URI is equal uh to so if we check it is the URI contact nope so we do not load or require that controller okay so it's almost like I need to say no no no no let's strip off the query string we may work with that later but right now I just want to know what the the the primary path is so as it turns out PHP offers a function called parse URL you feed it a URI in this case and it will parse it and separate the path from the cre string so let's use our handy dandy uh die and dump function and I told you you're going to reach for it all the time and if I give this a refresh now notice I have an array with a key called path that is only the path and that's what we want and then another key called query that contains the query string perfect this is just what we need so now I'm going to wrap this whole thing in a call to parse URL and now I want the value associated with the path key so we will grab that here okay so once again let's die and dump that variable give it a refresh and there we go even if we have something in the query string we've only matched the the portion of the URI that we care about great so let's remove all of this cross our fingers give it a refresh and now it works home about contact but we're not done yet okay so what we have here does work at least right now but it's kind of sloppy uh so I think we need to refactor and luckily things like this are really easy to refactor once you know what to look for so think about it what we basically have here is a mapping so if the path is this then require this if the path is this then require that if the path is is this then require that so couldn't we represent that as an associative array if we wanted to something like this we could say well if it's forward slash then load controllers index.php and then I'll duplicate that if it's slab then load about.php if it's contact then load contact so notice I've created a little map here or even you might even call it a lookup table a way to associate a given your ey with a corresponding controller so why don't we name that RS like so okay well now that would allow me to get rid of all of this and I kind of like how that looks it makes it that much easier for me to add uh new routes in the future that I want to respond to and handle but now how do we how do we require the correct value well think about it I have a URI and why don't I just check if that U I exists as a key uh within my routes array so I might say something like this and here's a new PHP function called array key exists so notice you give it the key in this case it would be the URI and then you give it the array that you're looking into in this case routes and what array key exist does is well exactly what it says it lets you know if the array has a key of the given name that exists so if we have a corresponding UR I only on that condition should we require the corresponding controller require routes URI and let's see if it works home about contact it all still works so that was a successful refactor or at least partially successful and I say partially because well again what if the user requests a URI that we're not yet responding to let's give that a shot let's see what happens maybe there's a typo or something like this well now we get the white screen of death and we definitely don't want that so why is it white well think about it we grab the current URI we set up our routes we check to see if a URI exists in our list of routes it doesn't so we never trigger this logic which means we go on here and we don't do anything so all we see is a white page it all makes sense yes but of course we need to handle this use case and generally we want to provide what's known as uh a status code so if you've ever heard of 404 page you can think of that as your way of saying well that page doesn't exist and in fact if you want to learn more about this just Google HTTP status codes we'll do it right now status codes and top link is fine yeah so notice we have all of these response codes like 400 302 500 400 you don't have to memorize all of them by the way but yeah they are ways for us to respond to a given request to provide a little more feedback back so maybe uh a user request a page and we want to redirect them somewhere else well there's a way to provide a response code to indicate that maybe we want to let them know uhoh something went wrong on our end and we can't show you uh this page well we might use a 500 status code for that another one might be I don't know what you just requested this page doesn't exist in which case we would provide a 404 status code and as it turns out that's the one we care about right now okay so in PHP we can set a status code by using HTTP Response Code and I will set it to 404 then I will say Echo sorry not found and then let's die and kill the execution okay so if I come back and refresh yeah now I at least have a little more feedback for the user and more importantly we are responding with the proper status code if I bring up Chrome developer tools or I'm sorry Firefox Dev tools or I can right click and choose inspect I can go to the console and give it a refresh and yeah notice right here so the user made a request for this page and the response from my server is a 404 not found we don't know what you're looking for so we don't know what to do here we're just going to give you some feedback there okay but sorry not found works but uh maybe we can integrate it into our application just a little better so what if instead I require a file like require views and how about 404.php and I will create that now 404.php and let's just duplicate some of this so I will grab my index file and paste it in and now this will say um sorry page not found and then maybe an anchor tag that sends the user back to the homepage go back home all right and then I will style this real quick uh like I don't know text toxcel make it bold and then maybe a little margin top and then I will style the link like text blue and underline it you know something pretty basic all right let's give it a shot if I come back and refresh o yeah this is an issue undefined variable heading and that's because while we're loading the banner the banner expects a heading variable to exist but it doesn't so of course we get a warning in this case though it's not overly appropriate to include the banner so why don't I delete it in the case of a 404 now if I come back and refresh this is better so now we have a page for home and about and contact or if the user visits some page that we don't know about we provide the proper feedback we respond with a 404 sorry page not found and we go back home okay pretty cool let's keep going so back to index.php uh I think we can refactor this now what do these three lines represent they sort of represent us aborting the current request so what if I create a function right here and I call it abort I could then take all of this paste it in like so and then here I can simply call abort a nice little refactor and everything's still going to work as you see there okay but often you will want to abort but provide a different uh status code once you learn more about them maybe a 400 maybe a 500 maybe a 422 uh but right now we are hardcoding 404 why don't we allow a boort to accept a status code we'll call it code and then we will substitute it here and here what I'll do is remember I need to wrap this in double quotes if I want to inline this variable here like that okay now really I should probably check to see well do we have a corresponding View for the current status code like is there a 422 PHP file I'm not doing that here because I'm just assuming I will never call it but yes in real life you you would want um some safety mechanisms in place for things like that but we're not going to worry about it but now yeah I could pass through 404 and this is all going to work cool but sometimes it's nice to say well well the default is 404 and if you want to overwrite it you can but the default is 404 so in these situations I can set the parameter here to have it A Fault by saying code equals 404 so now if I don't pass a code it will use 404 and this will work but if I pass something else like again 422 then code here is set to 422 and this is going to fail because again we don't have a corresponding View and that's why in real life we would want to handle uh that use case but yeah let's stay on track and this all works pretty cool okay what else can we do um H well what about this block here what is this doing well it's it's routing the current URI to the corresponding controller so maybe this could be its own function like function route to controller and then I could paste all of that in but notice we have these squiggly because well within this scope we don't have access to the URI and the routes that's outside of the scope of this uh function okay why don't we pass it in now I can call it route to controller and we're going to give it the current URI and we'll give it our array of routes okay next I think the abort function should go at the bottom so now we're getting into stylistic stuff how do I want this file to look all right let's see I load it and then we have uh parsing of the U Declaration of routes a function to handle routing the URI to one of those routes and then an option to abort with the given status code so if we come back and refresh yeah all of this is working just like it did before okay but now I'm starting to see that this this and this really all of this is related to routing and as you can imagine in a real life project if you're not careful everything gets dumped into this index.php file and you end up with a lot of um messy or spaghetti code so an initial refactor we can do is simply move this to a file called router and then I can uh require it all right let's do that now router. PHP and we paste it in okay so now we have a dedicated file that specifically and exclusively handles parsing the current request URI and routing to the corresponding controller okay so now index.php requires some functions for the app it requires a router and we're good to go here so if I come back and refresh yeah once again everything works like it did before but now I think we're in really good shape all right so now that we've managed to build admittedly a very basic and primitive router I think the next order of operations or the next order of business is to learn how to interact with a mySQL database so I'll warn you there's a lot to cover here but I hope you're excited let's get going the first thing we should do is create a database and of course if you want you can do it directly from the terminal like this MySQL dasu for username rs's root and we haven't set a password and sure enough I'm in so yes I could run the command create database my app you know whatever you want to call it end it with a semicolon and sure enough one row affected which means I have created a new database but yeah I these days I prefer to use a guey for things like this so instead I will hide the terminal and bring up table plus which we looked at in the first or second episode of this series all right so I'm going to rightclick and make a new connection the name can be anything you want I will call it demo and yeah pay attention to the host and Port here we will stick with the defaults but later we'll need to reference them from our PHP so just remember a host of Local Host and a port of 3306 all right next the user was root we don't have a password because it's local uh and that should be it so let's test it out and I do get green so I'm ready to connect and there we go all right so now to select a database I can press command K and we called it my app otherwise if you want to create one from scratch you can do it here all right and we're in so now what we might want to do is close this out and I will rightclick on demo and choose edit yeah and if we want we can set it to always load the my app database and I'll save that okay so now when I double click I'm directly within that database all right let's create our first table and we will use the very common example of blog posts okay so I just used the word table uh at least initially you can think of it sort of like an Excel spreadsheet uh that's a common comparison or even something like a form we've all filled out a web form before so imagine you're using Wordpress or something and you want to create your first blog post what would some of those form inputs be well you might have something like what is the title of this post so I will call the column name title the data type you're going to see all sorts of types here trust me you will mostly use 10% of these but the common ones are things like uh varar or varchar that would be uh any number of characters up to 255 you could have text and that would be useful for long form text you could have um time stamps you could have decimals and floats and integers again there's a here you will mostly use five or six so in this case why don't we use VAR card 255 okay next is nullable can the title be null well ask yourself would it make sense to have a blog post with no title probably not so let's set it to no and then do we want there to be a default value not really so that is our first column but notice how everything has a background of green in table plus that's because because it will not persist until you save it so I will press command s or controls and now I have created a new table that for now only has a title and then we have our ID which is the primary key for now think of it as a Unique Auto incrementing number that represents a specific row within your table so yeah what we have right now is the structure of the table but we don't actually have any data within it as you see here okay let's do it I will double click and notice the ID will autoincrement and it'll start at one so you can see there is a default value there so that means I only need to worry about title my first blog post and again notice how it's green it won't persist until I save so command s and notice it sets the ID to one if I do another one let's say my second blog post and once again command s now the ID is two so this Auto increments and it's a unique identifier that points or represents this specific row all right so think about everything we covered in this video we created our first database called my app and we connected to local host on Port 336 try to remember that and then we defined our first table within it and right now that post table just consists of an auto incrementing ID the primary key and then a title but of course in real life you would at things like the body of the post uh maybe a status for the Post are we in draft form has it been published has it been archived and then later you could have relationships to other tables for example it might make sense to include the person who created the post the user who wrote the post so think about it if I added a second table called users I could then draw a line from a record in the user's table to a record in the post table and that would be my way of saying this user created that post and that user down here created this post and this is what it means to have a relational database okay so you know what my original plan for this video was to also write some PHP to connect to the database but on second thought that probably needs to be its own lesson so to wrap up and this is also your homework all I want you to do is play around and get comfortable maybe add a new column create a new table update a record and you'll good to go all right welcome back we have a lot to cover in this video so no intro this time let's just Dive Right In I will open table plus access our database and yeah in the last video we created this post table but of course the end goal is to figure out how to query this table from our PHP and query is sort of the key word to do that we need to write an SQL or SQL query we'll do our first one together select star from post and I can run that or you can see I can press command return on the Mac okay and sure enough here's the results all of the records from the post table so let's break this down select is a keyword it's obvious what do you want give me this but what is star well that means everything but I could change it I could say well give me only the ID column or the title column let's try it out select ID from Posts and now you can see I get all of the records from the post table but only the ID for each one or I could say give me only the title or I could use a comma separated list select ID and title from the post table or in this case because that's all I have it's a functionally equivalent to select star now I could also add a wear Clause maybe I only want this blog post here okay let's use that primary key or the unique identifier select star from Posts where the idd equals 1 and now I get that single result or two pretty cool and more importantly pretty easy to write which I like all right let's now switch to my editor now of course later we will organize and refactor our code but yeah when you're first learning it's totally fine to dump and throw everything within index.php all right so we need to connect to our mySQL database and to do that we're going to use something known as PDO or PHP data objects I'll warn you this can be a little confusing and honestly in real life for working developers you don't you don't write this sort of code too much because it's already been done for you when you use libraries and Frameworks but nonetheless it's important at least figure out the basics and then later you can use what's known as libraries or abstractions okay so the first step is to initialize PDO to do this we need to create a new instance of the PDO class sounds very programmar and very confusing and even worse the idea of classes and objects and instances are entirely new to us we haven't yet reviewed it so here's what I'll do I will give you the 60-second rapid fire version so you understand it and then I promise later we will cover it in great detail okay so we can define a class like so and you can almost think of a class as a blueprint for anything now initially we we often say look for the nouns so the 101 your 12 years old uh example which can be helpful sometimes is a person well we could have a blueprint of a person and one person has red hair and is named Bob another person may have brown hair and is named Julia but they're still people right and that's the entire Point all people share similar characteristics and behavior so so what a person has ears a person has nose and toes and hair maybe not hair um people have similar Behavior like we breathe in we breathe out I hope we do that um a person can kick a ball potentially a person can move their hands so a class is sort of like the blueprint for what a person is and what a person can do so let's start nice and easy a person can have a name and what I'll do is I will start with this visibility key word called public for now this is a little higher level than where we currently are so I prefer you ignore it but if you want to research it it's just a way to declare visibility of this property to the outside world but yeah for now just come along for the ride and we'll explain it more in the future name and I never want to do something like this because then think about it I'm now saying the blueprint of a person is that all people have a name of Jeffrey and of course that's not true so I will simply Define it like so what else a person has an age and then a person has Behavior like a breathe so I could Define a function called breathe just like you're used to but notice how for this function or actually functions within a class are called Methods which can be a little confusing but they're still functions anyways notice there's no visibility before function so do we have to do this and the answer is well yes and no no you don't have to do it because technically the default visibility for a method or a function within a class is public so to some extent it's redundant now having said that it's just common practice to declare visibility these days so even though public is the default uh I would recommend just get in the practice of of being explicit and as you'll learn in the future there are other visibilities like protected and private but for now we're just going to make everything open to the outside World okay so let me give this a quick reformat to clean it up and when we breathe well what should we do there well remember functions are the verbs of the programming world including methods so why don't we just say Echo and to start I will write breathing all right so how do we work with this person class because remember I did say it's sort of like a blueprint right and just like H for a a home construction you'll have blueprints right but then you could have any number of homes that you build off of those Blueprints and maybe this one is brown and this one is white but it's still working off the same blueprint well you could refer to those homes as implementations or instances of the blueprint and we're going to do the exact same thing here person equals a new person just like that with the new keyword all right next let's set the name and age of the person person name equals John Doe and right here H this this is an ideal for a video this arrow is actually a dash and then a greater than sign but I'm using a fancy font that that turns it into an arrow but yeah on your own you may not see that just put them next to each other okay so notice I'm referencing this property but I don't type it out like a normal variable notice that I omitted the dollar sign all right let's do it again person age equals how about 25 okay so now let's use our handy dandy DD function to dve and dump this person and inspect it all right switch back and we'll give this a refresh and oh you know what I'm sorry just for a moment I need to comment out the router all right let's do it again and there we go so now notice an instance of a class is referred to as an object and for this object the name is set to John Joe and the age is 25 if I want to access them it's very similar to an associative array but instead of doing this syntax I once again use the syntax that we learned about so person name and that should give me John to change it to AG that'll give me 25 and then why don't we call some of the behavior on this class breathe all right breathe and call it just like a normal function okay come back give this a refresh and now yeah I have called that function or called that method pretty cool and even better within our class we can interact with these instance properties so for example what if I wanted to say John Doe is breathing I could say Echo this and this is a keyword that refers to the current instance I think of it as this instance all right this name and then a space is breathing okay so now because we're calling Echo I don't need DD as well so I can remove that and let's give it a shot come back refresh John Doe is breathing and yeah I can create as many instances of this class as I want one named John another named Jane who is 45 but again they all work off the same blueprint so yeah that's your 2-minute classes 101 introduction uh trust me we will go into this in quite a bit more detail in the future okay so back to work all of that to show you that to connect to my SQL we need to create a new instance of the PDO class now you can see this class expects an argument called DSN DSN stands for data source name again this stuff is very confusing think of it as a connection string a string that declares your connection to the database so what port what host what uh database name what character set things like that let's define it now and I'll warn you it's a little wonky to Define so we'll do it together first what are we connecting to my SQL next what host are we connecting to and you'll remember in the last episode I said to remember this the host is Local Host and then I can divide these key value pairs with a semicolon so the port is 3306 uh and yeah just in case you forgot how to find that you can I think click right up here and yeah host 127.0.0.1 is Local Host and then um the port maybe you have to close this out right click and go to edit here we go Port 3306 here's the username here's the database Okay cool so let's go back and now declare our database name DB name equals my app and then finally I'm going to as a good practice declare the character set Char or car set equals and we basically want utf8 but a better version of it so I will do mb4 again this is kind of high level stuff it declares how uh characters are encoded if we're not working with English or something like that you don't really need to worry about it okay and I will save this as PDO all right next we should probably handle situations where PHP was unable to connect and to do that we would use something known as a TR catch uh statement but again it's a new thing that we haven't yet learned so forgive me but I'm going to skip it just for now but we'll cover it later anyways I'm ready to prepare a new query prepare and yeah you'll remember what was our query up here select star let's do this one select star from Posts so I will copy that switch back and paste it in prepare this new query so yeah we are effectively preparing this query to send to my SQL where it will be executed so we often call this variable statement it is a prepared query statement and then again I said we send it to SQL to execute so I will call a method named execute and remember method function kind of interchangeable but the proper term is a function on a class is called a method but it doesn't really make a difference okay so now the only remaining step is to fetch the results so I can say post equals statement and let's use fetch all I want to fetch all the results as opposed to a single result or a single record okay so cross your fingers let's pass this to DD and see what we come up with so I give it a run and actually it fails so we screwed up access denied for user at Local Host yeah I forgot to provide the username and you'll remember that the username is roots so I could do that as part of our DSN or I could even do it as the second argument like so so if I come back and give this a refresh now it works or again you can do it directly within the DSN like this user equals root and if there's a password you would provide that as well okay come back refresh and now it works all right so have a look at what we get in response I have an array of arrays where each item is a record that came from my SQL so notice if we have a look here the first record has an ID of one and a title of my first blog post sure enough an ID of one and a title of my first blog post but notice we have a little bit of duplic here notice here is a key of ID and then zero and then here's a key of title and then one so notice it's kind of giving us both versions a keyed version and an indexed version but really in most cases you don't want that so there's a number of ways to do that but for now I'm going to declare how I want to fetch the results like this PDO Fetch and why don't we say associative array give me the results as an associative array rather than uh indexed so now notice if I come back and refresh we will remove that duplication and this is probably what you want so now to wrap up of course we have way more to do but to wrap up this video we can play around by we'll do it in line here and we could say Echo a list item and then the title of the post and then a closing list item and with any luck we have the results okay so I know we covered a lot here there's a lot of confusing stuff and there's more to come but it wasn't that many lines of code we figured out this confusing uh connection string we created our first instance of a class we prepared a new query to send to mySQL MySQL executed that query and then we fetched all of the results and then we looped over them and displayed the results so yeah more to do here but you're making really good progress stay tuned all right welcome back everybody here's where we left off in the last episode so we created this awkward looking connection string and then we passed it to a new PDO instance and then we prepared and executed our first query we fetched all of the results as an associative array and then we looped over the post and for each one we displayed the title of the post within a list item and here's what we get okay so to be honest there is so much we have to cover we need to talk about prepared statements and SQL injection and and different ways that we can configure the DSN but before we get there let's just take a few moments and refactor this into something that's a little more uh friendly to use okay so here's what I'm thinking if I were to at the top make a little note about what we're trying to do here I could do that with two forward slashes and now I can enter any text and this won't be interpreted as PHP it's just a comment anyways if I were to write this out I sort of want to connect to the database and execute a query okay so why don't we convert this to a class and we already learned a little bit about classes in the last episode but we'll learn a little more in this video we learned that we can create a class like so and I did say connect to the database and at least initially it's helpful to follow the nouns so why don't we start with that class database all right next upep we have and execute a query yeah in this example uh execute and query would both be pretty good method names because they can both be treated as verbs and remember we learned that methods are the verbs of the programming world so in this case let's just pick one do we want to call execute or query and this is where the design aspect comes into play if I'm working with a database class and I want to trigger a SQL query do I want to call execute or do I want to call query hm in this case I think I'll go with query public function query and yeah remember whenever we Define a function within a class technically we would call it a method and don't forget to add the visibility but yeah right now we're making everything public because we haven't yet dug into that all right so this is looking pretty good to start the next step is to create a new instance of the database class so I will Begin by creating a variable DB is very common equals a new instance of the database class okay so now I can call this query method by saying DB Arrow query and yeah you'll know you did it right because if you're using a good ide it will give you some intelligence and you can see yep you can call this method okay so now how would we go about refactoring all of this into our new database class and you know what we're going to do it one refactor at a time so we will Begin by selecting everything cutting it and pasting it into our query method okay so now when I call this query method yeah it builds up the DSN it initializes PDO It prepares a hardcoded query which doesn't really make sense what if I want to run a different query well we'll get there then we execute it and then we fetch the results and we save it to a variable cult post but yeah if we wanted we could return that and now we should have an array of posts if we did everything correctly so let's try this out post DB query come back to Firefox give it a refresh and yeah it still works so it's not very flexible because right now I have a database class with a query method and all that query method does is it selects everything from the post table which of course you don't want so yeah that would be the next step let's make this query Dynamic by turning it into a variable and we can accept that when we call the method okay so now if I scroll down you'll see squiggly here because we are requiring that you pass us a query so I will paste that in now yeah notice I've moved it out of the method and made it just a little more flexible so notice I can tweak this if I need to for example select star from post where ID is greater than one and in this case I think I only have one record so if I come back yeah notice I have complete control if I had a different table well I could say select star from users again I've made it that much more Dynamic but now if we scroll up it works but it's a little unfortunate because as you can imagine in a real life application you could potentially execute hundreds of queries as the user browses around your site and it's a shame that every time you call this query method we basically start over from scratch it doesn't really make sense instead it would be nice if I could build up our PDO instance one time and then every time we call query we we effectively reuse that same instance and as it turns out of course we can do that okay so where would that code go and as it turns out when we initialize a new instance of a class there's a way to say okay right when that instance is created I want you to do something and here's how we do that on PHP we create a function and it's very awkwardly named it's underscore uncore construct so when uh an instance is constructed that's how I think of it but yeah remember number two underscores and then construct so yeah if I wanted to I could say hi there uh just to prove to you that we are triggering this method automatically so if I come back to Firefox and give it a refresh sure enough that function or that method has been called by PHP automatically okay so it sounds like that's the perfect place to initialize our PDO instance so I will grab this and move it up here okay but now notice in our query method we have an issue expected to have access to that PDO variable but it's in a different scope now we moved it out of this method okay so here's what we can do right up in the construct let's define a instance property and again right now we're making everything public but later I'll teach you when it would make sense to not make things public all right and what should we call this well we could do PDO like we have here but really it's sort of our database connection that's how I think of it so why don't we call it connection okay so now I have an instance property on our class called connection now I want to write to it so instead of creating this variable PDO I will instead say dollar sign this for this instance Arrow connection equals new PDO and then stylistically I would probably put a blank line above it okay so now think about it whenever I create a new instance of database well we automatically call this construct method as we learned within it we initialize a new PDO instance and we assign it to this connection instance property and yeah by the way that's generally the term we use property okay what's cool about that is anywhere else in this class I can access that property so now if I want to use my connection I can replace this with this connection and on the connection we will call prepare so what we have here should work just fine let's give it a shot come back to Firefox give it a refresh and yeah I once again get uh all of the posts that have an ID greater than one let's remove that and try it again and now we have all of the posts in the database which is only two cool okay so what we have here actually looks fairly good but we have one issue right here I don't love this and here's why what if I were instead trying to fetch a single post well I might say select star from post where the ID equals one and I will just die and dump that post well it'll work if I come back and give it a refresh but notice it's it's effectively returning a collection a list so I have an array of arrays which means I would have to do something like this give me the first item from that array and that would give me this and that two is an array so I would then say then give me the title and that works but notice it's it's kind of weird I would expect a single array that has all of the attributes of my post but because we called Fetch all that's going to return to us a list so the solution is to not call fetch all but instead just fetch give me one record come back and refresh yeah so now notice I have a single level array here and I can once again do things like post title and that'll work okay so once again we're seeing that whether we call fetch or fetchall or maybe something else well that needs to be dynamic so instead why don't we just return the statement itself and yeah at least for now I can be in charge down here of whether we call fetch or fetchall so in this case I want a single record so I could call Fetch and then once again PDO fetch Association and notice this right here is kind of annoying it would be nice if we didn't have to to manually write that every single time we fetch the results and trust me you can we'll do that in the next video so if I come back and refresh there we go and yeah we later decide no I actually wanted all of the posts then I could switch over to fetch all and uh oh yeah of course we have to update this now I have all of the posts which is an array of arrays and sure enough that works all right and I will wrap up this lesson by creating a new database.php file and I will grab all of this here and move it and we'll paste it right here okay cool so now if I switch back we can require database.php and actually notice that I made that D capital and that's because whenever you have a PHP file that only contains a class and you're going to do this all the time in the future by the way again uh General conventions state that it should be capital okay so granted we still have so much more work to do but already things are starting to look and more importantly feel pretty good I think so uh yeah stay tuned for the next episode and we'll keep chipping away at it you know it's funny a lot of programming consists of taking code you have that already works but you don't stop there you keep iterating on that same code over and over until it doesn't just work but it's also beautiful and flexible to work with so with that in mind if we take a look at the database class that we whipped up here hm are there ways to make it a little more flexible and I think the answer is yes have a look at this DSN here notice that I've hardcoded many of the options here like the host and the port and the username and those will almost certainly change depending upon the environment and what I mean by that is well what about when we push this up to production so that the whole world can view the website well at that point the host is no longer a local host but I've hardcoded it here so yeah you often have have situations where you need to use certain configuration for your local environment but different configuration for your production environment and these are the sorts of things we need to think about so let's do this in most editors there will be some way to for example command click on a class name and it takes me directly to that file and here I can see the Constructor for that PDO class and notice yes it wants a DSN but then we can pass separately from the DSN the database username password and options okay so I think that's a pretty good first step all right so username in this case is root next the password because this is local is simply blank but of course in production you would have a password and then finally the options can be an array okay so if I come back to index.php you'll remember in the last episode where I noted how annoying it is that I have to pass this constant every time I want to fetch the results oh and by the way forgive me there's so much to cover and sometimes I forget things uh I didn't outline what those two colons on the class means uh the technical term is scope resolution operator but you don't need to know that my guess is if you could pull 50% of working PHP developers they would not be able to tell you what the name is and that's totally fine you just don't need to know it uh more important is knowing what it does so that gives you access to a static or a constant that was defined on the class class again there's so much here you don't have to learn every piece you can let it wash over you uh bit by bit you can think of a constant as nothing more than an identifier for a particular value but most importantly that value no matter how many instances of the class you have will never change and that's why we call it a constant it's not an instance property it's a constant so yeah notice this example on the PDO class it looks like we have all of these numers that represent different data types 2 3 four five yeah that's about it um for developers though the the numbers don't mean much to us it's hard to remember what four means right or what is the difference between two and four so instead the natural thing to do is attach an identifier to each number so now I can see Pam int is one what is zero oh that's Pam null and then when I ever need to access that value or in this case the number well if I switch back I can say class Name colon colon and then the name of the constant and as a general rule and good practice we make all constants uppercase to make it crystal clear this is not an instance property this is a constant okay anyways all of that to say I can now remove this from the fetchall call and let's declare it as an option when we instantiate the PDO class and I can do it just like this the key will be PDO and this also is a constant attribute default fetch mode and that will point to fetch Association okay so now that will apply across all uh results that we retrieve all right so now I can remove the username up here but that still leaves the host and the port and the database name that needs to be dynamic so what if we had some kind of configuration array and for example I could say the host is Local Host the port should be 3306 and the database name should be uh my app okay well if I defined that outside of the DSN I could then substitute it like this config host and then config port and then finally config database name but while we're here why don't we also do the character set and I'll paste that in and then once again update this as well all right so this is getting a little messy but we can clean it up and here's what we have and I'll hide the sidebar but next check this out I'm going to clean it up a little more I will call a function named HTTP build query that PHP provides and yeah as its name suggests it's actually intended for building up a query string like this example.com Fu equals bar this is the query string so if if I used this associative array it would do something like this by default host equals Local Host and Port equals 3306 and DB name equals my app Etc but yeah in our case we're going to use it not for a query string but instead a DSN connection string but the only problem is it uses the and symol as the divider but as it turns out if I command click through to the function definition here's the data here's the prefix that we don't need but the third argument is the separator that we want to use so let's give this a shot if I were to call this function on config I don't need a prefix but as the third argument I want the separator to be not an and symbol but a semicolon like that we think about it that would then generate uh this and that's pretty much our DSN isn't it so why don't we try this out in the browser and what I'll do is I'm going to pass this whole function call to our d D function and we'll have a look in the browser I give it a refresh and yeah I mean that's pretty much what we want the only remaining thing is this awkward MySQL colon section but what if we just added that at the beginning we prep pinned it MySQL colon and then we we concatenate whatever is returned from this function call so if I come back and give it a refresh and yeah that's pretty much our DSN isn't it it's exactly it all right so that was kind of a fun refactor we're using this function in a slightly different way than maybe it was intended so if I now save this as DSN this and this are functionally equivalent so now we can choose the simpler option if I come back and refresh everything still works the way it did before which is pretty cool okay but now hm even though I extracted this connection configuration into its own array we're still sort of in the same boat aren't we and here's what I mean as soon as I push this project up to production where the environment is different and for example the host and the port will be different well my application's going to break because I've hardcoded it to local values okay so whenever you have this situation where data should be dynamic dependent upon the environment the solution is to push those values upward all right so let's do that one step at a time first step I'm going to take all of this and push it out of the class so in instead of declaring it inline here I will accept it like so config all right so now I will go to index.php paste it in here and then pass it to our Constructor and yeah let's just clean that up really quickly yeah notice what I mean we've pushed it out of the class and upward to the next level where we call or instantiate the class and yeah of course everything's still going to work the way it did before we haven't changed anything here all right so that's better but now you're probably thinking well you didn't hardcode it in database.php but Jeff you're still hardcoding it in index. PHP so you didn't really solve the problem and again you're right so what's the solution push it upward again what if we extract this into its own file where we have one version of that file for local development and a different version of that file for production I think that would solve the problem so let's give that a shot create a new file and I'm just going to call it config.php and I'll paste that in but instead of declaring a variable I'm going to return okay so come along for the ride for just a minute now back in index.php I can say config equals require config.php all right and let's do a sanity check does everything still work and it does all right very cool and even better we learned something new haven't we we've learned that the return key word is not exclusive to function calls it can be used within regular files just like this and whenever I require this regular file this is what we return okay so now back in index.php I'm saying create a variable called config and make it equal to whatever is returned from this required file which is pretty cool okay so now let's go back to database.php are there any remaining values here that should be Dynamic dependent upon the environment and the answer is yes we are still hardcoding the username and the password okay so we have two ways to solve this you learned in the last episode you can declare the username and password as part of your DSN connection string another option though if you want is you could pass them in separately so why don't we accept a username and a password if you want to take this route and then we substitute them here now they're dynamic and that looks good and if you want you can even assign default values so you might say set the username to root or default of root because it's so common and the same for a password being an empty string for local development all right so back to Firefox give it a refresh and it still works but yeah I think these have been pretty good and sensible refactors notice that now other than this MySQL part which I'm just going to assume we're always using MySQL in this series but other than that everything can be Dynamic and if I ever need to change this well maybe Port changes to 3309 database changes to something else of course this is going to break when I try it but it proves that we are now reading from that file okay so now let's bring it back the final thing remember this configuration file is not exclusive to your database credentials you can use it for the entire application so with that in mind maybe we should key this like this let's create ay key called how about database and then I will paste all of that in and that looks pretty good and now think about it in the future if you ever have specific configuration that is not connected to the database now you have a place to put it for example as you mature you will often work with external services and apis and often those companies will give you uh tokens or secret keys that you need to reference in your code so for example at laracast I use a tool called pre-render and maybe they give me a token and a secret key that I need to reference well again this would be a good place to declare it because remember those token and secrets again will often be unique depending upon whether you're in a local setting or a production setting okay and trust me you'll learn more about this in the future so now if I come back to index.php and now we just need to update this to pass config database okay so sanity check it still works I I think we're done for this video but before I let you go I get it we covered a lot here and there were a bunch of new Concepts and sometimes that can be a little overwhelming so think about it we talked about uh taking Dynamic data and pushing it upward you learned about environments local versus production you learned how to return and require data from a file so yeah a bunch of Concepts here and if you need to watch it two times and only when you feel comfortable should you move on to to the next video I'll see you then all right next up we should discuss SQL injection as well as in general improper SQL query formatting and the dangers associated with it okay so in the US legal system we have this ideal that a person is innocent until proven guilty right well as it turns out on the web in in the programming World actually the opposite is true we should always assume that the user is guilty not innocent and I'll show you what I mean let's open up table plus and I will visit my SQL Tab and yeah a quick refresher let's grab everything from the post table or we can grab the post with an ID of two where ID equals 2 and as it turns out we can also use the or keyword so maybe I could say give me the post where the ID equals 1 or two and there we go or if we want to be a little more verbose we could say where the ID equals 1 or the ID equals 2 and we'll get the same thing but what if we instead applied that to a different table so you can see behind the scenes I've quickly whipped up a users table where the username is varar of 100 characters and the admin is a Boolean or a tiny integer of two characters where zero is false and one is true okay so if we take a look at the data I'm I have two administrators and one guest so if I switch back to my SQL query tab let's select star from users all right now let's find John where the ID is to or let's find John and any administrators like this where ID equals 2 or admin equals 1 okay so now yes we have John Doe but we've also retrieved every administrator from the system and then finally if we want into we could delete the entire users table by saying drop table and then the name of the users table so real quick before I execute this let's go here into structure into info and here is the query that I can run to regenerate to the table so I will copy that just so I can quickly recreate it okay so I will hit command return and now if I refresh with command R sure enough we've deleted that users table it's entirely gone okay so I will paste in that create query and now it's back all right cool so now let's take everything we've learned just now and figure out how it might be used against us all right so back to PHP storm and at the moment we're just selecting everything from the post table and then we dump the results so back to Firefox give it a refresh and sure enough I get an array of two posts but now let's switch it to the post with the ID of one and sure enough we get a single record and in this case of course if we're only getting one record we can stick with fetch I don't need a list or collection I just need a single uh result okay but now as you can imagine in real life we won't be hardcoding the ID instead for example the user will click on a post with an ID of one or another post with an ID of two and maybe we could pass that through using the query string like this ID equals 1 okay and now of course we're not yet doing anything with that parameter so that's the next step and as it turns out we can access that query string by using the dollar signore get super Global so why don't we pass that to DD and real quick if this is confusing well remember in the router episode we reviewed super globals right here so the first one was server to grab information about the request in the server this time we're using get to access information about the get request okay so if I come back to Firefox and I give it a refresh sure enough I now have an array of all query string parameters okay so now if I want to grab the ID I can access it like this cool so now you're probably thinking great why don't we save this or cach it to a variable and then we will inline it here all right switch back refresh and yeah there's the post with an ID of one and here's the post with an ID of two so yeah it works dot dot dot so your instinct might be to Pat yourself on the back and say good job me uh but actually no we've introduced a major vulnerability here all right so here's the problem we are taking whatever the user types into that query string for the ID parameter and we are inlining it as part of the SQL query so let's do this let's take everything here and extract it into a variable called query and then I will save that like so that way I can very quickly die and dump the query before we execute it all right I think this will help so if I come back and refresh this is the query that we will ultimately execute against their database okay no problem but what if I changed it two as we reviewed one or two and yeah that's a valid query isn't it so think about it this is a small little tweak that the user made but it illustrates a gigantic security threat in in your application so let's review another example what if I said give me the post with an ID of one and then we'll add a semic call in here and I will say drop table users all right we're getting a little sneaky sneaky here aren't we we are now triggering two queries one to fetch the post with an ID of one and then another that we definitely didn't intend to drop the users table entirely so let's give it a shot I will remove that DD and now we will trigger and execute that query so back to Firefox give it a refresh and yes we have the results but now if I come back to table plus and I refresh with command R pay attention right here 3 2 1 goodbye users table and now think about it without our permission an annoying malicious mean-spirited person was able to delete every single user in our database and do I have to say it that's really really not good okay but luckily there is a fairly simple solution these days okay so I have a rule for you here that I'd love for you to follow and in general you may have noticed this I'm not the biggest fan of programming rules as if they are you know Commandments from above that shall not be broken uh but in this case kind of is a commandment you need to follow this one okay so when accepting user input through a quer string or through a form never ever ever ever ever inline it as part of a SQL query that's what allows for SQL injection especially if you haven't formatted your query properly which usually people don't okay so here's the solution I'm no longer going to inline it directly instead and I'll show you two ways to format this I will replace it with a question mark select star from post where the ID is something something that later we will associate or bind to the query but here's the key thing to understand the query and the bound parameters almost travel in two different boats maybe that's a way to think of it you will send through the query to mySQL and then in a separate boat you will send through the parameters and when you take this approach you remove any possibility of improper formatting or SQL injection okay so now how do I bind the parameters well actually let's do this I'm going to open up a split visit our database class that we worked on and you right here when we call the execute method this is where you can bind the parameters and it will take the form of an array but in this case well hm I need to pass them through here so it sounds like this array should be dynamic why don't we call it prams and then I will accept it as part of the method signature and we'll default that to an empty array okay so now when I call the query method as the second parameter I can bind my ID like this all right cross your fingers switch back and uh let's start with the happy path give it a run and yeah it works let's switch to the ID of two and that works as well now let's try something malicious so if I switch back oh I don't have my users table anymore real quick let's go to the SQL Tab and here's my SQL query to recreate it all right run it give it a refresh announce back and yeah let's try to drop that table again give me the post where the ID is to semicolon and then drop table users okay so with any luck if I switch back and refresh aha the users table is still intact and it's intact specifically because we leveraged prepared state with bound parameters so just to be Crystal Clear if I brought this back to what we had before well now we are once again inlining the variable so we run it and bada bing bada boom your user table is now gone and this is the whole point of the video this is the main thing I want you to avoid never ever ever inline user data into a Cru string so I will bring this back and yeah this is a significantly safer approach okay so finally to wrap up I did note that there were two ways to declare this first I could use a question mark which is fine or I could use a key We Begin it with a colon and then we give it any name we want in this case ID would make sense okay so now the only difference is I pass an associative array where I reference the key and then the value and if you want it can be colon at the beginning or no colon it's entirely optional whatever you think reads best so once again again if I come back and refresh and as expected we get the exact same thing so yeah whether you reach for a question mark or these uh I don't know what the name is uh key Wild Card parameter something like that it doesn't really matter choose the one that you like best but the whole point and intention of this video and I'll drill it into your head one more time is to never ever ever ever ever accept user input and inline it as part of a database query you don't want to do it all right welcome back everybody but before we get started elephant in the room yes I'm wearing a hat yes it's a dad hat no it wasn't called that when I was a kid yes that means I couldn't shower today yes my hair is too messy for a screencast and yes I got a lot going on so let's get on with the show so here's what I'm thinking at this point you've learned enough of the fundamentals that we can start moving on to some miniature projects first up we will build a simple notetaking app now of course we could approach this in a number of ways but at this stage of the game in our learning why don't we begin at the database I will add a new table and yeah if our goal is to track notes well note is the noun so why don't we name the table notes okay a note should have a primary key and then we should also track the body of the note so let's set the data type to how about let's go with text it can be any length and no it cannot be null and let's save that with command s but finally it would make sense that a note belongs to a particular user so with that in mind why don't we also create a users's table and a user will also have a primary key and then a name that can be a variable number of characters it cannot be null and then why don't we also for good measure include an email and that too will be barar 255 and it cannot be null okay but now here's something interesting to think about would it ever make sense in our system to have more than one user with the same email address H and this is important this is database integrity and consistency could we ever have multiple users with the same email address and I've decided the answer is no that makes no sense so the email address always needs to be unique okay so we can do that on the database level by adding a unique index let's go down here and we'll add an index now we can let the index name be autop populated but I do want it to be unique and the column name is email all right let's save that okay so now and by the way I get it this is a New Concept so just come along for the ride we have introduced a unique index for the email column and this does a number of things but right now what we care about most is it enforces that only one user can have a particular email address so why don't we try it out let's close this out open my table and we'll do myself Jeffrey way and let's expand these okay we'll set the email to Jeffrey lc.com and then command s to commit it so now notice if I have a different user and we try to use that exact same email address as soon as I save it you're going to see an issue and there we go we have an error there's a duplicate entry for this email address and again that unique index is what enforced that all right so let's undo this by pressing shift command delete on the Mac all right so now let's move over to the notes table and create a new note and how about PHP for beginners is the best and we'll save that okay but now of course I'd like to create a refence or a relationship between this particular note and let's see this particular user so how do we do that well I need to update the table to add what's known as a foreign key let's do that now to the notes table to structure and let's add a new user ID and this column will point to the user who created the note that's the relationship here the note belongs to a user and then what should the data type be well well it should be the exact same thing as what you did for the primary key so in this case an integer finally can it be null well ask yourself would it ever make sense to have a note that was not created by any specific user and keep in mind the answer might depend upon the application in this case we're going to say uhuh it wouldn't make sense every note belongs to a person so no it cannot be null all right so let's save it and if I switch back to my notes table and into Data yeah we can update this user ID to point to a specific user but actually real quick notice that at the moment user ID was set to zero and there is no user with an ID of zero so this is another example of a potential pitfalls where your database consistency can fall out of whack for lack of better words we want to make sure that everything is consistent and if we have a note written by a user who doesn't exist that's a problem so again there are constraints that we can put in place to enforce this and I'll show you how for now let's update this user to one and then we'll go back to the structure to add our constraint okay so now on the user ID column check this out if I scroll for a bit you'll find a foreign key section so let's create a foreign key and yeah this is not as complicated as it might look so on the notes table this user ID column well what does that reference like it could be named anything does it reference something specifically and the answer is yes it actually references the ID column on the users table right that's what it points to it points to a specific column on the users table so the reference table is users and the referenced column is ID and then we have these hooks for what should happen when the referenced record is updated or deleted so here's an example imagine you have a user John Doe and John Doe creates a bunch of notes but then we delete John Doe's account so now his user record is gone but we still have all of these notes that were created by John so we have these orphans Now notes that point to a user who no longer exists so these hooks allow us to declare uh what should happen in those situations so for example I could say well if the user record is deleted why don't we Cascade and delete all of his notes in the process and as you'll find uh maybe that is not correct for your application but maybe for a different application it is correct another option would be restrict don't allow it to say no you can't delete this user because this user has a bunch of notes and we want to maintain our table consistency but yeah in our case let's just Cascade and delete all of his notes in the process and then I will save it okay so check this out we have a user Jeffrey way Jeffrey way has created let's go to data exactly one note actually let's do one more hi there blah blah and I'll point that to myself as well okay so now because we set up that foreign constraint watch what happens if I hit delete to delete the user that will now Cascade and delete all of the notes if I give this a refresh goodbye all of the notes in the process so again a foreign key and a key constraints allow us to declare and maintain our database consistency okay so you know what I didn't expect to spend a whole lesson just on uh databases and tables but this is really important stuff so in the next episode uh behind the scenes I'm going to populate this with a bunch of dummy records and then we will display it on the screen I'll see you then all right welcome back everybody let's Jump Right In where we left off in the previous episode okay so behind the scenes I've created two users as well as a handful of notes that belong to those users so notice this one has a user ID of one and that one also has an ID of one so those correspond to John now if I write a SQL query for that I might say select star from notes where the user ID is one or John and sure enough I will get only his notes and if I change it to two then I will get Kate's notes okay let's try to get this on the screen so if I open index.php of course a number of episodes ago we required a router and this router has some example end points that we respond to so let's have a look in the browser and yeah this probably looks familiar so let's do this I'd like to add a new notes link to the navigation bar all right we will go into views partial nav and yeah if I hide the sidebar here's our links so why don't we put it after the about page that will take us to slash notes we will activate it if the URL uh contains that and then yeah this is a little messy and by the way we could clean this up uh quite a bit but I I just want to stay on track for now and I will update this to notes okay so if I switch back and give it a refresh there we go we have our notes link but of course if I click on it we get a sorry page not found we get a 404 because we haven't registered a listener so to speak for that URI so that's the next step let's go back to yeah here we are let's go back to our router and we'll say duplicate this and listen for that's how I think of it sort of like a listener listen for when the user requests this URI and uh when they do I'd like to load my controllers slash uh notes controller all right that's the next step right here why don't we duplicate about so command C command V and I will call it notes there we go our heading is notes and this will load a view notes. view.php and just like before I can duplicate this to save ourselves some time notes. view.php okay so if I come back and refresh it there we go so now we have our homepage our about page and a new notes page okay let's take a quick moment to talk about this this is a really important cycle uh that you're going to appreciate down the line when you start learning about Frameworks so keep in mind what we did I wanted to create a new page for our notes so I started by registering a route uh listener or an endpoint however you want to phrase it well let's listen for this URI let's respond to this URI and when the user visits that page here's the controller that is responsible for for handling that particular request and then we created that that controller can now do whatever it needs to it can gather all of the data that's necessary and then it passes that data off to a view the view is then responsible for at least in our our interpretation the view is responsible for presenting that uh to the user and here we go so we're going to think of it sort of like the HTML layer some I bring this up because some people might squawk at the idea that the view is for is basically the HTML it's sort of a new thing but you know what it's fine for now you can dig into that later on your own okay so we have this idea of registering a route uh listener we have controllers we have views I promise once you start learning about Frameworks and laravel or Symphony you're going to feel right at home I promise okay so let's come back and this is looking good okay so now the next step is to fetch all of the relevant notes from the database and yeah I'm just going to assume that this guy here the stock model is is our John Doe so I want to grab all of John's notes all right let's go back and it sounds like we should do that from our controller because remember the controller accepts the request it can delegate it can prepare and then it passes that data off to the view okay so first up we'd like to access our array of notes from the database but yeah notice that well I want to interact with the database but if I go back to index.php we don't create our database instance until after we require the router and that router loads the controller so for example if I were to within our notes controller simply die and dump that DB variable we're not going to see anything let's go back and give it a refresh yeah and notice we get undefined variable DB which makes sense because again we aren't creating that DB variable into the database instance until after we've requireed the router and after that router loads the controller okay so that makes sense but now it is true this is something you will run into quite a bit where you have certain uh services that need to be accessible from throughout the entire application and H how do you make them available well as it turns out it's it's not too difficult but I think it's a little above where we currently are so I'd like to stay on track and punt on that just for now but I do promise we will tackle what's known as service containers in the future okay so why don't we do this let's grab all of this bring it over to our notes controller and I'm just going to manually load it at the top manually load it okay but now if I come back I just need to make sure before I load the router we already have the database available to us that way when we require the router and the router requires the controller then we will have a database class that we can instantiate okay so if we come back to Firefox and give it a refresh there we go we're up and running okay so let's write our query now I can say notes equals dbquery and yeah we're just going to write our query that we played around with at the beginning so John has a ID or a user ID of one so let's grab that switch back and paste it in and then let's fetch all of the results and then once again let's pass notes to our handy dandy DD function okay so come back give it a refresh and just like that we have all of John's notes from the database perfect okay so now when I load the notes view all I have to do is Loop over these notes and we already learned about that in section one of the series so let's do it h maybe right here we can say PHP for each notes as notes and I'm going to use the shorthand version and for each again this should all be a recap at this point uh why don't we just use a simple list item where we say give me the note body okay so come back to Firefox give it a refresh and there we go we have all of John's notes so that means if I were to go back to table plus let's add another one here how about thoughts on my continued learning of PHP and again let's say John's learning PHP so he has an IDE of one if I come back to Firefox and give it a refresh now we see that as well which is pretty cool okay so now with that in mind hm maybe instead of notes we should change this to my notes so let's go back to our controller and yeah let's update the heading to my notes there we go all right next maybe it would make sense for this list of notes to contain only an excerpt but then when you click on it it takes you to the full note or something like that okay let's see let's go back into our view and yeah maybe this should be a anchor tag that takes us somewhere we're not sure where yet like that and if I come back and refresh now whoops did I screw up yes I did anyways now uh they are clickable but you know what they should be colorful why don't we add a class of text blue and then I will underline it or how about when we hover over it we will underline it and then I'm sorry I need to use a shade of blue there we go okay but now what should happen when the user clicks on one of these notes where should we direct them and yeah in the future I'll show you how to do things like this where you say slash notes slash and then a unique slug for the notes and this makes for a nice and readable uh URI in the address bar but you know what right now our little makeshift router doesn't allow this so we're going to keep it simple instead we will send the user to something like slote and then I will pass through the ID of the note through the query string that's a nice and easy way to get started so for example if I did this all right so now come back and you have a look right down here we're saying load the note page and send through ID equals 1 but notice for every single link it says ID equals 1 so this is another case where of course the ID needs to be dynamic the ID needs to be well the ID of the corresponding notes in the database all right that's the next step so back to PHP storm and we'll say right here open up PHP and Echo the notes ID all right let's see if that works so once again have a look here ID equals 1 and then ID equals 3 and then ID equal 7 I think we're in business okay so let's click it but yeah of course we get a 404 because again I haven't registered an endpoint so that's our next step and again try to get into the process of what this looks like so we start by going to the router we register and endpoint slote we'll load a controller slote file that can be copied so notes to note all right and now H how do I grab that ID well again you already learned about the get super Global right so if I were to saycore get and then ID uh excuse me there we go one so that is the ID of the note that we want to fetch from the database so let's do this ID equals get ID okay so now our SQL query for this page will be select star from notes where the ID equals the ID that was passed through the query string but remember now I'm not going to endline it like we learned a couple episodes ago that's a big SQL injection or formatting security threat instead I will use a placeholder or a wild card like this ID and then I can pass through those uh wild cards as the second argument like this okay but now notice that well we could do this if we want but I'm creating a variable and that variable is only referenced in a single place so as a general guideline you don't always have to follow this but as a general guideline if it's only being used once just inline and and again most editors offer a way to do that automatically as you see there otherwise just do it yourself get ID and then I can delete this all right cross your fingers we come back to Firefox we give it a refresh and yep there we go we're loading the note with an ID of one and just to prove it to you ideas for next vacation the note with an ID of one ideas for NEX ification let's do how about number seven all right let's update this or actually go back to notes this one has an ID of seven and there we go it matches very cool but yeah at this point notice I'm still loading the view for all of our notes which we don't actually want and another problem is well why did that work did you think about that we were loading the view for a different controller but everything still worked and that's because well we wrote a query to fetch a single note but we did fetch all which means give me an array of the results even though because we're grabbing one by its ID there will only ever be a single uh result so we should update this to note and then change it to not fetch all but just fetch a single record okay now we can twe this and then create a new view so yeah as a general guideline uh for every single URI that you want to respond to there will probably be a corresponding view for it if there's something to present to the user all right so let's come back here and we'll say um H get rid of all of this it doesn't need to be with an anchor tag because we're no longer linking anywhere I can just present it uh maybe like this and to keep things a little cleaner I'll wrap it within a paragraph tag which probably isn't right because maybe your note could be multiple paragraphs but yeah for now and for presentation only I'll keep it and there we go okay so let's go back to notes let's look at work reminders and again in real life this would probably be a a fully fleshed out notes about things you need to remember for work okay so now let's just wrap up I think we're done but yeah let's wrap up by quickly adding a button that will link us back to all of the notes something like this sln notes and then we will say go back all right come back yeah but let's style it text blue 500 I should have some general uh link styling here yeah and then we can push this down just a little bit margin bottom of six really quick styling but yeah that should be fine okay so there's notes with an idea of one and then uh whatever this is three and then seven and again these are only the notes that were created by our fancy model here uh John do all right you're doing great work we'll keep going in the next episode all right welcome back everybody in this episode we will discuss uh what is it authorization status codes and Magic numbers so let's get going now if I switch to Firefox yeah in the last episode we added support for displaying all notes that were created by a particular user so in this case we have three but of course in the database it looks like we have five notes and notice that two of the notes were created by a different user and that's why we don't see it here okay so this is fine well at least initially it seems fine I can click through yeah it looks good but actually it's not good uh and maybe you picked up on this in the last episode we have unwittingly introduced a major security concern think about it what's to keep me right up here from passing through the ID of a note that was not created by me let's give it a shot how about this one right here the note with an ID of six was created by somebody else okay let's see what happens if I try to load that note ah it works so again this is a really big problem granted in this case they're dumb notes it doesn't really matter but in real life the notes you create should not be accessible to anyone that has access to a browser right clearly uh this is a really big problem so this is where authorization comes into play let's see how let's go into note. PHP and yeah remember this is the controller that handles displaying uh this particular page and yeah we can see right here we are grabbing the note that has an ID that matches the one that's currently in the query string as we see right there so yeah not a lick of authorization in place all right so we have a few ways that we might deal with this your first thought might be to Simply update your seq query like this select star from notes where the user ID matches current user and the ID matches the one that's in the crew string okay so now if I were to clean this up real quick we could pass them through user is and I'm going to just hardcode it for now because remember we haven't yet reviewed authentication but I promise we'll cover that in this series at the moment though we're just going to assume that the user with an ID of one is the currently authenticated user until we learn more okay so let's give this a shot if we come back and give it a refresh I think it's going to change and it does we get a warning trying to access array offset on value of type bu okay so maybe at the beginning of this series you wouldn't have known what that means but now you do what is Type bull a Boolean true or false so it looks like we have a value that's a Boolean could be true could be false but we're trying to interact with that value as if it were an array and why would that be well let's inspect it we'll come back to PHP storm and I will pass note to our DD function and we'll inspect it give it a refresh and sure enough it's false so now that makes perfect sense we load the view and we are interacting with false as if it were an array and that's why we get that error or that warning okay so why is note equal to false well it makes perfect sense we didn't get anything from the database let's try a different record we'll come back here's the ID of seven and that note was created by the current user so we return uh the appropriate record okay so this seems to be working but how do we deal with situations like this where false is returned well we could do something like this we could say well if there is not a note then there was some kind of issue right so we can call our abort function and be done so let's give it a shot we come back to Firefox give it a refresh and yeah it works so I guess that's good but it doesn't work in the way I would like and here's what I mean if you think about it there's a couple different reasons why note would evaluate to false think about it one reason would be you're trying to access a note with an ID that doesn't exist so if I were to switch back let's view the note with an idea of 6,000 or or whatever that is 600,000 well there is no coresponding record in the database so we should say sorry page not found but another reason might be due to this little section that we added here all right so imagine um yes a corresponding note exists in the database but you did not create it okay so that's a very different thing in the first example we display a 404 because a note was not found that makes sense but in the second example that's an authorization issue yes the note exists so it was found but you are not authorized to view it all right so we can see that there's two different reasons why we might want to abort and when we have these two different reasons it might be useful to provide a hint or a status code that indicates what the problem is okay so let's do this let's get rid of this check here bring it back to a simple finds note with a corresponding ID then we can say well if there's not a note abort we want to display a four of four but then let's add another one we might say well if the notes user ID does not equal one well then you're trying to access a note that was created by someone else so we would abort in that case but again the 404 status code isn't quite right remember a status code of 404 means page not found but as we just discussed in this particular example that's not appropriate instead I need some way to signal that well it was found but you are not authorized to see it and as it turns out that corresponding setatus code is 403 a 403 Forbidden okay so now we've separated the two different reasons why we might not be able to access uh this particular note so let's go back to Firefox give it a refresh and we get uncut PDO exception invalid parameter oh yeah I'm sorry we we removed the user parameter but I forgot to remove the binding as well all right so come back give it a refresh and there we go so notice in this example we are trying to access some fictional note that do not exist in the database so we get a 404 page notot found but this time let's change it back to two which is a note that was created by someone else okay and you can see right here it's trying to load our 403 uh view so it seems like everything is working we just need to create a corresponding view for that particular status code so I'm going to copy 404 I renamed it to 403 and I'll update the heading to un authorized okay so come back give that a refresh and there we go and in fact if you want to be crystal clear here you could say you are not authorized to view uh this page just to make it crystal clear to the user so switch back to notes I see my notes I can view a note but yeah if I try to tweak it to a note that I do not have access to I'm going to see a 403 Forbidden okay so let's wrap up by quickly talking about about uh Magic numbers okay so on this page alone I can see one two what you might call Magic numbers and again what is a magic number uh you can think of it as a number that has significance or or special meaning that is not explicitly declared so yeah in this case one what does that mean what is the significance of one well we know the answer to that question right now we haven't yet reviewed uh sessions and authentication so I'm hardcoding that one to signify or to represent the current user right but yeah imagine 6 months from now you might forget what that one refers to and this happens all the time by the way you're looking at code and you think well what does that mean what is the meaning of that number what does it refer to why is it important and yeah even if its meaning might seem obvious to you at the time it could be that a year later or or multiple years later if this is a long running application uh in it may not be so obvious so one option would be to extract that to a variable let's just assign a name I could say current user ID equals 1 and now I can substitute it here yeah it's just a small tweak and actually notice how we're breaking that guideline from an episode or two ago where we noticed that we only declared a variable once so we inlined it right but there's also situations where even though it's only being declared once it's still serves a purpose it serves the purpose of identifying what the value is it provides more clarity uh as to what the value is and that's what we're going to do here all right next 403 this is another good example uh you'll definitely get to a point in your career where you see the number 404 or 403 it's attached or related to a response of some kind and you instantly know what it is oh 404 not found or 403 Forbidden it makes perfect sense uh but it's still doesn't change the fact that well it is kind of a magic number and maybe it would be courteous to other people uh maybe maybe those who are not as familiar with status codes it might just be courteous to let them know what this means to provide a little extra Clarity and as you'll find with programming so much of this is figuring out how to provide extra Clarity how can I simplify this how can I make this more clear how can I remove the need for a comment this is what so much of programming is so how could we do this well well I could do the same thing as what we did up here I could say forbidden equals 403 and yeah I mean that would work but in this particular example I actually don't like this approach and the reason is because well I might want to abort with a 403 all over the place so yeah would I just have to assign it to a variable every single time um I don't like that instead why don't we do this Remember When You're Building applic there's nothing preventing you from creating another file I I often find in the early stages sometimes developers feel like well I got to work with what I have available to me and that's not true if you want to create another file you know how you do it you just create another file and then you keep going I know it sounds simple but trust me that is often a roadblock for newcomers so in this case why don't we create a class to represent this response I'm going to call it response. PHP we'll make it a class class and you learned about constants a number of episodes ago so why don't we uh create constants for each of the common status codes that we might want to return so we'll start with the 404 what does that mean not found so we'll call it not found equals 404 let's do another one for forbidden forbidden equals 403 okay so now check this out if I come back into our note if I want yeah I can bring this back to what we had before stick with 403 and in fact in many cases you might find you don't have to worry about the magic number because again it its meaning is so ubiquitous so I'm showing you lots of ideas and examples for when you might um refactor away from Magic numbers but that doesn't mean they're never allowed if you decide no everybody knows what a 403 means then then then keep it right it's all give and take you decide what's appropriate and what needs to be uh clarified a bit more okay but anyways if we instead require our new little response class I can now reference it within our note like this abort with a response of forbidden okay so notice it's a small little change but it does improve readability and all of programming is making small little changes that improves readability and functionality so think about it before we were saying abort with the magic number 403 that you are supposed to know what it means but after we're saying abort with a response of forbidden we're just tweaking the clarity that much and I think that's a pretty good refactor okay so a little cleanup like that and yeah here is our note controller as it currently sits still lots of room for improvement but I think we're making pretty good progress okay so to wrap up we try to track down the note that has an ID that matches the one in the query string but if we couldn't find any matching note from the database of course we abort 404 page not found I don't know what you want here otherwise if there is a corresponding note then we continue on and we do a second check well was this note created by the current user and if it was not well then once again we should abort with a response of forbidden otherwise if a note exists in the database and it was created by the current user all only at that point do we continue on where we load the view and we display the details of that corresponding note all right let's do our final test in Firefox and we will be done for the day so let's review how about this one here this note was created by me so I see it no problem next though the note with an ID of two was not created by me so I get an unauthorized and then finally if I do some kind of ID that doesn't exist in the database then I get a 404 not found okay everything seems to be working and we solved that pesky authorization issue I'll see you in the next episode there's much more to cover all right welcome back everybody let's Jump Right In so I will return to our node controller from the previous episode and yeah here's where we left off uh so I want to point your attention to all of this junk here all of this is responsible for uh fetching a note from the database and authorizing it so why don't we see if there are small little tweaks and refactors that we might use to clean this up a bit because remember this is what 80% of programming is you you get the first draft on paper so to speak and then you go over it again and again and again uh making microscopic improvements that really do add up at the end of the day okay so the first thing I see is this if not note then abort okay I wonder if there's a way that we could combine these like it wouldn't it be cool if there was a way to say uh fetch or abort and then it would just do that automatically for me think about it if if if I had that method if that method was available to me I would no longer have to write this and in fact across the entire code base I would no longer have to write logic like this I would simply use uh helper method like that but the problem is well this fetch method I don't own that's something that PHP provides internally I think it's actually a PDO statement class in fact let's just play around let's die and dump the note to see what we have here so I'll come back give it a refresh click on a note and yeah we see we have an instance of a PDO statement class that I don't own but yeah it's true though there will be situations where you wish you did own it so that you could add things so you could stack things like this so hm is there a way that we can allow for this and the answer is absolutely there's a number of options that we might consider so let's take a look right now we know that this query method is returning that PDO statement object that we reviewed in the browser okay but what if it didn't let's click through and yeah that's where we return the PDS statement but again what if it didn't hm well if it didn't maybe I could either wrap it inside of another object or simply extend the the API of this database class to offer some additional helper methods all right come along for the ride and see what you think if I'm no longer returning the statements well I could just return the object itself the instance and we can do that by saying return this okay so now when I call query I'm not returning that PDO statement I'm returning the same instance of database so in fact right now everything's going to blow up of course because now we're trying to call fetch on a database class and it doesn't exist so yeah if we come back to Firefox and refresh of course we get a fatal error and we'd expect that there is no fetch method on the database class okay so you know what let's do baby steps here why don't we start by adding a fetch method so I will switch back scroll down and we'll add it here Fetch and yeah this is basically going to do uh what we had earlier where we'd have something like statement fetch but now the problem is this statement object I don't have access to it it's outside of the scope of this method and instead it's inside of query right here's our statement and I want to access it from this method but I can't do that so it sounds like hm uh there's a couple ways we could do this but it sounds like why don't we assign the PDO statement to this object uh as an instance property like this this statement equals connection prepare and then I can update this like so and then finally I will declare it at the top now don't forget at the moment we are making all class Properties or object properties uh public because we haven't yet reviewed visibility or types or any of that stuff but yeah again in in real life this would probably be uh protected or private but for now public is fine okay cool so now that we've effectively assigned the PDO statement to the object I can grab it from from any method that needs to access it like this so I'm going to say return this statement Fetch and if we did everything correctly it all should just work come back to Firefox give it a refresh and there we go we're in business but now the key difference here and this is an important one the key difference is that I now own this fetch method which means if I don't want to call it fetch as an example I don't have to and in fact I think fetch is an ideal if I just want to grab a record if I want to find a record uh well why don't I just use a method like find well now I have that ability because again I own this method okay so now if I come back to note you'll see um by by making this refactor or again we could have wrapped up the PDO statement within our own class and our own object that would have done the same thing but either way we have regained control so to speak we're not just using somebody else's API we've W it up in something that we own so again this is a little higher level maybe a little more confusing but these are really important Concepts that you'll reach for throughout your whole career okay so now we've swapped it over to find everything still works and this is looking great so the next step is to add a method to handle this and remember at the beginning of the video I said it might be nice if there was a method called Fetch or abort or find or abort or find or fail whatever you want again this is the creative aspect of programming you get to name it whatever you want so in our case why don't we call it find or fail okay and that would ideally if we do it right that would allow us to remove all of this here and everything would still work just like it did before all right well let's do it back to our database class we now have a find method but I will add a second version find or fail and this is just going to say all right we'll try to find the record so this is is going to call that other method that we just created but then we're going to do a check here and we'll say uh remember I can't just say note because it won't always be a note it could be uh a user it could be a post it could be something different so we want to keep this fairly generic like result then I could say all right well if there's not a result uh and we're just reproducing what we had in that note controller then abort but otherwise if we do have a result I can return it and yeah if we did everything correctly this should just work let's give it a shot we'll go into this note and yeah let's now access a note that doesn't exist and we get a four of four it works exactly the way it did before but now we've wrapped up this incredibly common logic that you can imagine needing to perform throughout your entire code base so I think that's a pretty cool refactor let's come back to our note controller and now it's a little more simple all right next let's move on to this section here and again sometimes it helps to take a step back and just ask yourself well what is this code doing and if I were to explain it to you I would say oh this this code authorizes that the current user uh created the given note uh but notice that keyword authorize doesn't exist here but maybe it should so in that case maybe we could add a helper function called authorize let's try it out if we and this doesn't exist right now but if we had a function called authorize what would we do well maybe we could take the condition and pass it through and that would just do it you know again wouldn't it be cool if that was a thing and if it's not a thing make it a thing like this we'll go into functions.php we're going to add a new one here authorize this will accept some kind of condition or really a Boolean and then I could say uh well if the condition fails so if not condition or or falsy uh then we will abort with a 403 uh if you wish so response forbidden and I think that should do it and actually on this note it might be useful and flexible if we extended this for example what if we added a second parameter to allow the user to override the default status code and Right Now the default is response uh forbidden so then we could substitute it here but yeah notice now if the user wants or if we want we could pass a a custom status code that we want to use but now you might be thinking well wait a minute if we're performing authorization then isn't 403 always the proper status code and the answer is well yes and no uh maybe technically yes but there will be situations where even though the user may not be authorized to view uh a particular page or resource you don't necessarily want to indicate that to them because that provides that provides information about the state of the database maybe that's a way to look at it it gives them information that oh that record does in fact exist so maybe I could do something malicious knowing that another example we're going on a tangent here but 30 seconds another example might be um if you need to reset your password and you type in an email address you submit the form you've done this before right and then it returns and tells you we couldn't find a user with that email address uh and plenty of sites do this uh but if think about it it it is and in fact lass might do this but if you think about it if you think about this it does reveal information about the database because now you have a way to check if a given user exists or if a given email address exists in the database so notice you're revealing information that you may not want to in certain situations okay so that was a long way to say it could be useful to allow ourselves or our future selves to override the status code okay anyways let's come back and yeah I think this is actually looking pretty good so back to Firefox here's a record that doesn't exist here's a record that we didn't create and oh actually I expected that to work we didn't create this note but we could still see it so again notice these are the things you have to deal with all the time and this is where in the future you'll learn about uh testing automated ways to confirm that you didn't screw up as I did here so anyways if I come back to our note controller I want to authorize that the notes user ID equals the current user and that'll solve the problem as you see there finally if we view a note that we did create everything works the way we'd expect okay so let's wrap up by updating and this this fail yeah it does so because we made those tweaks to the database class we're going to have to update our notes controller to no longer call a fetch all method all right let's go to notes and yeah DB query and do we want to keep this method do we like that fetch all or do we want it to be something different like maybe you just want it to be called all or maybe you want it to be called get so here's my query and get me the results keep it simple whenever you can so with that in mind we're going to stick with get come back to database here is our method called get and again this is just going to say return this statement fetch all and again notice that I now own that method name come back refresh and that works as well so I think this is a pretty cool refactor so you know what I get it we've been sort of in the woods the last couple episodes as we talk about uh some nitty-gritty details and refactoring maybe that's not fun to you actually it's super fun to me but I get it it's nothing flashy that we can see on the page so in the next episode we will fix that by finally reviewing forms and how we can allow our users to create brand new notes that are persisted in the database I'll see you then all right welcome back everybody I think it's finally time to dig into forms and I say finally because if we're being honest it's probably a little overdue but one thing at a time right uh so let's get going the first thing I'm thinking if I switch to Firefox is there should be some button down here to create a new note so let's do that now I will go into my views the one for displaying all notes and then yeah maybe right here H well first let's wrap this whole thing within an unordered list and then yeah maybe right here we'll have a paragraph that includes a link to somewhere where that Link's text is uh create note and I'll need to style this as well so I will make it blue and then when you hover over it we will underline it okay so come back give it a refresh and yeah uh maybe we should give it a little Breathing Room Marchin top of six yeah you know it doesn't matter we'll turn it into a fancy button uh maybe in a little bit okay so now if I click on this where should we go well it sounds like we should create a new route for that so let's go into let's close out the views we'll go into our router but now I want you to notice how all of our route declarations are jumbled up against all of the logic here and uh I don't know maybe that's okay but it might be cleaner if we extract these routes into their own file so that we don't have to see all this junk every single time we need to add or tweak a route so with that in mind let's create a new file and it's just going to be called routes then I will take these out I'll cut it with command X and then move it over into our new file just like that but next instead of declaring a variable here why don't we take the same approach as we did uh when we created the configuration file where we just return directly from the file okay so we'll swap this out with return and then finally if I go back to my router I can now say right at the top routes equals require routes okay and then finally this URI variable we can really put that down here if we want okay and here's what we get so if I come back to Firefox and give this a refresh yeah everything works exactly the way it did before but now we have this nice clean simple file we can visit whenever we need to add a new route okay and as it turns out we need to do that right now so let's say how about if you visit I don't know how about notes SLC create that will take us to controllers slash uh and we could call it create notes or why don't we reverse it we'll say note create okay so why did I reverse it there well it doesn't necessarily matter it's just kind of a style thing but notice if we did call it create note. PHP it is now separate from all of the other controllers related to notes and remember in real life you could potentially have dozens and dozens of files so again it's not like it really matters but it's often useful if we group them and we can group them by beginning each controller with the word note or the or the corresponding resource and again on that note uh keep in mind that you'll eventually learn how to create a single controller that can respond to multiple request types but for now we're just assuming one request one Route One controller and we'll keep it simple okay so now we'll say right here as usual we will require a view and what should we call the view well how about exact same thing uh note create. view.php and I will we duplicate this notec create. view.php and yeah let's see what we can do here get rid of that and we'll just say create a note uh to make sure that it's working okay so let's go back to our overview and now we have a place to link notes SLC create all right let's give it a shot back to Firefox give it a refresh I click on create notes and uh H yeah we forgot to declare a heading uh but nonetheless it does look like it's working okay so let's fix that little issue and we'll be Off to the Races heading equals create note all right and I think we're in business so now before I start working on the form why don't we have a quick little conversation about uh naming conventions for your routes so of course remember there there's no there's no rules you can name these whatever you want but that being said there are guidelines uh where it's useful to follow them to be honest uh if you're working with other people it can be useful if you all follow the same guidelines that way your approach is going to be pretty similar to to Joe's or Sarah's approach if you work on the same team okay so I want you to notice these three routes here sln notes would be a page to view all of the notes and we can see that right here show me a list of the notes slash notes would be a page to view a single note or in fact eventually once you learn about uh routes parameters or wild cards you might see something like this notes slash and then you'd have some kind of wild card like we learned with um prepared statements where you could do something like that and that would say okay listen for notes slash and then some kind of um uh identifier or a slug notes slash one would show me the note with an idea of one note sl4 would show me the note with an idea of four but yeah for for now we're just keeping it simple because we don't have a complex router and we've named it slash note and then finally we have one called slote SLC create which of course would display a form to create a note so again notice that I'm not calling these like um view note uh create note and yeah there's nothing preventing me from doing that so I could do it if I want but I don't love it and further I'm I'm a big fan of of following conventions for the community you work and following common conventions and I think you'll find in our space people often follow what's known as a restful approach and I don't want to get into rest it's not appropriate and it's it's too soon to talk about that but for now I just want you to notice um I want you to notice the pattern so imagine any resource you have it could be notes it could be posts it could be users it could be anything maybe you're building a photo app then your resource would be photos well you might have a URI called SL photos to view all photos you might have a u like sloto or slos slash and then the ID for viewing a specific photo you might have a URI like slos SLC create to display a page or a form to create a photo so again I want you to to notice um this system and this pattern that I'm following and later you'll learn how to respond to specific request types like a post request or a put request or a delete request okay little tangent there but um file that one away for later all right let's get back to work so into our view we're now going to display a form so I will add a form here and we're going to start with the most Bare Bones form and then at the end of the video we we'll pull in uh a fancy looking form from Tailwind okay so we might start well actually before we do that let's go to table plus into notes and yeah we can see the form we need to create will correspond to the table here so really this is a simple one right now all I need is a body so yeah if we took the simplest possible approach I would have a text area I'd have a name that corresponds to uh and it doesn't have to but but frequently it will correspond to the column in the corresponding table and then you would have some kind of button so again this is not going to look pretty but we're making it super quick um to test things out all right so go back to Firefox give it a refresh I'm sorry create note and uh yeah that's all we get a very unstyled form okay so now let's just see what would happen some new note idea I submit the form and it looks like it disappears but we can actually see that the page did refresh and now the form data is included as part of the quy string okay very interesting and in fact one little thing I should show you if I did not include a name on the text area let's try it again all right one more time create and notice this time it is not included so you probably already know this but just to make sure we're all on the same page you want to make sure that all of your form inputs uh or I'm sorry form inputs include a corresponding name all right so now why don't we make my editor happy it's squawking because I haven't included a label so we'll do that now label for and this wants the name of a corresponding input uh ID not the name but ID so often you'll see people double up here they'll give an ID and a name and usually it's for this purpose okay so we'll say label for body and then we'll say um you know it doesn't have to be called body but that's fine note description whatever you want all right come back let's see yeah we want the input below it so maybe I could wrap this within a div and give it a reformat come back refresh and yeah you get the idea again we're not going to focus too much on styling because at the end of the video we'll pull in a preconfigured uh form that looks nice and pretty okay but anyways yeah I can fill out this form and when I submit it it seems like it just refreshes the page and updates the query string and this is a get request so by default a form will submit using a get request and as it turns out things like this get request get request get request get request get me that page uh but it's not the only request type you can make there's many more and one of those other types is a post request so why don't we tweak this and say form method is post all right and I won't change anything else here let's just see what happens so I submit the form and it refreshes again but notice how this time it did not include the foreign data as part of the query string and yeah this is the key difference between a get request and a post request both of them can be used to uh transfer data or information to the server but yeah with a get request you are doing it through or via the query string and with a post request you are doing it sort of in the shadows a little bit as part of the message body and later I'll show you how to inspect that and then finally last little thing I'll note on this uh technical term incoming sorry about that with a get request they should be considered uh item potent and that just means no matter how many times you make the request whether I do this one time or 10,000 times I'm not doing anything destructive I'm still going to get the the same results but that is not true for things like submitting a form so if I submitted this form and once it's complete we would persist a new note in the database so that means um if I did this 10,000 times wouldn't I have 10,000 records in the database that is not item potent so we should not use a get request uh for this form submission okay but now yeah that begs the question well I fill it out I submit it where did it go all right let's have a look let's go back to note create and why don't we do this I'm going to die and dump the server like we did many episodes ago all right let's do it again submit it and here's what we get so yeah let's just inspect this and see if there's anything relevant H lots of information about my computer but then I do see this one here request method post hm let's try reloading the page all right now we do it request method is get and of course I visited the page and that's a get request but when I submitted the form I changed the request type to post so that's why it's get when I visit the form like that but then when I submit the form and it reloads this page it changes to post okay so I think we can inspect that let's do this when the page loads why don't we say well if the server and I'm just grabbing this right here if the request method equals post well then we know at this point we are responding to the submission of the form you submitted the form all right let's give it a try refresh fill it out submit you submitted the form so now we have a way to distinguish between a get request to this URI and a post request to this URI cool but yeah now the next thing how do I get information uh from the form and as it turns out we have a new super Global dollar sign post all right let's see what happens refresh and there we go notice I have an array of all of the attributes from the form all right cool so now if you think about it we've added a form and we figured out how we can respond to the submission of the form we've learned how we can grab all of the data or the attributes from the form so the final step would be uh perform any validation that's necessary and then persist it or save it to the database so I'm going to hold off on that for one more episode and we will finish up this video by swapping out our ugly form here with something that's a lot more attractive and we'll do that now I'm going to visit tail when ui.com and yeah they usually offer some free uh components that we can use so I will look for form and yeah so notice yeah nicely styled professionally styled forms uh that we can pull from and it looks like this one on top is free to all so I will click on that come back and why don't we insert all of this right here and yeah clearly we have a massive amount of form data here but we can just grab the pieces that we are interested in so let's come back to Firefox and take a look and yeah I think we're most of the way there uh one little issue notice how the form input is not displaying quite like their version let's see why we'll go to the top here and they have a little note so it looks like this example requires a forms plugin but luckily this should be pretty easy to add because we are referencing Tailwind through its CDN so I will visit my head section and yeah I think it says easy as saying plugins equal form come back give it a refresh and oh that was not right maybe it's called forms okay okay good I got scared there for a minute yeah so now yeah that looks much better so now I'm just going to pluck the the the sections that I need so it looks like we have a notifications a personal information and a profile section let's just break it down I'll go back to only the profile section so let's see these are the dividers so the the little sections here with a little padding and a line so I can get rid of that I'll get rid of personal information get rid of the next divider and then get rid of notifications all right how's that looking yeah uh next you can keep it if you want but I don't think we need that sidebar so we have a grid call span one can I get rid of that yeah yeah we're getting there and then finally why don't we just keep this and yeah really we could get rid of everything else okay so this should be pretty easy let's get rid of that one we want about let's get rid of the photo yeah this is kind of what's cool about Tailwind is you can grab it and then just use whatever is necessary and throw away the rest so let's see how that looks mhm I don't think we need a little descriptor so I can get rid of that good okay so let's change this to body it's a text area and once again I'm just going to bring it right back to what we had before where we have an ID and name of body because that is the name of the column so finally we have a form here it is making a PO request and then yeah this action attribute may or may not be new to you that just specifies where the request should go so by default if it's not included that means we are submitting to the current page but it doesn't have to be that way if you want to do something like this make new note well now it's going to make a post request to this URI instead of the current page and yeah we we sort of talked about a restful system eventually you might do something like this and that would say all right we're going to make a post request to slash notes to to create and persist a new note in the database but for now I'm just going to keep it um to submitting to the current page all right and I think this looks pretty good update this come back and we have our form and I'm sorry last little thing and then I'll let you go we don't need a placeholder or how about here's an idea for a note about dot dot come back refresh and we have our form we submit it and there's your Cliffhanger and we'll tackle this in the next video all right welcome back everybody let's keep going right where we left off at the conclusion of the last video so we now know how to respond to when the user submits a form so next up let's die and dump the post super Global and have a look so back to Firefox right here and you'll notice behind the scenes uh I've cleared out all of the notes so that we can start from scratch okay so we will add some gibberish here submit the form and sure enough we get an array of all of the the inputs or the values from the form okay so now the next step would be to take those values and insert them into the database right into the notes table all right well let's see how we might do that all right so let's do this let's go into notes. PHP and maybe one more time I'm going to copy and paste this and then I'll show you a cleaner way that we can allow for things like this okay so now I can say dbquery and you know what we haven't yet reviewed the Syntax for an insert query but I'll show you a little trick let's go to table plus and manually add a note something user ID is one and I'll hit save and you'll notice if I go to the history tab here I can see a list of all of the actual SQL queries that are being executed within table plus so yeah in this case it looks like we say insert into the name of the table and then the columns and then values and then the corresponding values great so this is especially useful during the learning phase so let's go back to PHP storm and I'll use that insert into notes the body and the user ID and yeah for the values exact same thing we're going to leverage prepared statements so that we avoid any risk of funny business or or a SQL injection so yeah the values will be uh wild cards or parameters here body and user ID and I will pass those through as the second argument all right so body will be post body so grab the body uh value or attribute from the form and then we will do user ID and yeah we haven't yet reviewed uh session handling or authentication so I'm going to hard code this but I promise we're going to get to it all right let's just see what happens now so back to Firefox give it a refresh keep learning uh PHP we save it and we're not really providing feedback which we probably should but if I go to table plus and give this a refresh and there we go it works we're in business so H very cool but also very risky and here's what I mean yes you wrote prepared statements which is great you've avoided that potential uh Pitfall but that doesn't mean all of your security concerns are solved so have a look here let's create a new note and I'm just going to say um work on and then I'll say within strong tags something and then why don't we add some classes here so I know this website uses Tailwinds right so why don't we say text red 500 and font bold all right interesting right what do you think is going to happen here we save it we go back to our list notes uhhuh and it's red and bold and maybe you're thinking well of course what did you expect to happen but this could be a really big problem and here's why I'll show you another example how about within an H1 ah ah and then I'm going to force the font size to be something insane like I don't know 100 pixels and then we're not done I will open up a script tag and say hi from JavaScript all right and yeah let's see what happens here save it we go to all of our notes now every single person who visits this page is going to see an alert yes so now imagine you're building like a stack Overflow site or something like that if you didn't add the necessary uh sanitizing and precautions well now thousands and thousands of people are going to see an alert or or something way worse uh when they visit the page and even beyond that notice how because we gave the user full control they've completely uh borked the presentation of our notes list so yeah clearly none of this is desirable all right how can we fix it and let's see yeah we have a couple options here one method would be to sanitize the body of the note before it enters the database and yeah that would work another option that's very common is to Simply allow it to enter the database but then always Escape it when you display it on the page and I'll show you what that looks like let's go into our list of notes and yeah right up here here's where we display the note and yeah right here instead of blindly echoing whatever the user has typed into that form why don't we first pass it to a built-in PHP function called HTML special chars or cars all right so first let's see what happens and then we'll talk a little more back to Firefox I give it a refresh all right good deal it seems like we've solved the problem we're no longer displaying an alert for every single person who loads this web page and further we've restricted the author's ability to control the presentation of this notes list which is good but yeah just keep in mind if I click on the Note right back in that same boat so this is where we come back to that idea of the user is guilty until proven innocent or really you don't even need to say until proof and innocent just assume that they're trying to do something bad even if 99% of people are good you have to assume that they're going to try something malicious so that's why we run any user provided input or values through functions like this HTML special chars and you can see here it's going to convert all applicable characters to HTML entities yes so if I close this out back to Firefox view the source I'm sorry let's go back to our list here and view the source you can see hm where are we so so uh yeah right down here mhm so notice how that HTML special charge function converted the angled brackets here and the quotes to their HTML entity equivalence and when you do that uh this thing here is no longer treated as an HTML tag it's treated as just a long string and that's exactly what we want again just to make it Crystal Clear if I brought this back to what we started with and we give it a refresh scroll to the Bottom now it is treated as HTML which is why we see that alert all right good to know so let's update this and then I'm going to do the exact same thing anywhere else we display the note so how about one right here and I will paste that all right but as always and I'm going to tell you this a million times uh we're not done yet there's still more things to consider for example what if I try to create a note and I don't provide anything does that work seems like it does all right what if I just keep clicking this 3 4 five yeah what is that five or six notes that are empty and if I come back to the list here well it's collapsed but if I hit shift command c yeah here's all of the list items that are being rendered to display what is empty notes and again we don't want to allow that so yeah it can be a little overwhelming at times I get it there's so many things you have to think about in this video alone we leverage prepared statements to avoid the risk of SQL injection and then we used the HTML special chars function to convert any potential HTML into their uh HTML entity equivalents and now it seems like we also need a layer of validation to ensure that the user when they submit the form is providing to us the values and the data and the types that we expect so we'll take a look at that last element validation in the next video I'll see you then all right welcome back everybody in the last episode we left off with a cliffhanger didn't we we currently have the situation where a user can insert empty data into our database table which of course we don't want to allow okay so the solution is to apply a layer of validation and I'll show you how to do that in this episode all right so yeah just to restate the problem notice right now if I leave the body text area blank I can still submit the form and if I now switch to table plus and give it a refresh we have an empty row that has just been persisted okay so I know what you might be thinking your first thought might be well let's go to our form and here's our text area right here let's give it a reformat and let's add the required attributes so if you're not familiar with this this states that well I can't make any simpler actually it states that the text area is required you have to give us something in order to submit the form so if I come back and give this a refresh like that notice now if I try to submit the form it will prevent me from doing so all right so yeah you might think problem solved and even better you didn't even need to write a line of code simply append the required attribute to any form inputs that are required um but it's useful but it doesn't actually solve the problem so you can think of this as a layer of browser validation or client side validation and it is useful it provides immediate feedback to the user to help them uh but there's nothing preventing the user from Simply bypassing this layer of validation and I'll show you what I mean if I go to my terminal yeah there's nothing preventing me from manually submitting this post request and I can use Curl for that so I can say curl DX and that declares the request type in our case we want a post request the URL let's switch back see if we can find it yeah it's going to be Local Host Port 8888 and then the URI is notes SLC create next I will pass DD to provide the data to go along with this post request so I can say all right well the body should be nothing we submit it and yeah if I now go back to table plus and give it a refresh yeah there we go so you see what I mean we've now bypassed that client side or browser layer of validation okay and in fact if I just do it over and over yeah we're right back in that same boat okay so don't get me wrong it is useful to add that required attribute because it provides instant feedback validation feedback to the user but we can never um exclusively depend on it okay so the next step is to add some server side validation all right let's go back to our controller and yeah right here let's see it sounds like before we run our query we should first confirm that the body meets our criteria and we'll do it inline to start all right so let's see I'm going to use the St Len function that PHP provides of course that stands for string length and we're going to look at the post body attribute and if its length is zero well then it's blank and that means our validation should fail right all right so how do we represent this why don't we start by saying create a variable called errors and that'll be an empty array and then we'll do our validation checks and if this one fails we will append to that array like this errors body equals a body is required okay so now think about it if our validation fails or in other words if the errors array is not empty should we still run this query to update the database and of course the answer is no we should effectively abort and return to the form and then notify the user about what they did wrong or or or what validation error occurred okay so let's see hm if that's the case all right so we can check if an array is empty or has no members or items by using the empty function so yeah if I did something like this we're saying all right if there are no validation errors then it's safe to proceed so I can Nest that here otherwise we don't run that query and we require the view but now when we require the view there is an errors variable okay so let's see what happens now I will actually let's do this right now I can't submit the form because we added that required attribute which is helpful but it's not helpful when I'm testing this out so just temporarily I'm going to uh disable that but yeah in real life and at the end of the video I will return it okay so one more time I try to submit the form and notice if we did everything correct correctly actually let's clear that out and then we'll try it again so yeah I will submit this form a bunch of times and if we did everything correctly when I give this a refresh we no longer have those empty records okay so our validation is in fact working but now the next issue as we discussed is that we're not providing any feedback to the user so they have no clue what the problem is okay let's do this let's go into our view and yeah right below the text area so let's do this uh let's say look at the errors array and see if we have anything for body and if we do then we should display that validation message for the user like this errors body and then we can close this out yeah and I think that would do the trick so now if we come back and I submit the form yeah it doesn't look too pretty right now but at least we're providing some level of feedback to the user which is great okay so now let's make it look a little more attractive by saying about uh make it red and then extra small and then a little margin on the top okay one more time and yeah I think that looks fine for our example okay so now think about it we have two layers of validation we have the client side or the browser validation but then we also have a second server side validation that can't be bypassed so even if we go through the terminal like we did earlier notice body is required yeah yeah there it is it doesn't work here either and if just to prove it if we go back to table plus and refresh yeah there's no empty uh record here which is really good okay but we're still not done yes we are ensuring that you give us something but what if you give us too much of something like this I often get this with the lar cast Forum where people think it's appropriate to paste 10,000 lines of code that they want your help with and uh yeah you may or may not want to allow for that so yeah I'm just copying and pasting this like a crazy person to show you that right now you could give us a massive text that we then insert into the database and again maybe you don't want to allow that all right so let's give it a shot and yeah as expected we blindly throw all of that junk into our database table which isn't ideal so it sounds like we need a way to apply a maximum number of characters that we will allow or a minimum like imagine uh you're creating a registration system and you want to say well the password that the user provides should be at least I know 7 characters and at most 255 characters right you want you want to set a minimum and a maximum for the number of characters that are provided these are all things that validation can handle all right let's get to work I will clear that out switch back to PHP storm and yeah why don't we do uh another layer of validation let's do this let's copy that rule Rule and we will run another check if the length is greater than some kind of uh arbitrary threshold you've set for your application in this case a th might be too little you know it just sort of depends on what these notes are can they be incredibly extensive or are they really intended to be short notes it just depends on what you're building but yeah for the example we'll say okay the threshold the maximum is a th characters and if you've gone over that we can say um the body cannot be more than 1,000 characters all right so we'll switch back but actually actually real quick uh notice before I do that you can imagine situations where for any form input that the user fills out there could be multiple validation violations that you need to report like well you did this wrong but you also did that wrong so if you want to allow for that we might need to structure things a little bit differently but for now let's just keep it simple okay so anyways we submit the form and sure enough a body is required now we require something but I will add so many characters that will hopefully take us over the 1,000 character maximum we submit it and the body cannot be more than a th000 characters which is great but now we're on to the next problem and I'm sorry I told you all of programming is solving problems it's all you do uh so yeah the next problem is even if you make a little mistake like this uh maybe you didn't intend to do this notice I submit the form and I've now lost everything that I typed there and maybe I would have preferred to fix the mistake rather than starting from scratch very likely uh that's the case okay so how do we how do we do this well let's come back and let's go to our view and maybe right here as the value of course we can just add gibberish here and that will be included so maybe we could just say well if we have anything uh in the post uh message body for this then we should Echo it out so maybe something like this Echo post body but yeah it's not enough to do this this might be your first thought but notice if we give this a refresh yeah we get a warning undefined array key body because remember if we're just performing a get request then the post super Global will be empty and that means there will not be a body key so we can't always assume it I'll show you a little trick here though I'll show you the long form and then the shortcut in the past we would use the iset function so look in this array and let me know if a body key is set or exists and if that's the case I can represent that with a question mark then we will Echo out that value otherwise we will Echo nothing yeah I don't know if we've reviewed this yet this is the Turner operator think of it as a uh alternative Syntax for if else statements so the question mark is if so if this condition is truy then do this else represented by the colon do this all right so yeah you'll often reach for it for simple little on liners that aren't too complex but you can see right here that my editor is squawking because there's actually an easier way to do that so this is the benefit of using uh an IDE is they will often give you little tips like this so notice I can replace this and this is the equivalent I think it was introduced as part of PHP 8 or 8.1 I'm not sure maybe yeah maybe 8 something like that but yeah this is the equivalent so yeah these two question marks here technically they are referred to as the null coalescing operator if you want to get some points at dinner parties or uh or lose some points more more realistically but yeah it just checks if this value uh exists and is not null which is basically what we were doing earlier so yeah if it exists then Echo it otherwise Echo and empty string all right come back give it another run and yeah I think we're in business here so now if I paste in something that breaks the validation like we did before notice that this time we see the validation error but we don't lose what we typed into this text area and yeah that's probably what you want okay so now I think I've taken up enough of your time for this episode but yeah if we switch back to our controller this does the trick but as you can imagine it could get messy very very quickly and then further if we repeatedly perform these checks for every single form on our site that just doesn't seem to make sense to me and that's a little too much duplication for my taste so in the next episode we're going to extract all of this into a dedicated validation class I'll see you then all right welcome back everybody let's Jump Right In so yeah in the last episode we toyed around with writing our first set of validation rules but then we realized well it probably would make sense to extract this logic into its own file or its own class and that way I only have to write the logic one time and then throughout the entire application I can reference an existing uh function or method okay so let's do that now I'm going to call this class well validator okay class validator and yeah at least initially I'm going to keep this class very simple and also very pure and I'll show you an example we'll start with something simple like validating that you've given us a string of a certain size okay so we need the value and yeah if I switch back to the controller we could pluck this logic that we wrote in the last episode and paste it in here and return the result okay so now I can Swap this out with the value you give us when you call the function okay let's give that a shot I'm going to switch back and require the controller and actually real quick if we have not discussed this I can require a file like this or I can use it almost like a function both will work just the same and you can see sometimes I will absent-mindedly use both um coming from the JavaScript world where there's also a require function but yeah generally just stick with one or the other okay so with that in mind I will use this approach Okay cool so now yeah well at least initially I would have to instantiate a new validator and then right here I could use validator string and then pass through the post body and yeah so I've just taken the logic that we had in this file and extracted it to a dedicated class okay so let's give that a shot I switch to the browser refresh I try to submit the page and sure enough our validation is still working okay but a couple ideas to think about what if the user gives us an empty string so I'm just holding down the space bar here well if I submit it it seems like that worked so we go back to table plus I give it a refresh and now once again we have a new row with a body that's not empty but is composed of empty spaces okay so let's delete that and make sure that we trim it before we perform the validation all right so back to PHP storm into our validator and now I could say well why don't we trim the value before we check it all right so let's give it another shot once again I will hold down the space bar but yeah this time if I submit the form the validation is working the way you'd expect so we can see that the uh the trim function that PHP provides literally trims off uh blank spaces before or after your string and it turns out that's what we want in this case okay great but now what about well actually let's do this let's go back to the controller and you can see we have another check where we make sure for the example that your note can't be more than a th000 characters okay so what would we do would we create a new function or would we simply expand our existing function to accept a minimum and maximum number of characters and I think that second approach is probably the one we should we should use okay so let let's accept a minimum number of characters and we'll set the minimum to one you have to give us at least one character by default and then the maximum should be uh basically infinite so unless you explicitly set or pass this argument the maximum number of characters we allow is is infinity right so in those cases we can use in F for Infinity okay great okay so now think about it uh let's start by saying well let's let's update the value variable by trimming it so that I don't have to do it more than one time and then we will say well make sure that the value or the length the number of characters of that value is greater than or equal to the minimum so in this case greater than or equal to one by default but also the length of the value is less than or equal to the maximum okay and let's see if that works so I will come back to my controll and yeah now I can merge these into one so I will get rid of this and update this to validate string I want the minimum to remain uh one but the maximum is a th000 characters which again just to show you if I bring this back that's what we had at the end of the last episode so yeah now I'm just merging them into a single function call and then I could update this string to be a little more generic um how about the body or I'm sorry a body uh of no more than 1,000 characters is required okay and then finally we should handle the case where it is not valid so I'm going to negate it if it is not valid then update this errors array okay let's have a look in the browser so we submit it and sure enough the validation fails let's now add so much text that brings us over a th characters so I'm just pasting in Lauren IPM that paragraph over and over that should be more than a thousand characters so we submit it and once again uh the validation fails all right and I think that's a pretty good refactor okay so now let's talk about this this method is what we would call a pure function and I'll tell you what that means a pure function is a function that is not contingent or dependent upon uh state or values from the outside world and by outside world I literally mean the world that exists outside of this simple function and again what that translates to is within the body of this method I'm not deferring to any internal state I'm not referencing an outside class or object it's all contained so notice I call the method I feed it some values it works with the values and then it returns a response but there is no reference to this inside it and that's what I mean by it's not dependent upon uh existing internal States it's not deferring to to a different class or a different object it's all very simple and very pure so in these cases when you have pure functions we can make them static and that then allows us to call the method directly without first creating a instance of that class like this let's switch back and with this approach I can now simply remove the instantiation and instead just say class Name colon colon and then the name of the method method so yeah these two colons are how we call or trigger a static method on a class okay so if I come back and we give this another shot it still works just the way it did before but yeah just to be Crystal Clear if we don't explicitly make this a static function we'll notice we're going to see some kind of fatal error because we are trying to interact or call this method as if it were static but we didn't declare it as static so make sure you add that static keyword okay so yeah in situations like this for very simple and very again pure functions this is a good way to go okay great so now as you can imagine your validator class could could validate so many things like make sure you gave me a proper URL or make sure that you gave me a valid email address why don't we cover that example even though I I don't have an existing user yet we haven't built a registration system just to give you an idea okay so if we want that we'd create a method called email I would make it static and yeah we'd interact with it like this validator email and then you'd give us the value that probably came from the registration form or something so in this case Joe example.com seems to be a valid email address and actually on that not notice it's not going to ping some existing service to make sure that it is a registered email address it's just ensuring that it takes the form of an email address so this would return true but yes something like this well that does doesn't take the shape of an email address so it would return false okay so the implementation uh well there's a number of ways to do this you could you could paste a very dramatic uh regular expression but instead we're going to use a PHP function called filter VAR and this gives us a way to sanitize or validate uh a string in a number of ways and yeah if you want you can always just review the PHP documentation but in this case you can see we give it a value and then our desired filter and again switch to the documentation to see some examples so yeah things like uh let's see if I can see filter validate email yeah here we go here's an example so we call filter VAR we give it the email address and then we're going to reference our desired filter and in this case the one we want is filter validate email so I will copy that switch back paste it in and then I will accept the desired value and return the result okay so now yeah again we don't have an existing email address this is just a quick example but we could toy around with it right at the top by saying and we'd say validator email and let's start with something that is not a valid email address like this so we come back give it a refresh and sure enough it returns false but if we instead provide a valid email address you'll see it's not going to return true but it will return uh the the address itself which is a truy value so in other words I could say well if not validator email then once again that is not a valid email okay but if we use a real one I'm just being super crystal clear here to make sure we're all on the same page uh then we don't trigger this DD function so yeah I'm just giving you some ideas here and trust me once it's time to build something like a registration form this is going to be super handy think about it to register you probably have to provide a username an email address maybe a password okay well this will take you the whole way there basically think about it well let's validate your username using this method next let's validate the email address using this method and then finally maybe you've decided passwords on your site need to be at least seven characters long all all right we would validate that using this method but we'd set the minimum to seven and that would take care of it it takes you the whole way there okay so now to wrap up I want to note how the behavior that we currently have is no different than what we had at the conclusion of the last episode the only thing we've done here is tinkered and refactored and rewrote the code to be just a little more flexible and also more importantly uh pleasing to the eye and trust me that makes a huge difference and I've noted this over and over programming is rewriting all right welcome back everybody so you know what let's take a short pause on our notes exercise and instead just take a few minutes to focus on simple cleanup and organization and I'll show you what I mean right now in the controllers directory I see three files dedicated to notes or our notes resource and then if I open the views directory the exact same thing is true okay so now you can imagine for a real project where you have lots of resources like notes and posts and users and and categories and tags and and fill in the blank um very quickly with this flat directory structure I don't know it just gets a little messy so with that in mind why don't we put everything related to notes within its own directory okay notes and then I'll grab these three and drag them in perfect then I'll do the exact same thing in the view directory notes grab these three and move them over okay so yeah it just cleans it up that much so next of course I need to return to my routes file and update the paths so now I would have things like this notes but you'll notice now that these uh these note uh controllers are stored within their own directory maybe we could use a different naming convention maybe just something a little more traditional and adhering to Common conventions so for example right here notice that I originally named this file note create and I did that because if it was simply create well you wouldn't have known is it the create controller for a note or a user or a project or a category you don't know so that's why we made it clear but now that it's in a note directory or I'm sorry a notes directory uh I don't have to do that anymore so I can clean this up like so okay so now I would just return to my controller and I would update this like so cool all right let's keep going is there anything else we could do here well again following common conventions the controller or action for displaying all of a resource or a paginated list of a resource is often called index so if we took that approach we would rename this like so okay so just come along for the ride I'll rename this to index all right what else okay right here this next controller is responsible for showing a single not right so again following conventions we're going to change that to show and then I will update this cool so now we have index for showing all or a list of notes we have show for for showing a single note we have create for displaying a form to create a new note I think this looks a lot better and yet more importantly even we're going to follow this very approach the same naming convention for every resource in our application and you'll find when you do that it makes the whole project that much easier to reason about uh to get around to work on a larger team because again everyone is following the same convention so for example maybe in the future you have a resource for managing users and maybe you need to 6 months from now uh go to the controller that is responsible for uh displaying a form to create the new user all right well it's not like you have to go to your RS file and visit your lookup table you just follow the convention you know it would be something like users slre and that is the benefit here for every resource we use the exact same name and Convention okay so if we do that for controllers we're going to do the exact same thing for for our views So within notes I would change this to show. viw um this one would be index. View and then this one would be create. viw okay finally I just have to update those paths so I'll do that now and I think we'll be in good shape here okay here's one to show and then this one here at the bottom view notes create all right let's do a sanity check is everything still working and of course it fails but at least we know why so yeah because we moved the view to a new subdirectory the path to the corresponding partial here is no longer correct so we need to fix that and I'll show you how if I go into the view uh for this controller yeah this is where we require that file and it's not working uh there's two ways we could fix this one option would be to use a relative path from the current file so we could do something like this uncore uncore dur and that will give me the directory of the current file so in this case views sln notes and then from that point we could concatenate and go up a level into the views folder then into the partials folder and then to the file and that should work so notice if I give it a refresh we'll still see a warning but it will be for a different file yeah now it's trying to require navp h p and that would be fine another option is to use a full path from the the system route so I could say we'll go into the views directory and then into the partials directory and I think that would work as well yeah and we get the same thing all right why don't we stick with that since it's a little quicker so I will update this and then down here at the bottom as well and that should solve the problem and it does okay so now I just need to update this in these files and by the way notice how this is a little little painful as well because we have some duplication for setting up our template trust me there are tools and libraries available that you will eventually learn about that that make your templating system that much more enjoyable anyways let's update this and then is that it we got this one what about show down here and I think that should do it so refresh let's view a note that works uh let's create a note yeah and it seems like we're up and running here okay so nice little refactor that I think you should consider especially once you graduate to a dedicated framework where this convention here is incredibly common okay cool onward to the next episode all right welcome back uh I will warn you up front we're still focused on Project organization in this video and I'm going to make a lot of small adjust ments and tweaks so I tell you this because if you typically work along in your own code editor uh for each video maybe for this lesson alone don't do that just watch it come along for the ride and then at the end of the video you'll have a link to the source code and at that point you can update your own project all right let's get started so let's begin by discussing the project routs so why don't we start by opening any file here and at the very top I'm going to V dump and write hello there okay so have you ever considered what would happen if the user tries to access one of these files from the browser all right let's give it a shot so we load the homepage and yeah we see hello there but we'd expect that we are requiring the router after all but yeah now let's access router. PHP directly router. PHP and it works and just to make this Crystal Clear let's die afterward to prove that we are accessing and triggering and executing that file directly and as it turns out this is a big security concern that we didn't anticipate okay so yeah if you think about it right now our document route so to speak is the demo folder it's the root of our folder and normally all requests are going through index.php however the way the built-in server works is well if you have another file that exists and that that can be matched then it will load that file instead so yeah let's just try a different one like config and we'll say uh Echo hello there okay now let's try to load that from the browser config.php and we get hello there so again a big big security concern and we can't allow this okay so let's do this first let me undo our examples here and I'm going to change the document route and this document route is typically your public folder uh this is where your entry point will be so index.php will go there and it's also where you'd store uh for example stylesheets or images or JavaScript files so let's do that now create a directory called public and I will move index.php within there but just creating the folder isn't enough when we initialize or boot up our server we need to tell it what the document route should be so real quick if I run PHP DH let's look for DT yeah so when we boot up the server I can pass the DT option to specify what my document route for where the built-in server should be so let's do it again create a server at localhost 8888 DT and the document route will now be not the the root of the project but instead the public folder okay so now yeah let's refresh this page and notice we get a not found because it doesn't know anything about this config file all it knows about is this public folder because this is now the document route okay so let's switch back to the browser and tackle the next problem if we load the root URL now it's trying to require functions but it can't find it and again that's because we moved it into a new directory okay so rather than constantly updating our requir paths I think this is a good opportunity to choose uh a more seamless implementation and I'll show you how now the first thing I might do is declare a constant for the project and I we'll call this base path which will point to a path an absolute path to the root of your project and again people often call this base path so given that I'm in index.php well the root of this project would be the current directory as we learned about in the last episode and then let's go up a level like that so this should take me to the demo folder and we can confirm that by saying VAR dump base path okay come back give it a refresh and yeah it's still failing but notice now this is our path to the demo folder okay so yeah the next step we're not going to keep this but the next step would be to update all of these requires so you might do something like this require base path and then functions so now if I come back you'll see that it still fails but the issue will be related to a different file that it's trying to require yeah now it's trying to load database so again you could do this base path but again I don't know I just don't love it come back give it a refresh and yeah that worked but now we've moved on to uh the next issue further down the rabbit hole Yeah so this is what I mean when I say maybe we should consider a different approach for requiring files so here's what I'll do I'm going to go into functions.php and at the bottom I will add two helper functions for declaring a path that is relative to the root of the project so we're going to call this base path and we'll accept a path and then we I'll do let me give it a quick reformat here then what we'll do is return uh base path our constant and then we will concatenate the path that is provided when we call the function so again it's not too complex but it'll just make it a little easier to interact with and now whenever we need um to declare a path relative to the base path I don't have to remember uh what the name of the constant is okay so let's come back and now for these three what I could do is Select them and use our new base path helper function and yeah of course I can't use our new helper function for this require because it's for functions.php and that helper function doesn't exist yet okay so now if I come back and refresh yeah we still get the same issue but we've created a nice little wrapper that we can use throughout the entire codebase okay so let's do that now let's solve this Warning by going into controllers /index and here you can see we're trying to load a view but this time I'm going to swap it out with base path and then our view okay so switch back give it a refresh and there we go we're up and running okay but I think we can take this even further as you can imagine loading a view is something you will do constantly in a project so with that in mind maybe it would make sense to add a helper function like View and then I just provide the name of the view that I want to load okay that would be pretty cool why don't we allow for it functions.php add a new one here view path and then this would load think about it we can reuse base path so call base path and then we will start at the views directory and then we will concatenate the path to the users's uh provided view so yeah in this case we have index. view.php so this would load uh our base path slvs index. view.php and I think that's what we want all right so with any luck come back and refresh everything still works but now this is just a more friendly uh API so to speak it's easier for me to use and easier for me to grasp that we are requiring a view but even better and you might like this what if we move the require statement into the view function as well that might be cool okay so we give that a try but I bet we run into a little snag here come back give it a refresh and yeah hm we have a warning undefined variable heading okay so if you want pause the video and see if you can figure out what happened here okay here's the issue notice that we are loading a view and that view is looking for a heading variable however the heading variable was declared in the controller and now we are requiring the view from an entirely different scope and that's why it can't find it so yeah it sounds like if we want to take this approach and I like it a lot we probably need a way to pass all of our view data along with this function call so maybe we could pass an array as the second argument and yeah we could do something like this heading is heading or in this case I could just inline it so I could swap this out with home like so okay but now I need to go into the view function and accept the attributes which will default to an empty array okay but of course it's still not going to work because we aren't yet doing anything with that attributes array okay well as it turns out PHP has a function called extract so first come along for the ride I will call extract switch back and that does solve the problem so let's see what extract does I'm going to click through here with command click and yeah we can see it Imports variables into the current symbol table from an array okay that makes it sound super complicated just think of it like this it accepts an array and it turns that array into uh a set of variables where the name of the variable is the key and the value of the variable is the value associated with the key so for example if I also did fu is bar well then once I extract it I would then have a uh I'm sorry I would then have a Fu variable in in fact let's just try it out uh die and dump Fu and this should be bar and you see how that works super super handy stuff here okay so I think that is the way to go all right now let's update our other controllers so I will go to about I'll do the same thing here but load about. viw and then update this all right then we will go into contact and you know what I'm going to speed all of this up so I'm going to hit fast forward right now okay and that's enough yeah it's the exact same process there but now if we go into notes this will be slightly different so we'll start here and I'll paste this in we're going to load notes index. view.php The Heading is my notes so I can get rid of this and then really I don't need to access the DB variable in the config variable from my view and as it turns out before this refactor you could have done that which which might have led to potential issues but now we're avoiding that uh entirely so we'll just say notes is notes and now these two variables heading and notes are the only ones that will be available when we load our view okay so now I will copy this and update these as well this will be notes SLC create what is our heading it's create to note and what do we need here okay well H maybe an errors variable and I think that's it all right and then we'll go into show and did the exact same thing so paste this one in and we have notes slow this is notes and then I'm going to pass through a note variable that corresponds to this okay so I can get rid of that and I think that's I think that's right so yeah a lot of changes here let's see if I made any mistakes come back and refresh home about contact notes o now we have a new issue so it looks like in notes index yeah once again we were trying to require config but now we've changed our document rout so this is another case where I can require uh base path and then config.php come back refresh and uh H now when I go into my view yeah this is what I meant when I said just come along for the ride because when you make these sweeping uh project changes you have to update lots of file paths yeah so now let's see we're trying to load head. PHP and we have to update all of these to now reference uh our base path so I will use multiple cursors and change this to require base path and that'll be a fine and quick way to deal with this so come back and give it a refresh and that solves the problem okay so once again I will hit fast forward and update all of the other views where we require the exact same partials okay all right and that's done come back refresh once again home about notes contact let's view a note and same thing okay so come back here fix our require and yeah in a bit I will show you how to use containers so that you don't always have to manually build up your database class yeah we got to focus on one thing at a time so we don't get too overwhelmed okay and then here looks like we have an old require yeah I forgot to get rid of that okay good and then to create a note require validator okay good this brings us to the next thing I want to review all right let's open up our create controller and yeah here I'm trying to require my validator and again I could do this base path come back give it a refresh okay and then looks like undefined variable errors yeah that's because we only declare the errors variable if the uh form was submitted why don't we do that no matter what at the top so no matter what there will be an errors variable available to the view come back give it a refresh and that solves it finally let's create a new note mhm come on back yeah everything is up and running so lots of little changes like I said but I think it's for the better but we're still not done I want you to notice for any of these controllers how about this one here where we display all notes it's just assumed that we have access to a database class and we know that's the case because we declare as much with an index.php uh but I just I don't like the idea uh where every time I need access to a new class I have to require it within index.php not a good approach instead it would be cool if there was a way to lazily and automatically load and require these classes when I instantiate them or when I need them okay so let's try this out why don't we get rid of the database and response requires because now we're going to change it up so now when we load index.php we declare a constant we pull in our helper functions and then we require the router that parses the requests and figures out what controller needs to be loaded okay so that means if I come back to Firefox and I give it a refresh yeah and now as expected our controller no longer knows what database is okay so let's switch back and let's see right here I'm going to call this scary PHP function called SPL autoload register but don't worry it's not too bad this is going to accept a class and just to get us rolling I will die and dump the class so you can see when this function is automatically triggered by PHP all right switch back to Firefox give it a refresh and aha we have called that function or PHP called that function automatically and here's why if I go into the controller temporarily just to show you I I will comment all of that out and yeah this line right here is what's triggering that call so if I come back and refresh yeah you still see it there okay so the issue is PHP doesn't know what that database class is so it's trying to track it down and we have declared our implementation so to speak for how we should autoload files that aren't immediately available okay so now we just have to figure out what is the logic what should we do well we have database so why don't we just say initially require class. PHP and maybe just to be Crystal Clear we will start at the base path so we can use our helper function Bas path okay but actually you know what before I do that let's pass this to VAR dump just so you can see exactly what we are trying to require all right back to Firefox give it a refresh and yeah right up here this is what we are trying to load all right let's see if it works bring it back come back give it a refresh and there we go that fixed it okay so now these other warnings are just because we commented these out so let's bring it back like so come back give it a refresh and there we go perfect so that's kind of a handy function right it lets us declare manually how we want to go about importing classes that have not already been explicitly or manually required okay so we're about ready to finish up for this lesson but the last little thing and then by the way in the next video we will dig into name spaces which should be fun so I want you to notice how I have a bunch of classes here like database and response and validator that aren't uniquely uh related to the application we're building or in other words if I was building a to-do app I would have classes like to-do item or maybe task list maybe project maybe account those are all unique to my application but validation or a response or interacting with a database that's very generic that's very INF structure related so why don't we separate those a bit and and we can call this directory anything we want uh but I'm just going to call it for now like core just kind of deep down core stuff and then I will grab those and how about hm validator uh maybe the router maybe response maybe database I could even move functions there if I want actually maybe I will as well I'll grab those and move them into our new core directory okay but now of course if I come back and refresh the paths have changed so now it can't find the file okay that's an easy fix though let's go into our autoloader and yeah we will need to tweak our require statement and actually on this note a quick warning in the next episode when we get into Nam spacing we'll have to rewrite this again but that's okay one step at a time so yeah look in the core directory and then find to the class or we can inline all of this so I'm using PHP storm so can option uh return and I can choose convert concatenation to string interpolation and I think that looks a little better okay come back to Firefox give it a refresh and there we go okay so I'm going to leave it at that I think we made some great strides here so in the next video as mentioned we will dig into name spaces all right well welcome back everybody we can finally dig into name spacing in this video and don't worry I'm going to make it super super easy to understand all right so I want you to think back to the days before music streaming so before Spotify or before YouTube or YouTube music way back to when all of your music your full collection was stored locally as MP3s somewhere on your desktop right you have some folder called music you click on it and again there's your full collection of music okay so I want you to see that in your head and then I want you to tell me this answer this question did you store every single music track within that top level directory and of course the answer is no you categorized it right maybe according to style maybe you have a rock folder a pop folder a classical folder or maybe you categorized it according to the band or the artist's name right so now I want you to think well why did we do that uh and the answer is well for a few reasons one it is nice to group related songs so if you like you know zzy top or something like that then you would have all songs written by them in the same folder that is useful but another reason you did it is to avoid uh the Collision of song titles right multiple songs could have the exact same title and if you stored them all within the same directory well of course there's going to be a collision and you don't want to you don't want a song like uh I miss you and then another track that says I miss U-2 right you don't want to do that so again if you store them or if you categorize them according to the name of the band or the artist well that solves that problem and the exact same thing as it turns out is true for namespacing okay so let's have a look but first real quick I noticed at the end of the last video when I moved a bunch of files to the core directory these two were excluded so let's do that right now I will grab those and move them over okay next I'll need to update my paths our functions file is now stored within the core directory and the same is true for the router next though I think things will still break so if I come back and give this a refresh yeah now because the router is within a different directory it can no longer track down the routes file so let's fix that very quickly we'll go in here and yeah right down here where we require the routes let's swap that out with require base path routes.php okay come back give it a refresh and now we just have one more fix to make so once again within the router file it can no longer properly locate our controllers so if we come back right here is where we require the controller but once again let's start at the base path so I will do it here and then also when we load a view okay let's come back give that a shot and hopefully that solves the problem and yet it sure looks like it does all right now we can get started so yeah in the last episode we already got started with this idea of creating directories to group related Behavior just like with your music collection and in this case we're sort of grouping our core infrastructure code or or really this is sort of like our miniature framework code and yeah we called it core so now I want to create name spaces for each of these classes that lines up with that directory tree so if I open up for example database right here at the top I will give it a name space of core and immediately you'll notice when I do that I get all of these squigglies here next to other classes and further if I come back to Firefox and give it a refresh everything is going to break because now well it doesn't really make sense right we're trying to load a class called database but we moved it now database is within an entirely different name space so of course it can't find it okay so let's have a look at the error here CL database not found in notes /index so let's go into our controller notes slash excuse me notes SL index and yeah once again we are trying to instantiate our database class but again it's no longer located there we moved it into a different name space okay so we can fix this by using the full Nam spaced path and in this case it would be core and notice rather than a forward slash for the divider we actually use a backs slash as you see there and now this quickly goes away okay so this would be one way to do it another option is to add the use keyword at the top of your file so I could say use core database and now within the rest of the file I can just reference it like I did before so yeah in a way this is sort of like an alias this is the full Nam spaced path that I want to use within this file and then after that anywhere else I referenced it can simply use the class name alone that's the way that works okay so if I come back and I give this a refresh yeah we've solved that particular error but now we've moved on to another one so you'll see right here well we're trying to autoload the database path but remember in the last episode where I said well we're going to have to rewrite this in the next video uh this right here and yeah we're now to that point now that we're using a namespaced class well the logic is going to be entirely different so let's have a look here let's die and dump the class and if I come back and give it a refresh yeah and as you can see we're now dealing with something entirely different okay so let's do this for our reference I will comment and paste what class is equal to right now and let's figure out how we can translate this namespaced path into a require statement okay well if you think about it I don't want to use this back slash it needs to be a forward slash usually or or whatever the directory separator is for your OS so what if we did something like this PHP has a function called string replace and you can see here we search for some kind of uh sequence of characters and then we specify what we want to replace those characters with and then we provide the thing that we are looking at so in this case the subject the thing we are looking at is class we are going to look for a excuse me we're going to look for a backslash but in this case we actually have to escape the backslash to make it crystal clear that I literally mean a back slash character rather than something um that I'm escaping in this case a quotes Okay so look for a backs slash and replace it with well on my machine it would be a forward slash but again why don't we make it Dynamic by using directory separator so that we use whatever is appropriate for your OS for your OS okay so let's have results and take a look at that and in the browser and if I come back and I give it a refresh yeah we just swapped out that backs slash with a forward slash okay that helps so now when I make my require right down here require base path core well I no longer have to hardcode that that gives us this we could swap out result or I don't see any reason to create a new variable so let's just overwrite class at that point and I can substitute it here okay let's come back give it refresh and yeah it may not look like it here but I think we actually solved the problem so notice how the warning has changed oh oh and by the way seeing warning and error pages is just part of the job so get used to it but yeah in this case it looks like within our database file it's trying to load the PD class but notice it's trying to find that PHP class within the core directory and of course well that's not right that class does not have a name space of core okay so if I come back let's see what we're dealing with here and yeah right down here you can see we're trying to use this PDO class but it's set to undefined and it's set to undefined specifically because we applied a namespace at the top of the file and the way it works is unless you specify otherwise every single class uh referenced within this file will assume the namespace at the top so yeah in this case PDO well it's basically assuming core PDO and that does not exist this is a class that is provided by PHP it doesn't have any any nested name spacing okay so we solve that in one of two ways if we ever want to reference something uh from the global root that's how I think of it you begin it with a backslash so the difference between this and this uh is significant this says start at the root and look for a PDO class this says start within whatever name space you're currently in and then look for a PDO class so yeah we could update all of these but yeah what you'll start to find is it gets kind of annoying and it's easy to forget so instead why don't we just use the PDO class at the top of the file uh like so come at the top and I will say I want to use PDL and you'll see when you define these use statements at the top of the file it's almost like a little bit of documentation it's it's a little heads up of okay here's all of the stuff that this file uh needs access to so it can be really helpful uh from that perspective okay so now if I come back to Firefox I think we will solve that issue and we do okay so now if I come back to PHP storm let's just update some of these classes namespace core uh right down here to our validator same thing namespace core and yeah you would do this for all of your files uh specifically all of your classes from this point on okay and then at this point we would just do a quick sweep through all of our files where we are still referencing these classes and their former locations so in this case I can see database and validator of course I can do use core database and that'll solve it but don't forget if you're working along in PHP storm let the editor do the work for you so for example for validator I can press option return import class and again it does it for me okay so I just go through all of these f and make sure there's no squigglies that's basically all I'm doing here about contact yeah these are all static I think we're good to go here okay so hopefully that all made good sense to you you've now learned what name spaces are you've learned why you might create them you learned how to use them or import them if that fits your head um you're going to reference these all the time especially once you upgrade to a dedicated framework so make sure you understand everything you see here and we'll keep going in the next lesson all right welcome back everybody buckle up because over the next few episodes I'm going to show you some things that are probably a little more advanced than where we currently are in our learning but I'm still going to do it because I think you're ready so we're going to talk more about request types we will enhance our router to support these request types you will learn about service containers and we'll even build our own service container so all of this kind of fancy confusing terminology in three episodes is going to make perfect sense to you so why don't we get going all right so I will bring up PHP storm and yeah before we make any sweeping code changes here we first need to know the why because remember the why drives the refactor or at least it should drive the refactor here's another way of thinking of it uh there needs to be some kind of paino that leads you down a particular path and a particular refactor and I'm going to show you that in this video so for example if I go into Firefox and I click on our notes section we still don't have a way to delete a note so yeah maybe right here if I click on it here's the body of the note and yeah maybe right below it there should be a button to delete the note okay so let's go down to our views where we show a note and yeah right here below the body we want some kind of action for deleting the current notes okay so if I come back and refresh it's totally unstyled but this is basically what I mean okay so now pause if you need to I want you to answer the question is it appropriate to use an anchor tag for this sort of request okay pause if you need to and really think about it and the answer is no okay so remember a number of episodes when we talked about item potency a very confusing term it's even hard to say and you remember that what that means is no matter how many times I make a particular request it's not going to change anything right so if I if I make a request to view the homepage it's always going to show me the homepage compare that to a request to delete a note or to add a product or to update a product those things are not item potent and as such we should probably not use a standard get request which is what a a anchor tag will do for us okay so instead we will store this within a form and then I will add a submit button that says delete and yeah if you want we will make it small and red okay also we should have just a little margin above this form come back give it a refresh and yeah that's good enough for now okay so now when I click on this well of course by default it's going to submit a get request to the current page so we could change this to a post request and if I come back we try it again and yeah the page just effectively reloads even though we did submit a post request and that's because well think about it let's have a look at our routes section and yeah right here is our current URI so we now submit a post request that loads the show controller and this just displays the notes so so there's no change in other words um when we submit a get request versus a post request to this specific controller but if you want we could do it right here I could die and dump the current server uh super Global and if I come back and I now submit it sure enough we can see that we are submitting a post request to this page okay so yeah I guess once again we could do this weird check where we say all right well if the request uh method and again I'm just grabbing that right here that's the name of the item if that equals post then well we're just going to assume that's a request to delete um the the note but again maybe it could be a request to update the note so this is where you really have to think about the structure of your uis so another option uh if I were to come back to my round section you might think well let's use a completely different URI so for example we might say uh excuse me note SL delete should take us to a different controller and yeah I guess you could do it if you want and in fact it's actually a really common approach approach but I don't really love it and worse if I teach you this approach in a handful of episodes I'm just going to unte you so instead I really do want to stick with a common restful uh convention here and that convention says if you want to delete a particular note then you should submit a delete request to that specific note end point but now we have more problems lots of problems here as it turns out current browsers and then and forms do not support request types that are not get or post so if I want to submit a delete request or a put or a patch request usually for updating a resource well forms don't really understand that so now if that's the case and we still want to use these request types our application has to be updated to support it and we need to provide some kind of hint to our application to say okay well the form doesn't sub I'm sorry the form doesn't support submitting a delete request but that's really what I want all right so we we got to figure out how to communicate that uh as part of our application so here's what we'll do for now if we come back into notes show I'm just going to stick with a simple post request and then in the next in the coming episodes I'm going to show you how we can rewrite things to to make it a little more I don't know a little more seamless okay so let's come back into notes slow and yeah it sounds like this is what we have to do at the moment we check well if you submitted the page then we want to take this pathway otherwise we're going to take the pathway uh that you see right here give it a reformat notice how already it just feels gross the more IFL statements you add the the more complexity that you add as well and then if if if within one if statement you add another if statement very quickly uh things can go off the rails and and you'll you will encounter this over and over in your own projects okay but yeah we'll just say form was submitted delete the current uh note okay so how could we do that well we just need to write a query so I could say DB query and let's write a delete SQL query delete from notes where the ID equals an ID that should be passed through the form or when we submit the form but at the moment you can see we're not actually sub Ting anything uh as part of the post request okay so why don't we do this let's add an input that's actually hidden because I don't want the user to see it or in other words if I keep it like this uh and then we set the value equal to the ID of the current note so I could do something like this note uh ID okay so if we come back to Firefox and give this a Reload yeah sure enough we now have the ID of the note which is 17 and and that will be submitted uh when we when we press this button here but I don't there's no reason to show this input to the end user so instead I'm going to create an input with a type of hidden that way it exists and it will be included along with the post request but the user doesn't have to see it okay let's prove it let's go back into our controller here and say well before we do anything let's die and dump the post uh super Global and then we'll give this a shot so refresh and I will delete it and that didn't work what did I do wrong here see I talk a big game and then things don't even work um oh yeah of course we have to add a name for this input so we'll say ID okay and I I showed you this a number of episodes ago if you don't include the name it will not be included as part of the post request all right one more time sorry about that but sure enough we are sending it through okay great so now yeah right come back here here uncommon to this and we could say delete from notes where the ID equals the ID of the note that was included along with the post request but now remember we need proper authorization otherwise anyone could make this request even if I don't have an account if I knew that you had this this security concern I could manually make this request and start deleting the notes of all of the users in your system and I could even create a loop where I just go through every single ID and I try to delete the note um and I'm sure you could do that across lots of small applications where they don't quite know about authorization so what we'll do is grab all of this here I'll do a little duplication but that's okay because we're going to refactor this in the next episode bring this up and yeah if you want to delete the note we first need to to check the note and look at it and check the user ID who created the note and see well is that the same ID as the person who is currently signed in so yeah now we check all right track down the note that matches this ID and then we're going to look at the note that was returned from the database and we'll check well is that user ID the same as the current user ID and remember right now we're hardcoding that ID because we haven't yet reviewed uh authentication but in the next section I think we will take a look at that and everything's just going to work seamlessly Okay cool so assuming that we get Beyond this point then we could move on and delete the uh the corresponding note and I think this should do the trick the final step is well where should we go at that point well you've deleted the note maybe we should redirect you to the page that shows all of the notes and then PHP this is a little wonky but we could add Little Helpers if we want to in PHP we're going to say header and we're going to set the location to uh Slash notes and then we're all done so we can exit or die if you prefer all right so let's give it a shot I will come back back give it a refresh I will delete the note and sure enough it's deleted and it redirected us back to this page okay but now let's come back and change the current user ID to something like 25 or whatever okay well now if the user with an ID of 25 tries to manually submit a request to delete this note think about what happens we first track down the note from the database and that way we can look at the person who created the note the user ID and if we check well that user ID is one and we check all right well is one equal to the ID of the current user making the request does one equal 25 no so of course we abort entirely we don't continue the request all right let's give it a shots come back to Firefox delete it and yeah you are not authorized uh to view this page and if I come back to table plus we haven't deleted anything uh so that seems to be working the way we'd want okay but yeah now I just want you to take a look at the fact that we've created lots of branches here now whenever I visit this page it's not just the controller for showing a notes it's the controller for uh destroying a note or deleting a note here's a pathway for deleting it here's another pathway for for showing it and again for small projects it just doesn't matter very much because it's still relatively easy to understand but you just don't want to build applications this way so in the next episode we're going to figure out how to submit a form using something like a delete request type or a patch or a put and to do that we will need to update our router to support that so I hope you're excited we will work on that in the next episode all right welcome back everybody in this lesson we will extend or enhance our riter class to support different request types so for example if you have a form where you want to submit uh say a delete request to a particular controller how exactly do we do that well I'll show you in this video let's get going so we will get started in routes.php and yeah I want you to notice how for each URI and corresponding controller path at no point do we distinguish which request type we want to respond to it handles all of them which is why in our controllers we end up with some kind of gross code for example when we show a note yeah we have this check here well was the form submitted in this case we are deleting a notes otherwise we are showing the notes and again very very quickly this becomes very very messy so our job is to clean this up but how exactly do we do it well one option would be something like this where you instead return another array but each item is its own array and you could say well the UR on I if I reproduce what we have up here the URI is uh the homepage the controller path and real quick let's comment to this out to remove the squigglies anyways the controller path would be controller index.php and the request method that we want to specifically and uniquely handle or exclusively handle I'm sorry uh would be a get request and yeah we could do that and then I could repeat this and I guess it's fine but I don't know it it just it's not overly um friendly to interact with instead though what if we had something like a router object well if that were the case we could just call specific methods that match our desired request type like this listen for a get request to uh the homepage and then here is the corresponding controller path you know this just feels a little better to me and then later if we have uh which one was the delete request um well it would be something like this handle a delete request to slash uh note in this case then we could have a dedicated controller for this action and request type alone maybe controllers notes and Destroy is a common uh term there so our router object would have methods like get delete post put patch uh all of the different request types that a form could potentially submit all right I think this feels pretty good the next step is to make it work and that's the harder part okay but it won't be too bad I'm going to go into my core router class and yeah up until this point we've had simple functions but I'm going to upgrade this to a dedicated class I will rename it to Capital router and then for the moment let's just comment everything out and we'll start at the beginning class router and let's see if I switch it back to routes.php like I said we'll have methods to match each form request type so if I go back right off the bat I know I'm going to have a get method I will have a post method I will have a uh Delete method I will have a patch method I will have a put for now there are differences between patch and put but for now just imagine uh that it represents updating a resource there are some differences but for now you don't really need to think about it uh you can consider them synonymous and people are getting mad as I say that right now but at this stage just use one of them or consider them uh synonyms for now and then we'll talk about the differences later okay all right so this is looking good uh the next step when I call the get action or method it looks like we are passing a URI and a controller path all right so let's accept that and actually it looks like this didn't rename properly Capital router there we go so we accept a URI and then a controller path okay so what should this method do well think about it in our routes.php file we're calling methods all over the place so maybe each time we call a request type method like get or delete or post maybe it should be cached so to speak like maybe we should store it within a array that the router has access to so right up here we'll add a new public property called routes and we will initialize it to an array but this time I will introduce a small bit of visibility so up until this point we've made everything public as we've talked about and that just means uh the method or the property is publicly accessible outside of the class so if you have access to the object instance you can call this method you can call that one you can call this one you can access this property but as you'll find in the future there will be situations where maybe you don't want to expose or reveal uh certain information or data types so you can change that by switching public to uh either private or protected I often use protected so what this means is uh this property now is protected it is not available to the outside world within this class and within this object instance we can interact with it but outside of it you don't need to interact with it and that's usually uh the thinking I will reach for do you need to access this well no there's no reason why you would need to access this routes array outside of the router class so I will make it protected and yeah let's put a pin in it for now and then in the next series we'll talk quite a bit more about object uh oriented programming and encapsulation and visibility they're all kind of connected so now we can just push to the array we're figuring this out on the Fly this routes let's push a new item and yeah maybe we could reproduce what we had uh at the beginning of the video where we say well the URI is this URI the controller is the controller and then the meth should match uh well the method name you called so we can force and hardcode that to get okay so now the first time think about it the first time I call this method well in our router class we will push a new item onto this routes array all right let's do some more yeah I can do a little copy paste here and think about it I could probably remove some duplication in a little bit so the only thing that really changes here if you think about it is the method itself so let's just keep working along this would be method uh is delete and then once again accept the URI and the controller and then let's just do this I'm going to try to do this a little bit quicker all right this one is patch and then finally one more and this one would be put all right a little clean up reformat and there we go okay so why don't we try this out and actually this is a good demonstration of visibility if I want to quickly spit out all of the routes well have a look here I could die and dump router rounds so notice I'm trying to die and dump this property let's see what happens in the browser so we load this in Firefox and what warning require functions.php failed to open stream why what happened oh I see what's going on here PHP storm how dare you looks like I accidentally uh renamed the directory that's why the router okay okay I I see what's going on here you saw that you've been waiting for me to run into this okay fingers crossed there we go but now we get the white screen of death what's the problem here uh this isn't a JavaScript issue H well let's uh oh yeah of course this would be the case because we created a new router I'm such an idiot okay so let's think about the the flow one more time and I'll get us back on track so yeah right down here we're still trying to require the old router. PHP file that we've since upgraded to a dedicated class so instead let's just initialize it a new core router like so now you'll see it's squawking right now because we've upgraded it to a class but we haven't yet applied the name space so we'll do that now so yeah if I switch back we're seeing that white screen of death because we initialized our router but then we never actually routed anything so index.php completed and we didn't load a view we didn't do anything so we see a white screen okay we totally understand what's happening here let's get back to work so if I come back to router. PHP you'll remember uh before at the bottom of the page we have these three lines where we require our routes and then we parse the current URI and then we call this route to controller so let's upgrade it now we're still requiring our routes but you'll remember that routes.php expects access to some kind of router object and at the moment it's not available okay so let's come back and do this I'm going to grab all of this and I'm going to move it to index.php and we'll add it here so here's our router and then I'll paste these lines in next I will require routes.php and because I've already initialized the router object that will be available within this file that's how it works and now you can see this squiggly here because uh that property is protected but we we'll get to that in just a minute okay so we require our routes.php file this will populate uh the array of routes that we have here for the application then we figure out what the current URI is we parse that URL and then we're still calling this old route to controller function why don't we swap that out with something like router and what method do I want to call how about uh route we will use it as a verb in this case I want you to Route the current URI to wherever it needs to go okay let's give that a shot so I will go into router and we're going to add a new method here called route that accepts the current Ur okay so now if I scroll down here's the old implementation that we had let's have a look so we had access to a specific URI and then a list of routes and then we checked well if the list of routes has a matching uh key for that URI then that's the one we want to load otherwise abort okay so we're mostly going to reproduce that we will Loop over all of our routes so for each routes as route and then we might say well look in that route and remember each route is this array here so we might say well if the route URI matches the URI that we passed in here which is the current URI for the request well then that's the one so we could return require base path route uh controller right we're going to require the corresponding controller okay and that will handle 50% of the job we'll come back to it in a minute otherwise we want to abort because if we hit this line we haven't found a matching URI so if we scroll down you'll remember we had this old abort function let's grab it and bring it up like this uncomment it we could make this protected if you want reformat and yeah that's mostly the same isn't it so I could call abort all right we're making progress but now if I scroll up we're still not inspecting the current request type and that's something we need to do hm how could we do that so it sounds like for this to work properly maybe we need to accept a request method and this would be get or post or delete or or put or patch okay so let's come back to index.php and yeah now it's squawking because I need to give it some kind of request type so that's the next step how can we figure out what the current request type is from the form you'll remember if we inspect the server super Global and then the request method uh that will tell us if we have a get or a post request so yeah that would be an option and that does handle um the case where we have post requests but now do you remember a couple episodes ago when I said forms don't natively support uh submitting delete requests or put requests all they can really do is get or post so that means we need some way to suggest to our application that well I had to submit a post request because that's all form support but what I really want to do is submit a delete request okay so we can signal that through our view when we build up the form so for example we have uh within notes slow yeah in the last episode you'll remember we added this form uh that has a button that says delete and when you press it it should delete the note so now yeah you can see the method is set to post because again it's my only choice here but yeah I want to add some suggestion to the back ends that I really want a delete request in this case and I will do that by creating a hidden input and I'm going to give it a name with something unique that that ideally will not interfere with any of my other attributes so very common uh would be underscore method but again you can do anything you want if you want to do you know underscore underscore request method just something unique and the the underscores at the beginning are what make it unique because it's not very common again something unique that uh will will ensure that it doesn't interfere with your other form attributes but again underscore method is pretty common okay and I'm going to set a value of delete okay so now I submit the form and there will be this hidden input called underscore method that is set to delete so now think about it our router only has to check all right well do we have something in the post request called underscore method and if we do let's favor that request type over whatever the default request type was that's how we're going to handle it okay so let's come back down where are we index.php so let's see here from method we could do this in a couple steps um the old syntax would be to do something like this check check if underscore method exists within the uh post super Global and if it does I'm using the tary operator here then that's the one we want to use because the user signaled that to us otherwise I will stick with the default request method but yeah notice how uh I have a squiggly line here and that's because PHP storm is correctly indicating that there's a simpler way we can do this I can swap it out with two question marks this is equivalent to what we had before it's just shorthand so we're saying all right I want to use this if it's set and if it's not null otherwise I want to use this so yeah a small bit of new syntax for you there it's pretty clean but yeah if if if you're a little overloaded with new syntax then you can stick with this uh and that would be fine but yeah it's so much cleaner just learn it okay so now I know what the current URI is let's clean this up I know what the desired request method is so I will route the request okay so let's come back into to our router we now have a URI and a method so the next step is to say well let's check if the URI matches the current URI and the routes method matches the current method and then let's wrap this in a call to string to Upper and that will capitalize all of the characters otherwise uh if we have Capital get but the forms method was set to underscore get well those are aren't perfect matches right even though they are matches so we will we will basically normalize it so we are comparing only capital letters okay so now think about it when we route the request we Loop over all of the routs that were created right here so in real life you know you'd have you'd have a bunch of these here and we can get rid of that now then within our router we check for each item there well does the URI match the current URI and then also does the request method match the current request method if so let's require the corresponding controller and we're good to go we can return otherwise we couldn't find a match so we should abort which we do so here okay so now I can get rid of all of this junk and this ends up being uh a lot cleaner and we can even take it a little further but for now I just want to make sure things work so let's come back to Firefox here's our white screen of death let's give it a refresh and there we go it looks like our updated router is working okay so now I'm going to come back to routes.php and I'm not going to make you watch this but I'm going to reproduce all of these items here using our new syntax okay I'll get started all right and through the magic of screencasting I'm back in record timing and I have converted these six items here to the new syntax so I can get rid of that so here's our static pages and then here's our routes related to notes so if I come back to Firefox give it a refresh there's about there's contact there's notes let's create a note that's good let's come back let's show a note oh we have one issue called to undefined function abort yeah that's probably because we have authorization and we deleted that abort function okay so let's return it let's go into functions.php and yeah right there we no longer have an abort function it should live here anyways abort we want a status which will default to 404 and in fact let's just go to router. PHP and grab all this so we have a little duplication here but that's fine like so okay come back let's give it a refresh and there we go and notice in this case we're seeing you are not authorized to view this page because what was it in the last episode we were playing around with changing the current user ID so if I come back and give it a refresh now that works okay so we're going to come back to this shortly but I want to wrap up by doing a quick bit of cleanup on the router itself so again notice how every one of these methods is basically doing the exact same thing other than setting the uh request method so with that in mind why don't we add another helper method like add and this will accept the method the your and the controller and then this method alone will be responsible for appending to the routes array like that and we'll swap it out okay so now think about it this method can simply call this add and then we send through get URI and controller so it just ends up being a little bit cleaner and then I will update this one and this will be post and then this one will be delete this will be patch I know this is really stimulating but you got to do it and this will be put yeah it just simplifies it a little bit doesn't it all right and actually if you want to have a little fun you could even Swap this out with a call to uh compact uh like this this is sort of like the opposite of extract it creates a new array with these keys but then the values for each of these Keys is the variable Associated uh with the key which is kind of cool but I don't know it can be a little confusing and I don't want to pile too much on you so why don't we stick with this and I think this is pretty good and even better now our routes.php file yeah this works for me it's pretty clear and then in the future if I need to extend it to add uh support for additional things like authorization or middleware I I'll have a way to do that so I know we covered a lot uh if you have any questions at all please do ask them in the comments below otherwise we'll keep going in in the next episode all right welcome back folks let's go ahead and dive in right where we left off at the end of the last video so we now have a list of routes that can respond to a particular request type so this means if I head back to my controllers we can now clean these up like you see right here where we have a single controller that responds to a post request for deleting the note otherwise a get request for showing the note yeah now we can split these up into their own controller actions so to speak and if you remember this was the entire point of the routing refactor to allow for this okay so let's do this in my routes file let's see this is the route for showing a note so I'm going to duplicate it and say this time listen for a delete request to that URI and I will instead hit a controller like uh destroy. PHP and again that's a very common term you're starting to see common terms like show and Destroy and uh store and things like that we'll keep touching on it all right so if I go back to the notes controller actually let's just do this let's copy the show controller and rename it to destroy but now I can clean this up quite a bit I no longer have to do a conditional because we know we are responding to a delete request so I can get rid of that and all of that that and we'll give it a reformat okay so notice how with this refactor I was able to remove quite a bit of indentation and that's a very good thing as you will come to find okay so when we want to destroy a note we still have this kind of sloppy code for initializing our database we will fix that at some point uh in the near future we're still hardcoding the current user ID because we haven't yet reviewed authentication but again we tackle that in the next chapter and then we perform our authoriz ation and if that passes we delete the note but actually real quick I just noticed I accidentally edore get we actually want to check the post super Global sorry about that and then otherwise we redirect the user and uh we're all set to go okay so now I can close that and if I switch back to the show action once again I no longer need any of this I can remove all of the indentation and reformat yeah looks good to me let's do a sanity check in the browser we go to our notes let's view a specific note and try to delete it and there we go everything seems to be working but yeah again we've extracted that destroy action into its own file and we were able to do that because we updated our router to listen and respond to different form request types all right Mak sense so now well actually here's a cool thing if I try to create a new note I bet this fails because again we've we've tweaked our router do we get yes we get a sorry page not found and this makes sense if you think about it we are now submitting a post request to slnc create but if I go into our router here well we're not listening for a post request we're still using that old get request okay so we have one request to show the form to create a note but then I will create a new route that instead listens for a post request to this URI and yeah if you want you can keep this URI we have remember there's no real rules you can do whatever you want but try to follow conventions whenever you can and as it turns out common restful conventions would say if you want to add a new note then you should make a post request to the notes resource that's the way we do it okay and then for the action name well we would call it store again by Common convention it doesn't have to be store but usually it is and it's very helpful if you adopt these conventions because later if somebody joins your team or you join a different team if you're all kind of working with the same Playbook it becomes that much easier to to instantly grock or grasp uh the code base Okay cool so now if we come back let's add a new controller here and I'm just going to say hello to make sure that we are hitting this action all right let's go down to our views into create and yeah now our form will submit a post request to notes all right let's give it a shot come back to Firefox come back refresh try to submit the form and there we go now we're hitting that new controller awesome okay so once again we can clean things up I can go back to notes slash uh create and grab this right here remove it and place it within our new store action there we go I no longer need this conditional so we are reducing indentation which is good and this is what we end up with so it looks like I still need my DB class let's go ahead and grab that right up here and yeah I think this looks pretty good so we validate the request and actually real quick let's add our errors uh initialization and if we have no errors we can insert the note into the database and then finally we can redirect the user wherever they need to go how about sln notes and then we're done here so we can die otherwise if we reach this point we have some kind of validation issue uh don't we so yeah we could take this flow but often I like to check for the the problems first and then the happy path can go at the bottom so with that in mind we could say well if errors is not empty then the validation issue is here otherwise we can continue on with the uh Happy path right here okay so what should we do in the case that we have a validation issue well we could redirect somewhere or we can just return the view just like we did before and then I will return that all right so this action or controller handles persisting a new note to the database and that's all if I return to the create action for a note this one is now responsible for displaying a form to create the note so it ends up being a lot simpler and in fact we don't even use the database here so I can inline our errors variable and that's all we have here it's actually pretty simple all right so let's give it a shot back to the browser we will create a brand new note we persist it that hits our new controller we now see it here we can view it we can delete it which also hits our destroy action everything's working and again this was made possible because we extended our router to respond to different request types okay so hopefully you're feeling comfortable I'm going to pull the rug out from you one more time because we need to talk about service containers or at least a very basic service container in the next episode stay tuned all right hi everybody uh I don't want to do this but we should talk personto person for just one minute I don't mean I don't want to talk to you but I get it you want to see the code I do too I can relate but we still need to talk about one quick thing uh we will be discussing the service container in this video and I want to talk to you because we're starting to creep into more complex territory that you don't that you don't necessarily need to build yourself and then I still want you to understand the the basic premise and the basic concept so really if you think about it all of the things we've been building over the last 10 episodes or so like uh even validation but our router uh our database class this container we're going to add an app class once you start using a framework like Symphony or laravel they will provide these things for you for free that's why it's called a framework it gives you everything you need so even though I'm shown you how to build some of these things in real life most of the time you're not really going to maintain these yourself you're going to use off-the-shelf uh tools that are to be honest way way better you shouldn't in most cas you shouldn't build your own and yet I'm still showing you because again I want you to have a general understanding of what's going on here rather than it being some kind of uh black box that you don't really understand okay so just keep that in mind I'm going to show you how to build a container in this lesson and we can make it as complicated or as simple as we want but still if it feels a little too much or a little too overwhelming just remember in the future you won't be building this yourself so if you just want to skip over it even nobody's going to judge you okay let's get going I'm going to switch into PHP storm and if I go into for example my controller notes destroy action you will remember in a bunch of places we have code just like this where we need to instantiate our database class in order to execute some SQL okay so keep in mind that each time we instantiate database we also have to build up the necessary configuration to pass to the constru structor and you'll remember we set that configuration right here but yeah my point is it's just a little Annoying that I have to redo this every single time I want to perform a database query so we have it here here we have it here and then uh yeah we have it there again it's just a waste and as you can imagine for real applications this will constantly be a concern not just for a database class but for everything you will constantly have objects that require a lot of configuration or a lot of um a lot of tweaking in order to instantiate you might need a certain public key or a private token or you'll have to instantiate a dependency of a dependency to pass it in here and it gets very timec consuming so instead it would be nice if I could just do this a single time and then throw it in a in a container of sorts like just throw it in there and then if I need it I can take it out of the container that's what we're going to build in this video so I keep using this word container that sounds like a pretty good name for our class so I will do that now and I'll call it container and PHP storm will uh autocreate the class for me and then I did say we'll need to add things to the container and then remove them from the container and in fact I really like this super simple 5-year-old terminology however again just in the spirit of future Frameworks you might use why don't we change these to bind to bind something into the Container or and then resolve to grab things out of the container so a little more complex but also again immediately familiar once you graduate to a framework like Lille okay so what's the next step all right so let's do this I'd like some kind of playground so I'm going to create a new file and we will call it bootstrap.php and then our index file will require it so for now hm why don't we do it right here require base paath bootstrap.php okay and we're probably going to keep that file too but now I have a little playground where I can uh tinker and and and figure out how I want to interact with this container so I know I want to say new container all right and that automatically gets imported and then next I want to bind things in to the container and then let's see if I want to work with our database instance I could use a path to it using the name space so I could bind that key to a function that is responsible for building up the database object that's what we're doing here so I'm associating this little Builder function with a string called core database okay so if I were to go up to any place where we manually did it like right here let's switch back and paste it in here just like so all right and then we will return turn that from our function okay and real quick you'll notice that it's gray because I haven't set up the method signature on the container class but we'll do that in just a minute okay so now I can see that we have a string which would be like an identifier or a key for this finding and then we have a function that is responsible for building up the object it's almost like a little Factory function okay so let's uh let's do this let's open up a split go into my container class so that you can see these side by side and we'll say accept some kind of key all right and then the second argument is our function here call it whatever you want some people make it super generic like this I don't really love that but you know if you want to call it your your your Builder or your factory function or your resolver whatever you want here okay so now when we bind something into the Container think about it we need to store it somewhere we need to save it we need to cach it just like with the router lesson so I'm going to take mostly the same approach approach where I will have a a field here called bindings and then when I call this bind method I will push to this array almost identical to the router class okay so I might do something like this this bindings uh this will be an associative array I'll give it the key and I will make that equal to our resolver okay so now if you think about it the bindings array contains one item at this point the key for that item is core database and the value associated with that item is a function that will build up the database class however is appropriate for your project as you see here all right next within our resolve method we want to do the opposite right we want to take the object out of the container and how would we do that well we will probably need to call or trigger this function and then return the result right okay so let's do that now resolve should accept a key and that way I could say for example container resolve core database and then this method would look into our bindings array and say all right do we have anything called core database oh yeah we do so let's find the resolver or the function associated with it call it that will trigger this code and then return the results so in effect we would have a database instance fully built up and configured uh ready to go when we call this method here okay so let's do that okay so we might say if array key exists look for this key inside of the bindings array in that case we're good to go so I could say well the resolver is this bindings key and then I want to call that function and there's a couple ways to do this but why don't we stick with call user Funk this will accept the name of our function and it well calls it and then finally we will return the result okay but now what about the situation where you try to resolve something that is not bound uh within the container something like that what should happen in this case okay well maybe we should reverse it what if we do our guarding at the beginning and I say well if not exists within the uh bindings then yeah we don't we don't know what to do we can't proceed we have no idea what you want here and in those situations we can throw an exception something like this throw new exception this is provided by PHP and this is what you should do in exceptional uh situations and then later you can either catch those and respond to them however you need to or you can just let them happen now when we create an exception we can give it a reason so in this case what is our reason well we couldn't find a matching binding so maybe how about that no matching binding found for your key and yeah once again I can hit option enter and PHP storm and switch that to string interpolation if you like that just a little better otherwise if we get to this point we're good to go so I can remove this then reformat and yeah I think we are off to the races okay so we know that we are requiring our bootstrap class here so why don't we just play around with this let's comment this out and then die and dump the database class to see if it's working properly so if I switch to Firefox there we go we now have our database instance fully configured and ready to go which is pretty cool and yeah also if I were to instead uh resolve something that is not in the container well remember we' throw a new exception right so let's see if that works and what that looks like I give it a refresh and there we go uncaught exception so notice when you throw an exception you do have the option of catching it and then responding in some way uh maybe more graceful way but but I don't want to touch on that just yet for now this is fine we throw an exception to let us know there was no binding for this we didn't know what to do so we just aborted entirely Okay cool so I think this is looking good at least for our first pass but now well we have a new problem have a look if I go into my destroy controller well how do I grab that container right like it would I be in the exact same boat again where I basically have to build this up over and over so now I have to do this just to grab my database no definitely not it would defeat the entire purpose every time you need to use the container you have to instantiate it why would you do that definitely not but it does show that we need someplace to build up our container and then have access to it from anywhere in the application okay so to do that I'm going to build up an app class so just come along for the ride for a minute I'm going to call call it app.php and I'm going to add a static method here called set container uh quick refresher just in case you forgot a static method is one that can be called without having to first instantiate um an object so for example with this method being static I can then say app set container just like that if I did not have static here yeah of course I would have to build up a new instance of app and then I could say uh excuse me app set container okay so let's keep it as static for now because this is going to be super helpful now it's going to accept our container and then I will store it so why don't we create a static property called container and then I will uh initialize it static container equals container all right so now when I call this method I give it my container object and all it does is it saves it on this property it's the only thing it does right now all right next I need to get the container so I can interact with it right so why don't we do this let's copy this method and yeah if you want you could call it get I guess that would be consistent and it's very common but I don't really love using the get prefix if I don't have to why don't we just name it container and all this is going to do is it will return uh this value here it's going to return the container to me okay so now from anywhere in my application I have this app class and if I say app container I get access to the container and I can then interact with it um and and this is an example of a Singleton but again jargon terminology you don't need to worry about it uh right now okay so let's give this a shot and actually real quick can't forget to add the name space here all right so I will come back to bootstrap so here we've instantiated our container we've added our first binding and don't forget in real life you'll do this dozens of times potentially and now I want to set the container uh like so and I will pass that in and do note that I have imported app at the top automatically by PHP storm all right so I know we're covering a lot here that's why we had that quick conversation at the beginning of the video if you need to watch this two times watch it three times just to make sure you fully Gro and understand what's going on here okay I think we're ready to try this out so I'm going to go back to that destroy action on my controller where we were manually building up our database class and I will comment it out and instead I want to say app container give me the container and then I want to well let's see what we want to do on my container class I want to resolve my database instance so I say resolve and then we give it a path to the class or the key that I want to resolve out of the container and once again I'm just going to die and dump the DB class to make sure that everything's working the way we'd expect all right and then let's go to notes and I'm sorry we don't even have a note here let's add one super quick we view it we click delete that will hit our destroy controller and then we should die and dump the database object and everything is working very very cool okay so now if we did everything correctly all of this stuff here can now be replaced with our container app container resolve our database pretty cool and in fact if you want I'll show you a little tip notice how I am manually writing out the path to our database class but as it turns out if you just reference the class name itself and then colon colon class that will uh basically translate to a string of the full namespace path to the class and if you even want to inline it you could do um this and that way you get some autoc completion some intelligence uh you might prefer that it's still going to work the same okay cool but now I want to focus on some Creature Comforts it would be nice if I didn't have to say app container resolve database wouldn't it be cool if I could just say like app resolve and then it just works and real quick by the way I would almost always import this so I will bring that back but yeah wouldn't it be cool if I could just say app resolve and then the app class would delegate to The Container class and give me what I need okay the problem is right now the resolve method is defined on container uh right here and not on app but think about it you're in charge is there anything preventing you from just having a static method here called resolve and then you give it the key no and if you're instead thinking well there's nothing preventing you but you're adding a bunch of duplication no I'm really not I'm not reproducing everything I have here I'm just deferring I'm delegating so the app class can say okay well let's grab our container and then I will call resolve and pass through the key you see how it's just kind of passing it through app is just it's adding an importance here yeah you can call resolve and if you do I'm just going to delegate it over to the container class it just makes for a more more I don't know friendly and intuitive API to access it directly off of the app class okay so with that in mind maybe we should do the exact same thing for bind bind and then of course I will need a resolver okay cool and again those delegate okay and then of course I want to return the result here okay so now if I come back to our destroy controller yeah I ideally hopefully this will just work let's give it a shot view the note click delete and everything works just like it did before but now we are resolving things out of the container which means yeah I can I can switch over to any place I was referencing this before and swap out that instantiation with a reference to uh our container as you see here so let's do that paste this one in as well is there one here yes there is there we go all right so we're about done here but finally to wrap up some quick closing thoughts yeah just keep in mind that the container we've built here is incredibly simple on purpose to demonstrate the general pattern but yeah once you graduate to a dedicated service container that for example larl provides you will find that it does so much more it has support for uh Singleton where you get the same instance no matter how many times you resolve it and that would be very useful in the example of of our database class here by the way it also has support for things like automatic dependency resolution which is a fancy term that just means there are situations where you wouldn't even need to specify how to build up an object the container could possibly do it for you automatically uh to use a madeup word there and yeah basically it will look at the class and then it will look at the dependencies on the Constructor and then don't forget each dependency could have its own dependency and those sub dependencies could have their own dependencies and yeah the container could recursively go through each of those and build it all up on the Fly and it's really cool but far beyond the scope of a beginner uh Series so yeah this is the container that we're going to stick with for now and uh hopefully it was useful to you finally our app class provided a way to basically make this container Singleton available anywhere within our application all right so please do ask your questions below otherwise onward to the next lesson as always all right welcome back everybody okay so we have one more episode to complete our first notes uh crud app or resource if you like and then after that we can move on to sessions and authentication which should be a lot of fun okay so let's dig in right now if I switch to my browser here's our notes section and yeah we can create an example note and that works fine we can view all of them we can view a specific note we can delete a note but yeah we can't yet edit and update a note and that's what we will do in this episode all right so let's go into our browser and yeah let's do this um maybe we can actually if I switch back real quick maybe we can reuse uh this form here okay so this is the create page so I will go to views notes create and I'm going to copy and duplicate this and we will call it uh edit. viw okay so now if I go into actually let's start at the route level let's say listen for let's grab this one right here listen for slote sledit and that will load a controller called notes sledit all right that's our next step create the controller so once again let's take something we already have and duplicate it and I will call it edit.php and yeah at least initially to make sure this is working I often do this let's just Echo hello and see if we get anything in the browser okay so let's give this uh actually let's go into a specific note and then update to the URI to be note sledit all right and sure enough we are hitting that controller okay so let's switch back and yeah let's think about what we need to do we want to load a view to edit an existing uh note we've already created that view the heading will be edit note and yeah let's just leave it like that come back and refresh the page and there we go okay so now of course I need a link to edit that note so maybe when we show it yeah possibly uh right down here we will add an edit link okay so let's go into to views notes show and here's where we delete the note but you know what we might even move that to the edit section let's hide the sidebar but yeah right here we'd have something like an anchor tag that will go to noteedit and we'll call it edit okay it's not going to look pretty but if I give it a refresh there we go okay so yeah ideally I'd like well let's think about this actually maybe when I click on the edit link here is where a delete action should be located so if that's the plan I can switch back here and delete this or actually I'll copy so we can save it for later and then uh I will remove it from this VI okay next why don't we do H let's add a footer and add it here and then add a little margin top mhm and then why don't we style this as a button uh so maybe we'll give it I don't know a text Gray 500 yeah and then I'll do a border of the uh the current color so a border that is also gray of 500 and I'm sorry I should also just come along for the ride if you're not familiar with Tailwind so we have a border and then I'll give it some padding on the left and right and a little less on the top and bottom mhm um and then we'll make it rounded and yeah maybe a little less padding and yeah just just something simple to get us going okay so now if I click on this um we can edit the note but yeah really this isn't right of course because I don't see the note here so if I'm editing a specific note I have to fetch the specific note and to fetch a specific note I need to know what note we are working with so just like when we show a note when I click on the edit link we need to include the ID of the note that we wish to edit so again right now we are we are passing that through as part of the query string so we'll do something like this note ID and uh let's give that a shot okay come back give it a refresh and now when I click on the edit button there we go we are editing a note and specifically the note that has an ID of 39 all right next step is to track that down so we will go into our edit controller and yeah actually if you want want we can just steal some of the code we wrote in the show action so stuff like really a lot of this because yeah if you think about it so much of your controller action logic revolves around uh finding things validating things authorizing things so um they will often be somewhat similar so I'm going to paste all of that in and notice my editor will automatically import those classes but if you're in something like Visual Studio code you might have to do that manually Okay so let's see uh we're going to track down the corresponding note that should all be the same if we couldn't find the note then we abort with a 404 we then authorize that the um the current user which we're still hardcoding for one more episode uh we're authorizing that that user has access to view and edit this note because otherwise if we didn't have this then anyone could access that edit uh URI to tweak your note which of course we don't want toow so we have to to implement authorization at every level here okay otherwise if we did find the note we can pass that through here okay cool so now if we go to the edit action think about it where we have the text area yeah right here I can replace this with uh the the body of the note so note body all right cross your fingers come back give it a refresh and there we go okay but now think about it what if I change my mind and I want to cancel well I probably need a cancel button right here okay so let's go back to our editor and let's see right down here and you know what it looks like uh when we used that Tailwind uh layout they already had some nice styling for a button and again I know this is a big mess and you might think why would you ever want to repeat this over and over don't forget when you're actually building applications there are ways to isolate these things you could extract um the button into its own component you could create a dedicated CSS class like button where you apply all of these there are many different ways to tackle these things but again utility classes and Tailwind just aren't part uh of this series but we have plenty at layer cast if you want to learn more so anyways right up here why don't we duplicate this but swap it out to an anchor tag and then I'll say this will take you back to all of the notes and then we'll just say cancel and then the only thing I want to do here is change the background to cray 500 let's see how that looks Yeah just something like that and you know what why don't we even add a little more of a gap between those items yeah and then let's just do justify end so I'm just applying uh a display of flex box I'm pushing all of the items to the end of the row and then I'm adding a little gap between each of the children and then we get something like that okay so now if I click on cancel it takes me back to viewing all of the notes okay perfect so yeah you can see now we have a little inconsistency because we created our dummy uh styling for that button so what I'm going to do is copy all of that go back to our show View and then I will update this so that we can be a little more consistent perfect okay so now about it when I make a change here to the notes well I should be able to save or why don't we instead call it update so right here we can say update but when I click on that what should happen where should the form submit okay well again if we're following restful conventions let's have a look we're going to go into our routes file and you know right here we could say well if we make a patch requ EST to a specific note that should update it so why don't we do this router listen for a patch request to slash notes and that will hit a controller called update okay and this will be our last uh resourceful controller we'll call it update.php and once again we are just going to say updating um to confirm that we are hitting this controller I do this all the time are we actually hitting this file or not it's just a small little step that that can save you some time okay so let's make sure that when we edit a note and we submit the form right up here it submits the uh appropriate request it's now going to visit slote and remember browsers do not support patch and delete requests and you can see uh it's not going to allow that but as we learned a number of episodes ago we can now sneak it in by creating input that is hidden that has a unique name of underscore method and a value that is equal to the request type that we actually want our code to to treat the request as so in this case I'm saying all right well I actually want you to treat this as a patch request our router will detect this and then route accordingly right so let's see uh I think this is probably right let's come back to the browser give it a refresh and click update and there we go we have responded to that patch request and loaded the appropriate controller cool okay so now let's think about it what needs to happen here when we uh hit this controller and why don't we write it out as comments well first uh let's find the corresponding note right uh then maybe authorize that the current user uh can edit the note and then we should probably validate the form so for example if you try to edit the note but maybe you don't include anything or you include too much uh well that should trigger a validation error in which case we should return here and provide you some feedback okay so validate the form uh and then if no validation errors update the record in the notes database table right these are basically the steps that we need to do here okay let's get going and once again I can steal some of this code that we have here so let's go into update find the corresponding note so we have that right here select star from notes for the ID but yeah in this case we have a post request so maybe we should pass through the notes ID as part of the form that would be one way to do it okay so if that's the case we need to return here and add another hidden input called ID where the value is equal to the ID of the note that we wish to update again this is one way that we could tackle it later I'll show you how to include the identifier as part of the URI but for now we'll keep it as a hidden input okay so back to our controller try to track down the notes uh let's then authorize that the current user can edit the note so once again authorize that the notes user ID equals the current user ID next we want to validate the form so we will create a list of errors and then let's just show you right here where we did it a number of episodes ago we'll just steal this to save some time paste it in all right so that will automatically import our validator and we can say all right we're going to validate that the body uh that text meets our criteria and again notice as I'm doing this this is one pain point that we might want to solve we are now repeating validation logic so I can see here for example that the body for a note can be no more than a th characters but I also declare that logic here so you can imagine situations where it becomes out of sync for this form Your Body Logic is different than for that form so yeah these are things I want you to think about where you have little pain points and little pieces of duplication that could eventually become out of sync if you're not careful so in your head I want you to be thinking about what could I possibly do to normalize that to isolate it so that I only perform this validation logic or whatever the logic happens to be in a single point okay that's something to think about but for now we will keep the uh duplication one thing at a time right all right so finally if there are no validation errors or another way to think of it is well if we do have validation errors then we need to reload that form so for now I'm just going to return the view but again later we will learn about uh a process where if validation fails you redirect to um a specific controller but again we're not quite there yet because we haven't yet talked about uh sessions and things like that and Flash messages uh so for now I'm just going to return the view directly so once again notes edit. view.php I'm going to send excuse me I'm going to send through the errors I will once again send through the heading but again we have some duplication there which is annoying and then once again we will pass through the corresponding uh note all right so this is what we get otherwise if there are no validation errors we can update the record so we can just run an update query DB query and here's how we can write that update the notes table and I'm going to set the body of the note equal to whatever body we have uh in the bound parameter but which one I can say where the ID of the note equals and once again another parameter okay so the ID I care about is post uh ID and the body will be the body that the user typed into that text area like so okay finally we're all done here so the last step would be redirect the user all right so why don't we for now just redirect them back to all of the notes so I can say header location equals notes and then we're done here so I can die and yeah I want you to notice a few pain points as we worked on this uh as you'll find later once you graduate to certain Frameworks we can simplify so much of this logic things like this uh error handling checking for errors there are ways that we could simplify that uh dramatically there are ways to remove this duplication obviously in real life you're not hardcoding the current user so just keep in mind there are further ways that we can simplify this uh quite a bit all right let's give this a shot in the browser so I'll give it a refresh here's our note and I'll say has been updated we update it oh and it just worked we didn't even have a mistake there so I click on it and that's what we have in the database let's confirm it if I switch over to table plus there we go okay but now what happens if I switch back if we fail uh the validation and just to make this a little easier on me uh why don't we make the validator like if it's more than 10 characters something that will instantly uh trigger a validation error okay well now this alone would trigger an error so I let's do this gibberish here if I update it all right well we have a couple things here yes we do see the validation error and remember we got that for free because uh we copied our view so you'll see right here just to make sure we're all on the same page we already had this check from our create form where we say all right well if there is an error for the body then let's display it as part of a paragraph tag but also I want you to notice that this is kind of annoying potentially annoying you type in something here it does trigger a validation error but when we update it it reverts back to what you originally had and there might be situations where you want that but usually you don't want that but I'm going to hold off on fixing this again until we learn a little bit more about sessions okay so just hold tight on that one uh otherwise though our validation does seem to be working just fine if I tweak something that that kills the validation well we don't update the database at all instead we return to the form and we provide the user with a bit of feedback so this seems to be working uh pretty well okay and then further um if we try to edit this but uh the authorization fails and we can test this out by just manually updating this like that well now the current user has a different ID so we try to authorize it and we see wait a minute the current user did not write this note so they do not have permission to update the Note in which case we will uh we will forbid it as you see here okay so all of that seems to be protected all right and I think that completes our first resource okay and you know what I want you to really focus on the conventions that we're following here if you can try to adopt them and maybe that means taking out a sheet of paper right now and cop ing these down so you don't forget so index will show all of a resource give me all notes um show will show me a specific note um create will show me a form to create a new note store will be what we hit after you submit that create form so this is responsible for storing the note for persisting the note uh what else do we have here edit shows a form to edit a note update is where that edit form will submit so that controller is responsible for updating uh a specific note and then of course destroy is responsible for destroying the note uh removing it from the database so notice these conventions are being followed here in each of our controller names and then we also mostly adopt that as part of our URI the only thing that's missing here is really rather than SL notes we would do something like sln notes slash and then some kind of ID and then when you update it you would hit that as well but we haven't yet talked about uh routing wild cards and that's the only reason why we haven't adopted this but um we can talk about that in the future all right and yeah that does it for your first initial crud app and by the way if you're not familiar with that term crud stands for create read update and delete and that's exactly what we've done here and yeah if you think about it so many of the things so many of the tools on the internet really do break down to simple crud operations for example with our notes create a note read a note show me the notes uh update that note or delete this note uh what about a to-do app create a to-do show me my to-dos delete this to-do uh what about uh invoice maybe an invoicing app create a new invoice update the invoice show me all my invoices delete this one again so many things break down to simple uh crud applications and that's why we reviewed it here okay but now finally in the next episode we begin a brand new section where we can discuss uh session handling and authentication I hope you're excited stay tuned all right everybody we have now reached a brand new chapter on session handling and authentication and real quick before we get started I'm not trying to be condescending but if you've made it this far seriously give yourself a pat on the back you deserve it this is dozens of episodes hours and hours of content and you're still here and most people give up very very quickly so it's super admirable you're doing a great job I promise we'll get to the other side uh so yeah let's ease into this new chapter by talking about what exactly are PHP sessions so why don't we begin by looking up the general definition of the word session and yeah I'll point you to number two a period devoted to a particular activity nice and simple okay so within the context of a website it would be a period where a user interacts with your website and their interaction is going to be different from my interaction so this is my session this is their session okay that's good enough to get us started so let's go into our project here and yeah let's just play around I'm going to go into the index controller for the homepage now you've learned about super globals there's a post super Global there's a get super Global there's a server there's a request there's also one related to sessions and this will take the exact same shape of dollar session and we can interact with it as an array so why don't we start by putting my name into the session and real quick I will warn you this isn't quite going to work the first try but I still want to do it this way so that you have a better understanding of why we must do one step prior to this to get everything working okay all right so now think about it I now have a session an interaction with this website that is unique to me and this data here these attributes will be remembered as I browse the website now I'll tell you right now it's not permanent we're not saving it to a database so it is temporary and often that session will be deleted for example when you close the browser or even if you don't close the browser uh depending upon the defaults it it might delete after half an hour or a day it just depends but again that is a key thing to to keep in mind here it is not permanent sessions are not permanent okay so yeah we can just try this out though when I visit the homepage I'm going to put something into the session and then when I go to the about page I want to grab that information out of the session so why don't we do this let's just die and dump and let's see if I can grab the name out of the session and let's see if that works all right I'm going to go to my browser okay so now at least we think we've put my name into the session so now when I go to the about page and we try to fetch my name out of the session does it work no it doesn't we get undefined Global variable session okay well I just told you this exists so what is going on here okay well here's the issue anytime you intend to work with sessions in your application the first thing you have to do is start up the session you can't interact with that super Global until you have started the session and generally you want to do that as early as possible so why don't we do it in index.php you know it doesn't have to be the line but just for now let's put it right up here at the start I will call a function session start okay so with no other change let's give it another try I come back to the homepage we give it a refresh we started up a session we then put my name into the session and now when I go to the about page we fetch it out of the session okay so this is pretty cool we now have data that can effectively persist from page to page and again it's temporary it doesn't live forever so in fact let's just try this let's close out my browser entirely and yeah I've reopened Firefox from scratch and sure enough all of that prior session data has been destroyed so again I don't mean to reiterate but this is a key thing to understand session data is temporary okay great so let's go back to the homepage where we put something into the session and then when I go to the about page we can uh we can grab that data all right so let's do this let's go back to our about controller and get rid of this D and dump call and instead I want to Echo uh the person's name within the view maybe within the banner so we'll go into views partials banner and yeah at the moment we are dynamically displaying a heading but yeah just temporarily let's swap that out with hello and then I will reach into the session and grab the person's name just like that all right so let's go back to the browser and refresh and sure enough I do get hello Jeffrey and that will persist across every page for the lifetime of my current session so just keep in mind once again if we close that Firefox and bring it back we get a warning and of course if you think about it for more than 5 Seconds this makes perfect sense think about it within index.php we started a session and then we hit our about control roller that loaded a view the view loads a banner and then we tried to fetch name out of the session but at this point there's nothing in the session because when I closed the browser before it was destroyed so now we're starting from scratch and yeah PHP saying um you don't have anything in the session for name the point where we put it into the session is within the homepage and you may not always load the homepage first of course so yeah notice if I go to home then we put Jeffrey into the session uh it gets saved on the server and as a cookie uh on the browser and I'll show you that in just a minute and then for repeated page requests uh it is remembered so yeah in plenty of situations what you'll need to do is check well is this available otherwise uh use a default or or render something different like guest hello session name or guest okay so now my name is in the session so we say hello Jeffrey once again let's restart we reload once again my name is not in the session so we see Hello guest for every single page until we update the session with my name and then that is what we will reach for okay so now how exactly does this all work what's going on here all right well there's a couple pieces to this Puzzle first up I want you to rightclick and go into inspect this fine but really I want to go to storage and then you'll see session storage but don't be confused here this is actually U part of a JavaScript API we actually want to have a look at the cookies so there's again there's two pieces to this puzzle we are going to store a a file effectively on your server and that file contains uh your your session data and then we will also store a cookie on the browser side and this communication is going to be essential for for determining uh um whether to start up a new session how the data is communicated Etc all right so let's have a look and yeah sure enough I can see one cookie for this website and notice the name of the cookie PHP session ID and then there's the corresponding value and we can also see important information about when it expires what the domain is the the last time it was refreshed which is really important um yeah so let's bring this down and I see Hello Jeffrey but what if I just rightclick and I delete all of them so let's delete all my cookies and then I come back and give it a refresh and now I see Hello guest okay so that's a key thing to keep in mind here if I delete the cookie on the browser side well the next time I reload the page basically what's happening is that cookie is not transmitted it is not sent to the server and because it's not sent to the server the server thinks okay well I just need to wire up I need to whip up a brand new session so once again we're starting from scratch here and I'd have to repeat and there we go here's our cookie once again okay so that's the client side piece the server side piece is a basically a file is being stored on your server that contains information uh about the session okay so what I think would be cool is if we could figure out where that file is being saved and it might differ depending upon on your machine usually the default is going to be some kind of temporary uh temp directory uh on your server but yeah again whether you're on a Mac or Linux or or a PC it might be a little different and you might want to Google for 5 minutes to figure out uh how to find this file I'm going to run PHP and then the info flag and this will spit out a lot of information related to my uh current server so yeah now I want to figure out where what is the path to where these session files are being saved and I just happen to know it's called session. saave path yeah there it is now in my case it's set to no value on your machine it might be the same or it might just tell you exactly uh where that path is and if that's the case simply copy it and CD to that directory otherwise if there's no value set then it defaults to the default and that default is again the temporary directory so let me see on my computer where that is I'm going to Echo and again this this is probably unique to um Mac but I'm going to look for temp directory all right and this is it so let's see if I can go directly there all right and you can see I am ordering the files according to the date and sure enough I see these various uh session files and these are the ones we care about so how do I know which one we want well let's go back to Firefox and and just to make sure this is up to date yeah so I can see one where the session ID is uh this it starts with 82k all right let's come back and there we go session U 82k okay let's drag that into my editor and there we go name is Jeffrey okay so now we know this is pretty cool now we know when you write to the session uh those attributes and that data is literally being written to a file on your server let's try another one let's go back to uh actually let's just stay on how about contact.php and I'm going to write something else to the session how about um we'll do my last name way okay let's come back to Firefox and we'll go to home about notes contact and at this point our session should now have uh two keys name and last all right let's come back let's return to that session file and there we go we wrote to the session so it was updated uh within that session file on our server okay and now we can see if I bring this back to storage cookies yeah again eventually these will expire um I I I don't remember what the default expression it could be minutes 30 minutes or something like that but you can tweak it uh otherwise though it could go longer uh it will immediately be destroyed of course when you close the browser so how long it lasts uh can depend on a few variables and that's something to keep in mind but yeah otherwise when we write to the session we will constantly update the last time uh the session file was updated basically and that way you don't have a situation where you're browsing the site and then randomly up everything got deleted and you lost all of your session that's not going to happen as long as you as you keep it active and you keep uh starting up the session all right so yeah this is interesting we have two pieces to the puzzle we have a session file and then a cookie that is stored uh in the browser and if that cookie is deleted if you've ever heard somebody say delete your cookies well let's just go ahead and do it delete the cookie and now when we start up a new session well we don't send a cookie to the server so PHP picks up on that and it says okay I'm just going to start up a new uh session and notice that this one has a different uh value so if I go back to my finder notice that well yes we still have the old session file and we'll talk about that in the next episode but yeah now because the cookie was deleted it created a brand new session uh file to store this data okay so I think that's enough for now but we still have so much more to cover again this is a whole chapter on sessions so it will conclude with building a login system but for now I just want you to get comfortable with the general practice of starting up a session and writing to it and in the next episode we'll figure out how to destroy a session and what steps you should follow whenever you do that I'll see you then all right hey everybody so in the last episode you had your first introduction to session handling right sessions 101 but now let's kick things up a notch and figure out an actual practical use case for sessions within an application all right let's get going if I open my routes file yeah of course we will build a form to register a new user so let's start with the routes and we'll keep it very simple uh this will go into a controller's directory and why don't we call it I don't know registration SLC create how about that all right let's go in here create a new directory called registration and then our first PHP file for uh create all right so this will load a view and just like before it'll go in a registration directory and uh we'll name it the same thing all right let's create the view views U let's add our directory and then create and I'm sorry I forgot we gave these a view uh extension all right and then just to save myself a little time why don't we grab some of this and then we can replace it all with uh register here something like that all right let's have a look in the browser all right so here's the homepage and yeah I don't yet have a link to register we will probably put it right up here but yeah for now if I manually visit that URI all right it works now of course in this case I get a warning uh because we haven't yet provided a heading variable but sure enough we are loading this page okay so here's what I'd like to do next I will once again visit tand ui.com and I promise I'm not trying to sell you on it uh at all but they do provide some free templates that are great for little exercises like this so I'm going to look for some kind of form yeah it looks like they have one to sign in and register and this should be fine for our needs so why don't we uh copy this and see if we can make use of it I will place it um I'm not sure maybe within this main tag yeah so let's scroll up and yeah we already have the forms component uh here they want us to update the HTML and body tags to make uh to make the height 100% but I don't know if we'll even worry about that so let's get rid of that and yeah let's just cross our fingers and see how this looks so if I come back and give this a refresh I still see my warning but sure enough we have the beginnings of of a uh login form or a registration form okay so next I don't think we need a banner here so let's hide it and that will remove the warning and yeah I think this looks good so now let's just update a few things like uh sign in would change to register all right uh what about this section here instead of signing in we are going to register for a new uh account I don't we're not going to have any kind of trial all right um remember me and forgot your password those are useful but we're not going to worry about that here so let's grab H forgot your password here we go let's grab all of that give it a reformat come back refresh and this is good enough at least for the demo okay so now and by the way this is populated maybe from my password manager but of course uh we have an email address and a password so the next thing I'd like to do is update the form itself and you can see what do they give us by default uh it's going to make a post request but the action is a hash symbol so why don't we have it uh post to that exact same endpoint and then we will have a look at each uh field all right so yeah in our database we're going to call this column email so why don't we update this like so all right password looks good and then the only thing I don't see is uh some validation errors so I think we did this H let's go into note SLC create and yeah a number of episodes ago didn't we have something yeah right there all right let's switch back and I don't know if this is right but we could try putting it there to start and we could say if there's any errors for the email show it here this may not be right for formatting uh with this component but it good enough at least to illustrate uh the approach and we'll do the same thing if there happens to be any errors for the password all right come back give it a refresh and this looks good to me okay so now if I were to submit this form of course we're going to get a 404 because it tried to submit a post request to/ register but we haven't yet created a route for that so that would be the next step go back to your routes file I will duplicate this line and now listen for a post request and that will hit a store action or a store controller okay come on up and let's duplicate this store and now I'm just going to say here to show that it works register the user okay come back give it another try hit register and now we have hit that endpoint okay so of course at this point within the post super Global we should have access to the email address and the password that the user provided so let's give that a shot I will type password Here We register and we see it looks like T1 has some kind of uh remember input that I will get rid of uh but then we have our email address and our password okay so that means the provided email will be post email the provided password would be post uh password okay so now yeah at this Point you're going to follow the exact same steps that we've used for every other form just with a slight tweak so think about it uh we would want to validate the form inputs uh we would want to but then at this point after we validate think about it you'd want to check what if I try to register Jeffrey lc.com but there's already an account for Jeffrey lc.com we need to check for that so check if the uh account already exists and then at this point we would have a branch so like if so if yes then we'll think about it what should happen if somebody tries to register an account but there's already an account maybe we should U let them know maybe we should redirect them to a login page how about that redirect to a login page that we haven't yet created okay otherwise we could say if the account doesn't exist then create it or save save it or save one to the database uh and then log the user in and redirect that's sort of what we're dealing with here and yeah a quick note on these comments of course you don't have to do things like this you can skip over it but I find even after having done this for years and years it's useful just to get your mind in order of what do I need to do you know if you're trying to plot out your day you might take out a notepad and say I got to do this and this and this the same is going to be true uh for the programs you write and then when you're done you can just erase each comment as you complete it all right so in this case validate the inputs well I could say validator and you'll remember uh we have two methods one to validate a string and one to validate an email so why don't we start with the email validate the email and if it is not valid then let's append to an errors array like we've done uh before so we might say error email um please provide uh an email address and not just an email address but a valid email address all right next why don't we validate the password uh let's do a string for the password and you'll remember when we created this a number of episodes ago we can accept the number of characters that we want to check for so why don't we say a password has to be at least seven characters but no more than 255 characters uh 255 is just a common maximum character count uh for your for your database uh VAR cars or or variable character columns okay so the next step would be um well if the errors array is not empty then we have a problem so again you will eventually learn about a process where if validation fails you would actually redirect but at this point we're still going to return a view so let's return turn our registration SLC create View and then I'm going to pass through the corresponding errors all right and then oh yeah I forgot to update this if we uh if we have a password validation error please provide a password of at least seven characters okay so let's give this a shot in the browser all right so back on the registration form let's try a password of only three characters and yeah of course it looks like The Styling isn't quite right there I see a shadow I'll have to figure out what H when UI wants you to do there uh but otherwise it doesn't really matter sure enough we are uh triggering a validation error and then we provide feedback to the user which is good all right so let's switch back and at this point if we get Beyond this clump of code that later I'll show you how to clean up and organize better uh then we can move on to this section check if the account already exists so what we might want to do is grab or resolve our database class that we created and then I could say dbquery and let's say select star from the users table where the email address equals the one that was submitted through the registration form and if there is well think about it that means hey we already have an account for that email address so let's uh run that query we'll send through the email and get the result so we'll save that to result and then find a corresponding record and then die and dump and we'll have a talk about this all right so before we run this in the browser let's switch over to table plus and we'll have a look at that users table from a number of episodes ago and yeah right now it just has a name and an email why don't we tweak this a little bit uh let's say instead of name we're going to have a password that cannot be null okay so now again it's super simple in real life you'll have many more columns but at the moment our users table contains an email address and a password and that's it and let's then populate it with something like Joe at example.com and then a password that's stored in clear text which is a really big no no and we're going to fix that in a little bit but not quite yet okay and yeah we'll give it a shot all right so back to the register page we will register uh an email address that already exists in the database and we should die and there we go we die and dump the results we already found a corresponding record now in this case we don't even need to do anything with the results so if you want you could check uh if the record exists or you check for the count uh using a SQL query but this will be fine however if I try to register an account that does not exist within that table you'll see that it returns false so yeah at this point this is where we have our Branch we could say uh user and yeah right here you say well if we have a user in the database then someone uh with that email already exists and has an account right that's basically what that means so we said uh on that condition redirect to the lockin page so we could say header uh location is login but you know what that doesn't even exist yet uh we haven't yet created that route so for now I'll send them to the homepage and we will build the login page um maybe in the next episode otherwise we have this pathway save one to the database and then log the user in and redirect and this is where we can actually start working with uh sessions so let's see we start with a new query insert into the users table and we want to give it an email address and a password and the values of course will be email and password and then I will pass those bindings through so again for the moment I'm going to pass this password and clear text but yeah in the near future I will teach you how to Hash the password and then compare it when we build the login form and that's why I'm holding off all right so we have created uh the account at this point we sort of want to mark that the user has logged in so I think that would be a good use for sessions I could say session and yeah you could do something like this logged in if you want or maybe you just add maybe a key like user and you make that equal to uh whatever you want how about an array itself where the email address is uh the user's email or maybe you add multiple things like maybe you you add the user but you also have some helpers like this that you set to True whatever you want to do here okay so uh there's more to do here um I ideally there are some good practices about how you um create new sessions how you log in when you regenerate the session but we'll get to all of that uh in the next episode or two the final step for now is to redirect um and often this is like to the users's private dashboard or their settings area for now once again we will redirect to uh the homepage and then we can exit or die and we can do the same thing up there as well that's always a good practice after you redirect uh kill the script basically exit because uh you want to ensure there's no scenario where uh the the script continues being executed after the header all right so a lot of stuff here and again I promise you there are ways to clean this up and ways to simplify things but it's good to do it this way to have a general idea of the flow and you'll find that this happens over and over where you submit a form and you need to validate it a little bit you may need to run a database query you may need to um respond dependent upon the state of that database uh you might want to append things to the session or to the cache this is all really common stuff that you will write over and over okay so the only remaining step is to ensure that this works so I think we're going to make use of this all right so let's say when the user goes to the index uh controller that will hit this view so let's scroll down into the index View and yeah maybe we can go into the navigation area and let's see what I want to do if I switch back is uh find this section here with this guy so it looks like they're using unsplash.com there it is so let's see if I get rid of that is that the one yeah okay so why don't we do this why don't we'll still use that Avatar to assume that you're logged in but I might say well if uh session you user and remember we can't always assume that anything is in the session so we could check for if is set or uh assume that it's false we could do something like that if they're signed in then uh show that image otherwise maybe we have uh a link to register or log in right so let's start with a registration link register and that will go to slash register and yeah this is how we can handle uh that sort of flow all right so if I switch back and give it a refresh now we have a register link that's a little hard to see we'll make it white and yeah now uh if we're not signed in I can click on register and yeah we can create a new account for myself uh Jeffrey lc.com password that should create a new record uh within the database if we switch back give it a refresh sure enough we have an account where again the password is stored in clear text and you don't want to do that but I promise I'll show you that in a little bit okay but either way now we can see that we have written to the session uh and because we have a user in the session uh that conditional that we just wrote earlier returns true so now you know we can say you are sign you know whatever you want to do here uh to to signal and it's still black but you get the idea uh to signal that the user has now signed in and they now have permission to access certain pages that are exclusive to logged in users okay so we covered so much there I'm very sorry about that but we had to get through some of this stuff uh in the next episode we're still focused on sessions and we'll keep digging a little further so I just want to finish up by once again Drilling in that because we have uh signed in and created a new session we now have a cookie with this session ID and yeah then on the surface side as you learned in the last episode a course responding file will be created that contains details about the session Associated uh with this particular ID so in our case uh if we opened that file again we did this all in the last episode but it was pretty beneficial to me when I learned how it all worked if I open that uh specific file you can see details about my current session and that's why you want to be a little bit Careful by the way uh if you're not careful you can fall prey to what's known as session hijacking and that's basically where a malicious user gains access to this cookie and can swap out that value uh with a different ID but again that's a little more advanced than where we currently are we'll get there uh but for now let's just take things step by step and move on in the next episode all right welcome back everybody so yeah in the last episode we added support for basic registration so yeah if I want to log in Sally at example.com sure enough we are signed in and that has been recorded in the session so if I rightclick and go to storage cookies sure enough here is our PHP session cookie all right very cool but we do have one problem uh think about it what would happen if I try to visit that registration page again even though I'm already signed in all right let's see what happens slash register and yeah I see the form to register for a new account so what exactly would happen here if we try to register another person yeah this just gets very strange very quickly if I have a look at table plus and then if I open the users table yeah this is weird so we registered an account for Sally and then while Sally was signed in we registered another gibberish account and signed that in which is really weird so yeah as you can imagine if you're already signed in we need some kind of protection in place that restricts you from being able to access certain pages and of course that works in both directions so for example this notes section well maybe that should be limited to only uh members or people who are authenticated right if you're a guest well you don't yet have permission to access this page yeah so that's what I mean when I say it works in both directions okay so let's think about this what are some options for solving this problem now of course we could tackle this page by page if you want so for example if I go into registration SLC create yeah here we want to say well if you're already signed in there's no need for you to access this page again so let's disallow it yeah so you might say something like well see if we have a user in the session but assume we don't and yeah if we do have a user then let's get out of here so let's redirect you to somewhere so let's send you back to the homepage and then uh kill the script or exit uh or die whatever you want and yeah that would work so if I come back and I try to manually access that register page notice it instantly redirects me back to the homepage and that's what we want but we once again have that issue of duplication so if there are other controller actions that are restricted to guest only yeah at the moment I would copy and paste this into every single controller uh where it is applicable which I definitely don't want to do okay so here's another option what if we tackle it at the route level let's see what that might look like let's go into my routes file and yeah why don't we say uh yeah here we go register so what if there was a way to declare when I register this route that it should be restricted to only guess and I said only so why don't we just add a method like only and then we'll give it some kind of keyword like only uh only guest only guest can access this particular route meanwhile if we came up here maybe something like this where you access your notes we could say Well only authenticated users can uh have permission or authorization to access this specific route yeah that feels good let's see if we can make it work and we'll start with this one only all right well it sounds like if we want to call an only method on our router we need to return to the router and make some tweaks all right let's open up core router and yeah let's see here's our class H maybe right down here we're going to have a method called only and this accepts some kind of key and then let's die and dump the key just to confirm that we are calling this method because I think at the moment none of this is going to work work all right let's come back try to visit register and yeah sure enough we get a fatal error call to a member function only on null all right so what's going on here uh we tried to call an only method we declared it on the router but it's not working all right let's go back to our routes and have a look so it sounds like we're calling a get method and then we call an only method on whatever is returned from the get Method All right well let's have a look at the get method the get method uh doesn't return anything at all so that is why we are getting the error because null is returned okay so let's do this we're calling an add method the add method adds a new route binding and then down here at the bottom why don't we have it return the current instance and that way we can continue chaining off of this router object okay so now for all of these verbs like get post put patch delete let's have it return whatever is returned from the ad method which again is the router object and if we do that we should be able to continue chaining off of that router all right so if I come back to Firefox and refresh there we go now we're getting our uh authorization key where really it's more like a middleware uh a middleware is a little higher level than where we currently are but for now think of it sort of like a a bridge that will take us from an initial request to the core of your application and that Bridge has the ability to um really do anything at once but for now that bridge is going to authorize the user so again are you a guest are you signed in uh have you confirmed your email address have you blah blah blah it doesn't matter what it is the key point though is that bridge will check the user inspect the user and then respond however is appropriate for the application that's what I mean it's a bridge to the core of your application okay so in this case I need to associate uh this middleware which we're calling what did we call it guest yeah I need to associate that middleware with the most recently added route because if you think about it here we registered a route and then we called only so if I switch back it's sort of like I need to say okay well go grab the most recently appended route here and then we need to associate this middleware with it okay so let's do this why don't we say by default every route has a middleware but it's set to null there is no um there is no middleware by default for this application however if we call only we will change that so what we could do and what we basically want to do is grab the r array figure out whatever the last item is within it and then update its middleware key to be equal to what whatever uh the key that I passed in is okay so now how do we grab the last item uh there's a bunch of ways um and in in recent versions of PHP we could say what is it array key last this will give me the key for the last item within uh the routes array there's really a bunch of ways to do it there might even be a newer way in phpa to make that a little easier but I think this will work for now okay so I think that should do the trick why don't we finish up by dying and dumping the full routes array to confirm that this works so if I come back and give this a refresh H where's register there we go so here's our endpoint and notice that it now has the guest middleware associated with it so if I go back to rounds and we come up here where I said well let's say only uh off only authenticated users come back refresh and there we go so slash notes now has an off middleware key associated with it okay perfect so now the next step let's get rid of that and return this so that we could potentially uh chain further the next step is well when we figure out what the corresponding route is we need to apply that middleware so let's do this when we try to match a r we check well does the URI and does the uh method match up if so then right here let's apply the middleware okay and I'm going to do this in long form and then we will condense it so yeah we might say something like well if the route middleware equals guest then let's think about it what do we need to do in this case well we need to say well let's confirm that you are a guest or we could say well if session user and again we'll just default that to false uh but if there is a user then you are not allowed to be here so once again we would redirect you so notice I'm taking that exact logic we wrote before and I'm just throwing it in here at least for now we'll clean this up in a moment and then I will exit or die and yeah let's give it a oh actually real quick real quick we have to go back and remove that old code that we wrote before okay but yeah switch back and give it a shot so I'm on the homepage we visit SL register cross your fingers and yes sure enough it does work it redirects us to the homepage because again we're signed in and we have no reason to access that page yeah just don't forget if we didn't apply the guest middleware then you can access it/ register and yeah now you can see the reason for things like this okay let's bring it back and now Implement uh what's effectively the opposite so to access the notes endpoint you have to be signed in okay so let's do this let's open up I don't yet have a log out method uh we will tackle that I think in the next episode when we build a login form for now I'm just going to manually delete the cookie which will remove that reference okay so now if I visit the notes endpoint yeah even though I'm not signed in I'm able to access a members only section of the web website okay so let's fix that we will come back to our router and yeah again this is a little sloppy I'm going to clean it up at the end of the video but I could duplicate this and say well if the route middleware is off then we basically want to do uh the opposite so our check in this case would be uh well if there is not a user in the session and again we will assume that's false in that case we will once again redirect you we should probably uh update the status code as well but for now it's okay so let's come back and give it a refresh and there we go we no longer can access the notes endpoint because we aren't signed in but if we do uh well let's register some brand new person all right now we try to access it as a member and it works exactly uh what we would expect here okay but now as you can imagine this gets pretty sloppy pretty quickly so instead what if uh the handlers for each of these uh middleware could be stored within their own file all right let's give that a shot why don't we to start H where could we put this let's just put it in core for now let's add a directory called middleware and one of them will be a class called o this is our o middleware all right and what's our name space here it's core middleware all right let's duplicate it and then we'll have another one for guest or or again you can name these whatever you want if you want it to be guest only that can be your class remember there there's no rules here name it whatever you want okay uh so H how should we do this each of these will have a handle method so notice how I'm updating each one that sort of means they're conforming to a similar contract and that contract states that each of them provides a handle method that can be called to determine and evaluate whether uh the request can further continue to the core of your application Okay cool so let's do this let's open up a split return to my router and in my off check I'm going to grab that cut it and move it in here so I'm just moving I'm extracting this logic into a dedicated file like so all right next let's go into guest and I'll do the exact same thing right uh here okay so now incrementally what I could do is say well if we have a guest middleware then let's instantiate that guest class uh and then call a handle method on it yep and then we'll do the exact same thing here new off middleware and then call handle so if I come back and we try this again yes I'm signed in I can access the notes endpoint but I cannot access the register endpoint all of that is working just the same okay but next again as you can imagine if we later add some middleware I don't know to access this route you have to confirm your email address or something like that so maybe we'll say uh email confirmed or something like that and that would hit a confirmed email middleware again just notice how every time I add a new routes I have to return to the router do a check uh it's just not necessary I guess is what I'm saying so instead what if we could simplify this a little bit H it sounds like if you think about it we're associating a key with a corresponding middleware class so the guest key points to the guest class the oth key points to the class so why don't we set up some kind of lookup table here's what I'll do I'm going to add sort of like a parent class called middleware and what I'll do here is create like a map so I'll call it map even and we'll say guest points to guest and O points to off all right let's see how that would work now we'll go back to our router and now let's comment all of this and replace it with our middleware class and do note whenever I type that in PHP storm it's going to import it at the top just so you don't get confused uh but yeah I could say middleware map and I will pass through the route uh middleware all right so are we on the same page What's Happening Here we are referencing this constant we are passing through whatever the key was so if it's guessed that's going to return a path to this corresponding class uh if this is instead you know if this is evaluates to off then it's going to return this class path okay so now think about it I have our middleware here which is now uh guessed or off at the moment let's instantiate it or we could even resolve it out of the container that we built if we expand that just a little bit and that would be cool but for now we will instantiate it and and then call a handle method yeah so this is a more Dynamic automated way to handle what we were manually writing over and over again okay so let's check it come back give it a refresh and oh oh we're getting too cocky here undefined array key on line 61 oh you know what I think that is it's probably because most of the time this is null so maybe we should instead say well if we have a middleware registered for this route only on that condition should we do this and I can get rid of that commented code yeah maybe that'll work let's come back give it a refresh and it does okay so once again I'm signed in which means I can no longer access this register endpoint that works as well and what's even better is now down the line once I add more middleware it's a lot easier I don't have to return to that router class which is always a good thing I can instead write new code maybe we call it confirmed that will be something like email confirmed class and yeah I add new code and I can instantly start referencing that within my routes file so for example I don't have any appropriate place here maybe if there's like a forum and to access the Forum you have to have confirmed your email address or something like that um that would be one way to go okay great so really this wasn't that much effort and it's pretty flexible when you think about it so now let's just do one more thing if I come back to my router I'd like to do just a little bit of cleanup um this is fine but what if we had some kind of method like resolve right on the middleware class so that would accept the key and I'm just sort of tucking away some of this logic move it here and I could say static uh which is just late static binding it's it's the current instance look in the map constant uh which can be public is probably fine uh and then look for this key that will give us a class path and then we call handle on it okay but I still have a couple alarm bells that we need to address but we'll tackle it in just a minute so let's say middleware resolve route middleware cool that now hits this method and the first check will be well if we don't have a key at all then there's nothing to do here so maybe we can just return early next we find the corresponding uh middleware class and we call a handle method on it okay so a couple more issues but let's make sure this is still working incremental refactors yeah I'm signed in I try to access register and uh it disallows it great but yeah think about it what about now if I were to reference let's just update this to be Fubar some kind of middleware key that we don't know anything about let's see what would happen access SL register and we get a fatal error as you would expect of course undefined array key Fubar and then also class name must be a valid object or a string so what's happening here is uh middleware is equal to let's just have a look null so we're trying to call handle on null which we can't do so let's do this let's say if we don't have a corresponding middleware then that's exceptional Behavior we don't know what you're trying to do here so I will throw an exception that says uh no matching middleware found for key and then we will add the key here and then let's add a period and then let's just merge all of this into string interpolation and maybe even wrap the key within quotes and then let's see what am I missing a brace reformat and yeah I think that'll do the trick so now if I switch back to Firefox and refresh we still have that warning I will deal with that but yeah now notice the error is no matching middleware found for key foar and this is what we would want you're trying to reference a middleware key that our application knows nothing about so it is appropriate to uh to throw an exception as we've done here okay finally let's just update line 18 and yeah right here uh we're trying to reference again a key that doesn't exist off of this array so why don't we say if there's no coresponding uh key in that array then we can set middleware to false that would then uh trigger this logic here where we do throw an exception and yeah I think that should do the trick and yeah again this exception here is exactly what we would want in this situation okay so now I can go back to our R file and I can fix the issue and then if I go into the router itself yeah this ends up being just a little bit cleaner I think uh once we find a coresponding route we then pass any middleware that might be set on that route to this resolve method and that will figure out okay do we have a corresponding middleware class if we don't then let's abort otherwise uh instantiate it and then call the corresponding logic yeah so just a little bit of work there but trust me things like this will be incredibly useful for all of the applications you build all right welcome back everybody so at this point we have a functioning registration system and also a a very simplified route middleware implementation that we worked on in the last video so now I'd like to build the login form but actually real quick before we get to that I think we need to return to the concept of uh password security and hashing so let's get going now I've cleared out our users table so why don't we once again register Joe joe.com all right and yeah at the moment the only feedback I have that we are signed in is this uh this stock photo that we've seen the whole series uh but sure enough if I switch to table plus and refresh yeah I can see that Joe has an account so why don't we do this uh back to Firefox why don't we add just a little more feedback uh maybe the homepage says hello and then the person's name or in this case their email address all right that's easy enough scroll down to the home View and uh excuse me I will have it say hello and then let's look in the session for our user and then grab their email address otherwise if we don't have a signed in user we can default to guest okay and I think that should do the trick now we see hello jojo.com okay great so yeah now if I switch back to table plus once again all right and yeah here we can see that we're storing Joe's password in clear text and I know I've mentioned this a couple times but I'm going to do it again never ever ever ever ever ever ever ever ever 10 times never store uh passwords and clear text it's a horrible practice and a significant security concern I mean think about it how many times in the last half decade have you read about a big company experiencing some kind of database breech right well when that happens the attackers gain access to a users table that includes your email address and your act ual password that they can then use for I don't know financial institutions to sign into your Facebook account whatever they want to do there it is a horrible practice so we need to fix this right now I'm going to delete that account entirely and I'll switch back to PHP storm and let's do this let's go into our registration controller store so this is where we submit the form and yeah if we scroll down we validate still a little messy here we need to clean it up a little later uh but yeah right down here I even added a little note in the source code never store so I'm going to say it 11 times it seems all right so it sounds like when I insert the user's password into the database I need to Hash it and luckily PHP makes this pretty darn easy I can wrap this in a call to password hash and if I click through here to the signature yeah so we're going to provide it as the first argument the user's password and then as the second argument uh which algorithm which password hatching algorithm we want to use uh at the time of this recording uh you don't even need to know what it is but it's called bcrypt and it's incredibly secure so it also happens to be the default so as the second argument we can reference a constant of password bcrypt or again if we did password default uh at the time of this recording that default is bcrypt so uh just keep in mind if you choose this option maybe in 5 years it will change so if you want to force bcrypt uh you can use it like this otherwise you can stick with the default all right I know I want bcrypt so I will choose that algorithm and this is really all we need to do let's give it another shot uh refresh one more time this is so annoying but I have to delete the cookie which removes the reference to the session so that when I refresh we start from scratch and yeah now let's reference or or register Joe 2 I'll provide a password all right let's give it a shot back to table plus and refresh and yeah this is what I want to see not your actual password stored and clear text but instead a hash of that password and yeah now in the future if your database is breached well yeah they will gain access to your email address but that password even if they want to crack it it's going to be incredibly difficult and time consuming uh if not impossible though never say never very very very very 10 times very uh difficult to crack the password and yeah as a rule of thumb this should be how you deal with passwords for every user registration system you ever build for your entire career all right so let's see we have user accounts we have a registration system we now have password hashing I think it's finally time to build the login form okay so if I go to table plus we have this account from the last episode joejoe.com but right now Joe's not signed in okay so let's add a login link to the nav bar all right let's go let's go into nav and let's look for that register all right let's see all right so if we have a logged in user we display their Avatar otherwise a register link and actually on that note let's scroll up uh I want the in to be the same as what you see here so maybe I can grab this and then update this right now so the HF or herf goes to register and then we can update the styling all right and again just keep in mind because this is a simple static HTML website there's a lot of duplication when it comes to the HTML and the Tailwind classes just keep in mind in real life there are ways to componentize these things so that you're not repeating the same Styles over and over and over it's it's just not relevant to what we're learning here and and we're not yet ready to learn how to create components for things like that yeah just keep in mind in real life that won't be a problem okay so there's our link and then we can update it to register okay so now hopefully if I add a second one for login and maybe that will hit a login endpoint that we haven't yet created yeah hopefully the spacing is okay good I'm happy with that all right so now register to register new account or login to sign in okay but right now of course we get a 404 because we haven't yet set up a route all right so I'm going to go into my routes file and I'll put it right down here if I visit SL login that will hit a uh controllers and what's the endpoint um how about sessions create how about that and then once again we can use our middleware here and actually on this note we added a couple middleware two episodes ago but I I I probably behind the scenes need to go over all of these routes to apply the necessary middleware okay but yeah we'll get to that eventually so now listen for a request login and if you're a guest we should load a sessions SLC create controller so I'll do that now sessions SLC create. PHP and as we often do we'll say login all right let's give it a shot refresh and there we go it works okay so now as we've done before I'm going to load a view uh we'll say session slre view.php all right let's create the view and once again like we talked about I'm going to duplicate a bit more but that's fine and paste in the registration form here okay so if I come back and refresh let's go to login and it looks the same uh but now we can tweak it however we need to log in see how that is is that the button yeah next let's update uh The Heading H register there we go login good uh you have to give us your email address as well as your password then you click the button okay so now if I scroll up where should the form send us well it should make a post request to sessions again if we're following sort of a restful practice uh sessions is our resource so create uh display a form to create a new session and then if we post to that endpoint uh that should well store a new session at least that's one way to think of it another option is if you just want to keep it simple post a SL login and that would be fine too whatever you want all right let's go back to my rout section and now listen for a post request to SL login uh and that will hit our store action okay once again come on up it's getting a little easier now that we understand how this works and I'll say submit the form all right come back log in Joe and oh that didn't work maybe I need to refresh all right login Joe hm it's not working what did I do wrong listen for a post requ oh yeah yeah of course um we have sessions okay so one more time there we go okay so let's come on oh and by the way if you're wondering why I didn't do session slre you can that would be fine in this case login is just an alias uh but yeah you could also have a redirect um from SL login to SL session SLC create again it's just you're in charge you can do whatever you want here there's no there's no requirements there's just guidelines that that maybe you should follow if you want and if you're on a team it's good if you all adopt the same system but otherwise there's very few rules when it comes to this stuff okay so let's come up into our controller and now log in the user if the credentials match okay so the first thing I want to do is figure out what it means to log in now you'll remember when a user registers well we do log them in so remember what we have here we validate the form and then right here uh this creates the new user account and then right here this is basically what it means to log them in we add this user key to the session okay so with that in mind a first refactor might be uh well let's store that within a function called login okay and we can go into core let's add a new function here uh later we will probably extract the class but yeah for now when I'm not sure what I'm doing sometimes it's fine just just create a function a simple old function and we'll paste that in okay so now maybe you'll give us uh and a a user which could be an array and then we will update it like so okay so now actually you know what why don't we H how do we do this why don't we only put the user's email so we'll do something like that yeah okay so now if I switch back we can log in uh a user is that right yeah so I'm doing that because maybe at some point you could say log in this user uh array and maybe that has lots of attributes on it like a password uh timestamps and things like that well I don't want all of that to be put into the session so for now I'm just putting the email address there and uh and that's it okay so now I have this function that I can also call from my login form so let's go to sessionstore and yeah I know if the credentials match I can call this login uh function and provide our uh user object so I know it's going to be something like this okay let's begin so to sign in if I switch back very similar you have to give us your email address and your password so you'll notice that I can reuse a little bit of this all right and then I also actually I need my database so I will grab all three of those and I will paste them in all right let's import that as well as my database all right next once again uh we need a little bit of validation here okay so validate that you gave us an email and then also validate that you gave us a password but in this case I don't care about any minimum all I care about is whether it matches up with what we have stored in the uh within the database so we'll do something like that okay then I can say if it's not empty then once again let's send them back to the login form so return view session SLC create and then what also we need to send through the errors so assuming that validation passes what's our next step Well Log in the user if the credentials match so now we need to check uh match the credentials all right so it sounds like we need to uh use our database object to perform a new query and we might write something like this select star from the users table where the email address equals the email email that was provided uh through the login form and then I'll pass that in here okay so you know what I've already forgotten what my API is so we have find or find or fail let's do find like so all right so we're doing this incrementally let's die and dump the user and have a look uh we log in Joe and yeah we did find a corresponding record in the database however if I switch back and we try to find some account that doesn't exist in the database and we log them in uh we get false which is what we'd want all right so we might say if uh if there's not a user found well think about it we need to uh reload The View and then send through an error and the message can be no matching account found for that email address okay let's give it a shot refresh try to log in jod or J and uh there we go no matching account found for that email address okay so what's the next step if we reach this point we have a user but we don't know if the uh password provided matches what we have in the database right all right so how do we do that well it's not as simple as just saying uh if user password equals the password that was provided from the form because of course the password from the form is the real password and the password in the database is the uh the password that we hashed using uh the the bcrypt algorithm okay so again PHP makes this pretty easy for us all right so we can use password verify and notice if I command click through uh you can see we want to give it the user's password and then the second argument is the hashed version and then it return returns a Boolean that indicates whether the two uh match okay so the user's password followed by the hashed password from the database and if that's verified then we're all set to go we can log the user in like this and then we should probably um redirect them okay otherwise and here's a quick little tip I could do else for otherwise but in this case I returned or exit did early which means the else statement is a little Superfluous I don't need to do it so I can just do this down here uh otherwise the um the valid the password validation failed in which case yet again I can grab this all right return the view and we'll say no matching account for that email address and password all right so I think this should do it it's a little bit messy we have room to clean this up I don't like that I keep returning this view over and over and there are ways to deal with that but nonetheless in terms of the long form transaction script here's what needs to be done uh this is mostly it okay let's give it a shot and let's first log in an account that doesn't exist that fails okay next let's try an account that does exist but has an incorrect password and that also fails finally let's use his actual password which is password l in and there we go everything works we can see the cookie was created the session file was created and we do see hello jojo.com all right let's switch back and see if there's any quick refactors we can do here uh right here one thing I think we can do is there's no reason to return this view two times why don't we instead get rid of this and say all right well if we found a corresponding user only on that condition should we move on and perform this next check otherwise if there was no user or if there was a user but the password verification failed in both of those cases we will hit this point uh where we you let them know no matching account found and this gets us around or it allows us to skirt around the issue of uh letting the user check if there are certain email addresses in our database now unless both of them match the email address and the password we just let you know hey couldn't find anything uh try again all right so that's a that's a simple little refactor that removes some indentation and generally when it comes to cleaning up code I'm often thinking about just the little things not these drastic changes not not big architecture changes but Small Things how can I get rid of this indentation how can I make this El statement redundant how can I uh wrap this up so that the the code is just a little more clear and that's why I I tell you with the validation this kind of sends up a bell for it rings a bell for me there's just a little too much going on here and instead is there a way to wrap it up or encapsulate it a little bit so that it's it's easier to work with so again that's just a little aside when it comes to refactoring but those are the things that I want you to be thinking about for your own projects okay I think that's fine for now so at this point we're signed in to wrap up this lesson why don't we add a logout link and then we'll be done okay so let's go back to our our nav partial all right so let's see if you're signed in this shouldn't be an anchor tag uh we'll talk about that in a minute it should be a form but I just want to see if the styling is okay no that's not right all right so tell you what if you want uh fast forward about one minute or you can come along as I debug a little Tailwind so looks like yeah so relative ml3 okay I wonder can I do another one like that and then put this in here yeah okay and then I'd have to do another wrapper so yeah we might want to restructure things a little bit if session user false then close it out I'm being kind of quick and dirty with this template because it doesn't really matter for for the subject material but yeah I think that would be okay all right so anyways if I switch back yeah I noted that you probably shouldn't use an anchor tag for your logout links and I say probably because honestly in the wild you'll find hundreds and hundreds of examples where people do this very thing but generally uh many episodes we talked about item potency uh and that would apply here when I click on this we are changing things we are adjusting the user we are logging them out we're changing the session so I really shouldn't use a get request uh in that scenario instead why don't we use a form uh that will submit well let's think about it if you want to destroy a user's current session should that be a get request no we just established should it be a post request well technically it has to be one but what do we really want we want a delete request so why don't we um create a new hidden input uh and as we learned many uh episodes ago we can set the name and did we call call it method I think that's right and this is our way to instruct our server the how we actually want it to treat uh this request in terms of routing to the proper controller okay so then I can say uh we'll have a button here and this will be uh log out all right and then that will hit um sessions or really you know what maybe I should just make it singular make a delete request to slash session okay so let's come back and give it a refresh and we got to fix our colors text white all right and now when I click on it it's still going to fail uh because we haven't yet set up the proper route all right that's our next step let's go to our routes file and a couple things uh first I decided I want this to be singular update that and then within here uh update the name or you can keep it plural if you want just like that and I think that should update all of the references okay great so anyways if I come back to my routes file we're now going to listen for a delete request to slash session and that will hit a destroy action okay but now think about it what should the middleware Y in this case in order to respond and log the user out they of course first need to be logged in right so why don't we set the middleware to be uh off and yeah again behind the scenes I would need to update all of these uh to add the the relevant middleware we just haven't we haven't done that yet all right so let's go ahead and create our destroy action and then I'll I think we'll be done at that point all right log the user out all right so think about it what needs to be done in this case well at the point we hit the script we know that we have a signed in user because of the middleware so all we would really need to do is uh destroy the session maybe clear out the session file maybe delete the cookie uh and then finally just redirect the the user right so at the end we'd know we would redirect them to a goodbye page and exit and then the first step would be something like this like let's clear out our session super Global uh what else what about the session file that's stored on the server well we can call a PHP function called session destroy destroys all data registered to a session so we want that as well uh but now a lot of people stick with just this but we should also probably clear out the cookie that exists in the browser and expiring a cookie is always a little weird in my opinion what you have to do there's no easy way to just delete it you would have to update the cookie and set its uh corresponding expiration so I show you how to do that we're going to set a cookie and if we click through here yeah so when we set a cookie we need to give it the name of the cookie uh an optional value of the cookie when it expires so you could create a cookie and say well this should expire in an hour uh or at the end of the user session or we could put it in the past which means expire it instantly uh which is what we want in this case but then also it's a good practice to provide the path uh where the cookie is available and then also the corresponding domain so to do that we have to write a little bit of extra code but it's not too bad and you only write it once so what is the name of the cookie well we've been playing around with this haven't we if I go into storage that's the name of the cookie PHP session ID all right the value can just be an empty string uh next the I don't do this too often next when it expires yeah let's just set it to some point in the past so you'll often see things like this like time minus 3600 3600 is an hour it doesn't have to be an hour it could be 7200 UH 60 seconds in a minute 60 minutes in an hour is how you get 3600 you're just setting it to some point in the past all right next I said the final arguments are the path uh where the cookie is and the domain so to grab that there's this extra function called session get cookie prams and you once again if I click through here I know this is kind of nitty-gritty stuff but again it's like you only do it once or you use a framework where they handle it for you so don't worry too much about all of this stuff uh it returns an array with the current session cookie information including the path and including the domain all right let's grab our Rams and then pass through the path and the domain and yeah I think that should do it is there anything else they want me to add uh secure false uh none of this would apply uh in our case but again if you want all of that would be included in the prams and you can just keep passing that through in fact let's just do it um to be extra safe but it's probably okay to Omit that in this case all right so yeah kind of a bunch of uh lower level steps we need to follow to log a user out you clear out the super Global just so it's not referenced anywhere else uh in in in the nearby in the script you destroy the session file you delete the cookie so once again I don't like writing this over and over so let's wrap it up and we'll call it of course log out and yet again because we we don't have a dedicated class for it just yet we're just going to throw it in here until we know what to do it with it and I'll paste all of that ugly stuff in all right so if I switch out when we hit this inpoint we log the user out and then we redirect them and hopefully uh that should be everything we need and actually the only other thing I'll tell you is often when you log in a user uh as a good practice people would recommend that you regenerate the session ID so we learned about the the session file that gets saved uh to the server and that has a unique ID it might be good for security purposes uh to to regenerate that ID and update the cookie and the session file name as part of your login just in case a malicious user has that key and is doing something with it you never know uh so it's a good practice so we could say session uh what is it regenerate ID again I tell you these are lower level things you you don't do too often so it doesn't have to be on the tip of your tongue is what I mean and then if we click through there update the current session with a newly generated one and then you can pass in a Boolean uh that indicates whether we should clear out the old session file or not and again uh excuse me if I switch back again as a good practice let's say yes yeah that's that's the minimum of what we need to do for log in and log out all right crush your fingers and let's see if we got this to work uh so we're on the homepage we click log out that empties out the super Global uh the session super Global it deletes the cookie it deletes the session file and then finally it redirects us back home and says hello guest you're signed out okay great so now if I log in again and oh warning uh looks like we have a lingering plural session let's go into the routes file there it is clear that out let's go into that controller session SL create yeah that's right and then within that view excuse me S SL create are we loading form session yeah okay I think that's all the references so if I come back and refresh yeah now that works I can log Joe in we have validation looks like I can't type there we go now we're signed in uh we can we can access pages that are exclusive to logged in users and then we're done uh when we're done we can log out okay last thing I promise I'll let you go notice this notes link is still available uh it doesn't work because of the middleware but maybe we shouldn't even display it if you're not signed in let's do that and then I promise I'm going to let you go let's go to notes and yeah right here once again I could say if session user False only on that condition do we display that particular link come back refresh and now I'm happy all right great job thanks so much for coming along okay welcome back everybody so in this episode I would love to return to the concept and practice of refactoring because uh look here's the deal all of us go through multiple phases in our programming career in phase one which is what we've sort of been at uh all of these episodes in this series you are most focused on uh to be frank figuring out what the hell you're doing and getting it to work so that when I click refresh uh in the browser it actually works that is top priority in this phas but of course once you move on from that you realize it's not just enough to get it to work there are other things to consider like Clarity like readability like um can I extract this to another project if I needed to or if I handed this code or I showed this code to Joe or Sarah over here would they understand my intentions and then of course there there's also a really nice element of of creativity does this reflect my creativity do I want to code it this way or do I want to code it that way and sometimes one is not necessarily better than the other it comes down to to your approach and how you want to uh communicate some of these Concepts uh to your future self and of course uh others who might be on your team okay so with that in mind let's return to one of our controllers I will go into controllers sessions and store okay so this is the code that we wrote in the previous episode and it handles the process of validating the form and then attempting all of this it's not very clear but if I break it down we are attempting to log the user in uh and redirect them and if we were unable to do that then we return to that login page okay so yeah right now we're at Phase One it works but it's not very clear uh it takes me some time to break down what's going on here and I'd really like to fix that I would like to assign some names to these Concepts that I'm referring to all right so why don't we begin H why don't we begin with this validation we've dealt with this approach for too long and I think it's time to fix it so again let's just speak it this is how I like to begin my refactor I just say out loud even if I'm by myself in my office as I am right now I say it out loud so what does this code do well it handles validation for a login form login form hm uh why don't we create a class called login form that can be responsible for handling validation all right let's give that a shot now the next question I have is where do I put this where do I put login form class does it go in controllers well no it's not a controller does it go in core well I guess it could but here's what I'm noticing the core directory is almost like for the core of my application the the sort of functionality that ideally I could reuse across all of my projects or in other words the these core files are not necessarily maybe excluding functions which we should extract but yeah otherwise uh this core functionality isn't necessarily unique to this particular application it's like infrastructure code validation routing interacting with a database uh having a container you know things like that so if I were to put you know for example a forms directory in here well those form classes are very much unique to this one application and it just feels a little bit off right so with that in mind H maybe once again we should restructure things and yeah this is if if you're annoyed by this where if you're thinking he keeps changing it I'm doing it on purpose because this is the reality of programming you try it this way and then you think yeah that's not right why don't we change it why don't we move this over here maybe it would make maybe it would make more sense if this was not part of that but instead part of this this is the reality and the the practice of being a programmer so with that in mind why don't we store anything related to our application within this HTTP directory this is the HTTP entry Point uh into our application so from that perspective things like forms make perfect sense but then further even things like our controllers could go in there as well so why don't I move that like so but of course you can't just do that so if I try to load this in the browser of course it immediately fails we get a warning oh I tried to find this controller but it was nowhere to be found okay let's just take a quick moment and see if we can fix that first St I will go into my routes file and yeah right now we are providing a full path to the controller directory uh but you know what do I need like notice every single route a controller is within this directory so maybe I can have a convention that all controllers just go in that controllers directory we don't need to be explicit so with that in mind I'm going to use multiple cursors to select every uh instance of that string and remove it now we just have something like this when you visit the homeage page load this controller and our application just knows where to find that controller okay but of course it's still not going to work so if I come back well same problem we're trying to find it uh in the root of your project but it wasn't there and of course that is correct okay let's go into my router and then right here is where we require the corresponding controller so um this is a little bit app specific maybe but I think it's fine so why don't we go into the the base path into that new HTTP folder into controllers and then try to find the corresponding controller so yeah if I come back into routes you can see if we have about that PHP the router is actually if I switch back going to look in HTTP controllers about that PHP okay so cross your fingers does it work please it doesn't work let's see what the problem is what did I do wrong uh in the rout HTTP controllers no such f or directory all right let's figure it out so we have oh I'm sorry you saw me do this controllers goes in HTTP dis dis all right come back give it a refresh and there we go uh good that was close call but we got it working okay so that makes me feel a little better now I have a dedicated place and I I've separated things that are unique to my application um I've separated that from core infrastructure framework uh code which I like I think that I think that's a good way to go all right so now let's create our first form and you'll remember I said uh we want a form class to handle a login form and validation and everything that goes along with that so why why don't we say login form keep it simple okay but now I think my name space is incorrect this should actually be HTTP forms login form okay so next I said it's going to hand validation so why don't we have a method like validate and yeah let's just see how we might interact with this if I go back into sessions store yeah this is all the code that sort of needs to move there so why don't we just uh well let's comment it out for now and let's see instead we would instantiate login form and that gets imported at the top just to make sure we are clear so we'll have our form and then we want to call form validate on it but immediately as I write this I can see well I need to provide the attributes right so I could either provide an array of attributes or I could pass them in individually and we just have to decide what approach do we want to take um I think I would probably do some kind of attributes thing but for now just to keep it uh as one to one as possible why don't we pass them in individually like this email password okay so I'm just going to go back and forth this is the refactoring process introduce something new try to interact with it go back and forth this accepts the email and uh excuse me and the password and then I switch back all right what next well that code would then need to run most of this all right let's paste it in uh uncomment reformat uh import any missing classes all right so how's this looking we call validate and then we run validation but then right here notice this login form is going to return a view and maybe you're okay with that but this is where we get into discussions around what is the responsibility of this class um maybe this particular class should not be responsible for doing that particular thing or maybe it should and again this is where it comes back to creativity uh what allows for the most flexibility um there's a number of decisions that go into or a number of of considerations that go into uh even simple decisions like this so in my mind I I'm not sure I want a validate method on a form class to load a view I don't think that's quite right so I'm going to get rid of it and instead I just want it to be simple it's going to validate uh given attributes uh and then return errors maybe but really if I come back uh excuse me let's go into our controller I almost feel like form validate should just return a Boolean did it validate or did it not but right now it's just returning an array that could be populated or could be not so instead why don't we just return whether or not the array is empty so if it's empty it validated right because there are no validation errors it's empty uh if it's not empty then that would be falsy of course of course or false uh which means uh the form did not validate okay I like that so now I could say well if the form did not validate then this is where this code could go so I will paste that in and uncomment if the form did not validate let's return uh that login form and pass through the errors but now where are the errors well of course they are locked inside of this validate method okay so what if instead we have a property called errors something like this and then I can get rid of this and simply write to that property like so okay okay well notice I've made this protected and we've talked a little bit about visibility right this means well this property is protected uh from the outside world they don't need to interact with it but often they do need to at least access it so in this case it'd be nice if I could grab the errors from the outside a couple options are to make this public and just say yeah if if you need it fine uh some people would squawk at that because they'd say well then from the outside you could you could manipulate errors into a state or configuration that isn't quite right there's lots of reasons to consider making it protected and then adding what's known as uh a getter and that a getter is just a method that gets something return this errors but now it's almost like I have a hook by calling this method I have a hook to potentially change things maybe other things need to be involved before I return the errors and now I have a place to do that versus interacting with that property directly but as always it just sort of depends okay so now that I have an errors method I can just say form errors if the form did not validate then return that login form uh and pass through the errors notice how this is adding more clarity versus what we had before where this is very procedural I'm building up an array and then I'm writing to that array and I'm doing all of these uh validation specific checks overall though that condenses to validating the login form so I like this okay so if we did everything correctly I can get rid of that and I think we've just had our first refactor let's see if it works I will go to login and let's fail the validation and actually let's just force it um for the password you'll remember we allow a minimum and a maximum number of characters so why don't we just temporarily say a maximum is five characters which is not right but it gives me a way to instantly fail the validation so we run it and we redirect back and we include the validation method everything seems to be working if I now get rid of that and then we use the actual password we're in okay first refactor is complete and I think this is looking pretty good but we still have a lot more to do in this file and we will tackle that in the next episode Cliffhanger all right welcome back as always so yeah in the last episode we took our first refactoring step by extracting a dedicated class that is responsible for validating the login form and already I think this has improved readability a good bit so why don't we keep pulling on that thread a little bit and continue on to the next part of the page and yeah once again I'm going to say out loud in an empty office what this code does and then I I will try to identify the nouns and the verbs all right so this code finds the user and then attempts to log the user in uh otherwise return to the login form and provide a uh a little bit of feedback yes so find the user and attempt to authenticate them that's really what's going on on here okay authenticate I had a verb attempt H maybe we can make this work let's go into my core directory and why don't we add a class called well authenticate is a verb so why don't we make it a noun by saying something like authenticator all right uh next my verb was attempt and what what parameter should I pass to attempt if any I don't know yet let's come back and take this one step at a time so if I I were to comment well let's just uh yeah let's comment all of it out for now and we're going to have this new authenticator class all right I will call that off and I know I'm going to call an attempt method but what am I attempting to do I'm attempting to authenticate and to do that I need credentials like an email address and a password so yeah maybe once again we pass through the email and the password all right so let's accept it here all right and what does attempting uh actually mean well it means basically what we had here so why don't we do this one step at a time switch over paste this in and we start by tracking down the user but yeah right here I don't have that DB class anymore so I could do uh dependency injection but for now why don't we just resolve it out of the container like this because at the moment we're still sort of in the playing Phase as you'll find a lot of programming is really playing around toying around seeing what works seeing what doesn't and sometimes that means you will write code for an hour and then undo all of it in favor of something else and that's totally fine it's just part of the part of the flow okay so we track down the user and then what do we do well right here we say well if you could find a user then uh check if the password matches and call this login function but now this feels a little weird I have this authenticator class that's responsible for authentication but it's deferring to a little helper function we created uh an episode or two ago that doesn't feel right why don't we grab login and log out and bring them into this new class like so okay we'll make them both uh public like so okay so now up here we will defer to our login method and then uh if everything's good we redirect okay again just little baby steps one little change at a time and we will continue tweaking this uh as the episode continues all right so finally what about this code though well you could move it in there but let's talk about this now what I would say is our authenticator is doing too many things at this point now I've introduced a new responsibility and a new piece of knowledge the Authenticator knows how to load a view it knows where the login form is and it knows uh how to pass errors to The View and it also knows what message should be passed this is too many things I feel like the controller should be responsible for returning the view not the authenticator class it's not the responsibility of the authenticator class to do something like that so in that case I don't want that I'm going to keep it here but now of course I need to figure out well under what condition would it make sense to return this View and that condition is if we were unable to log the user in so why don't we say if you could not successfully um log in the user or authenticate on that condition and let's reformat on that condition alone do we return this view okay so that means attempt should return a Boolean so let's see right down here return false but yeah then if I go right up here if we could log the user in the authenticator is redirecting and it's the exact same problem it has too much knowledge it knows what to do uh in the event that authentication passed and that's not quite right the controller should be responsible for that I think so in that situation we return true okay so now my attempt method returns a Boolean that indicates whether or not we could successfully log the user in so if I come up well why don't we do this let's say if we could attempt to log the user in do something otherwise do something else okay and the if is a simple redirect and that's what we end up with here okay but I still see a lot more we can do first up you'll notice throughout the last 10 episodes or so every time I want to redirect I I have to write these two frankly annoying lines of code header location and then I write the path and then I exit uh for security purposes what does that mean though let's just do it again empty office what does this code do it redirects to the homepage okay the verb is redirect I need something called redirect to help with readability so let's just say redirect to the homepage and then make that code work all right let's just add a simple helper function in our little uh Global functions file redirect to a path uh like so and then I can paste in what we had before and then let's do this let's uh replace the quotes and then I can substitute the provided path and yeah that will do the exact same thing cool so now a small little baby step to make the process of redirecting just a little bit clearer very cool so the next thing is and this is sort of a style Choice a lot of programming comes down to style as we've discussed if else that is correct however if we redirect we know that we kill the script we exit which means the else uh portion is a little Superfluous because we would never get to this section uh in the first place some people will keep it though because again they think it makes it Crystal Clear if this otherwise do that or if you want you could remove it like so and to be honest with you sometimes I will do one sometimes I will do the other it just sort of comes down to like what what feels right and for whatever reason uh sometimes it feels right to do it this way and another time it feels right to do it that way it's sort of like if you ever have to go somewhere in town you might take one route in your car to get there and for whatever reason you go a different route coming home there's sometimes no real Rhyme or Reason to it it's just what felt right at the time and the same is true for programming as it turns out all right let's read some code 75% of of programming is reading so let's keep reading it over and over until it makes good sense but actually real quick before we do that uh you'll notice that this DB variable is not being used anywhere and that's because of course we extracted that logic to the authenticator so now I can get rid of that and then we also have two more Imports that are no longer necessary and I like what I'm seeing here okay let's read the file so we create a login form and we try to validate the email and the password and if that failed then we have to return to the login form and display the errors otherwise if validation passed then we will attempt to authenticate the user based upon the provided credentials and if we were successful they're now signed in and we can redirect them wherever they need to go otherwise once again we go back to the login form but this time I hardcode the errors okay so I see my next refactor that I'd like to make notice that this and this are very similar but they're still slightly different so have a look this one returns to the login page and passes the errors from the login form this one also returns to the login page but this time we hardcode an email validation message based upon uh that failed authentication attempt okay so yeah this can sometimes be a little tricky so I will I will teach you a pretty cool refactoring strategy that I use all of the time so uh whenever you're in a situation where you have two pieces of code that are mostly the same but slightly different instead see if you can make whatever change is necessary to make those two pieces of code identical I'll show you an example so if I want these two pieces to be identical this code up here needs to be the same code at the bottom okay well how do I make that work though well it sounds like this message here that we were hardcoding would instead need to come from this errors method uh on the form validation class so it sounds like I need a way to append a new validation error to the login form okay well maybe and let's just write it out what would I want to do maybe something like add error or if I can maybe I'll just do error we give the corresponding field and then the message that goes along with it yeah and if we could make that work that would solve the problem wouldn't it then this uh snippet here and this snippet would be identical and once they're identical the whole reason for this is once they're identical we can merge them okay but one step at a time let's go into login form and add a new method called error this will accept the field and the corresponding message okay so let's just update the errors list we pass through the field and the message okay and I think that's it so if I come back that solves a problem all right step two merge them into one so how do we do that well I can get rid of all of this code here and yeah maybe at the top we can we can swap out this form validation why don't we say if the form validated successfully in that case we don't return to the login page but instead continue on to the next uh step of the process which is attempting to log the user in okay but if we could not uh successfully log them in that is the point where we add a new or we manually append to the form errors list so think about it if we make that small adjustment we've now refactored our way out of the duplication which is really cool okay so let's see let's read it again create a login form try to validate the credentials if we were successful attempt to authenticate the user if we were successful redirect otherwise update our errors list and then return to the login page perfect okay what else can we do here are there any other small tiny refactors we can make one thing I see is I only reference this off variable once uh so again this is a style choice but if you like you can automatically inline it or manually inline it if you want uh again it's just a style Choice it's not necessarily better it's it's it's a style thing and in fact if you're not passing Constructor args if you like you can a the opening and closing parentheses and we get something like that yeah not necessarily better in that case just maybe uh closer closer to adopting my my own style uh style guide and yours might be a little different okay what else anything else well once again we have the explicit else statement that's a little redundant because redirecting will already kill the script so in that case I could optionally remove it and then this is what we get and then once again do I use the form in more than one place yes I do so I can't inline that I need to keep it all right let's read it a fifth time we load this page we instantiate a login form we validate the form and then we attempt to authenticate the user and then uh if that was unsuccessful we return to the login page I think this is looking pretty good actually and in fact I think it's looking good enough that we can move on to the next episode all right so let's see welcome back Everybody by the way uh for our next refactor we're still working in the same controller but yeah for this episode I want to point your attention right here where we return a view all right so at first glance you might think well what's the problem with that um well it may make more sense if we break it down when the user visits the login page they provide their credentials they submit the form and that will then hit this controller right all right we we all understand that but now in this example if the form validation fails we return a view and pass through the errors and yeah if we try it out that's exactly what's happening so again you're probably thinking well what's wrong with that Jeffrey uh well there's actually a couple issues I want you to notice that uh the form validation failed but we didn't redirect back to the login page that's not what happened here we didn't perform a redirect there is no 302 uh status code instead we just returned some HTML effectively that's what we did directly from the post request okay so now watch this at the top you know like right here I'm just going to V dump and say um I have been posted all right just come along for the ride so I'm going to submit this form but Force the validation uh to fail here and of course we see that message at the top but now watch this if I click this refresh button I get a little modal here to display this page fire Firefox must send information that will repeat any action so yeah it's basically saying long before you did a post request and if you refresh this page we're still going to perform that very same post request so if I refresh again I see have been posted and I can do this over and over which means with this current implementation we have a risk of effectively um or effectively duplicate form submissions which again is not something we want to to allow the next issue is this if I were to once again submit the form it fails and then I click away and then we think oh let's go back to that login page let's see what happens I come back and no I expected to to return to the login page but instead I see document expired yeah so all of this is a result of our current implementation which is uh in response to a post request simply returning a block of HTML and again that's just something we don't want to do so instead we're going to follow a very very common pattern known as and I'm going to have to break it down what is it p uh for post uh R for redirect and G for get I don't say This Acronym very much what is it prg prg is that right post redirect get it just refers to I'm sorry I should have looked at up before the video it just refers to uh a common approach especially for uh hitting controllers and Performing form validation all right so what that means is uh P for post you're going to make a post request to submit the form and then if in this example the validation fails we don't return uh a view as you see here we perform a redirect that's the r that redirect will send us to a new page where we then perform a get request and that's where the G comes into play so p r g you don't have to memorize it clearly I didn't but you do need to memorize the general uh flow in the general pattern okay so with that in mind we're going to have to tweak some things here because it's not as simple as just saying well return a redirect back to the login page I wish I could do that but now we have this pesky uh issue of how to deal with the errors all right so let's try this out come back to Firefox let's go to the login page fail the form submission and yeah sure enough it does bring us back to that login page and then we've also solved the problem of if you submit the form then you click away and then you press the back button remember before it failed uh now we don't have that problem so All That Remains is to figure out well how how do we deal with errors in this situation and if you remember back a number of episodes ago the whole point of taking this approach was because we weren't quite sure at the time or we hadn't raised our skills uh at that point to to handle this unique situation of how to deal with validation errors because think about it before we were just loading HTML and passing through data but now we are performing a complete 302 redirect so at that point we perform a whole new page refresh and we don't have those errors anymore so how how do we grab it or or in other words how can we literally pass these validation errors on to the next page request and yeah if you're thinking well we learned about sessions can we use sessions for this absolutely we can and that is the standard practice for things like this all right so we got a work cutout for us um let's take this in a few steps first we could do something like this where I say session and create a new uh key called errors and make that equal to the form errors this might be your first uh stab at it okay so then when we redirect to the login page that of course will take us into our HTTP controller sessions create View and yeah right here I could pass through the errors like this by saying uh give me uh the errors key if you have anything otherwise we will uh default to an empty array and yeah this would be an initial very very basic implementation let's see if it works though so I come back to Firefox I fail the validation we perform a redirect we pass through the errors and yeah there we go it seems like it works but this is a pretty naive implementation and here's what I mean watch what happens if I leave and then I come back they're still there let's give it a refresh maybe it'll go away if I refresh and no I can click through the whole site and it seems like the validation errors persist and of course they do if you think about it remember that was the whole point of our authentication system we store details about the user in the session and then it will persist across every page load for the lifetime of the user session and of course the same thing is going to be Tri for these validation errors so yeah it's almost like I want this particular session key the errors to have an expiration date right so yes put the errors in the session perform the redirect load the HTML and then expire that key from the session so that we don't run into this problem where even five or 10 minutes later I return to the login page and I see all of this stale validation data that doesn't apply anymore all right how how could we do that well maybe with a little bit of trickery we can get it to work so let's start by going back to our store controller where we handle the login form submission so hm it's almost like we need a way to distinguish between data that should live in the session indefinitely and then data that should instead be flashed to the session for onepage request and then it immediately expires so to speak so here's what I'm thinking why don't we use a custom key to make this explicit and uh maybe we'll call it something like flashed but you always want to be careful that you don't accidentally interfere with a different key that the user or me uh or I am trying to put into the session so you will often see libraries or Frameworks precede the key with an underscore or even two underscores and again they do that just to remove the possibility of of uh interfering with a key that you provide as part of your application I think one is fine and why don't we call it flash okay so now think about it I could do something like this and now we've made it just a little more explicit we can take it further and we will but yeah a first step towards being more explicit that the errors should be flashed to the session and then immediately uh expired okay so now we redirect the login page we can come back but now the login page needs to know that the errors were flashed right so we would have to do something like this uh to get things working and yeah that would work now now keep in mind of course we haven't solved the problem yet of expiring that session data but yeah everything still works the way it did before so now I need to figure out where do I expire that session data let's see if we come back into our entry point into the application yeah this is a little messy and that's going to be one of our refactors but you can see this is where we route the request so could we route a request and remember that's going to figure out which view to load or which controller to load it will require the controller the controller will load the view that will present the HTML to the user and then we would hit this point so maybe yeah just right here we could clear out any flashed session data and again later we will refactor that and organize things a bit more but for now would that work you think and in that case would we just do something like session uhor flash equals an empty array or even just unset it entirely and if you're not familiar with unset just think of it as delete delete that key from the session super Global array all right would that work well let's give it a shot so once again we'll go to home we'll go back to login I will fail the validation we perform a redirect we Flash the errors to the session and then after again after we loaded this whole page we hit that point so hopefully if I give this a refresh we won't see the errors anymore and yes that's what we want so again now we've solved that problem where for some reason the validation errors just persisted for the whole session which of course we didn't want all right so this is good now I actually want to perform a refactor because at this point notice I had to know what the name of the flash key is and that's not a huge concern and yet still it exists in multiple areas of our application and if at some point we were to for example right here change this uh well then I would have to remember to go back and then update this to flashed and then again with our current implementation what if for another form I don't know like uh notes create maybe right down here we want to flash something like this well I again I would have to manually write that so what I'm saying is the opportunity for these things to become out of sync is pretty high so that tells me I need to consolidate I need to encapsulate just a little bit more okay let's see what we can do in our core directory why don't we add a new class and it's going to be really really simple in fact these are going to be mostly like Global functions they will be static but yeah I will have a class called session that can have some simple helpers for us so for example uh put something in the session we'll call it put you give us a key you give us a value and then we put it in the session and you like I said I'm going to make this stupidly simple uh for the initial implementation so something like this session key equals value done all right so so what else would we need to do with the session well we put things into it we want to take things out of it or get things out of it all right let's do another one get me something from the session you give us the name of the key and we will return session and then the key but then what if the user or we uh pass a key that doesn't exist in that super Global we should handle that and maybe give them the opportunity to provide a default so maybe something like this give me a default and we'll we'll set that to null there is no default but you can overwrite that when you call this method and then I can do something just like this so if the provided key exists in the session return it otherwise if it's null then return the default okay what else put things into the session get things out of the session what about like determine if something is in the session does the session have this key well maybe a method like has has and then the key and we could manually write this but maybe I can just defer to the get method so this is almost like a helper like this so think about it if I return that if the key exists we would return that value if it doesn't exist we would return null so we're dealing with Tru the or faly values why don't I just convert those into a Boolean so now the has method will return true or false depending upon whether the session uh has the given key all right has put get well what about the other thing we talked about where we want to flash something to the session well let's go back into our controller into sessions into store and yeah right here I want to abstract that away that was the the the main motivation for this class in the first place so let's add another one called flash you will give us a key and you will give us a value and I'll paste what we had in earlier for reference Okay so we're going to put it into underscore flashed and then replace this with the key and then make that equal to the value you provide so now we have a function or a method that explicitly um puts something into the session but then marks it as uh being flashed or we we originally called it flash it marks it as something that should only live for a single request okay um that's looking good let's go back here so now I can say session import that and there we go Flash the errors like so okay but now if I come back to publicindex yeah right down here remember we were talking about well you keep repeating the same key uh there's no need to do that let's just call a method on the session class that does the opposite right so like on session and I don't know I might think for a minute what is a good name we had been using expire but maybe even something like unfl flash it to the session you know do the opposite of this maybe that's fine so if I did that um I could say session uncore Flash and then yeah let's unset it cool so now if I come back into our index.php file yeah I no longer or or or this file no longer needs to know what the name of identifier we use to handle flashing session data I can just say session UNF Flash and that'll take care of it and again yeah we might want to take a few moments to think of a better method name uh but for now it's clear enough okay so are we all on the same page let's do a quick recap now when the user visits the login form um they provide their credentials they submit it we validate it and if if validation fails or the authentication attempt fails we now use our handy dandy session flash method to flash the validation errors to the session and then we perform our redirect now when the user redirects to the login page that will hit this controller where we're still manually fetching the errors from the session but yet now I can update this like so session get but yeah now we have another issue if I did this it wouldn't work right think about it if we try this out so it'll redirect back and actually we think it's working but it's not like let's um let's do session equals an empty array and actually what I'm doing here is Flushing the session that's probably another method we should add to that class but yeah if I manually just clear out the session so I can start all over so we try it it redirects back and yeah this time I don't see the validation errors and yeah it makes sense there is no key in the session called errors what's in the session is underscore Flash and within that array is an errors uh key so yeah I again I don't want that to leak out so I don't want to do something like underscore Flash and then even if we added something like this like dot notation well that unique key has once again leaked out of the session class and I don't want that so why don't we just do this uh when you get a key let's first see if you have flashed that key to the session and if you have that very likely is the one you want and if it's not flash to the session then we will fall back and look for it at the top level of the session super Global so for example I could say well if uh session uncore flash key and then I'd have to say well if that is set then that the one you want so yeah this is getting a little Annoying to write but we can refactor it like that and I think that would do the trick so yeah if errors exist within the flashed uh key then that's what we want so return them otherwise see if errors exist in this example see if errors exist at the top level okay fail it and I hope this works and it does okay so now we can perform just a very quick refactor here really it's fine if you want to keep it as it is but if you want to have a little fun you could also just do this I could select all of this and then down here do something along these lines I don't know how that looks to you some people might squawk I kind of like it but again this is a style Choice very much it's not better than what we had before remember one line doesn't immediately mean better than four lines actually often it is not the case but yeah for little simple things like this I don't mind mind it so yeah look in the uh underscore flash key see if you can find something related otherwise fall back to looking at the top level otherwise fall back uh to the provided default I think it's fine so one more time let's check our work there we go I'm pretty happy all right and yeah I think that mostly does the trick so finally uh back in our session class remember we talked about adding a helper method to flush the session entirely let's add that now and maybe that would just set the session super Global to an empty array and yeah then we can make use of that Elsewhere for example you'll remember in our authenticator class right here at the bottom where the user logs out well immediately I see that so I could replace it with session fles but also I see more stuff related to sessions so maybe all of this could move to our session class so in that case well that's not the same as flushing the session all of this code is is destroying the session so maybe I will select all of this and replace it with session and a new method destroy the session and now all of that logic can instead live here if you prefer okay so I will paste all of that in and then we're already in the session class so I can replace that with self or St static and yeah I think it's fine for this code to live here all right so again this is a basic initial implementation everything's static which means they are effectively Global functions but for our current implementation it'll work just fine all right so we'll keep working on this in the next video all right so let's see we've been making pretty good progress on our refactor so now we can return to something that you might have missed notice if I try to log in with phony credentials here yes it redirects back yes we see the validation errors but notice I don't see the old form data all right well you'll remember a number of episodes ago we actually solved this so for example if I go to sessionregistry request we returned HTML so that means or that meant we could then do something like this where we say all right well if there's any email in the post request then display it uh otherwise default to an empty string but yeah of course now well that's not going to work because we're using a new system uh and I've already forgotten the acronym again post redirect get yeah of course at this point when we redirect back there isn't anything in that post super Global so we don't see it all right so it sounds like we need a different system all right let's get back to our controller and yeah here it is so these values need to be remembered when we redirect back to the form H well isn't it the exact same process as what we did for flashing uh validation errors why don't we also Flash the old form data all right let's give it a shot I will say session flash I will call it old which is a really common convention and then I'm only going to send through the email address yeah and you probably noticed this many times there's never a situation where we should manually populate that password input you always have to re-enter it yourself all right so now when I redirect back to the login page there will be this old key within the within the session flash okay let's get it out so we will go back into our login page and yeah let's see what we would have to do here we would have to say something like look in the session and then look I'm going to have to get that flash key again and we talked about not wanting to repeat this key across the entire application but for now I just want to get it to work and then we'll clean it up all right so look in uhor Flash look in Old then look for email and use that value otherwise again default to an empty string all right and I'm sorry let's close that out all right let's give it a shot so we'll come back and give it a fres try to sign in with phony credentials and notice I provided an email and a password but if it redirects back we only repopulate the email field which again is um sorry which again is expected Behavior okay cool yeah I don't I don't like this at all and let's just see if we give it a refresh and yeah that's fine as well we don't end up with any errors due to the way we structured this but yeah it's just cumbersome to write so let's go back into our session class and yeah we do have that get method that will automatically look for the flash key all right so let's come back and switch over to that see if it's any better we have to use the full class path which is core session get old and then look for email otherwise uh if that's null default to an empty string all right a little bit better let's come back give it another try yeah that seems to be fine it repopulates the email I give it a refresh yeah this is expected Behavior but again it's just a little bit cumbersome I hate having to provide the full class path um yeah it's not perfect why don't we tweak this let's grab all of this and I'm going to switch over to my functions file and add a new helper function how about something like uh well again it's a common convention to use this function name uh called old old for example once you graduate to something like laravel larl will have an old function that gives you old form data so that's why we're sticking with that name uh we're going to give it a key and yeah if I were to paste all of this in it would be nice if I could just do something like uh this but notice here we are assuming uh if you couldn't find old form data for this key just return an empty string uh maybe instead you can override that if you want so we will set a default to an empty array but yet if you want to uh when you call this function you can override that default and I'll give you an example of that in a minute okay so now we're just taking a slightly cumbersome line and wrapping it uh within a less cumbersome function okay so now I should be able to say old email and if I come back let's give it a shot we cross our fingers and yeah this is what I want uh so now if I give it a refresh that works and yeah of course if I could override the default we wouldn't want to do that here but just to show you how this is working you can set a custom default value if and when it makes sense so for example sometimes what you want to do is if you have like an existing user you could do something like this we'll get the old email address from the form request and if you couldn't find one default to the current users's email address and yeah now we have the ability to do that but yeah I think this is precisely what we need all right so believe it or not we are still not done refactoring this controller and I can't wait to show you what we're working on next I'll see you then hey everybody all right I'm going to warn you we have a lot to cover in this video some new Concepts some new techniques so yeah with that in mind let's skip the intro entirely and Dive Right In okay so once again we are back within the same controller that handles logging in a user but this time I want to point your attention to all of the form validation crap and I call it crap not because it's bad but just because there's so much here I mean let's think about it I instantiate the form then I call validate and then in the event that validation fails we redirect back but of course as we learned we need some way to also pass the validation errors as well as the old form data along with that redirection and now I want you to think about a real life project and the number of forms uh that you will have for example for L cast there's a form for registration a form for checkout a form for login a form for gift certificates a form for leaving a comment below this video a form for posting to The Forum uh a form for for updating your profile and your account details or adding a team member uh if you have a team account which are $75 a person by the way um it's just a lot of work and think about it with this approach for every single one of those controllers you're going to have a form you're going to call validate and then you're going to have this duplicated code in every single one of those controllers which again is just not ideal all right so hm what if we took a slightly different approach what if we took this form validation and moved it up a level like this and then I got rid of the conditional entirely okay well how would that change things well I instantiate a form I call validate but then I immediately move on to authenticating the user so yeah because we've removed that conditional now if form validation fails we don't really do anything in that case we just ignore it and that's not what we want okay so how could we allow for this approach but still handle uh redirecting back to the form in the case of failed validation hm well maybe we could tweak things a little bit for example maybe we could inline all of this so what if I could just say login form validate all right that would be good but yeah of course right now that's not going to work so let's see if we can make it work if we change this to a static function well this then becomes what we would call um a static Constructor it's just a static entry point uh to instantiate your class okay so if we added a Constructor here and then yeah I would have to accept the email address and the password however you may remember a number of episodes ago I discussed an alternative approach where we uh instead accept an array of attributes why don't we consider that approach instead okay so if we took that approach the validate method would also accept an array of attributes and then maybe all of this validation here could instead move up to the Constructor like so so now whenever you instantiate this form we immediately validate it and populate the errors okay so now this would update to this attribute email and then uh this attributes password cool that's kind of a cool approach so now when we instantiate login form we instantly validate uh any of the attributes that are relevant to the form all right so that means when I call this static Constructor the first thing we would do is instantiate the class okay so now we have a dedicated instance and now yeah maybe we can tweak the API a little bit because before this validate method returned a Boolean but yeah we're changing it up a little bit so maybe instead if validation fails an exception uh would be thrown okay so let's see how do we determine if the validation fails well let's see do we have any method no so we would have to check if we have any errors in this array okay well again we're going to refactor a lot of this but we would start by saying well do we have any errors and if that's true that means validation failed okay so with that in mind maybe we should wrap that up within a helper method something like uh I can think of a few options like has errors that would be a common approach another option would be something like failed did the validation fail okay either one would be fine with me um so yeah we could just grab that and move it down here and then return okay so this failed method returns a Boolean that indicates whether or not uh the form validation failed okay okay nice and clear so let's see we could say well if the form uh the login form validation failed well like I said we might throw an exception okay so you learned how to throw an exception many episodes ago something like this however I'm sensing that we might need to do a little more with this exception and we'll need to pass through a little more as part of this exception so with that in mind why don't we create um a new custom ception class and I'm going to put it right in here as part of the core directory but yeah we're starting to see now we have multiple files and classes related to validation and at that point you might consider creating a dedicated validation directory uh as part of your core folder but yeah for now let's not do that okay so this is uh well what is it it is a form exception form validation exception why don't we stick with how about validation exception all right now if we want this to be a custom exception we need to reach for inheritance this will extend exception now I think we've only very very lightly touched on inheritance in this series uh I promise we will talk about it more but for the time being just think of it like this validation exception is an exception and as part of that it inherits behavior that comes from this parent class and yes that's a way we often think of it this is the child class and whatever it extends then becomes the parent class so now we have this validation exception we'll come back to it and work on it a little more but if I switch back to the login form now I'm not going to throw just a plain old exception I'm going to throw a validation exception all right so next right here what if the form instead is valid what should we do what should we return in that case and yeah this is where we start designing our API how do we want this to feel for example do you want to return true do you want to return the instance itself so that you could further chain and call methods on this class it just depends and at the moment I'm not sure maybe it returns true maybe it returns uh the instance it just depends okay but for now let's stick with the instance and then come back to our controller and take a look all right so now we're calling validate but you'll notice it's squawking here because we should be passing through an array of attributes so let's do that now email is post email and password is post password all right so now it seems a little redundant to declare these variables and then repeat ourselves so maybe I can get rid of that entirely all right but now if we do that well right here we were expecting the email and password so maybe hm what if we just inline assign this to an attributes variable and then here I can pull the email address out and the password out would that be one way to handle it and I think the answer is yes okay next if I come down here well I still wanted access to that form variable and luckily we did return the instance if validation is successful which means I could save this to a variable cult form and yeah that removes the error that we see there there okay so now at this point I would expect you to be thinking all right fine we made these changes but but why what is the benefit to this approach and I'll tell you but first let's test this out in the browser and force the validation to fail okay so with that in mind let's go in here and then just temporarily why don't we say the password has to be at least 100 characters just so I will instantly fail validation all right let's go to log in and then provide a password that will of course uh not meet that validation rule okay and yeah looks like we actually have a few issues that we need to fix first up undefined property on line 14 of login form all right I'm going to go to line 14 and um oh yeah obviously you saw this and you were waiting for me to run into it all right what else do we have here uh if we give it a refresh oh yeah okay it looks like that solved all the problems cascaded and fixed those other issues okay so now we get a validation exception on line 28 and we would expect this because we did throw an exception okay so now the next question is well how do we deal with that well I'm going to show you this in two steps the first option of course is to Simply wrap this within a try catch so try to execute this logic but catch a validation exception and then do whatever you need to so caught it just to show you how this works now if an exception is thrown we will catch it and we can respond however we want okay so that means we could do things like this where if validation fails Flash the errors uh and Flash the old data and yeah here I'll just grab that out attributes email and um and then what well redirect back to the login page like so okay so this doesn't yet handle uh this section right here but again we're just taking this one step at a time all right so now if we come back and reload yeah we get a different warning undefined variable form on line 14 all right let's go to line 14 and yeah it seems like at this point form is undefined and it could be a little confusing because we defined it right up here so what's the problem well the problem is we said create this form variable and make it equal to whatever is returned from this validate method but we never even got to the point where we returned we instead through an exception so yeah at that point where we handle the exception we don't have access to that form variable and just to prove it to you if I die and dump form uh what are we going to get null not what we want okay so now it seems like we need to fetch the errors uh and then potentially the ult form data off of the exception how could we do that hm let's go into our exception class and it's just empty at the moment what if we added another static Constructor and this can be anything you want it could be with errors and old data I don't really like that but yeah whatever you want this static Constructor will be called Throw and that would allow me if I switch back here into login form it would allow me to change this to validation exception thre and then when I call that method I can pass through any extra data that I require this would then do something like uh well very similar to what we had before create a new instance and then throw the instance okay so now this and this implementation are functionally identical cool but next yeah maybe I could pass through the errors as part of this so I could send through and remember I can't call this because I'm in a static method but I do have an instant variable that that that is effectively this so I could say instance and then we have an errors method don't we so why don't we call that method instance errors and then I will accept the errors here okay so why don't we H why don't we assign it we could do protected errors and initialize that to an empty array and then I could say well create a new instance set the errors and then while we're here why don't we also pass through the old form data well how do we get that old form data H let's scroll up and yeah well we have the attributes right there don't we but I don't have a easy access to them why don't we make this uh publicly accessible so I could either do this and then I could Define the attribute right here or in PHP 8 I can Al just do it as part of this so public array I don't think we've covered this because we haven't yet talked about types which is at the very end of the series um but for now I'm going to keep it like this even though I am using a type think of this and what we had before as equivalent so it is a public property but we're also going to give it a type uh and that type is an array and this just means I expect whatever we instantiate this login form with to be an array not a number uh not a string not a function it should be an array and that's what a type is okay and we'll talk about that a little more uh later in the series okay so now my instance has access to the attributes and yeah if you wanted to that means if you if you wanted to take this approach like we had earlier that would still work but this is fine okay so now if I switch back to one split yeah we can pass through uh those attributes instance attributes all right so now if I go into validation exception we will accept them and uh just to be consistent I I will call it old yeah old form data um stale data whatever you want to call it is fine with me okay so now let's assign it old equals uh that array and then I can update it here all right so cool now when the login form throws an exception it will pass through the errors and the old data as part of it all right so now I think we can finally solve our problem if I come back to the controller yeah remember we had that issue before where we don't have access to the form variable from up here because an exception is thrown before we could assign to it uh but yeah now I can grab the errors and the old data off of the validation exception but yeah it's not as simple as just doing this I can't say exception uh errors because and you can see right here errors is marked as protected which means it's protected from being accessed from the outside as we're doing here so you have a couple choices uh one option is just make it public that could be fine uh option number two is to create a getter so this would be a method that simply gets uh your protected value it wraps it up and gets it if you need to do anything before you return the errors now you have a place and a hook to do that uh that would be fine another option would be uh to declare it as public but then you can also say well it's read only which means we can assign to it once and then you can never update this value again and often uh that that solves the problem and the reason why you would create the getter in the first place but yeah we haven't talked about types too much and then read only is brand new so that's why I generally avoided it but there's no reason why you can't use these things in your projects right now okay so if we took that approach why don't we do the same thing for the old data like so all right now they're public but read only so they're assigned to once and then they can never be uh updated or changed all right so let's come back and now the error goes away and we'll do the exact same thing uh with the old form data like so and that solves the problem all right let's cross our fingers and switch back to the browser refresh I will submit the form that will fail the validation and we redirect back okay so it took a lot of trickery and a lot of tweaking and again you still might be thinking but why like is this necessarily better than what we had before and I'd say the answer is well no but we're not done yet what if we graduated this Tri catch up a level so that I don't always have to do it as part of my controller logic hm well once again let's open this in a split and then I'm going to return to publicindex so right here is where we perform our routing it's where we load the controller and we require this file so why don't we perform the tri catch here like this try to route to the controller but catch and what do we want to catch a validation exception we're not going to handle that as part of our entrypoint file okay so let's see we would take all of this and this would move here and let's make sure that's imported if it hasn't already right looks like they have been and then if the tri catch is here it no longer needs to be in the controller and we can return to something like this and then I can get rid of these two uh Imports that are no longer necessary all right let's see does that still work let's come back refresh submit it and yeah it all magically works the way it did before but now this is starting to look a lot better in my mind so I can simply call this validate method with the understanding that if validation fails we will Flash the errors we will Flash the old forign data and we will redirect back okay but notice I didn't say Reda to the login page even though that's appropriate for a login form it's not going to be appropriate for the registration page or the video comment page uh like you see on laracast so that means I can't always always assume that we are redirecting back to the login page okay so it sounds like this needs to be dynamic H well let's do this uh I know what the answer is but I'm going to show you how you can figure out what the answer is let's die and dump the server super Global when an exception is thrown all right submit it and yeah here's everything we have so let's look and find uh and search to see if I can find the previous page all right there's login and yeah it's the only reference and it looks like it has a key of HTTP refer all right why don't we use that all right let's come back get rid of this and I will redirect to server and then HTTP uh refer however I do have this router uh class so could I just tell the router to do that hm let's see let's go into router and yeah maybe I could add a method uh where should we put it I don't know maybe right here and maybe the router can know what the previous URL was okay well if that's the case I can grab this like so and return that value yeah that would be one option maybe the router can perform the redirect itself uh if if that would make sense but for now it's just going to return a string that would allow me to say redirect to the previous this URL okay so with any luck if we come back and try this it's still going to work the way it did before but now uh the process of redirecting back to the previous form is dynamic and we're no longer hardcoding the login U all right so try to route to the controller but catch any validation exceptions that might be thrown and here in a single place not every controller but a single place we can Flash the errors and Flash the old data and then redirect back that's one way that we can solve this problem all right so if I come back to our controller take a look at this it's starting to look pretty good so we begin by validating the form and if we get to this point that means no exception has been thrown so the next step is to attempt to log in the user but now what about this hm we have an issue here so let's work through it let's come back and remove this minimum so that I can I can pass the validation and proceed to the next step and let's just see what happens I'm going to try to sign in Joe with a jibberish password and yeah it redirects back but there's just no feedback here okay well let's think about why if the authentication attempt failed yes we do append to uh the login form errors list as you see here but we've now tweaked things to the point that we only redirect back if the uh validation exception is thrown okay so with that in mind maybe we need a way to manually throw that exception or manually call a method uh that will throw the exception okay H all right well why don't we do this let's add a method and we'll call it throw and then this logic here can move within it and then I can update instance to be this because I have an instance me me here not a static method okay so now if it failed I could say instance throw like so and then at this point these two can be combined I could say return instance failed well in that case throw the exception otherwise throw the instance and that is equivalent okay so now we have a way to perform validation we have a way to manually add an error to the validation errors list and now we have a way to to throw uh the exception okay so now let's switch back to the controller and then write down here if the authenticator failed we append an email to the errors list and let's do this let's return the current instance so that I can continue chaining that would then allow me to say form error throw and then I can get rid of this entirely and in fact why don't we move this onto its own line and this is what we end up with okay and then finally let's do this let's reverse it I often like to do my guard Clauses before the happy path but in this case I'm doing the happy path before what is effectively the guard Clause so why don't we extract all of this into a variable like signed n like so and then I could say well to reproduce what we had before if you were signed in then good let's read correct but let's tweak it let's say if you weren't signed in so I will move this out of it in that case uh append to the form validation errors and then uh manually throw that exception otherwise we can continue on with the happy path and this is what we get and then and this is just a style thing but I would say this line is a little long for my taste so why don't we do that formatting instead and the same here all right and I think that does it for this controller so tell me what you think we validate the form we attempt to log in the user and then if it fails we return back to the previous page otherwise we send them on to the homepage so I want you to consider this and then what we had earlier and to show you that we will visit GitHub to a previous commit and yeah this is what we originally started out with and I want you to compare it to what we ended up with right here okay and I don't want you to just compare the lines of code even though that matters I also want you to compare the clarity notice that with this approach we are telling things to happen so we're saying login form validate authenticator attempt to sign them in form add this error notice that we are being good managers so to speak we are properly delegating whereas with this former approach we weren't delegating at all instead we were almost being uh sort of like a microman instead we were saying hey give me this data and I will be the one who performs the validation and I will determine what we need to do here and I will check if our authentication uh works and I will verify the password and I will redirect back there's a lot of micromanaging here whereas with this approach there's a lot of delegating and this is the one that I would recommend okay I think it's time to move on start a new chapter and finally talk about composer and yeah I say finally because truthfully it's a little bit overdue yeah it's just how it goes there's a lot to cover here all right so what is composer well first for this video why don't you work along with me visit get composer. org and yeah as you see here on the tin composer is a dependency manager for PHP so offers us a way to install PHP packages but now you're probably like well great I don't know what composer is and now I don't know what a dependency manager is and I don't know what a package is all right well a package is nothing more than code just a collection of files that you then make available to anyone in the world all right but how does anyone in the world install your package well they're going to use a dependency manager like composer so let me give you some ideas as you can imagine uh when you build your own projects you're not going to code every single line by hand like we've done in this series there's really no point uh you know that you know the phrase don't reinvent the wheel well so often the same is true for code why spend hours and hours and hours and hours building something that has already been built many years ago and has been iterated upon uh again for months or for years there's no point it's a waste of your time all right so let's say you want to I don't know uh interact with Amazon S3 storage well again you could interact with their API yourself or it looks like we have an SDK that we could pull in if we use a framework like larl it looks like we have a service provider to assist with that great uh maybe you want to test your code we haven't talked about that much uh but we will get into it very soon yeah it looks like there are some packages one called mockery one called PHP units one called pest PHP that I will introduce you to uh maybe you want to make some kind of application on the command line so where the where the command line as you see here is your interface rather than a browser all right well that's called the console all right well it looks like Symphony offers a console component that we can pull in and then even further if we want to style it and make it look very pretty we can pull in a tool called term wind all right so you get the general idea whatever you need to do there is probably a package that is available to you okay rhyme intended all right so let's pull this in together and yeah work along with me get composer. org we will hit download and yeah you can see at the time of this recording we're using 2.5.5 and all we're going to do is copy all of this and now in my case I already have composer installed but there's no harm in doing it again all right so while that's doing its thing yeah if you want you can quickly uh peruse this page here and yeah here this is probably the most interesting part most likely you will want to put composer. far and that is available here all right we will want to put that in a directory that is part of our path so that we can simply call composer from anywhere in our application okay so you can see they are moving composer. far into our user local bin directory okay so let's just copy that and do the exact same thing all right so I will paste that in move it into my path and yeah hopefully we're all set to go so we can test this by closing the tab opening a new tab with command T at least for me and if I run composer there we go we're up and running okay so now I want to well before we pull in a package why don't we create a basic composer. Json file because actually as it turns out before I introduce you to any of these packages is I first want to introduce you to composer's built-in autoloading feature so let's run composer anet within our current project composer and it okay this command will guide you through creating your composer. Json configuration now in our case I'm not building any specific package so very quickly I can enter my way uh through most of these settings as you see here next do I want to Define my dependencies interactively no I'll do it myself uh same for development dependencies all right now check this out do we want to add psr4 autoload mapping uh I'm going to hit in to skip but that actually is something uh that we want to tackle I just want to do it manually for you all right would you like the vendor directory added to your git ignore so this means uh do we want this folder to be included ultimately when I push all of this code up to a production environment and generally no you don't want to do that so we can add the vendor fold folder to thisg ignore file and that is a way to instruct git to well ignore this directory that's exactly what it does all right so now if I switch over to PHP storm all right and yeah we can see two new files here composer. Json that's our configuration file for composer and then also G ignore which is unrelated to composer entirely it's related to well git any folder or file that we specify here will be ignored by git and yeah you can see it added slash vendor so that means ignore your vendor directory but I don't see a vendor folder all right well that's the next step we need to run composer install so install our composer dependencies but right now if we have a look well I don't have any dependency specified but still let's go ahead and run it all right so have a look where is it yeah right here nothing to install update or move and yeah it makes sense we didn't ask composer to install any package so it didn't install any package but then right down here at the bottom generating autoload files this is what I want to finish up with so yeah as it turns out in addition to composer being a great dependency manager it also ships with a great autoloader and as it turns out that's what almost all of us use these days and in fact very rarely will developers Define uh uh configuration like this instead we just use uh what composer ships with all right so how do we use it well let's just try a couple things out uh number one here's an experiment will it work automatically well if I got rid of our autoload registration and I switch back to the browser and no it's not magic it doesn't happen automatically so we do get a fatal error class core container was not found all right so so the next question how do we make use of composers autoloader well if I switch back here is that new vendor directory and again that was created when we ran composer install and if I open it up this will contain all of the packages that we ultimately pull in uh with composer but right now we just have one folder for composer itself and if I open it and by the way you don't need to pay much attention to any of these files I'm just showing you to give you a quick bird's eye view of what's Happening Here and yeah you'll see a bunch of autoload specific files like uh individual classes I want to autoload our Nam spaces or psr4 based autoloading so what is psr4 it's just a specification for how we can go about autoloading files that's it it's just a spec um for now that's all you need to know about it all right so we are going to make use of that so if I come back to composer. Json here's what we do here I will add a new property called autoload and this is where I can Define and configure how I want autoloading for my application to behave and yeah I want to take advantage of psr4 okay so let's see what we have right now for our namespaces we have this core folder and an HTTP folder now ultimately I think I'd like to graduate to a top level app folder but for now we can keep them separate so if I open up any of these classes that we've created it looks like my top level Nam space is core and that Nam space corresponds to this directory name all right let's try it out I'm going to say the namespace core corresponds to the core directory name now I will warn you there's a small little mistake here that I introduced on purpose and I did that because it's a near certainty that at least for one of your projects you will make this mistake as well and luckily composer can find this and notice it and then tell you how to fix it all right so we'll get to that in a minute so whenever you update your autoloading configuration you will want to switch back to the terminal and run composer dump autoload and that'll repopulate those autoload files but now we can see yeah right here a non-empty psr4 prefix must end with a namespace separator a namespace separator is well let's go to any of these uh well do we have one how about middleware that's a name space separator just a slash all right so it's telling us right here uh a psr4 prefix has to end with that backslash all right so we'll do it right here but now PHP storm is squawking again and that's because well as it turns out a backslash can be used for escaping purposes so now it thinks I'm trying to escape that quote and I'm not so I actually need use two backslashes I'm going to escape the backslash yeah a little confusing you'll get used to it all right so let's run it again composer dump autoload all right and I think we're all set let's go and check just for fun if I go back into that composer folder and into autoload psr4 it looks like the file was changed on disk so let's reload it and sure enough we can see this mapping and yeah it's very simple it's saying this name space can be found at our base directory which is just the root of the project and then into the core folder okay now we actually had two as we talked about and again eventually we will merge these but for now uh we'll double up so let's add another top level name space for HTTP all right back to composer let's duplicate this and then swap it out and Yeah notice I don't have to do it for every nested directory I only have to declare the top level the root uh name space all right so let's run it again and now again just for fun and so that we grasp what's going on here if I switch back and we give this a Reload yeah now we have two mappings okay so is that it is that all we have to do can I switch back to Firefox and cross my fingers and hit refresh no it still doesn't work and that's because well yes we have defined these mappings but I still haven't acquired composers autoloader into my project so that's the next step let's go into public index.php I can now delete our old autoloader uh function and yeah maybe right here I can say require and I want to pull in Vendor and then this file right here autoload.php okay but I can't just do this I can't say vendor autoload.php because remember I'm currently in the public directory so this would look for a vendor folder within public and of course I can't do that so I need to go up a level to the root and then to vendor and yeah it looks like many episodes ago we defined a constant for that so why don't we do that now base path and then concatenate vendor autoload.php and yeah I would even move this as high up as we can go so in fact why don't we just do something like that and yet this is very common very typical for any modern PHP project or package package if you inspect their entry point at the very top you will see a require statement that pulls in composer's autoload file if you're using a framework like larabel have a look one of the first things it does is pull in composer's autoload file all right so let's come back and this time actually cross our fingers and now it works everything's working exactly the way it did before but now we are leveraging and benefiting for free from composers built-in autoloader all right so now in the next episode we will pull in our first package stay tuned all right so now that we have composure on our machine and ready to go of course the next step is to then install a package and I will pull in two all right so we can research which package we need in a couple of ways first upep you can visit packages. org and search for what you want so I'd like to talk to you about Collections and yeah here's what pops up and notice that they are ordered according to downloads so yeah generally the the top five or six often the top one or two will be the one that you most care about or or at least they are most uh reliable because they have been downloaded the most number of times so yeah I'm a big fan of larl so I'd like to pull in this package right right here illuminate Collections and yeah if you're not familiar with a collection think of it almost like an array but on steroids it gives us a way to wrap an array and then call any number of methods to to filter that array or customize it or iterate over it uh and everything in between okay so yeah this is the package that I want but I also want to show you a different way that you can research instead you can do it from the command line I can say composer search and then provide your keyword here in this case collections and here's what pops up and notice of course the output's going to be very very similar and here's the one that I want all right let's pull it in composer require and then let's grab the name right here the full name and give that a go all right and you can see all this stuff being pulled in all right very cool now if I return to PHP storm and open composure up Jason there we go we have pulled in that package all right let's use it and yeah usually at this point you will want to visit the documentation for that package so I'll show you a little tip if I click on here uh often the name will correspond to a GitHub repository so notice right here the link if we open this up in a new tab is github.com and then here's our full repository name okay so in this particular case uh because it is extracted from the layl framework I don't immediately see documentation here but I will note most of the time the documentation for a repository will be available right on the GitHub usually at the bottom within a rebe yeah but in this case it's not and that's okay instead we'll go to ll.com and don't worry we're not yet learning about laravel but yeah if I look for collections we can we can see a quick Bird's eyee view of how it works so notice I can call collect I accept some items and then I can uh work on those items I can map over them I can filter them I can split them into two I can uh manipulate them anything you want to do really all right so let's give it a shot let's create a new file and we'll call it playground. PHP and yeah this is going to be temporary and now as we learned in the last episode the first thing we should do is require the uh the autoload file okay so now let's instantiate a collection and yeah because we pulled in this package we now have a new collection class that we can work with all right and that gets imported at the top so let's feed it an array of items like 1 2 3 4 or it can be anything you want it could be numbers it could be arrays themselves uh whatever you need so for example if I want a collection of all numbers going up to 10 um then we can do something like this okay so why don't we call it numbers and then just as a sanity check let's die and V dump the numbers and then view this from console PHP public playground all right and yeah if I scroll up notice I don't have an array anymore I have a collection instance it is a wrapper around that array that gives me all of these different methods that I can uh trigger so if I want to grab the first item within the array if I want to flip the array if I want to I don't know figure out if the uh collection contains a particular item we can call this contains method and notice I can see we have to give it a key and then optionally an operator and a value all right so let's just try this out uh let's say if numbers contains and how about 10 then we will die and say it contains 10 you know we're just playing around uh for a minute and if I give that a run it works uh if it contains 100 uh well in this case we don't do anything so we don't see any output at all but it's working uh I could say I don't know numbers map over them so notice this ultimately is going to be running php's array map function uh that you learned about if I call numbers filter well then that's going to be ultimately deferring to array filter have a look and I show you this just so you you have a basic understanding of what's going on here yeah ultimately it defers to php's array filter uh function so yeah if you wanted to you could even construct your own uh collection class and that would be fine and this is where it all comes back to um other than for learning purposes is it a good use of your time to build up your own collection class or would it instead be better to leverage something that has been literally pulled in millions of times uh and have and has been debugged uh hundreds and hundreds of times and improved hundreds and hundreds of times uh and you get that all for free so it's a good bang for your buck so yeah anyways in this case if I want to call filter so why don't we say filter the numbers down so we will provide a call uh this callable will be triggered for each item in the collection and then I return a Boolean that indicates whether or not the item gets to remain in the collection or filtered out so yeah in this case and we just say like return is the number less than or equal to 5 uh if it is then it remains if it's not it's filtered out so I will say excuse me less than or equal to five bit of a long variable name there but it's fine and then once again let's V dump that variable and view the output all right and sure enough we have a new collection of only the numbers that are five or less all right you get the basic idea let's pull in another package and this time I'm going to use uh composer search so I want something to help us out when it comes to testing up until this point we are manually testing every piece of the puzzle so to speak but as you can imagine in real life when you're building larger projects you need some level of assurance that the changes you just made didn't break the application and this is where automated testing comes into play now the tool that I really like is either PHP unit or pest PHP and as it turns out pest PHP is actually itself a wrapper around PHP unit okay so let's pull and pest in the same way composer require pest PHP all right so now we can see a Little Help from composer it's saying hey a package like this probably belongs in your required Dev section so now we can distinguish between packages that we will use in production and then packages that are only useful during the uh local or development phase such as automated testing so do we want to do that yes all right so now if I switch back and return to composer. Json give it a Reload yeah now you can see we have two blocks we have an object for require and then another one for require Dev and yeah again required Dev is for local or development only it will not be included as part of your production uh vendor assets or repositories okay cool all right so let's have a look we will go to get started installation and yeah we've already done the first step the next step is to run vendor Ben pest andit all right and we can see what this does it'll create a configuration file named pest at the root level of your test sweet all right let's paste this in oh and I'm sorry we have one quick issue do you trust pest plugin to execute code yes I do sorry about that and now we're ready to get started so I will paste that in all right and yeah here are all the files that were created all right let's have a look in the editor all right and sure enough I do see a test directory and it looks like we have folders for feature and unit test all right so we're going to dedicate maybe one or two episodes to test um of course at larach we cover it in significant detail but yeah I just want to stay on task we don't want to get too far from the original goal of a PHP for beginner series but it is important that you understand the basics of testing all right so why don't we open unit and we have an example test here and yeah this is the syntax we call test we give it a name and then we have a call back here or a closure where we can perform our expectation and and yeah an an expectation is exactly what you think it is an assertion that I expect this to be that to equal that to be more than that to have this to contain to have a to to be an array with this number of items whatever it is you need to test you can do or perform as an expectation okay so how do I run this little example test well I can do vendor Ben pest all right and sure enough our feature test and our unit test passes why don't we get the test to fail I'm going to change this to false expect false to be true well that's instantly not right and it should tell us when I run our test suite and it does failed asserting that false is true right here and then I can fix the problem all right so again the next episode we will talk quite a bit about testing but for now why don't we wrap up by giving you just some kind of real World example of a test hm how about how about let's go into container and yeah maybe we can test binding something into the container and then resolving it out all right so let's go into test unit and I will update this and we will call it container test and by the way notice the convention of ending a test file with the suffix test so why don't we test it can resolve uh something out of the container all right so typically when you're writing a test there will be a series of steps you will need to arrange the world and often that's uh instantiating a class building up a dependency whatever you need to do uh we'll call it arrange the next step is act so perform your action do whatever it is that you're trying to test and then at the very end assert or expect and this is where you conf confirm whether or not it actually worked and that's where we would write our expectation all right so arrange the world well this would be uh working with the container so maybe I can instantiate this container class all right let's do that now new container and then I should also bind something into the Container so why don't we just call bind and then I will pass a closure that returns Fu or don't forget there is a short hand and uh single line Arrow function that uh I will often reach for okay so now I'm ready to act well let's say container resolve Fu and this will give me the result the final step is to perform uh our expectation what do I expect result to be well I expect result to be and you know what why don't we call it bar instead I expect it to be bar so expect results to be or equal is fine in this case bar all right let's give it a run and there we go it does work now if I were to force it to fail why don't we do something like this you can see uh the result here well we ran this specific test but it didn't work the way you expect okay so if I bring this back your next thought might be well why is that useful I can still manually test that and confirm it works and you're right but because I have written it down here and I've automated it that means I can run this test hundreds and hundreds and hundreds of times for free and I never have to manually confirm that this piece of functionality works and trust me as you maintain a project over a span of potentially years these things will build up and continuously prove their usefulness and then further it helps us with confidence and here's what I mean by that if six months from now I'd like to refactor The Container class I can do so with confidence because I immediately know if I make a mistake the test will instantly inform me whereas if I didn't have those automated tests yeah I could perform these refactors but trust me it can get tricky and I'd have to do a lot of manual testing to see well did this work exactly the way it did before or have I changed it and did I break code that was using this container class over here it gets very very risky very very fast so what ends up happening is that for the projects that don't have these automated tests backing them up people just don't refactor in so many cases uh they'll have a confusing piece of code that nobody touches because it's simply too risky to play with but yeah tests absolutely fix that which allows us to write cleaner and better code all right so yeah let's say maybe when we resolve yeah maybe right here we don't call the function we just return the resolver and we think that works but if I run the test it fails so again we're working with the container class we made a change we thought that change would be fine but our test instantly reveals M something you did just broke this code so maybe you should revert uh and then try again and now it works all right so why don't we take one more lesson we're about done with composer so in the next chapter let's take one maybe two more lessons to dig a little deeper into the world of testing I'll see you then okay so if you don't mind why don't we dedicate just one more episode to testing uh so that we can get you reasonably comfortable with um if not the the workflow the general approach and what you can expect and what it looks like um because here's the deal in reality testing is its own world you know what I mean like everything in programming you learn something new and you very quickly realize oh this is its own world and there are conferences dedicated to this one thing this one piece of the programming puzzle has its own conferences so yeah if you want to be frank we could dedicate course after course after course after course to teaching you the uh the ins and the outs and the and the nuts and bolts of testing and we just don't have time for that and it's beyond the scope of a beginner series like this but yeah nonetheless I do want to give you one more episode where we discuss everything from you know the the general approach the different styles of testing what you can expect what it looks like all of that stuff okay let's get going yeah of course in last episode near the end we installed Pest and we now have this new test directory and I want you to notice how it's categorized into these different uh styles of testing one is called feature and one is called Unit um you know these days I'm not even sure if it's if it's that useful to categorize things in this way but nonetheless it's good to understand the basic idea unit represents well uh one unit of your codebase that unit could be a single class a single function or a small collection of classes but still notice how they they comprise a single small typically uh unit on the other hand feature test refers to something much wider uh a feature in your application that feature could be um what would be an example from laracast oh here's one uh I just built a referral system for lass that's a feature so we could have a feature test called referral test and within there I can describe the the rules of a referral system what does it consist of what are you allowed to do what are you not allowed to do so from that perspective we might realize that when we write tests it's not just to ensure the thing works even though that's very useful uh but it's it's also almost like a scratch Pad it's a great way to gather your thoughts for example let's go into example test here and rename this to referral test we're not going to build this out uh but just to give you an idea of the approach you might Begin by writing the various features as tests so we might have something like uh and by the way we can use this test function or it uh they are aliases use whichever one best fits uh your your description for the feature so for example um it allows subscribers to earn money by referring their friends okay so yeah this in this case this is very tough top level very um zoomed out but still it would be a fine test to write and it might be fairly in-depth uh for example you might write the test uh in such a way where you create a user you sign the user in you generate a referral code for that user and then you um create another user who redeems that referral code and when they do redeem that code and by the way maybe when we speak it out and we describe it here we realize oh redeem is a good verb and that should be referenced or represented uh in the codebase somewhere so maybe if you have a referral uh class then maybe you have a method called redeem so again this is what I mean when I say it's almost like a scratch pad it gives us a way to gather our thoughts and then start identifying uh patterns or keywords that we can then work into the code base so yeah on that note I think in general you'll find that uh the testing Community sort of splits and a two there are those who see testing as nothing more than a uh necessity to ensure that the thing actually works and they're right uh but then there's another group who strongly feel that the way you approach your test will help determine the design of your application so from that perspective the testing um influences the design of the codebase and their right to so as as with almost everything in my life there are good points on both sides of the equation and my recommendation to you is don't worry about it uh learn what you can and then discard it all and just make it work for you so for example if writing these tests before your implementation code just doesn't work for you no matter how hard you try don't do it and by the way that's referred to as test First Development or test driven development uh on the other hand you might find situations where it makes sense in this context but not in that it's too hard to to wrap your mind around the flow but over here it makes perfect sense because you have uh explicit input and output expectations it doesn't matter there's no rues the Only Rule is that you make this work for you okay so yeah you have a good idea now of what a feature test might look like and trust me there are there is dedicated tooling to assist with this because right now you're probably thinking well how do I visit a page from a test how do I fill out a form from a test and the answer is well you could write it yourself but it is so much work uh I wrote a little framework many many years ago to help with this and yeah it's a massive amount of work and again beyond the scope of uh of this video or this entire series to be frank uh but but as with anything there is dedicated tooling across the board there are tools like dusk U there are tools like browser test uh there are um JavaScript tools that literally open the browser and interact with your website like Cyprus all of them are really useful and uh as you as you become more comfortable I would encourage you to check those out but yeah for now just understand the general idea of what you might want to test so on that note you might also say it disallows guests from participating in the referral program so yeah maybe you've decided uh like I have if you don't have a laracast account um we're not going to let you participate in in the referral system maybe it's just too difficult or maybe we need you to hook up your uh your billing details it doesn't matter you decide what the rules are for your code base and your feature and then you write the mount and then you write the test to ensure that it does what you expect okay cool uh next we have this container test that we worked on in the last episode which is this is incredibly real world uh this represents a simple unit test that we can resolve something out of the container but now do we have anything else we might want to work on here um we could test some middleware we could test the validator these are really just simple static functions but you know what uh I think this would make sense so let's give it a shot uh let's create a new test and we're going to call it validator test.php all right so why don't we say it validates a string all right so let's pull in our class we're going to call the string method and you'll remember if we quickly uh switch back we give it the value and then an optional minimum and maximum uh character count okay so let's switch back and we'll say Fubar okay so if we run this should this be valid is Fubar or a string absolutely so let's save that to result and then say expect result to be true so I could do this or I could use the method to be true all right let's give it a run so I could do it directly from my editor because I'm using PHP storm and really most editors these days will have some kind of inline support but yeah for now let's just do it directly from the terminal so I will run pest on the test unit validator test and of course it Returns Green okay now I'll give you a little tip though let's do this let's inline this variable entirely and we could do another one so for example if I said false I would expect that to be false and if we give it a run we are we already know that's going to work let's do another one and this time why don't we feed it an empty string and that should return false because it's empty give it a run and that works okay um we could add another one here and we'll clean this up and refactor shortly it validates a string with a minimum uh length so for example if I run this but I say uh the minimum length should be 20 characters well in this case Fubar is not 20 characters so I expect that to return false we give it a run and that works okay this is exactly what we want and notice how it's just proving our expectations our assumptions and that's the entire point so whether we wrote this implementation code before or after again it doesn't really matter maybe it's a personality thing do whatever you want um I find I kind of do both uh there's certain situations honestly like this uh I would write the test first before the implementation code but then there's other situations where I don't know it doesn't really work for me I feel like I have to spike it out a little and in those cases I'll write some uh implementation code first and then I will backfill or fill it in uh with some tests both work it doesn't matter do what you want okay cool let's do another one for email and then we'll clean things up so we'll say it validates uh an email all right so if I call email with Fubar I will expect that to not be valid give it a run it works if I give it a actual email address or a dummy email address in that case it should return true give it a run and oh it doesn't work failed asserting that food bar is true yes of course so already the test is informing us that our assumptions aren't exactly uh what the code says so in this case I was assuming it returns a Boolean but in uh but I'm sorry but instead it returns either false if it is not an email address or the value if it is so now we have to decide are we okay with that or do we always want it to return a Boolean so for example do we want to force it to be a Boolean well if we take that I think it'll fix it and yeah that does solve the problem but again this is a decision that you have to make does validate email return a Boolean or does it return false or the email itself you have to decide that and a quick note we haven't talked about this very much but uh you can leverage types to be a little more explicit about uh the the the types of input that you expect and again we haven't talked about this very much because uh it's not a highlevel topic but only because I think there is a beauty in teaching the basics of PHP in a very Dynamic uh way that's the way I learned it and I feel like it's just easier to grasp when you are not constantly throwing syntax uh at the viewer at the person who's trying to figure out how all of this works but nonetheless it can be incredibly useful so quick little 30 second primer um if I want to be explicit that this parameter should be of type string then I could write string here and now if we were to call this email method and feed it an array or an object or a class or something like that it's going to fail and it will let you know hey you gave us an array but we thought you were going going to give us a string and we expected you to give us a string so maybe you need to take a look at this okay and then we can also do return types represented by a colon and then the uh the type so in this case if I want a Boolean and actually take a look at this so real quick without the type if we give it a run it fails because uh we're expecting a Boolean in response so one fix was to manually cast it like this and that works however another option is to declare a return type of a Boolean so now notice if I run it that fixes the problem too so this is teaching us that when we declare a return type if what we return doesn't match that type it will automatically be cast and the best way possible to become that type um you can disable that if you want if you want to be a little more strict uh but nonetheless it is an option that you might consider so in situations like this this uh and this are redundant and you still might want to keep that redundancy but nonetheless it's not altogether uh necessary Okay small little tangent if you want to learn more about types definitely do so but that's the extent uh that we will cover in this series but maybe in a follow-up series we will dedicate the entire thing to discussing types and PHP and the pros and the cons and the benefits and um um I'm repeating myself at this point let's keep going so now why don't we wrap up by maybe doing one more so let's do this let's go ahead and import this at the top and that way we can simplify these and why don't we validate um I don't know it validates that a number is greater than um a given amount or something like that so we could say greater than and we'll say uh we need to give it the value so maybe the value is 10 and we expect that to be greater than uh one well if we run that that should return true okay so let's do this I'm going to call this method only using Pest and that declares that well you can skip all of these right now I'm only interested in this one test alone so we give it a run and notice uh we only have one test here and it failed of course call to undefined method validator greater than okay so now we're taking a test first approach we're seeing a test failure and that is guiding us uh to write implementation code so let's do that now we go into the validator I create a new uh static method and we're going to call this greater than this will accept and we'll add a type this time a value and then a greater than amount and that will be an integer okay let's give it a run now it's still going to fail but we should change uh the failure message and again this is sort of a Cornerstone a bullet point of test first developments you want to make that error message change so even though you're getting R if you can change the error message uh ideally you're making progress and that's the case here all right so now the method name exists but it's returning null when we expected true to be returned okay so let's do this let's be clear that we want a Boolean in response and why don't we just check to see uh if value and I'm sorry this should be an integer of course you caught that uh this should check if value is greater than um what we have here all right we give that a run it works but now let's just sort of prove our assertion so if I come back here because here here's the problem and you want to be careful about this maybe you just return true here instead and that still Returns Green so we have to be careful of trusting the test too much uh sometimes you can have all green on your test Suite but the codebase doesn't work because well it's not doing what you thought it would so let's add one more test here and say well uh and what condition should that return false well how about something like this is 10 greater than 100 no so that should return false it's kind of a silly example but nonetheless it shows you the basic approach okay so if I come back now if we did that Superfluous thing where we hardcoded true the tests are going to inform us uhuh that's not working there's no way uh that satisfies both of these uh expectations so now we can write the real code run it again and it Returns Green and yeah as simple as this dummy little example is it sort of represents the general flow so if you'd like to keep working on this yeah on your own just pick one of these files that we have here and write some tests for it uh start simple how about yeah we can force log in a user so what you would do is you would write a test and you'd give a descriptive name and then you would instantiate the authenticator you would call the login method you would feed it a user and then in response you would assert that well there should be user in the session so actually look into the session and confirm is that uh equal to what we expect here and if it's not you know you did something wrong okay yeah you know what why don't we end it there uh originally I was thinking of doing two episodes but I'm very worried about overwhelming you maybe that ship has long since sailed uh the truth is right now in your learning if you want to escape by it and kind of ignore it for a bit that's okay just keep in mind though once you start building real projects that others depend on and make use of it's really a necessity so be sure to consider it when you feel comfortable all right I'll see you in the next chapter all right welcome back everybody I think it's time to finally wrap up this series so I would love to give you some next steps however before we do that I have a slightly maybe possibly bitter pill to swallow uh and it's this at the end of this video what I'm going to do and what I'd recommend you do is delete the entire project all right so now you hear that and you're thinking what why did we go through all of this effort building up a framework of sorts if we're just going to hit the delete key uh in the final video and here's why uh as with everything it's not about the framework specifically it was all about the friends we made along the way or or the education we we acquired along the way uh the simple reality is when it comes to things like session handling uh as we worked on here building up a router handling a response uh creating a container authentication all of this stuff validation it goes on and on and on the reality is that work has been done it's infrastructure work that these days none of us needs to be responsible for unless we just happen to have that personality type where we have to control everything otherwise trust me there are better more tested uh more more flexible versions of every single component we built here so our little validator here now of course this is mostly a proof of concept but in reality there are dedicated third party validators that are highly tested and can offer uh or can work with any possible calculation you can think of the same is true for building up a super flexible router or even uh these middleware that we created again very very simple implementation here but there are once again third-party resources that that take it to the next level so yeah everything we did in this series was to teach you the fundamentals the basics of what these things are now even if you don't use your own uh makeshift middleware you understand the basic concept this idea that uh it's almost like layers of an onion that can handle or respond to an incoming request or an outgoing response the same is true for session handling and why would we reach for that and when is it useful and what's an example of using it uh in the real world okay so let's do this I'm going to switch over to the terminal and like I said I am going to remove with recursive force that demo project of course it's on GitHub if you still want to refer to it okay so now we're going to switch over to a dedicated framework of course in the laravel world the two big shots in terms of Frameworks are larl and Symphony uh I'd recommend have a look at both uh peruse the documentation figure out which one sort of fits your head and and your way of understanding things a little better and then go with that and of course of course down the line even a few years from now if you want to toy around with the other that works as well okay but of course this is lar cast.com I have personally decided on larell and that's what I would recommend to you as well and in fact as it turns out a lot of the decisions we made when we built our little micro framework were made with the understanding that if you graduate to laravel it will all instantly look uh at least 80% familiar okay so with that in mind why don't we install a fresh copy of laravel and then we'll take a look at the underlying directory structure and I think you will be pleasantly surprised by how immediately familiar some of these terms and some of these directories are to you all right let's get going I will go to get started all right why don't we skip down to your first LL project and let's see you should ensure that your locom machine has PHP and composer installed success we've already done that if you're developing on the Mac can be installed within minutes using a tool called larel herd uh herd is a first party or maybe second party uh tool that well does what it says on the tin it creates a local environment for the Mac it works great it's what I use I would highly recommend it otherwise on Windows if you need a refresher or you'd like to review some different uh installation options yeah just take a look here getting started on Windows getting started on Linux you'll learn about a tool called Docker as well as a Lal wrap around talker called sale but yeah otherwise if you already have the the basics installed on your local machine you should have everything you need to go okay let's switch back and now we're going to create a new project all right so we'll do this directly through composer all right I will paste that in and yeah this is going to create a new LL project and why don't we call the folder demo all right it's installing Lille 10.2 at the time of this recording and that'll take just a minute to pull in all of the dependencies so now if I switch over to our demo project and I list all of the files yeah we're all set to go here so take a look at this larl ships with a command line utility called Artis and we can run it by using PHP and then the name of the tool artisan and yeah here you can find commands for all of the various operations and actions uh that you can run and trust me as I look at this even even to me it's a little bit overwhelming but like everything 20% of these commands will be the ones that you run uh every day probably even less maybe 10% but the others are there when and if you need them okay so if I scroll to the very top you will find one command called serve this will serve the application on the development or the PHP development environment so let's run that now PHP Artisan serve and sure enough we have a local server running here all right so now you can copy that or on my machine Mach I can command click that link all right and there we go congratulations you now have your first LEL install all right let's open this in our editor and take a look around okay so I have opened up that demo folder that we just installed from the command line and yeah granted there's a lot of files here a lot of directories it even goes further and once again it can immediately be a little bit overwhelming but but fight that trust me all of these configuration files you will reach for them only when you need to and often when you are editing them you are following instructions that tell you to edit them so don't worry about this too much however what I do want to point your attention to is this we have one directory called routes all right let's open that up and I see web routes here yeah I we we get this we understand what's going on here we built something very similar in our own project and we can parse what's going on here well we have a route and we're going to listen for get request to this URI the homepage and then in response to that it looks like we are returning a view called welcome okay where where is this welcome view called well at the time in this recording larl stores views within the Resources directory so resources views now if you're watching this in the future in 2024 or 2025 it's possible that views might be a top level directory every once in a while they make slight directory changes but nonetheless you'll figure it out all right so let's open up views and sure enough I see our view again think about how incredibly similar this workflow is to what we did uh throughout this series so here's our view and let's just do this let's delete everything and replace it with uh the obligatory hello world all right I'm going to go back to my browser I will give it a refresh and there we go everything's working okay what about passing data to the view well once again let's go to our route and we can do that as the second argument we'll say greeting is this time universe and now I will have a variable called greeting available in the corresponding view now I can do it like this and if I come back and give it a refresh but of course whenever you're using a framework there will be dedicated helpers and and shorthand and things like that that you can reach for so in this case notice that the file name is welcome. blade. PHP now in our project we called it welcome. view.php but as it turns out with LL blade is a dedicated template engine that that includes a few luxuries and one of those is a shorthand for echoing out uh escaped variable values so in this case I can use uh these two braces here so now if I come back and give this a refresh and yeah it still works of course okay so in a general layer project this is typically the approach you will take now what about conditionals remember in our series we used this syntax if some kind of value and we even learned about a shorthand like this well if true only on that condition do we display hello world but of course if it is a falsy value then we should end up with a blank page all right well once again using blade there are shorthands and we call these directives it's basically uh just just a little bit of sugar to make it easier to write like this at symbol if so provide your condition and then we can say and if yeah notice it's just a little bit easier to write and as it turns out behind the scenes larl is still going to compile this down to a raw vanilla PHP if statement but yeah this just makes it a little more I don't know easier on the eyes when you're working on it refresh we see it if we change it to false of course we return to a blank page okay so now we've learned if nothing else I can install lfl I know where I can create a route I know how to respond to a route so for example if you want to create another one let's listen for about and that can return a view uh it can load a controller it can even return uh an array it can return Json food bar this is especially useful if you're building apis uh it's a little bit higher level than where we currently are but nonetheless just know that these things are options as you see here and here's the raw data that was returned otherwise you can return simple strings as you see there or you can create a new view so let's return a view called about and then I know that by default it's going to be located in the views directory okay but what if we want to put it in a subdirectory like Pages slab then you could do something like this Pages slash or you can even use do notation which uh corresponds to a slash some people like that because they think it's uh again a little easier to write all right so create our directory our directory called pages and then another one called about. blade. PHP now uh in this case I'm not even using um Master files or or layout files but when you stick with this you will learn about all of the various things you can do with blade which which are quite significant we'll say about page all right I'm just giving you the 101 here come back give it a refresh and now we have a landing page for um telling the user about ourselves very cool okay so next what else do we have here we have the public directory this is typically where you will store your images or your JavaScript files and you'll remember in our uh little framework we also had an entry point that that was responsible for sort of booting up the framework it pulled in composer autoloader it handled uh routing the request it caught any potential uh validation errors and things like that and of course lville has one as well next we have the app folder and this is where you're going to spend most of your time if you need to generate console commands you can do it here if you need to create dedicated controllers you can do that here so notice within our routs file we are this is this is useful for very simple projects typically but I think you'll find for many projects just having a simple callback function isn't enough you need a little bit more structure and that's where dedicated controllers come into play so when you generate a controller it will be stored here and you will find that very easily you can you can migrate from a closure here or a call back to a controller and why don't we do that now uh let's get rid of this to keep things simple and why don't we create a welcome controller all right we can do this from the command line PHP artisan and these will all be listed under the make name space so anything make is generating a file you can generate a controller an event a factory all of these various um terms that lell offers a mailable a notification a model in our case I want to make a controller so let's do that now PHP artisan make controller and why don't we call it home controller all right so notice it goes directly within that controller's directory and here's what I'm going to do I'm going to take this right here copy it and move it into our new home controller so let's create a method here and we will call this invoke uh this is a common magic term for what we call single action controllers so as it turns out a controller can respond to multiple uh routes or it can handle just a single action uh I think you'll find in your projects you probably will use both but in this case if you're only doing a single action like we are in this case we can call the method invoke which is a magic uh PHP method name all right so now though if I switch back to our web file we need to update this so let's change it to say when you visit the homeage I want to load the home controller so we provide a path to the class as you see there now if I come back and we return to the homepage and give it a refresh we get a blank screen let's go to our view oh yeah of course I was testing out uh blade directives there all right come back refresh and yeah this time we get the typical Hello Universe okay but now we are using a dedicated controller to respond to the incoming request which is really cool okay so I'm going to stop right there because of course we have a dedicated series at laracast called laral from scratch and a quick little tip you can visit laral froms scratch.com to instantly access the latest version of that series uh and yeah it's going to start from the very beginning and tell you everything you need to know uh it's a little bit long but for good reason it'll take you from maybe where you currently are which is you know you understand the basics you know the syntax um but maybe when it comes to building an actual project you start to melt or you start to fold a little bit because it's so much to keep in your head and really that's the benefit to a framework all of that infrastructure code that we worked on in this series even down to validation and middleware and routing we can now delegate it it's almost like taking all of that weight off our shoulders and throwing it at the framework and saying you be responsible for that I don't want to think about it anymore all I want to focus on is the application itself and that is really the huge win that stems from using a dedicated framework [Music] what [Music]