[Music] L document you'll need to have both Peach P Lo your larel immediately [Music] all right so check this [Music] out hey there how are you doing uh I'm going to let you in on a secret when I work on courses for lar cast I just about never ever write scripts but this series is a very special one and I care about you so much that I took the time to sit down and prepare a formal introductory script and I'd like to read it to you right now please be excited it goes a little something like this hello it's nice to meet you my name is Jeffrey and I'm here to teach you the ends of C it's so boring and I already know it uh hi I'm Jeffrey uh I've been working with Lille for over a decade and you know what to pet myself on the back I'm one of the few people who can say I've actually been working with larell for over a decade uh yeah I was there in the early days uh back when LaRon wasn't even a thing and if Lon is new to you that is a larel specific conference uh these days they are held all over the world and thousands and thousands of people attend uh but back then nobody knew what laravel was uh in fact when people heard the word they called it LEL not laravel and actually some people still do today but trust me the correct pronunciation is Lar fell uh but yeah back then nobody knew what it was and we didn't have a laracon yet and when we finally did have a laracon maybe I don't know 60 people showed up and you know what I was one of the presenters at that very first conference so I say all of this again not to pet myself on the back but to to persuade you that I've been doing this for a really long time and if you're just getting started in larl I think I would be a great tour guide all right that's my Spiel so if you'd like to learn the ins and outs of laravel want you come along one day at a time let's go now before I can start showing you how to write larl apps of course the first step as always is to get your Tooling in order now in the past when it came to setting up a development environment uh for PHP I don't know it could sometimes be a little bit overwhelming because there's so so many different tools to choose from it's sort of decision paralysis right which one do I pick and of course everyone has a different recommendation and while that's still of course true these days there are oneclick solutions that are really incredible and I can happily recommend so yeah maybe traditionally you might pull in a tool like zamp or M or whamp uh on Windows you might use a tool called Lon and by the way all of these are still developed today and they're excellent um the whole point is and here's another one on the Mac uh you could install everything manually quote unquote using home brew so you could do things like Brew install PHP Brew install MySQL all of these still exist and are great and they are options for you but if you're just getting started with larl I can happily recommend uh larl herd it's a magical and I hate using that word but it's kind of true it's a magical oneclick utility to get you up and running building PHP and specifically larel out so right down here just click on the button uh on my machine I see download for Mac OS but rest assured there is a Windows equivalent otherwise on Linux you probably already know what to do but yeah otherwise you might consider this tool which is still great okay so let's just work through it together and get set up I will download it all right let's drag this to my application directory close it out and open it up all right welcome to herd let's get started all right notice it is downloading PHP 8.3 which is the latest version at the time of this recording now there is a free version of herd and that's going to do everything you need if you want some extra bells and whistles you can of course pay for a professional version but yeah if you don't want to do that the free version will take you as far as you need to go uh for this course and further we'll skip it for now all right there we go so notice we now have binaries for herd PHP laravel and a tool called composer which you may or may not be familiar with but either way don't worry we will cover it when we get to it all right next all PHP projects placed in the herd folder will automatically be available in your browser and this is one of the coolest things you're going to love this all right so let's get started all right check this out if I go up to my menu bar I now see a new herd icon here's where I can see any processes that I have running I can switch between the versions of PHP that I have installed and this is one of the great features uh if you have multiple projects where some of them depend on an older version of PHP you can run those simultaneously on your local machine which is really cool you don't have to worry about it at all so notice in this case it looks like there is an update for 8.2 available and If I want to pull that in I can do so with a single click which is really cool but anyways if I switch over to the general tab here I can see a list of paths where herd will search for any potential PHP projects so by default you get your home directory slard but yeah you can register as many as you want so in this case I've added an additional folder called code and that's fine as well all right let's give this a shot so I'm going to go into my home directory slard of course it's empty right now and we're going to use this new laravel binary and this is included um out of the box with herd and this is again one of the benefits it includes everything you need to get up and running right away so I'm going to say larel generate a new project and I'm going to think of any name I want let's keep it very simple and we will call it example all right so it's going to ask me a handful of questions would you like to install a starter kit a starter kit is exactly what you think it's it's a way to jump start a project with um layouts templates authentication it's really cool but for now I want to start from scratch all right test framework again we're we're going to stick with the defaults do we want to get repo no we're just playing around all right so notice it's creating a new folder called example and it's pulling in all of these dependencies and again you didn't even need to know that composer was a thing uh in order for this to work which is really cool but again don't worry if you if you want to learn more you're going to learn more all right which database will your application use why don't we stick with the basics sqlite which is a file based database all right that's done list the files there's our example project we'll CD in there list them again and that's the Lille framework ladies and gentlemen uh really cool and even better we can instantly view this application in the browser by visiting the name of the folder. test don't believe me let me show you let's give it a shot example. test and there we go say hello to the landing page for larl 11 everything's configured and we're ready to get started but now real quick before we finish up if you chose not to use herd yeah you might take a slightly different pathway and like I mentioned you could use a tool like largon or zamp or Docker and sale and all of those are excellent but they have slightly different installation steps so just keep that in mind if you need any help be sure to ask questions in the comments below and we'll do we'll do our best to help out okay but but otherwise in the next video you are going to create your first route I hope you're [Music] excited all right welcome today twoo look at you you're already making progress doesn't it feel good I got a brand new shirt it's a new day let's talk about routing all right so here is the example larel project that we installed in the last episode episode and actually real quick on that note you can consume this course however you want goes without saying do whatever you want but I would highly recommend grabbing your computer and working along with the video each step of the way it really does make a massive difference when you have to type out uh each character okay so in that Spirit pull up your example project and open it in your editor of choice uh Sublime Text Visual Studio code PHP storm Vim they're all good it doesn't make a difference all right here we are now I'm going to warn you uh right off the bat this can feel a little overwhelming there are so many files look at this app models providers bootstrap resources storage test vendor oh my uh it's a lot to take in but like everything you don't have to learn it all at once trust me you don't have to learn it all at once uh we will focus on one piece of the puzzle at a time and then when we're done you'll have a a pretty solid understanding of the entire framework I guarantee it okay so where do we begin uh with any project where do you begin well why don't we start with the homepage so I'm going to switch over to the browser now because we used herd in the last episode I can visit example. test to view my project but yeah if you if you chose something different then you might need to manually boot up a server and you can do that using Artis and let's just put a pen in that for now we'll talk about it more in the future but yeah for now just write these three words PHP Artisan serve and that will boot up a local server to view your project okay but anyways yeah I can see a bunch of cards here links to the documentation lar cast larel news and uh the ecosystem as a whole all right so if I wanted to tweak something on this page where would I go all right let's do that now so the first stop on our journey is going to be this routes directory have a look at web now one of my favorite things about laravel is it's so clear so even if you didn't understand what a route is you could probably parse what's going on here let's have a look routes get forward slash well that's typically the homepage right when you get or visit that homepage then run this function and it looks like the function returns of view called Welcome all right and you know what that's exactly what it does so more specifically we are declaring a rout that listens for a get request and a get request is just visiting a URL in the browser in this case listen for a request to the homepage if we instead were listening for a request to the about page then I might do something like this all right so in response if the user visits that page trigger this function and the function will return a view called Welcome All right so now the next thought is well where is the welcome view well it's pretty clear we're going to go into the the Resources directory views and sure enough we see a file called welcome and notice it's not welcome.php it's welcome. blade. PHP once again let's put a pin in that uh but if you want a a head start blade is lel's templating engine it's just a layer on top of PHP that that offers a few bells and whistles that you'll find uh to be pretty useful okay so if we have a look at this this is the markup for that homepage so why don't we do this I'm going to select everything within that body tag and replace it with hello world give it a refresh and it works we're in business okay so now think about what you've learned here you've learned that you can visit the routes file you can declare route and that route can return what we refer to as a view and yeah for now again keep it simple a view is the markup and the template for what the user views and it's a little more complex than that but at this stage of you're learning that's good enough all right so why don't we do this let's declare a new route so I'm going to go back into rout web I'm going to copy this and we'll do it again this time if the user visits slab then what do we do well we have a couple choices we could create a brand new file called about or you could even return a simple string about page all right let's come back and give it a shot all right example. test slab and there we go we see about page it works okay so now I know what you're thinking when would I ever do that H you actually might be surprised and further in addition to returning a string you could return an array so this uh we're getting a little ahead of ourselves but in situations where you want to build an API of sorts this would be one way to do it fu is bar and if we come back and give this a refresh and sure enough our response was converted to Jason which is really cool okay but for now we're not talking about apis let's keep it really simple so I'm going to return a view called about now let's go into the views directory and I'm going to create a brand new file but this time let's forget about blade we'll talk about that shortly for now I'm simply going to call it about.php and I will paste in a big chunk of HTML so I might say about page and I can say hello from the about page all right let's switch back give it a shot refresh and there we go we've rendered our view okay so now we have a brand new LEL project where we have declared two routes one of them loads the home page and that just says hello world for now and another one loads the about page okay so yeah notice it wasn't that complicated you're in and out and that's the entire point of this course at no point do I want want you to feel overwhelmed at all so yeah baby steps are going to take us all the way through uh this initial 30-day course so here's your homework I want you to keep playing around with these routes why don't you create a brand new route called Contact and that contact route should load a view called Contact see if you can get that to work and then move on to day three I'll see you then [Music] welcome to day three glad to have you so I don't know about you but whenever I'm learning something new that's web related and this could be a tool or a library or a framework like larl I don't know no matter how much experience I have I always turn back into that absolute beginner who just wants to learn how to make a a simple three-page layout and it makes sense if you think about it if you can figure figure out how that works you instantly know a lot you understand how the life cycle of a request Works within the context of your new framework and that means a lot all right so in that Spirit we're going to do it again we're going to build that simple basic uh laughable three-page layout using LL let's get started all right so here's where we left off at the end of day two we have a default route for the homepage and then we added a second one for the about page and if you did the homework you should also have a third route for a contact page but if not that's okay we can do it together route get contact and this will load a view called Contact okay so now we have home about contact and then corresponding views but notice how we're still using the the name welcome uh that ships with the framework by default why don't we rename this to index or how about home all right so if I update that name I also have to update the view home all right and here's what I'm going to do I will visit the about page and copy all of this and paste it in and if alarm bells are going off for you good job we will fix that shortly but for now we're going to create uh a bit of duplication so hello from the homepage hello from the about page and then we also need a new one for the contact page so I will duplicate this and this will say hello from the contact page all right so update a few values here and there we go let's give it a shot in the browser all right so we have the default homepage we have an about page and then finally a contact page but of course we don't want to manually update the URI in the address bar each time so let's add our first simple navigation area we'll do it at the top we'll call it nav and then I will Nest Three Links the first one goes to the home page the next one goes to the about page and of course the third one goes to contact all right so it's not going to be pretty but if we go back to the homepage and give it a refresh we see some basic links here all right so now at least from the homepage I can quickly access about or contact but yeah of course the moment we load that new uh view we lose our navigation area so yeah if if you're a beginner here's what we all did we just pasted it in crossed our fingers and hoped for the best like this and yeah it is true that would work but clearly we can all see this does not scale and it's not the best idea all right so instead we're going to reach for layout files here's what I'm going to do I'm going to update the file name of each of these views to include the blade suffix so notice it's the name of the view. blade. PHP and we talked about this a little bit in day two blade is lille's templating engine think of it as a thin layer on top of PHP and ultimately when you load the file in the browser it all gets compiled down but yeah it's like a small layer on top that gives you some extra goodies uh gives you some helpers some shortcuts uh directives which we'll learn about in the future as well as layout files or Master files as you might know them so I'm going to update all of these one more and yeah if I switch back to the browser nothing will change at least uh from the end users point of view so there's home about contact it all works but now yeah we can upgrade our code base so I will create a new directory here and I'm going to call it components uh this directory name is important by the way if you're not familiar with that term think of it as any kind of reusable block uh that could be referenced in multiple places around your application uh a task a menu a drop-down uh item a layout file uh a card a message an avatar any of these would be just fine so notice how I said layout well layout is a component and when we create a file within this directory it's a signal to laravel that it should be treated as a component so let's do that now and again don't forget to add that blade suffix there a lot of people forget that uh at least initially all right so what I will do is I will take all of this wrapping code and I will instead place it within this layout file here all right so this looks pretty good to me except for this final line here that of course is unique to the homepage but we'll fix that in just a minute so here's what I'll do I'm going to return to my home view delete it entirely so now if I come back to Safari and reload the homepage of course I don't see anything at all and that would make sense but now I want to reference our layout file and we do it like this we interact with it as if it were a custom HTML tag so what's the name of the tag well you gave it a name when you created the file in this case layouts so we always start components with x Dash to ensure that they're unique and they don't interfere with existing HTML tags and then we reference the name of the component all right and that's it this is really cool so if I come back and give it a refresh sure enough we are loading that layout file which is great all right so now if I return to layout. plade maybe now we can get rid of this section here that doesn't belong in the layout file it belongs in the unique view I will cut that come back to home and yeah what do we do do we just paste it in here well yes but if I come back to the browser and refresh I'm not going to see it here and that's because well we're doing it properly but within the layout file we have to explicitly declare where uh that H1 tag should be slotted in so to speak so where should we put it where do we slot it we slot it right here that's where I effectively want to copy and paste uh anything within this layout tag directly here all right so uh with glavel there is a variable name that's always available to you called slot so I could do well I'll show you the long form way and then we will use some of the blade helpers but yeah I could open up PHP and then Echo this variable called slot all right come back to the browser give it a refresh and it works all right so are we all on the same page this is really important if you don't understand anything here please ask a question in the comments below we have created a new component for a layout file some people call them Master files that works too now the layout file is almost like the structure for your application it's all the surrounding markup it's the head tag it's any scripts or stylesheets you need to import it's the general structure it's the navigation area it's the footer and then typically you have a main section that will always be unque for each page so we will Define the structure and then we will slot in any page specific markup okay so here's our home view notice how much cleaner all of this is I can replace the contact page with hello from the contact page and then about and we are removing all of that duplication which is really great all right so come back give it a refresh home about contact and now if I ever want to add a fourth page maybe something like meet uh meet the team notice I can update the navigation area within a single file rather than manually updating every single view where we pasted that markup uh it's clearly the way to go but I'll come back and remove that okay so I'm going to finish up by showing you your first uh blade helper so yes I can open up PHP and Echo out this slot because we're using blade we can instead create two opening and two closing curly braces so this directly translates to PHP Echo and then whatever variable you provide in this case slot so notice if I come back and refresh we get the exact same thing because it is the same thing uh behind the scenes your blade code is being compiled to vanilla PHP so yeah for now when you're first learning whenever you see those braces in your head translate that to PHP Echo slot this one's just easier and more common to write all right great so yeah think about what you accomplished here for day three you learned how to build your first simple three-page layout and listen I get it I know it's super basic but it's a right of passage anytime you're learning something new and you should be proud of yourself this is really cool stuff and you also had your first introduction to components in layout files which is super powerful and very prominent in the LL community so you need to learn it all right so what about your homework for day three um if you choose to accept it I would like you to got it all right so we worked on this navigation area right I want you to extract each anchor tag into its own component or I want you to create a layl component called nav dlink and that'll be a file and you have to figure out where does that file go and within that file I want you to paste that anchor tag that we have here but you got to remember you can't also paste the label or the name for the anchor tag that part will need to be dynamic so you will need to leverage slots just like we did in this video all right see if you can figure that out and then I will see you in day four [Music] by all right welcome welcome to day four everybody Why Don't We Begin by quickly going over the homework from day three so you may remember I asked you to extract one of these navigation links into its own dedicated component so let's do that now together so in my components directory and actually a quick note uh I made it capital here it's kind of muscle memory from other Frameworks I also use uh but it can absolutely be lowercase if you prefer all right anyways uh nav link. blade. PHP all right let's grab this and paste it in like so switch back and now this can become xnav link like so all right obviously a little more work to do but let's have a look in the browser all right come back give it a refresh and yeah we do see the home link but it's not very functional right this needs to be dynamic so that it can be used for any nav link item all right so why don't we do that slot technique here let's come back to layouts and now this can become home this one can become about and this one can become contact all right come back give it a refresh all right that looks good but now of course you'll notice they're all linking to the exact same place all right so this is where the homework got a little bit tricky you may not know about this so it sounds like I need to pass in a an href like we did like we do with a normal link right that would make sense however in the navlink component how do we access it right uh well as it turns out all laral blade components have access to an attributes object and that object will contain uh all the details for any attributes you pass and by attributes I mean href I mean ID I mean class any of these okay so if I come back to our component yeah what we could do initially is just open up an echo um PHP Echo and then say attributes and that will properly be stringified now yeah again keep in mind attributes is an object so there's actually more bells and whistles than what you initially see here for example if you want to merge in some sensible defaults you could do so like this but we're getting a little ahead of ourselves so let's keep it very simple right now all right back to the browser give it a refresh and now we should see the about page and the contact page and yeah just to be crystal clear here what if I wanted to say uh the about page should have a style tag where the color is green or something like that well that too will be included in that attributes object so if I come back and give it a refresh sure enough it's green okay so now you're probably thinking okay fine but why would we ever do this uh and the answer is well maybe for simple things you wouldn't however in real life a navlink is a little bit more complicated than a simple anchor tag uh think about it you will need specific classes or styling based on whether it is the currently active page or not um there might be other situations where the presentation should differ based upon I don't know where you are in the website or what your screen size is anyways the whole point is it gets a little bit more complicated than a basic anchor tag in most cases so if we extract all of this into its own naving component we can isolate any of that complexity into a single file which is really cool all right but yeah that was just an example I'm going to delete it and now I want to make things look a little bit more attractive so here's what I'm going to do I'm going to switch over to tailn css.com and actually on that note before we begin um if you don't know what tail1 CSS is trust me it's entirely fine you don't need to it's not a prerequisite for the course it's just a way to quickly and rapidly build up um some layouts and such without having to refer to a CSS file so Tailwind is a CSS utility framework and what utility means is you can declare classes that refer to specific uh CSS properties effectively so for example there might be a class name of text red 500 and that literally refers to set the color to this shade of red there might be another class name of mr-2 and that translates to set the margin right to level two uh so again it's very easy to learn but it's not a prerequisite all right back to work now one thing that I especially like about Tailwind is it's companion Tailwind ui.com so this is a paid tool but they offer free uh example components and those free ones are the only ones that we will use uh for this series okay anyways check this out if I browse components and we scroll down to application UI yeah notice they have examples of sidebars and multicolumn layouts and headings it inss up being a really great way to quickly scaffold uh any new application that you're working on okay so anyways I'm going to click on stacked layouts and yeah right here you'll see usually the first one is free to anyone but if you want any of these custom ones uh you have to pay for it and again we don't need the paid plan here so if you're working along we're just going to grab the free code here and I can click on it and that will give us what you see right here a quick application uh layout or UI okay so I'm going to grab this and within layout yeah we're going to replace all of this and it's a big chunk of HTML so that's okay we'll go over uh anything that's important and we'll probably delete a bunch of this as well all right so let's go back to the browser give it a refresh and what's going on here well we've pulled in uh this Tailwind component and notice all of these utility classes but we haven't actually pulled in the Tailwind CSS uh framework so you can attach this to your build tool of choice if you know what that is but otherwise while we're still in the in the playing Phase the toying phase I'm just going to reference it on a CDN and I can do that I believe I have a shortcut for that yeah I can do that by creating a script and setting the source to cd. tailwind css.com and that should do the trick so if I come back and give it a refresh Tada it works pretty cool all right so now I want to take two minutes and just quickly delete anything uh that we're not going to use like these menu bars and such all right so your profile I'm going to search for that and yes notice uh for anything that requires a bit of interactivity in JavaScript they will include notes for what classes you should uh toggle in our case though it's not going to be relevant because we won't have any drop- down menu all right so what you see here is the user's profile all right give that a refresh and now it's gone but notice there will be mobile styling as well so we should get rid of that uh as well all right here's the mobile version come back give it a refresh and now that's gone good all right what else uh we don't have five links we only have um three so we have one for home one for about and one for contact and then I will update these links cool and there should be let's see yeah this is the mobile specific version so if I come back and refresh we've updated it here but notice for desktop view uh we haven't so I'm going to look for dashboard one more time aha here we go let's update these as well home about contact all right come back give it a refresh that looks good to me next we have our heading here so it's set to default and if I scroll down here uh there we are and then notice it says your content here so example content goes here or the slotted content right and we learned about that in the last episode there you go so this would be the main content area uh for each individual page so let's see can we just swap that out with slot all right let's give it a shot so we come back give it a refresh and now notice a quick note it's going to appear as if we're on the homepage because those CSS styles are hardcoded on that home link but we will make that Dynamic shortly uh anyways right now we're clearly on the contact page as you can see here and then we're on the about page and then we're on the homepage okay but what about the heading here and this is where it gets a little bit tricky we've learned about setting a default slot here but now we've learned there's a section outside of that that also needs to be dynamic based upon the current page uh and there's a couple ways we can do this but one way that I like to is to Simply assume this is a variable do you want it to be heading title anything you want let's call it heading okay but now if I come back and give it a refresh it's going to blow up because well now it's looking for a heading variable that has not been defined so that's proper behavior okay so how do we Define that well if I come back to the homepage um there's there's two options here we could pass it through as a prop and a prop is just kind of a custom attribute like this heading or we can declare a named slots so think of your slots as different areas where you paste content and you could have a slot here a slot there and a slot down here right but you need a way to distinguish between them so we assign names this is your your dashboard slot this is your main slot this is your footer slot right so if we know that this represents our default slot at the very top let's create a new one for our heading slot and we do that by writing x-s slot colon and then in this case the name of the slot or the variable so we have heading here and I can say home page all right come back give it a refresh and it works very cool so yeah this is one way that we can solve that problem and I think it's probably going to be the path of least resistance um like I said we could talk more about props but I don't want to get too into the weeds when it comes to components because we have many other things to talk about first all right so let's go to the about page and update this one as well like so contact and again this can be anything uh you want we're just using a basic uh string for now so home about contact I think we're in business all right so now the last little fun thing I want to do is swap out some of these images uh instead of the Tailwind UI logo why don't we use of course the layer cast logo and I will paste that in right here yeah layer cast.com images logo logo triangle or use your own logo come back give it a refresh that looks nice and then finally this guy this ta one UI guy I'm always seeing uh let's come down where are you buddy right here let's swap that out with our mascot Larry the robot so I will paste that in and once again lc.com images lar aif face and nope there's two versions of this dude where's the other one here we go here's the other one like that so come back give it a refresh and I like it okay and then finally I think this dude's name is Tom Cook why don't we change his name to Larry robot and we'll do just me Jeffrey lc.com all right give it a refresh come down and now we see Larry robot all of this is looking good especially when considering we spent maybe 10 minutes or so on this okay so now in the next episode I'm on the contact page but the home button is highlighted which clearly is not correct so we'll have to figure out how to conditionally uh create layout or apply styling based upon what the current URL is or what the current route is so yeah I'll show you how to do that in day five no homework today I think you've done enough uh and I'll see you later bye [Music] welcome back everybody to day five do I re-record that I'm going to keep it welcome everyone to day five um today we are focused on these navigation links we need to figure out how we can apply custom styling based upon what the current routes and you'll learn about that shortly uh or what current URL is let's get going all right so for a visual yeah notice how the active navigation styling is hardcoded to the homepage even though I click on these so we got to fix it so why don't we start within our layout file and actually real quick notice how Tailwind has given us a little bit of feedback that we need to uh set the height to 100% on both the HTML and body tags we missed that in the last episode so let's do that now height full um and then a background of a light gray then we also have to set height full to the body all right so now if I come back and give this a refresh uh you'll see a gray background here but also um you can't tell but the height of the container is now the the full height as you would expect all right cool so anyways I want to go down to our navigation links right here home about and contact and of course that translates to what you see here and yeah again not notice how the first page has the active link styling which is a background of this gray 900 uh and generally with Tailwind 100 level 100 will be the lightest version and 900 will be the darkest um so if it is active it looks like we want white text and a dark gray color for the background and that's what we've done here uh otherwise it should have a lighter gray color and white text when you hover over it which is what we have here all right so here's what we can do we'll run a conditional to determine whether or not the current page is the homepage in this case and for this anchor tag is the current page about and for this one is the current page contact and if that is truy or true and I'm going to hardcode it just temporarily in that case we want these stylings that Tailwind has recommended so I will paste that in here otherwise and I'm just using the chary operator here otherwise we want these so I will grab that and paste it in okay so now I can remove all of that and here's what we get all right so let's get rid of this and yeah because we've hardcoded true it's going to be the active styling right and we see no change but if I change this to false and come back of course the styling updates all right very good and actually let's switch over to the homepage okay so now the only remaining step is of course to substitute this with the real method call so as it turns out laravel out of the box includes a request helper function uh you can call it to grab information about the current request now one of these methods on the object is called is and this allows us to pass a Rego expression a pattern and it will determine whether the current page matches that pattern so I could say if the request is the homepage then apply active styling come back refresh and it works but notice now when I switch to the about page it's no longer highlighted and that's what we want all right cool so now let's do this let's come back and I'm going to select all of that and paste it in here and then another one for this link okay all right next I can get rid of all of this because it's now included as part of the conditional like so now I can update this if the request is about if the request is contact and I think that should do the trick Let's cross our fingers give it a refresh and now we have about page contact page home page P everything is working just like we want and that's great okay so now remember a couple episodes ago how I noted that yeah a real life navigation link starts to get a little bit messy once you um change styling based upon the screen width or you have conditionals to determine uh special active or selected uh styling so with that in mind why don't we reintroduce that naving component and uh see what it looks like all right so I'm going to come back to components I'll create a brand new one here called nav link. blade. PHP all right I'll switch back select the whole thing and some of this should be a recap because we've already done this once so yeah as we discussed last time we don't want to hardcode the HF we should pass that in un let's hide the sidebar all right so now all of these will change to uh xnav link components and then all of this class junk including area current and we'll update that shortly as well uh can go away so I'll do this one as well and this one okay let's go back into our component clean this up just a little bit all right let's tackle uh this one ARA current um if you're just playing around feel free to delete it but if you're building a production app and you want it uh to be as accessible as possible this is for screen writers and it's a way to indicate if the current link um represents the current page in a list of pages uh if instead it was set to false that means it is not uh the current page so yeah once again we could do a check so I could just grab uh let's just grab this whole thing paste it in and then instead of using CSS classes I could set the value to page uh if it is true or false if it is not true all right that looks good next uh home yeah of course I'm just removing any hardcoded values so this can be our default slot and that means right here home will be effectively pasted there about for this one and contact for that one next the current URI um there's a number of ways we could handle this of course we could inspect the href but another way I want to show you is to introduce a prop that indicates whether this nav link should be marked as the active nav link and actually real quick let's go over that so within blade components you will hear about attributes and then props so attributes represent HTML attributes the H rev the ID the class anything uh a prop would be anything that is not an attribute and we we basically distinguish between them because you have to know well should that prop be included as one of the attributes that we Echo as part of the anchor tag well no right so if you have a prop called active and you Echo it out as part of the attributes now you have an anchor tag with an attribute name of active and that doesn't make sense so we have to distinguish between the two and here's how we do that at the top of my blade component I'm going to use a blade directive you'll know blade directives because they begin with an ad symbol and notice how my editor um autocompletes all of the available options here and there's countless ones again don't feel overwhelmed you will use a fraction of these but you have um directives like if or unless or for each or dump to quickly dump something to the screen uh think of them as little bits of shorthand or sugar that ultimately compile down to vanilla PHP um Echo statements or function calls so in our case we want a new prop so we can declare our props as an array and we've decided we want a prop called active Okay so I'm going to show you how this works and this will really help I think we're going to spit out all of the attributes that might be potentially in uh as a naving so for example in this one I'll set ID equals something here just so we can see it in effect all right let's come back to the browser give it a refresh and then inspect this all right and notice it does include the href and the ID and it does that because we spit out or echoed all of the attributes here so if I remove that and give it a refresh of course we're not going to see them okay so yeah what about this active prop well let's come back here and just say um again for the about page active equals and then some kind of value well notice if I come back and refresh the page there is no reference within here to that active uh property and again that's specifically because we declared it as a property if we didn't do that then larl will assume it's an attribute and it will be included um as one of the attributes that we Echo so that's what I mean when I say we have to uh explicitly declare any of our props so they can be distinguished okay so now instead of running this logic here and keep in mind we could still do this but I think you'll probably find that it's a bit more flexible if you pass it in from the outside so we're going to replace that with a simple check of our prop and we can access that prop by using the variable name for the prop so if I declare active up here I have an active variable down here so if that's TR the use the active styling otherwise use the default styling and that's the way it works okay finally because we are checking this variable there should be a default just in case it's not passed in when we reference the nav link so why don't we assume that by default it is not active all right so notice we pass an array the key is effectively the prop name and what the variable name will be and the value will be the default uh value associated with that name or that variable all right let's come back into layout and yeah let's just try this out now for or let's imagine the contact page is the active link I can just say active and I want to show you something so I could pass anything here and it's going to work because we're just checking if it's truy so if I come back to the browser and refresh notice it works but notice even if I change this to false and come back and refresh it's still going to work so how come well it's because right now um that false value is actually being passed as a string rather than a Boolean so is a string of five characters truy yes it is it doesn't matter if the string says false it's still truthy so what we really want to do is say no when I write false here I actually mean false when I write true here I actually mean true not the string true so here's how we do that let's come back to my editor and notice right now false is green just like every other string here that's how my editor is styling it but if I add a colon at the beginning of the attribute it changes to make it just a little more clear that oh no this is a Boolean it's not a string so as it turns out with LL and blade when you prefix a prop um name with a colon that is your way of indicating that the value you provide there should be treated as an expression rather than a string so notice in this case we've given it false it will be interpreted as false and it won't be uh it won't be selected if I change it to true it will be interpreted um as true and now that's working all right so now that I can provide an expression I can bring this back to what we originally had which was request is contact in this case uh so we're going to copy this and now this one should be treated as active if the request is about and then for home we check if the request is forward slash and yeah I think that should do it so we have contact about home everything's working and now you know what you've actually learned surprisingly a great deal about blade components even before you learned about eloquent and that's that's a very interesting way to learn but that's just how it happened to work out and I think that's a good thing actually so now you have a dedicated blade component you've learned about attributes you've learned about props um keep in mind you can also do things like this where you could declare um a PHP directive and we could do n PHP to create our block effectively and then Within here you could have some kind of code you could do a conditional you could uh inspect the value of active and then tweak it in certain situations and all of that is isolated within the single uh file component which I think is really cool all right and that does it uh so you know what really good job I would imagine for many of you this is sort of foreign territory these are new ideas and I I hope you're excited this is fun stuff to play around with all right so day five homework um let's continue with this component idea I would like you to introduce a new prop we will call the prop type and this will indicate whether the nav link should be presented as an anchor tag or a button tag so think about it within your component you will need to run a conditional uh if the type equals a then it should be an anchor tyde else if the type is button then we need to format this as a button Buton tag so I want you to see if you can figure that out if you need help as always ask questions in the comments below I'm there most days I will do my best to help you and if not me somebody else will step in but otherwise I will see you as always in day [Music] six all right welcome everybody to day six um and actually on that note we're about a weekend if you're still going strong congratulations please keep going okay so today should be fun we're going to figure out how to pass data from our routes file into our view but um as always of course before we get into that why don't we solve the homework Challenge from the last episode let's go all right homework so if you remember I asked you to update your navlink component to include a type prop I said the type could be an anchor tag or a button and we should INSP that value to determine whether or not we create an anchor tag or a button so here's one option and first let's create a default value so by default if you don't pass a type prop uh when you when you reference the component here we will assume that it is an a an anchor tag but it could be a button so why don't we try like let's imagine contact here should be uh a button so I want to pass that in as a string so I don't have to include a colon because by default it assumes a string and that's what we want all right so the quick way to do it in this case is we could probably just get away with changing uh the tag name to reference our variable now I say we could get away with this because I think it's going to work let's have a look refresh and now we have home about but I bet when I click on contact it doesn't work because it's being rendered As A Button as you see here so yeah it does work but here's what I mean if we switch back notice our editor struggling here we got a lot going on and if I hover over this squiggly line it says tag start is not closed because it just can't handle uh something like this so instead what we might do is split it into two real tags so here's what we could do let's undo it bring it back to what we had and we're going to take this in two steps so first we could open up traditional HP tags and I could say if type equals a we're going to use the um the short tags then display an anchor tag and then down here let's handle the else uh condition and then finally one more to close our conditional okay so we could copy this paste it in and notice in this case we could check if the type equals button but in this case it can only be an anchor tag or a button so I can safely just say if it's not an anchor tag no matter what it is we're going to treat it like a button but yeah if you want to be a little more strict you can do that okay so otherwise um create a button so we're going to accomplish the exact same thing but yeah our editor will beat us up just a little bit uh less all right let's come back refresh once again and yeah now we have home is an anchor tag about is an anchor tag and contact is a button uh and of course notice the button still has an href because we did pass it in so of course you would want to switch back and if you're trying to create a button then of course you would omit the hre in that case but yeah it's still going to work just the same okay so now finally step two like I said we can use these traditional um PHP tags of course but blade includes helpers to simplify some of these steps so just keep in mind though like behind the scenes it all gets compiled down to vanilla PHP as we've learned but it's a little bit easier to use the blade directives just like uh what you learned about in the last episode when it came to props so as it turns out we could swap this out with a blade directive called at symbol if so if in this case type equals a then run this code next this is else right so as you can guess the blade directive is called else and then finally down here indiff well we have a blade directive called indiff yeah that's what I mean and let's uh reformat that this real quick there we go it's the exact same thing it's just a little bit easier on the eyes and easier on the fingers too so let's go back to the browser give it a refresh everything's working just like before and again I can't click on the contact page because it's a button that works all right but yeah this was just an exercise I'm undoing all of this uh because we don't need it in this case it was just an example bring this back I'm wearing out command Z but I think we are in business okay okay so let's move on to the topic for this episode which is passing data to views so let's close this out and I'm going to go to my routes file now I I I'll let you know right now um it helps initially to manually open the directory and find the file but in real life I'm not doing that uh usually I have the sidebar closed and in my editor and probably yours too you could hit something along the lines of command or contrl p and then you can type the file that you want to access so in this case it is web.php and yeah that's just normally how I would navigate my project but yes sometimes I will open the sidebar just to make it Crystal Clear where we're going in the code base Okay cool so why don't we stick with the homepage so as it turns out we can pass a second argument to this view function that will be an array where each of the keys will be extracted into variables once your view uh or your template is loaded so for example if I have um greeting equals hello well now when I load my view I will have access to a variable called greeting let's try it out make sure you're working Along by the way so open up the sidebar again we will go into our home View and now I have access to a greeting so I could swap this out with greeting period all right so let's switch back refresh and whoops looks like we have an error and actually this is a good opportunity to be introduced to lel's error page which is really good when I was just getting started it wasn't nearly as helpful uh but yeah in this case we can see the issue it looks like it's related to our component and we have an unclosed uh bracket so I might have been a little bit too aggressive when we hit that command C button all right did that fix it yes it did and sure enough we have our greeting so if we come back to routes yo come back refresh it is working properly so let's do another one um um name you know n of these matter I will do Larry robot okay now we have a greeting variable and a name variable so I can reference that here just like that come back refresh everything's working all right very cool so now let's switch back let's get rid of all this actually let's switch back and pass through something slightly more complex um ultimately in this course we're going to build a job sport so why don't we start thinking about that uh maybe we could have a list of jobs that are currently available so the variable name will be jobs or the key name is jobs and that won't be a string it will be an array of available jobs where each item is its own array and then you could have things like this like what is the title of this job well maybe director and then maybe salary and we'll lock that to you know whatever $50,000 uh a year okay so there's one item why don't we do a total of three this next one is programmer and this one you know what with AI we're going down the tubes let's bring this down to $10,000 a year to be a human programmer and then finally why don't we have um teacher uh at a school maybe $40,000 or something like that all right so now when we load our view we will have access to a jobs variable that is equal to a list of jobs now let's go ahead and loop over them so again I could open up PHP and say four each but let's instead use one of the blade directives and again what's cool about these directives is you can guess what they're called if I want to do a four each then the blade directive is called for each all right for each jobs as job and then of course you need to declare um the end of the block right so you will almost always have an end and then the name of the um the directive end for each okay so let's begin with a simple list item where I Echo out the job uh title and let's have a look in the browser refresh and there we go we have three jobs a director a programmer and a teacher uh next why don't we do a colon and we'll say pays uh and then we'll do job salary per year come back refresh there we go uh why don't we make this bold so what I'll do is wrap this within a simple strong tag and there we go so now with that in mind why don't we tweak things just a little bit uh instead of an about page I'm going to change this to a jobs page get rid of that and if I were to come back to web now this could become jobs and that's going to load a view called jobs okay so now I'm going to take or steal all of this and paste it in like so and then this can return to a simple homepage all right so all I did was create a new route that listens for when the user visits example.com or example. test/ jobs and in response it loads a view called jobs and it passes through this data that we're currently hardcoding but of course you know in real life that will probably be fetched from a database and we'll talk about that in an episode or two all right so let's go into home snatch our four each and paste it into jobs all right and then finally let's update uh the about page to point to jobs like so all right refresh and now we have a homepage and a brand new jobs page that lists all of the jobs that are currently available for your business or whatever very cool so I want to finish up though by making each of these clickable and when I click on it it should take me to a dedicated job listing page so hm how are we going to do this well let's go back to jobs and yeah H let's do this we're going to have a list item and of course this should be wrapped if you omit the UL the browser will create it for you yeah just a decent practice is to include it um so now we know these are all going to be anchor tags so I will wrap them like so and this is going to take us to to a new route why don't we say jobs slash and then maybe some kind of identifier or a slug that represents each individual job that we're offering so let's add an identifier like ID we're going to keep it really simple ID is one for this one ID is two for that one and ID is three for this one so now we have one key that is unique and will always be unique that represents this individual item okay so now if we switch back to our job listings page think about it if I said job one we now have a hook of sorts that will say all right fetch me the job that has an ID of one if I did job3 we know find me the job that has an ID of three we have a way to do that okay but now how do we create the route for this because really we need a route that says listen for job slash and then some kind of value it could be anything it could be dynamic so how do we do that well I'm going to go back to my routes file here I'm going to create a brand new route and why don't we reuse this one here to save some time listen for jobs slash and then could be one could be two could be three could be 10,000 right so why don't we instead represent this with um I don't know like a ID or we could even call it job what job do you want but yeah I'm going to call it ID just for now so here's the cool thing about larl laravel will automatically detect that this is wrapped in braces and it knows oh this is a wild card so I'm going to I'm going to grab that I'm going to contain it and then I will pass it to this function so that you can use it however you want I'll show you let's call it ID and then I'm going to dump an ID and actually instead of dump I'm going to switch over to a DD function which means dump and die so dump the ID and then kill the execution because all I care about right now is just quick seeing what is the value of this variable so as it turns out this dump function and the DD function you are going to love I promise okay so let's switch back example. test job1 and we get one if I do three then we get three so yeah notice it's a wild card and larl took care of all the work of grabbing it isolating it and passing it to our our closure here or the call back function which is so cool isn't it okay so now think about it I'm going to duplicate this jobs uh listing but again we could extract it and later we're going to do that there a bunch of duplicated jobs isn't a great idea but yeah what I could do is have our list of jobs here and then all we have to do is say well give me the job where the ID equals the one that you passed in so why don't we say job equals and do you know how to do this well you could do there's a number of ways to do it you could do a for each Loop over each of the items and then manually check is the ID of that item equal to um the ID that we're trying to reference if so that's the one you want uh but as it turns out you're using a framework so you should leverage the framework uh I will teach you about collections later in this series but for now it would be helpful to know that laravel includes an ARR class and that stands for array of course and this gives you access to countless methods as you can see here to interact with arrays so if I want to find the first item within an array that matches some kind of criteria I could use the first function I give it our array and then I provide a function and this function will be called for each item within the array and it will receive the current uh item so in this case it's going to Loop over the jobs and for each item it will pass that into your function so job would be equal to this on the first iteration then this one then this one you get it okay so now this should return a Boolean that indicates is this the one you mean is this the first one you're trying to find so in our case we're going to say return job ID equals the ID that was passed in but as you may know um because we're in a closure here I don't have access to the ID here so you have two ways to solve this one with traditional PHP you would add use use the ID make that available here and that would do the trick another option is to instead use a short function that was only recently introduced as part of PHP 8. x one of them so that would take the form of this FN accept your job then use an arrow and then do once again job ID equals ID but notice we don't run into that problem where we have to add use and that's because of the scoping here and this will do the exact same thing and generally if you can use a short closure here for things like this I would recommend it it um if it's new to you and it feels weird Everything feels weird at the beginning stick with it and then you don't think about it ever again all right but do whatever one you feel most comfortable with right now that's most important and that'll give us our job okay so now let's leverage our dump or our DD function to just do a sanity check did that work all right let's come back to the browser all right refresh uh we are on job3 and sure enough it found that item let's go to job SL2 if on that item job SL1 very cool but now what if it's job sl5 we get null so right now we have to be aware of that the user might request a job that does not exist and we have to figure out what to do in that situation okay but happy path first so now I'm going to return job and I will uh pass through our job to the view finally right here we can use the fully qualified class path but instead I'm going to import it so you can do it manually or use whatever shortcuts your editor provides in PHP storm I can press option return and do cleanup code and now notice it automatically Imports that at the top okay so are we on the same page we have a new route to show a job uh right now we're just duplicating the list of jobs but we'll fix that uh soon I promise and then we search for the job that has the matching ID uh that's uh included as part of the URI once it finds it and this is Happy path so we assume that we're going to find it we load a view all right let's go into our view now and and it looks like we don't have one yet so I will copy jobs paste it and call this one job. blade. PHP and then down here um yeah maybe whatever you want we could have an H2 this would be job title and then uh we don't have much else we could do a salary uh this job pays job salary per year and that's good enough for a little demo here uh real quick let's add a couple classes here these are Tailwind classes uh text large you can leave it blank if you want but yeah we're just making the font Bold and the text slightly large easy enough for me all right back to the browser and there we go here's our director position what do we have here job with an idea of one here's number two for a programmer three for a teacher it all works so now think about it all you have to do is link to that specific page within your job listings view so right here let's make it Dynamic job ID let's see if it works so here's our jobs page um we don't have any styling yet but notice they are clickable so here's our director position let's go back here's our programmer position and here is our teacher position so yeah the last thing I'm going to do is just add I don't know text blue hover underline for each of these just to make it not great but just to make it a little more clear that these are clickable links H maybe I should be a teacher all right this job pays $40,000 here's all the details here's a form um I can fill out to learn more we are well on our way to creating a job board all right so yeah we're not actually going to build the real jobs board uh platform until the end of the course when you feel quite a bit more but yeah throughout the series you're going to see little nuggets little traces of of Concepts that we might use once we start building that thing officially so you're doing great work uh this video went a little long so no homework today I will see you in day seven [Music] bye okay welcome to day seven so I'm going to Dive Right In because we have a bunch to do here I'm going to start within my routes file and yeah you'll remember in the last episode uh temporarily we duplicated the list of jobs so I defined the array here and then we did a copy paste down here as well but yeah clearly um that doesn't scale at all so we need to solve this problem but H I'm going to solve this problem in a very incremental way and I'm going to do it uh in this way because I think it will help you better understand some of the concepts that we will discuss in the next episode so just bear with me and come along for the ride okay so if we're thinking incrementally well the first thing we could do is just push the array up one level so I could select our list of jobs here cut it and then push it up one level which in this case is just the routes file so I could have a list of jobs like so and then if we scroll down we could use those jobs so make that variable available within this closure here and then I can pass it in okay then I can do the exact same thing here so get rid of it and then once again make that variable available in this function and yeah we have now removed that duplication back to the browser click a link and yeah everything works exactly in the way it did before which is great all right let's keep going uh next I'm going to wrap this within sort of a data container so let's create a class called job and I wanted def find a method that will fetch all of my jobs and I just said the word all let's make that the method name so I have a method called all and I'm going to make it static that's fine for now and we will select all of these right here this whole array and bring it in like so all right and then of course I don't need to define the variable here okay so yeah it's just a container uh at this point if I call job all that's going to return this array to me okay so now we can scroll down we will no longer need ed jobs so I can get rid of that because now we have a class and I can replace the variable names here and I'll select both of these with our job class colon all all right makes sense we now have a class with a method called all that returns an array and let's make That explicit by adding a return type we can do that by adding a colon and then the type of the data that we're returning in this case an array so we're just being explicit about what type of data is being uh returned from this method okay so let's go back to the browser once again give it a try and everything works just as it did before cool all right let's keep going does it make sense to have a class name job inside of our routes file no it's not really where it goes so why don't we instead place this within our app directory but where do we put it well I think we're going to use the models directory here okay now let's take 30 seconds to quickly go over this because I think it's important and by the way that's why I'm doing a side camera view it's that important to listen up open your ears okay uh model is a key term and it comes from the MVC architecture MVC stands for model view controller uh and it's not unique to layl lots and lots of tools and Frameworks uh adhere to it uh it's just a system it's a methodology for how to go about constructing applications and how each piece of the puzzle should and can communicate with each other so model view controller MVC and as it turns out you've already learned about views right it's the presentation layer controllers we're going to talk about more but what we're doing in that routes file where we Define a route and then we have a function that handles that route that's your controller basically but we'll get into that more in a couple episodes so that leaves model now I'm going to keep it very basic your model can represent uh your data persistence but also the business logic tier of your application so think about it if you were building a jobs board platform the concept of a job is really important and it would have all of this Behavior associated with it right uh what are what are the rules for creating a job um Can jobs be marked as open or available or filled uh what happens when a job is filled you know there are all of these questions that you have to ask whenever you build an application and then that doesn't even account for how do you store these jobs do you write them to a file are they being placed in a database how do we remove a job how do we archive a job how do we delete a job all of this stuff uh can be encapsulated under this umbrella of model so H if we have a model's directory and we have this job class well maybe the job class should go in the models directory so let's do that now if I open up models you'll see we already have a user class and we will learn about that more a little later so let's create a class here and I'll call it job and you'll see my editor populates the class but I'm going to remove that so that I can copy over the one that we've already created so I grab that and move it over okay now if I scroll up real quick I want you to notice that we have a namespace of app models and notice how that correlates to the directory structure Here app models okay so I'm going to assume that you understand what a nam space is but if not the 5-second explanation is it's a way to organize your code right as you can imagine the class name job is not that unique so for example if I look in the entire project and framework for job right at the top I see three different files that have the name job one of them refers to a cued job one of them refers to an interface and one of them is our job model so as you can imagine without some kind of organizational structure in place you have collisions just like 20 years ago when you are organizing your downloaded music you didn't put everything within a top level folder right instead you grouped it according to the artist so all Jam miroy songs went in a jam miroy directory all uh zzy top songs went in a ZZ Top directory it was a way of grouping things to avoid potential collisions and also just to make things easier to reason about okay so all you need to know right now is larl conforms to an autoloading standard called psr4 and that is defined within your composer. Jason file and yeah if I scroll down you'll see it right here autoload psr4 and if this is all just gibberish and you're like I have no idea what I'm looking at that's okay just come along psr4 is a convention and a standard for autoloading files and we can Define our mapping so to speak right here and Lille does this for you automatically so Lille is saying right here I want an app name space and I want that route to be located at this path okay so the app name space is located at this path from that point onward any directories you create are sort of like creating a new folder when organizing your music so notice how user follows that app models is the namespace if we go anywhere else how about HTTP controllers controller then it will follow that namespace app HTTP controllers and when we do this we now have uh enough sophistication to automatically import these files without having to uh traditionally require them like you might have done 15 years ago with PHP okay so all of that to explain when I come back to my routes file all I have to do here is use it and it's instantly available to me I can say use app models job just like that okay back to the browser click a link and yeah everything works again just as it did before which is a good thing because now we're getting a little bit more comfortable we've learned about views and now we're dipping our toes into this idea of models and extracting data into its own class to which we can then apply behavior and logic to so for example what about right here this section where we have a route that listens for a specific URI to view a single job when we do we fetch all of the jobs and then we have this array class that LEL provides that finds the first job that matches the ID from the URI or the URL so this kind of behavior could go in the job class couldn't it let's give it a shot I'm going to select this whole thing here and I will command click on job which will take me directly to the file and let's add a new method here once again it'll be static and I'm going to call this find because I want to find a specific job with the given ID and that ID should be an integer all right and then I will paste in that code okay so ultimately we will return an array so let's import this class illuminate support array and then I will add the return type to make it clear that we expect an array to be returned here okay so now notice job all well we're already within this job class aren't we so why don't we just say static all and that would be fine and now we've taken some relatively confusing code and we've isolated it behind a simple method that makes it very clear what it does oh this code finds a job with the given ID okay so now check this out we'll go back to our routes file and I can get rid of this confusing logic and just replace it with jaw equals job find by the given ID notice how much that cleans things up too all right let's test our work okay so back to the browser give it a refresh click link it still works the way you did before but now it's even better um and that's cool and I think this is really cool actually so now remember in the last episode we we touched on this idea of the happy path and the happy path is if everything went according to plan this is how it works so what about if it didn't go according to plan for example what if the user tries to visit a job uh with an ID that we don't have in our system like 20 well right now we get an error right so for the job class when we used the find method we expected The Returned value to be an array but null was returned because there was no matching item here so this makes sense but also real quick we should talk about return types uh if I come back to the job class if you did not add this return type and types in general are optional in PHP but if we did not add this your uh error message will be different from mine because it will be caught at a different point in the script's execution so have a look if I remove it come back and refresh it still doesn't work because within the view we're trying to uh interact with it as if it were an array but it's not it's null so it still fails but it fails at a different point and whether you enjoy types or not and believe me there are world wars when it comes to to topics like this uh just know that one of the benefits is it will it will pick up on potential issues uh earlier in the scripts execution and generally that's a good thing okay anyways come back give it a refresh and now we know okay well we have to handle the situation where we're trying to find a job but one wasn't available and we have to handle that in a specific way all right let's do that now so we're going to try to find the matching job however in certain situations job could be null so why don't we just check for that so if is null or I could just write if not job and that will effectively do the same thing then we should probably abort and display a 404 page 404 uh stands for not found it's a browser status code and it's exactly what we want in this case you're trying to access this page but we we don't have anything to show you sorry 404 not found so with LL we have a helper function called abort and we can include a status code as the first argument here and by the way one thing that I really love about LL is how all we have to do is call the support function and it will then Bubble Up in our system to the point that Lille will catch it and understand what to do so H we have a 404 exception here I'm going to translate that into the appropriate response and you don't have to do anything to make that work have a look here if I switch back to the browser and we refresh notice that this time we do get a 404 not found page all right so I think that about does it for day seven uh real quick we're no longer using this class so I can remove the import and I think we're in pretty good shape here so notice we've cleaned up the routes file considerably uh we've learned about models and we've created our first model uh we've learned a bit more about data encapsulation and behavior and how to handle uh the sad paths or the the unexpected paths you've learned about custom uh status codes and how they are converted into responses automatically by larl we really covered quite a bit for day seven so no homework for today keep playing around with this get comfortable and then I think you're ready for day eight I'll see you then [Music] all right day eight welcome back everybody so in our job class up until this point we have been hardcoding our job listings and actually on that note if you're just building this for your company and at any given time there will only be you know two or three jobs available and you don't mind manually updating this file uh whenever A Change Is Made then keep it simple this is fine there's nothing wrong with this whatsoever however yeah if you're building an actual jobs board platform that allows people to sign up and and create new jobs then this doesn't make sense right instead we probably do need a dedicated database to to house all of our job listings and that's what we're going to work on today now you remember when we initially installed this application uh larel asked us which database we wanted to use let me show you that again LL new testing and it'll ask a handful of questions and then it will pull in all of the dependencies that lell requires through composer and then right after this it's going to say all right cool what database do you want to use so notice by default it chooses sqte which is a file-based database that actually kind of gets a bad W sometimes uh it turns out you can use this in I would almost say the majority of situations if you're Google you probably can't do it you know if you're Amazon you can't do it but if you're just a reason ably uh sized business and and you don't have database rows going into the millions and millions and millions then you might be okay at least initially so that's why larl chooses it as a sensible default but yeah otherwise if you prefer my SQL or MySQL uh then you can select the one you want so here's what I want to show you I'm going to cancel out of here uh with control C because we don't need it but if I switch back to PHP storm and I go into my environment file that database choice is determined here so your EnV file is where you configure all of the various uh preferences and passwords and and strings uh for your project so notice it includes such configuration as what database do I want to use um is my application currently in a debug State well if I'm working locally the answer is yes when I push it to production the answer will be no or false um what else do we have here what session driver do we want to use what Cash Store do we want to use uh if I'm connecting to some kind of API as part of my project maybe there will be an API key that I store here and I can add my own so I could write some app API key and then I paste in whatever string they provide me and then I can reference that safely throughout my entire Project without worrying about very sensitive uh codes or passwords or sequences being shared potentially through GitHub and things like that so this is important and we're going to talk about it more in the future but for now I just want to point your attention to the fact that if you want to figure out what your default database connection is you can visit this file or you can run an Artis command to view it so let's go to the terminal I will visit my example project that we're currently working on and yeah we touched on this just briefly Lille ships with a tool called artisan and when I run this you'll see a variety of commands that you can run a huge variety but again like everything you're probably in most most situations not going to run 90% of these you'll find a handful that you reach for and then every once in a while you'll reach for a different one okay however if we come up you'll see they are sorted according to a nam space so we have an off name space a cach name space uh you'll find a make name space uh this Nam space is for creating or generating files so if you want to quickly generate a class or an event or a Factory or job and you'll learn all about this uh later in the course you would use the make name space but yeah if I scroll back up notice within the DB namespace there's a command called show display information about the given database all right so let's have a look at that now PHP Artisan DB show all right and now we have a quick UI into our default database I can see it uses SQ the path to that file is here and then here are the various table that are included at the moment now here's a key thing to understand when we initially ran that LL new command one of the steps in that chain was to run your migration and build up the database and corresponding tables so I say that because if you're wondering wait a minute we're just learning about databases in this video and yet all of these tables have already been created how come well that's why now I also say this because if you created a ll app without using the LL new command you will need to run this manually and you can do that by saying PHP Artisan migrate and I'll show you an example of that let's go back to PHP storm and you'll remember from up here the path to the database is right here so we can check that go into database database.sql however what if I delete this and then we start again okay PHP Artisan migrate and let's put a pen in that word migrate just for now we're going to talk about that more shortly but if I run it it's going to say all right you're using sqi fine but I don't yet see a database do you want me to create it yes so now it creates it and it runs all of your migrations to build up the necessary tables uh that LL thinks you want as well as the tables that the framework itself will require okay so now if I switch back to PHP storm it manually creates that file now your next question of course is okay cool but how do I connect to the database how do I see the tables how do I inspect all of the rows within each table and the answer is of course you got to connect to it in some way uh you could do it directly through the command line if you're comfortable with that or I would recommend using a dedicated guey uh for your OS of choice so here's what I recommend so visit table plus.com uh at least at the time of this recording it is Far and Away the best database management guey I've ever come across it's a free download and there are versions for Mac windows and Linux so everyone should be happy and all on the same page I'd highly recommend it so give it a download and open it up when you're ready now once you open it you'll see a screen somewhat similar to this maybe minus the the layer cast connections let's create a new one at the top and one cool thing about table plus is they support all of the various uh connections so MySQL or postgress or sqlite or even reddis uh everything will work let's click on this one here and yeah it wants us to know what's the name we're going to call this our example database and next it wants a path to that file so we're going to give it a path directly here now you can either manually select the file or I will just do it in line users Jeffrey way herd because we installed herd in that directory my project is called example database and then the file is database.sql okay I'm going to give it a test to make sure that worked looks good let's give it a color of green save it and then I can double click here and here we go we're all set we're connected so here's all of the tables that are available to us we have one for users and sessions and migrations and jobs and failed jobs most of these I'll warn you are used internally by the framework and honestly you can almost forget they exist especially right now they are not important to you other than uh potentially this users table so come down here uh we can see the data and in this case there is no data yet we don't have any records but if I click over to the structure tab here's the structure for each of the corresponding tables so for a user of course a user consists of a name and an email address and a password and uh various timestamps which is great and we can append to these if we need to so if I switch back to PHP storm now you'll see there's a migrations folder and actually I just want to show you this one more time if I switch back to the command line when we ran that P P Artis migrate command it ran these files right here have a look create users table create cache create jobs table so it seems like the logic for creating one of these tables is coded in PHP which is neat if I switch back let's open it up and here are the three files now these are long file names because they include the timestamp but that's okay so if we have a look at the users table inside the sidebar yeah this is think of this as the blueprint for a table so we can see right here we want to create a table called users and then create a table called password reset tokens and then create a table called sessions and real quick if I switch back there's users there's password reset tokens and there's sessions they're all here and they were defined within this very file okay so now within the closure here this is where we we construct uh the table effectively so a users table needs to have a unique ID so we call this ID method let's come back there's the ID next it should have a name and that should be of type string so there's a name next it should have another string column for email but we want that one to be unique and yeah we can keep going on here we have a password we have timestamps and they're all represented here okay so what if we wanted to add something else like what if instead of name we wanted first name and then last name well I could do something just like this okay but it's not magical I can't change this file and then switch back and give it a refresh we have to rerun the migrations and that's what I want you to think of this file as it's a migration file okay you can run your migrations to make these take effect you can roll them back you can reset them it's really very cool actually on this note one of the coolest things about migrations is how because it's defined in PHP and effectively inversion control I can then share this with a teammate and then he or she only has to run a single command to generate a database that looks identically to mine so there's no more of that like trying to manually keep things in sync what's your table look like did you add the index here make sure yours looks like mine that's a nightmare you don't want to get into that situation and this solves that okay so let's make this take effect I'll switch back to the terminal and run PHP Artis to view all of the available commands and we'll scroll up to the ones related to running our migrations now I see two immediately useful ones migrate refresh and notice that resets everything and starts your migrations from scratch so of course you would never run this within production because it would drop all of your database records but yeah in the initial development stage this is incredibly helpful it's a way to say okay just drop everything and build up my database from scratch once again the next useful one is migrate roll back roll back the latest or most recent database migration so yeah notice if I open up the sidebar each of these is its own migration and you will create more on your own so you could have a migration to make a table you could have a migration to drop a table you could have a migration to add a couple columns to a table or remove a column any of those could be their own migrations just think of them as actions that you want to perform on a database Okay so you could say well just roll back the most recent one we ran uh and then rerun it these are all things that you can do directly from the command line okay but yeah in our case we haven't done anything yet so I will refresh all of our migrations from scratch PHP Artis migrate colon bres and notice it drops all of the tables and then rebuilds them from scratch okay so let's go back to table plus and actually this is an important note that you will run into specifically with site so if I try to hit command R to refresh notice I'm not seeing any difference so what I have to do in this situation is close out and then reopen the connection so let's close it out reopen it from scratch and now if I come back and switch to structure I can see the changes there very cool okay so now I want to finish up by creating our first migration so let's go back to the command line and I'm going to say PHP Artis make migration and now it'll ask me a question what should the migration be named keep it very simple just describe what you're doing if you're creating a table then write create such and such table now we actually have something a little bit tricky here I want to call it jobs right however LL already includes a table out of the box called jobs so yeah we don't we don't want to double up there so we'll need to embellish it in some way why don't we call it job listings table all right and now it creates the file in that same migration strory if I switch back I can find it here so now I see two methods up and down up represents applying the the operation whatever you want to change or add or remove and then down should do the inverse so this is do the thing and then this one is undo the thing so in our case the initial scaffolding is to create a table called job listings but if we undo the thing then we would drop that table entirely um another example if you had a migration to add a column then here you'd add the column and down here you would remove the column and that way you can apply the migration or roll it back at any given time okay so they've given us some initial suggestions well your table should have a unique ID and it should have some default timestamps uh when was this record created when was this record last updated and those are usually good ideas to include all right so go back to job and yeah it looks like for each one we just need to add a title and a salary so let's do that now table string for the title of the job listing and then for the salary we could actually set this in a number of ways uh if we're thinking of it as money then we would want to think in terms of sents uh that's generally a good way to deal with money a foolproof way to deal with money in our case though we're thinking of salary as whatever the employer wants to put they could put $500 a month or $50,000 a year or something else so I'm going to keep that as a simple string uh column salary all right that's it so I've created a migration class I've defined the blueprint for that table now I want to run the migration so this time I'm not going to run migrate fresh because I don't need to reset and start all over I just need to apply that newest migration so I can run PHP Artisan migrate and notice it knows it doesn't need to do the other ones it already did those the only it hasn't yet done is this one here okay so let's come back to table plus and maybe hit command R to give it a refresh but yeah if I come back here it is all right there we go so now I'd like to finish up by populating some records by switching to the data tab so if I switch back to the job file we have director programmer and teacher so I'll do this very quickly director salary is some arbitrary number uh I'm going to leave the timestamps at their defaults for now I'll do another one programmer 60,000 whatever and then one for Teacher also uh 50,000 something like that so notice they're green that means I've created the records but I haven't yet committed them to commit them you can hit command or control s and now that has been committed okay recap so we have now created a new job listings table and we manually populated it with a handful of Records so we used a migration class to Define the initial structure of that table we ran the Migration by running PHP Artisan migrate from the command line so now things are looking pretty good but of course the next step is I want to fetch that data from the database and then render it in the view so how do we do that well I'll show you in the next episode Cliffhanger I'll see you later [Music] hi everybody Welcome to day nine of 30 days to learn larel you're doing great and I'm really excited for this one because I get to introduce you to eloquent uh and eloquent really is one of the the pillars of the larl framework I really do think you're going to love it okay jargon alert uh eloquent is an O RM not an O RV not an SUV an O RM and this stands for object relational mapper um here's how you think of it an O RM Maps uh an object in your database like a a table row to an object in your PHP code so think about it we can go into table plus and view the details for a single record a row wouldn't it be cool if that record just had some kind of representation in your PHP code just like I can see a comment or a post uh within my database what if I just had a post object that included all of those details well that's sort of what you can think of uh when when we reference the term om or you might have heard of active record this is lel's active record implementation and again you're going to love it so let's have a look okay so return to your editor and open up your job class I want to convert this into an eloquent model and it's really simple but first up this data here is Superfluous right it's being stored in the database we don't have to double up so I will remove that entirely just for now okay so all I have to do to make a class a PHP class into an eloquent model is to extend the model class so I can say extends model and you want it to be illuminate database eloquent model so in my editor that automatically gets imported as you see here okay but notice immediately when I did that we got this red squiggly line declaration must be compatible with model all so as you can imagine eloquent has its own API for how we can query the database and part of that API is a method called all and also part of that API is a method called find so you know what we can do yep we're getting rid of it all there's no reason to reinvent this wheel okay fun so now let's play around let's go into the routes file and yeah within the home route we're just temporarily going to try out some queries so I will reference our job model and notice we have all of these methods that we can call due to the fact that we extended that model class so let's try out job all and let's just see what happens is that instantly going to give me all of the records from that job listings table well let's see we'll try to get our jobs and then we will die and dump the response okay to the browser all right well I do see a collection but notice the items are empty so we have an empty collection and we know that's not right so what's the problem okay well here's a key thing to understand larl and eloquent uh by extension rely heavily on conventions so if we if we switch back if we have a job eloquent model eloquent is going to assume that you have a table called jobs but if I switch to table plus the table isn't called jobs because remember we had a little bit of a collision there didn't we lell already includes one out of the box called jobs so we had to tweak ours okay so we have two choices to resolve this one would be to rename this to job listing and notice how the name of the class is the singular form of the table so if you had uh so if you had a table called comments your eloquent model would be comment if you had a table called posts then your eloquent model would be called post right that's an important thing to keep in mind so we could do this or uh in situations where you want a unique table name you can add a protected property called table and then here I can assign it job listings okay so now if I switch back to the browser now we have a collection of three items and check this out item itself is an instance of that new job class so now we have a place to tuck any any Behavior that's related to a job whereas before we didn't have that we were just dealing with simple uh scalers there was nowhere to put that logic except in your routes file which doesn't quite make sense most of the time okay so if we scroll down you'll see there's an attribute section that has information about uh the title and the salary for this particular uh row if we go to the next one this one I believe is programmer and then of course the third one would be teacher okay so check this out if we go back to my routes file if I want to grab the first item well we have a couple ways to do it so jobs is a collection as we've seen and one way that we can interact with that collection is to treat it as if it were an array so that means if I want the first job I can just grab the first index uh within that array so to speak okay so if we come back and we scroll up and give it a refresh now I don't have a collection I have a single job instance that contains these attributes and if I want to grab one of these values I just reference it directly like this title director um salary $50,000 if I want to grab the next item I can just do one and this will be $660,000 and the title is programmer cool so you see how easy that was we were able to uh entirely strip our little API that we built in that job class because eloquent includes it and way more uh directly out of the box which is really cool so I want to see now if I can reproduce our list of jobs so right down here when the user visits SL jobs we fetch them all and then we load a view called jobs so I wonder will this just work right out of the box I think it should so back to the browser click on jobs and it just works but now we're no longer hardcoding that array okay what about a single job yep that one works just as before very cool now we're not quite ready for forms yet but we're going to tackle that very soon but of course we can also use eloquent to insert or delete records from the database so I'll show you a new way that we can play around here open up your command line then run PHP Artisan Tinker think of this as your command line playground for your larl app it's a great way to get your bearings and try things out and see does this work the way I expect it to you can create variables you can grab them you can manipulate things you can make sure like I said that when you call this function is it returning what you expect let's play around and see if that works this is a good place to do that so why don't we play around with eloquent app models job and if I want to create a job we call a method create it's all incredibly readable so for the values we can provide an array here so a job listing has a title so I'm just going to say Acme director and then a salary is going to be one million million dollar and I believe those are the only ones we have here all right so you call it create method you pass an array and you include all of the the relevant uh columns that your table will require so if we run that though we get a mass assignment exception uh to be honest I wish this didn't happen out of the box because I think it is immediately confusing to newcomers and it requires a bit of knowledge that you may not have yet now effectively what's going on here is larl is providing some Safety and Security out of the box it's saying hey you might want to be a little bit careful about Mass assigning these attributes all in one go and that's that's exactly what we did here by the way uh and it's fine if you know what you're doing but again Lille is just trying to to keep you on the straight and narrow so yeah what what's the potential danger well in real life you will often be responding to a form request right so you could have a form to update the title of a post the user submits that form and you could potentially just pass the array of those form attributes to this create method but you know rule Ru number one when dealing with users is you have to assume they are malicious and they're trying to do something wrong so what if they tweaked that form request to also update the author ID of the post as well and you didn't know that you didn't ask them to do that but they snuck it in anyways well if you then blindly pass that um array of attributes to the create method you're no longer updating the title of the post like you thought you're also updating the author of the post which could be catastrophic now imagine in a scenario where you're updating the admin status for a user uh and and you didn't even know you were doing it so this is what Lille is protecting against as long as you are thoughtful and you know exactly what data is being passed to the create method it's entirely safe but that being said larl by default protects you against this and you either have to turn off the feature or do what we're about to do right now notice after the red warning I see add title to the fillable property to allow Mass assignment on the job class okay so I'll show you what that looks like I can command click to go to the job class and we can add a property called fillable this represents all of the attributes that are allowed to be Mass assigned so for example if I wrote title and uh salary this means these two items and these two items alone may be Mass assigned so if that malicious actor tries to update the user ID as well well it would be as if they never did it because it will be ignored entirely when we pass it uh to that create method in this example okay so let's come back I'm going to hit contrl C to exit out and then we will open PHP Aron Tinker one more time all right and now rather than rewriting this by hand you can usually press the up Arrow key to cycle between uh your old commands Okay so if I run it now it's going to work there we go so it creates the record within the database table and then it returns to you a new job instance that includes all of those attributes okay very cool so let's inspect all of our jobs job all and we should have four items and we do we have the initial three that we created and we have our fourth one and also notice in this case because we're going through eloquent it will automatically set these default timestamps which is very cool all right so we now know the all method we know the create method but what about that find method that we manually created uh in episode or two ago well of course we can use that as well I'll show you app models job find and we need to give it a unique identifier so that's why most tables will include some kind of unique ID as you see here so if I want to find this new one I created I could say find seven and that will return to me that record from the database so keep in mind what's going on here it's not magical a SQL query of course is still being executed at some point behind the scenes but yeah sometimes it does feel magical and you know what it effectively is Magic uh the the eloquent code base is very very very very very very very very very very very complicated and confusing I don't know what I'm seeing when I look at it uh but that's the great thing I don't have to know what's going on there it just works uh so now rather than um memorizing or learning how to write these um potentially confusing SQL queries eloquent uh tucks that away behind a nice API I have a method called all to fetch all the records I have a method called f to find a specific record of course I can add conditions like where I can add joins um I can do anything I can imagine behind this nice clean API all right so if I go back to table Plus let's give this a refresh and now we see our new record so what I'm going to do is go ahead and delete these old ones and we'll stick with only the ones that were generated through eloquent and that's fine but now if I switch back if I want to delete this job then I could simply say job delete whoops forgot the dollar sign one more time and notice that returns true to indicate it was successfully deleted if I switch back give it a refresh now it's gone okay so um I think we're in pretty good shape now you've had your first introduction to eloquence the only remaining thing I want to show you is that in this example we already had a job class that we converted into an eloquent model but most of the time you will be starting from scratch so here's what I want to leave you with and this will be your homework as well if I run PHP artisan make you'll see there are a bunch of make commands and you learned in the last episode These are used to generate uh files so as you can imagine is a make model commands now often these will accept certain arguments but it's hard to know which arguments those are so I'll show you a tip if you add help before any of these commands it will give you help for the command shocker all right so now if we scroll up at the very top we can see all right we can provide the name of the model and then we have various options that we can include so when we generate a new model this is often the the start of A New Concept in your application so it's it's a great entry point for also constructing other things and that's why we have these options like- C to also create a companion controller for the model or a factory or a migration or a policy or a cedar you don't know what a lot of these are yet but you will soon so notice the one at the top- a or-- all which is the long form it would generate a migration a cedar a factory a policy a resource controller and a form re in addition to the model so you don't necessarily need to do this yet because you don't know what half of these are but I want you to know that when you start working on these these new ideas and you add new sections of your site you wouldn't start by creating the migration you'd probably start by creating the model and then the model would create the migration as part of uh as part of its logic that's something to think about okay so out of the box and we're not going to keep this if I were to say make model comment notice that will create a new file within your comments directory and you'll see it right here and notice it extends model it uses this trait uh called has Factory we're not quite ready to talk about that just yet uh but you can you can leave it where it is um with the understanding that you'll learn more in the future okay let's do another one and again keep in mind I'm not going to keep any of these I'm going to delete them all at the end of the video Let's do make uh model post but this time I want to also create a migration notice I can add- M for short so let's do that now dasm and now it creates two files it creates the model but also corresponding um post table migration let's have a look at that post looks good and then migrations of course go in the database folder and I can see it right down here so notice these these generators give you a way to quit and rapidly um start constructing some of these new features which is cool so I could say a post consists of a title uh it consists of a body but a string is too short so that would max out at 255 characters of our car instead we're going to use text because it could be a very very long blog post and we want to allow for that so yeah you're starting to get comfortable right we are generating models we've learned about options to also generate corresponding migrations you learned in the last episode you can run phb Artisan migrate to commit that migration so that is now relevant uh and visible within your database so you're making really good progress here I hope you're excited and yeah this is all just so incredibly useful and Powerful I can't stress it enough this is the Bedrock of so much of the larl code you will write even 20 years from now okay so your homework is yeah work on it get this into your fingertips play around you can delete it all when you're done generate a variety of models uh practice also generating the migrations as part of those models and then fill out the migration and then run PHP Artis migrate to see it in the database and then start writing queries using uh PHP Artisan Tinker to fetch items from that database and then see if you can manipulate an item or delete it or add a new one that's your job play around and get these keystrokes uh under your fingertips all right I'll see you in day 10 is that right yes tomorrow is day 10 so we will next talk in day 10 all right see you later in day [Music] 10 all right ladies and gentlemen welcome back to day 10 let's get to work so today we're focused on the database folder now you're already amiliar with migrations and that's great but now the next stop on your learning is factories so have a look at this one that comes out of the box user Factory okay so I see a definition method and it looks like it has various uh database table attributes that consist of fake data so notice we have name corresponds to any kind of fake name and then email corresponds to a unique fake email address uh a timestamp that can just be set to now and then it looks like we also have additional methods to to configure that that generated user in some fashion so if we want a user that's in an unverified state it looks like we can call this State method where we tweak the attributes in some uh shape or form okay so what do we use a factory for well the answer is many things we can use a factory for any situation where we quickly need to scaffold or generate in this case a user so hm imagine you're writing a test and that test says well given I have 10 users when I da da da then I should ba ba ba right well that first step given we have 10 users we could use a factory to quickly generate those uh another example would be for simply uh whipping up your local uh environment so for example in our case we have job listings right and if I switch to table plus right now we only have one but yeah when we're working in our local environment it might be useful to have potentially 50 different job listings and I certainly don't want to manually create 49 more records so again a factory is a a good use case for that okay so we have a user Factory here how do we use it well you can do it anywhere you want anywhere you can write layl code uh once again though I'm going to reach for PHP Artisan Tinker now if I want a fake user then I need to reference my user class and actually on that note let's switch back real quick so let's go into app models user and yeah remember when we generated a eloquent model using PHP artisan make model we saw that there was a use has Factory trait and I said I think let's put a pin in that just for a moment well now we're taking the pin out uh has Factory adds a number of methods to the user class uh for generating factories and one of those method is wait for it drum roll dot dot dot Factory okay so let's play around user Factory create create a new Factory for the user class this is our API so I'm going to give it a run oh but it fails oh yeah I remember this okay this is good this is a good learning opportunity so we tried to generate a new user Factory but it noticed that there's no column named name even though the factory includes one so let's have a look real quick if I switch back to user Factory yeah this is what comes out of the box but you'll remember a number of episodes ago just just as an exercise we change name to first name and last name so if I switch back and and view the structure for a user yeah we tweaked this uh any number of episodes ago so of course it's failing that's expected Behavior okay so we could either bring this back to a simple name uh column or why don't we update this so instead of name I will have first name and now you see this fake function here uh this makes use of an API called Faker and I'll switch back here and Faker includes a variety of methods for just about any form of fake data you can imagine and what's cool about apis like this is you can just guess what it is so for example if I want a fake name there's probably a a method called first name and there it is I didn't even know that was one but there is right that's the cool thing about apis like this so with that in mind is there a last name method yes there is so I can update this as well okay so uh we're going to give it one more try but take a look at this if I press the up Arrow key and I run it again it still fails and this is an important thing to remember uh when you run PHP Artis Tinker all of that code is loaded into memory so when we make changes well we have to exit out and then restart so I can press control+ C to uh exit out and then I will bring it back up all right and now once again I can press up to cycle to my last command run it and this time it works okay so notice it creates a new record within the users table and it returns to us a new instance of that user so if I come back and switch to users let's go to data sure enough we have a new record of fake data okay but what about situations where I want many records well we can do this you user Factory and as the first argument to this Factory function we can provide a number so let's create just to illustrate this let's create a hundred fake users all right that's done it's very quick give it a refresh and yeah now you can start to see the power of this so when you are working in your local environment and you're playing around with some things and you want a bunch of different uh job listings well you could use a factory to quickly scaffold them so let's do that now if I switch back yeah the moment we only have a single user Factory uh and of course I could duplicate this and rename it to job listing Factory but yeah situations like this always reach for a generator so contrl C PHP artisan make Factory and yeah don't forget if you're confused about what argument to pass you can proceed it with help and I can see all right let's include the name of the Factory and then optionally I can include the name of the corresponding eloquent model all right beb artisan make Factory um job Factory all right let's give that a run and now we have a factory for a job all right so what about the attributes here well it looks like we have a title and a salary all right so let's do a title and this is a job title so I believe the faker library has a method called job title and it does great next salary um what could we do here we could do a fake number of sorts um or or remember it doesn't have to be random so in situations where it just doesn't matter whatsoever then feel free to hardcode a value like if if this is if this is fine and will suit your needs then you can do that uh but if you want a variety of salaries for filtering or something like that then you would want to make it Dynamic so it just depends uh on what your needs are all right and I think that should do it so let's give it another shot PHP Artisan Tinker app models job Factory create so again notice how all we had to do is create the corresponding Factory and larel smart enough to figure out what that mapping will likely be give it a run o we get called to undefined method job Factory okay let's scroll up and I think I know why yeah so remember this particular class we created manually because a number of episodes ago we already had a plain old job class to work with but I want you to notice the difference here if I switch to user it uses this has Factory traits and yeah we saw this a couple episodes ago if we make any old uh model make model post that uh the generator will include this trait here but again because we manually created the job class we haven't done that yet okay so let's delete this and manually add it on we're going to use has Factory and notice that long path there so ideally make sure you're using some kind kind of IDE or editor that has autoc completion use has Factory yeah you have to pull in this trade because the trait is what affords us that factory method call all right sorry about that let's do it one more time HP Artis Tinker up create a factory for a job and there we go this time we have a data processing equipment repairer that sounds like an exciting job and there we go all right once again let's do a bunch let's do uh 300 random fake jobs and again notice how quick that is give it a refresh and there you go we got musician physicist Warehouse geological data technician uh it's pretty cool actually when you think of it now what about if I switch back to user you'll remember excuse me let's go into user Factory okay so you'll remember there's an additional method called unverified and it looks like if we want a user in an unverified state that would mean email verified ad is set to null but notice by default up here it's just set to now so if we switch back all of these users where is it will have uh the email verified at uh timestamp set okay so how do we activate uh this particular State and that would be the term by the way that we use State well like this app models user Factory and then we call the State method which is unverified create and that's it so notice email verified that is set to null so yeah you're not going to reach for this all the time but trust me once you start building um more substantial projects you'll run into situations like this where yeah you need to create a model or a record that's in a very particular States uh usually for the purposes of performing a test so I'll let you take a look at this notice you create a method uh give it any name you want and then within that method you call a State method on the object where you pass it a closure a function that returns an array okay so you can create these yourself as well for example often um we'll just do this as a quick exercise often for simple projects your user table might have an admin status and let's say by default uh it's set to false you're not an admin yeah maybe in certain situ s you want to say well given I have a user who is an administrator when I bada bing bada boom then I should ZIP zap zap right uh so yeah that would be a good use case for a state so I could just copy what I have here and say okay well this one this state will be called admin and this will set the admin status to true all right and that's it now you have a new piece of state so you would say user Factory atmin create and now that will use all all of this data but then it's effectively going to grab these attributes and merge them and override uh the defaults and that would be one way to deal with this lovely now keep in mind in the next episode we're going to have a full lesson around eloquent relationships but I kind of want to scratch the surface just a little bit to finish up this video and you'll see why in just a minute now it makes sense that any given job on our site would course respond or have a relationship to a given employer so you can imagine if if we're really popular and Microsoft signs up then Microsoft could have a hundred different uh job listings and we want that relationship to exist okay so let's do this I'm going to go into my migrations folder to our job listings table and now I'm going to say well a job listing belongs to an employer so we probably want some kind of foreign ID called I don't know employer ID that would make sense so for every single job listing there's an employer ID column that points to the corresponding employer uh but right now I don't have an employer's table so that's the next step let's do that real quick PHP artisan make now we could do migration but like we learned at the end of the last episode we could also start with the model which would be employer and then I could say also generate a migration as part of that so let's give that a run and now we have two new files our employer eloquent model and the create employers table migration cool so let's have a look at that right here so an employer will have a name and yeah maybe at least for a demo maybe that's enough to get us up and running cool so if we switch back to our job listings table now check this out I could say uh well I could say unsigned big integer employer ID so why are we doing unsigned big integer well that's because whenever you call this IND method within a migration that's actually creating a big integer column let's see if we can find it yeah so it's creating a big integer that automatically increments so when you generate your foreign Keys you want to make sure that the type of the foreign key is identical so that's why I'm also using an unsigned big integer however another option is to use this table forign id4 and notice right here the the argument it expects is an eloquent model so I could say well follow a convention and create the necessary foreign ID for an employer and that would be another way to do it all right so let's give this a shot now because we've made some changes and we're so early in the project I will often uh run migrate fresh just drop everything and and run it from scratch all right so now we've built up all of our tables uh from the beginning okay so if we come back give it a refresh of course we've lost all of our seed data and that's fine but if we have a look at job listings we now have an employer ID a title and a salary and the employer ID refers to this new employer table all right so now if we go back to our job Factory this is no longer enough and in fact if we try it out um where are we there we go let's try to create 300 jobs it doesn't work because of course employer ID was not provided so we need to update our Factory so employer ID but yeah what do we set this to uh do we hardcode it well if that's fine for your needs then great have at it it'll be the quickest option but yeah usually it would be helpful to say well whenever you generate a job as part of that I also want you to generate any uh corresponding relationships like an employer so we can do that by saying employer Factory just like this so now when larell comes to this it'll know okay we also need an employer Factory so I will generate that persisted in the database and then use that unique ID as the corresponding employer ID okay but now this isn't going to work either right let's give it another shot pachon Tinker run it again and it still fails employer Factory not found all right let's see what the problem is we come back up we now have an employer model it is using the trait but there's no corresponding uh employer Factory okay so let's have a look at this if I run phb Artis help make model yes we know that we can use- M to create the migration but check this out we can also pass DF to generate a factory as well so here's what I'll do I'm going to delete this just so we can do it together PHP artisan make model I'm not going to do dashn this time because we already had the migration but I will say uh employer dasf and now we get the model and the factory cool so here's our new employer Factory and like I said all we have right now is a name so I could do a fake um maybe is there a business no company yeah company let's do a fake company name all right so are we on the same page now when I want to generate a new job it'll create a fake job title uh it'll hardcode a salary and then for the corresponding employer it'll reference an employer Factory so larl will read that it will then generate a new employer record and that will have a unique ID right and that ID will be substituted as the employer ID here all right let's give it a shot PHP Artisan Tinker press up and this time I'm going to generate how about 10 jobs all right and it works all right let's have a look in our database so I exited out and I'm going to reopen it again when you're using SQ lights sometimes you should do that when you drop the database entirely and build it up from scratch uh if you ever have a situation where your table is not reflecting the change you made it's probably related to that all right so here are the job listing we have forest fire fighter landscape artist manager a pipe fitter and each of those uh belongs to a corresponding employer so let's see the forest firefighter belongs to the employer with an idea to and it looks like that one is whatever whatever this is these all look like confusing Law Firm names uh but but that's that's entirely fine and again I want you to notice how each of these job listings belongs to its own employer now there will be situations where you want multiple job listings to belong to the same employer and for that you can use a method called recycle uh we're not going to get into that right now but if you want if you want some extra credit you could have a look at that but yeah otherwise I think I think that's going to do it uh for this episode all right so model factories you've learned that they are excellent for scaffolding data for your local environment and also for the purposes of preparing a a test now we wrapped up by learning just a little bit about database relationships we set it up so that a job listing belongs to a corresponding employer and we got that to work on the database end but what about the eloquent end so if I do have a job object how do I then fetch the name of the employer who created that listing Well that's going to be the subject of day 11 I'll see you then bye [Music] welcome to day 11 the topic of conversation is eloquent relationships which trust me you're really going to love all right let's get going so we discussed in the last episode that there should be a relationship between a job listing and a corresponding employer so a job Bel bels to an employer might be the terminology we'd use okay so if I had a job object yes I can access the title or the salary but what about information around the employer well right now we can't do that we've defined that structure on the database end but in our PHP code it just doesn't exist so let's make it exist and luckily eloquent has our back I'm going to create a method here called employer so if I have a job and I need information about the employer then the method will be called employer and this is going to return a relationship type now in this case I've said multiple times a job listing belongs to an employer so belongs to is our key word there return this belongs to and now I want to reference the class that it belongs to in this case employer so yeah as you can imagine there are multiple relationship types a job belongs to an employer but in Reverse does an employer belong to a job no that doesn't make sense an employer can have many jobs so that relationship type is called has many and then there's a variety there's a half dozen there's has many there's has one there's belongs to there's belongs to many um and then there's some more complicated options that we're not going to worry about right now all right so this is all we have to do here check this out PHP AR Tinker I want to find any job so let's say app models job and rather than calling the find method and providing an ID if you ever just want the first one that comes up I can use a method called first all right so we have forested firefighter now because I have that relationship defined in my eloquent model I can call employer but notice real quick this can be initially confusing I know it's a method but I'm not going to call it as a method I'm going to call it as as a property just like I'm referencing the title or the salary for the job and when I reference it as a property Lille is smart enough to pick up on that and it will know okay well we don't have an employer property on this model so what you're probably trying to do is access the employer relationship all right so if we give this a run now notice we're no longer in a job instance we have an employer instance okay so that means what I can do here is say job employer and now I can access any of the attributes from my employer and in this case we just have name pretty cool right so even cooler though think about what's happening here let's do it one more time all right so this is effectively running a query like select star from jobs limit one so yeah notice we're only focused on the job listings table it hasn't yet referenced the employer table so here's a key to understand at the point where I say job employer a second SQL query is being performed and we refer to this as lazy loading so lazy as in the loading and the query is not being executed until the last possible minute and the last possible minute is when you request it so here is where a new SQL query would be executed and yeah it would be something like uh select star from employers where I D equals 2 in this example and that's why we have that foreign ID there so that we can point to a specific employer all right that's a key thing to understand but now what about in Reverse so if I have an employer at models's employer and again I'm just going to grab the first one here uh it would be nice to grab all of the jobs that the employer has uh published so what method would we access here well something like jobs right so it sounds like we need a method on the employer class called jobs let's do that now employer and I'll create a new one here jobs and yeah this time what is the relationship well just work it out in your head what's the relationship between an employer and a job well an employer can sign up and create many jobs so an employer has many jobs has many job and that's it so now think about it if we have our employer object and we call jobs well that's going to return a collection right because it could be one or many jobs that are associated with the employer so you'll see that reflected here let's contrl C bring it back up all right I'll press up find the first employer and now if I say employer jobs all right and yeah notice we get a collection of items so an eloquent collection for now just think of it as an array on steroids you can still Loop over it like like any normal array but it also includes a full API and a number of methods to to make the process of filtering uh inspecting uh looping any of that stuff will become infinitely easier because it's all wrapped up within this collection instance all right so within the collection we have our items all of the items and in this case there's only one because this employer only has a single job so if I wanted to act that first job again I can just interact with it like an array or like a collection and one of the methods on a collection is first okay and I think we're going to stop right there for day 11 uh so you wouldn't believe this but these two relationship types alone has many and belongs to they're going to take you so far it'll take you 85% of the way there and yeah keep in mind there are more relationship types uh there is a belongs to many relationship which is great for pivot tables and then there are polymorphic relationships which are a good bit more complicated but yeah these two that we discussed they're going to take you so far you won't believe it okay so your homework is get this into your fingertips get it into muscle memory play around delete the code when you're done use the example of a Blog because we all immediately understand it uh what's the relationship between a post and a comment well a post can have many comments so that method you'd create is a has many relationship uh what about the relationship between a comment and a post well the comment belongs to the post what about the relationship between a post and a user well a post is written by a user so the post belongs to the user or an author what's the relationship between a post and tags well this is kind of a a cliffhanger a post can have many tags but in reverse each tag does not belong to a post so why don't you hold off on that Tag's example because it requires a new relationship type that we didn't talk about in this episode we will cover that naturally in day 12 I'll see you [Music] then okay so for day 12 I want to create a connection between a job and any number of tags so if you've done this before you probably know well we'll probably have to create some kind of pivot table but yeah then how do we represent that relationship within our code well the answer is to use a belongs to mini relationship and I'll show you that today now Why Don't We Begin by creating our tag model phb artisan make model tag and this time I also want a migration and a factory cool so now we have the model the factory and the migration okay so yeah why don't we start within the migration file now what does a tag consist of well at least initially a name should be fine okay so think about it we have a jobs table we have a tags table but then we need something in between right a connecting table and this is our pivot table so think about it within this table I could store the tag ID as well as the job ID so I could say all right the job with an ID of one uh is associated with the tag with an ID of one all right new row the job with an IDE of one is also associated with the tag with an ID of four next one the job with an IDE of seven is associated with a tag with an ID of nine right you get the idea it's a standard Fair pivot table okay so let's create that now uh you have two choices so I could create a brand new migration but keep in mind there's no hard rule that a migration class can only ever contain one schema create call so for example if I just wanted to group these together so I could have our tags creation as well as our job tag uh table that would be fine as well uh and I think you'll find you you'll do both it sort of depends on the order that you create these things so for example if you were to add the pivot table a month from now it would be within its own migration but if you're doing it all at once this is fine you could group them inside the same file something to keep in mind okay cool so what should our pivot table consist of well mostly foreign IDs right so I'll show you we can do table forign ID for a job so this is going to handle our job uh ID column next we're going to need another one for our tag ID so I can say foreign ID for tag now in terms of timestamps uh this is mostly a preference uh you have to decide when you create a new record in this pivot table would like to track uh the the Tim stamp for when that happened sometimes that's important other times it can be omitted it just depends but we will add it in this case now I'm about ready to run this but real quick a little gotcha so when we run foreign ID for job that's going to prepare a job ID foreign key but we have to be careful because we want job ID to point to our job listings table rather than that jobs table that larell includes out of the box so if I command click on the method you'll see that I can override the column name and that's what I'm going to do here so I will call it job listing ID and that's a little more appropriate okay let's give it a run and run it PHP Artisan migrate all right so if we come back and refresh here's our tags table and here is our job tag pivot table now on that note keep in mind the naming convention here we take the singular form of each of the connecting tables and then we sort them in alphabetical order and separate them with an underscore so jobs and tags become job tag and that's fine okay so now let's talk about constraints so if I were to manually add a tag here we'll call it programming and let's go into jobs let's say how about the job with an ID of 10 okay job with an ID of 10 is associated with the tag with an idea of one right this is fine however what if I were to delete that tag like so well if I come back give it a refresh it still lives so now we have an orphan don't we we have a record that points to a tag that does not exist in our system and yeah we don't want to allow for that so this is where we can add a foreign constraint and this is especially important because SQ light defaults are a little bit different from MySQL so this will be a good exercise all right I'm going to switch back and for my job listing ID I'm going to add a call to constraint so create a constraint and then a second one to Cascade on delete and then I'll do the exact same thing for tag ID okay so what this says is create a constraint and then if that referencing record happens to be deleted I want you to Cascade and delete this pivot record as well and the same is true for tag so if we have a a job ID of one and a tag with an ID of one but then the tag with an ID of one is deleted it will Cascade and also delete the pivot record as well okay so I want to roll this back and run it again but notice drop if exists only deletes the tags table so we need another one here for job tag okay let's give it a run PHP artisen migrate roll back and PHP Artisan migrate we'll do it all in one go cool okay so now yeah let's manually create another tag and then we'll say within job tag the job with an ID of 10 has a tag with an ID of one and we'll give that a save and we can see the constraint is in place because we see these little arrows here connecting them so I can click it and it'll take me directly to that record further within job tag if I go to structure notice I can see the foreign key right here okay but we still have a problem again this comes back to sq light defaults if I were to return to tags and delete this record it lets me and if I come back to job tag oh it's still there so what was the point we added the constraint but it didn't constrain anything uh what's the problem yeah this is a common thing that people run into so it's good to know okay so the defaults for SQ light specify that constraints are not enforced but in your larl app they are enforced but yeah keep in mind we're not in our Lille app right now are we we're just accessing our database directly so we are bound by the defaults of SQ light rather than the defaults of larabel okay so that means if we're directly within our database gooey and we want these constraints to take effect we need to manually turn it on but in our laral app we can ignore it they are turned on by default and of course if you want to reverse that and turn them off you can within your environment file okay let's go to the SQL Tab and I will run pragma foreign Keys equals on all right turn on foreign constraints okay so now if we come back to tags let's read that one all right we should still have our pivot record but this time if I were to delete the tag it will Cascade and also delete the uh excuse me also delete the corresponding pivot record as well that's good and of course the same would be true if we deleted the uh referencing job okay very cool so now I want to see this in our PHP code because that's what we most care about okay so let's set up the relationship we now have a model for job and tag but no relationship between the two okay let's start within the job so if I have a job and I want to access all of the tags for that job then our method would be called Tags and again if you can't remember what to call that just imagine you have a job object and you want to access something well ideally what would you call you would do something like that so there's your method name okay so our relationship is not a has manyi it's not a belongs to it is a belongs to many relationship so it belongs to but it also can have many and this makes perfect sense when you think about it so does the tag uh called programming does this belong to how about the job with an ID of 10 well yes but it doesn't exclusively belong to it many many jobs can be associated with this tag so yeah we don't have a belongs to relationship it's almost like a belongs to and has many relationship and yeah we represent that with this one right here belongs to many okay so let's reference the corresponding tag class and then I also want to do it in reverse now what's cool is when it comes to belongs to many relationships it's the exact same code on both ends so for example if I go to tag imagine we have our tag object and I want to access all of the jobs that are associated with this tag then I would do something like this right all right so we have our method jobs and that too will return a belongs to mini relationship and we reference the job class and that's it cool all right so now I want to play around with this let's go back uh we have a tag of programming do we have any pivot records no I will manually add one like so so and let's give it a shot I'm going to start by opening PHP Artisan Tinker we will find that job so app models job it had an ID of 10 and now if I want to find all of the tags that are associated with that job I can run job tags but actually as I think of this I wonder if we'll see an error oh we do okay this is helpful at the very least so no such column on the job tag pivot table called job ID all right so it's expecting a column name of job ID but we know that the actual column name is job listing ID and that's because lel's assuming a default here that usually will work but in our case our PHP class is job but the corresponding table is job listing so yeah in situations like that where you have to avoid certain collisions you need to be explicit about the column ID and here's how we do that come back to job and if I command click here you can see that we have the related model then the table name and then the foreign pivot key and the related pivot key so let's add that here so I'm going to overwrite that and I can use a named argument for this so I can do the name of that argument colon and then not job ID job listing ID and that should fix the problem okay so boot it back up find our job then get the job tags and this time it works all right a little bit of a a bit of weirdness there again this would only be ref relevant in situations where your eloquent class doesn't perfectly line up with um the relationship or the table name something to be aware of and also this is going to be true in Reverse so if I have a tag and I want the jobs well it's going to look again for job ID but that's not quite right so in this case we don't want the foreign pivot key we want the related pivot key so could update this as well related pivot key would be job listing ID all right so let's give that one a shot bring it up let's find the Tag app models tag find one and now if I want to access all of the jobs associated with that tag I could say tag jobs okay and now we get a collection of one item all right this is great but now I want to finish up by quickly showing you how you could attach new records and it's very simple you you could say tag jobs but notice I'm not going to access it as a property that would give me this collection here and I don't want that instead I will call it as a method and then run attach I want to attach a new record so I will give it the ID uh of a new job that I want to attach so how about this human resource director 7 so I could give it seven or I could give it a full call to at models job find seven either one of those is going to work okay so now if we come back to our pivot table we have two records great but now here's a little gotcha if I were to run tag jobs again I still only see a collection of one item and this is because this collection has already been loaded into memory it's not performing a new SQL query so if you want to fix that of course you could either refetch the the tag from the database and start all over or you could say tag jobs get just run a brand new query and now we get a collection of exactly two items so why don't we say uh tag jobs get and pluck the title so this is just going to grab a single uh field or attribute from each of those jobs so now we have a brand new collection of only the job titles that are associated with this particular tag hi all right so yeah it's kind of a lot depending upon your skill level uh if you're already familiar with pivot tables and relationships of this sort then this is probably a cakewalk but otherwise if it's all new to you then it might take a minute and that's okay watch the video a second time work on the homework which is this uh you're working on your little blog idea right well a post could be associated with any number of tags right and now you know how to represent that you have a post table and you have a tags table the next step is to create the intermediate table a post tag pivot table so play around see if you can get that to work and when you feel comfortable and only when you feel comfortable move on to day 13 Lucky 13 I'll see you [Music] then all right folks welcome to day 13 today we'll have a look at the n+1 problem let's review an example so in my routes file we have an .4 jobs this fetches all jobs from the database and then loads a jobs view I can command click on that in my Editor to go directly to it now if we have a look at this in the browser this is what we get not the prettiest thing in the world so you know what why don't we take 60 seconds and turn each of these items into a card of sorts to start let's swap out the unordered list for a simple div and then for each card this could be a div it could be an article or it could even be an anchor tag that way the entire card is clickable so why don't we try that out I'm going to make the anchor tag a block level element and then what we'll do is maybe add some padding on the left and right uh a little bit more on the top and bottom and maybe we'll have a border and then maybe a color of Border gray 200 maybe something like that okay now next we don't want blue text so I will delete that entirely and I will remove the hover styling all right let's see what we have so back to the browser give it a refresh and yeah that's looking just a little bit better the only remaining thing might be to make each of them rounded and then I want a bit of space in between each one so I'll show you a little trick on the parent element you could do something like space y4 and that I'll add just a little bit of uh margin in between each of the individual items and I think that looks fine okay so now notice the entire thing is clickable and it takes me to the actual job page cool all right so now the next step is I'd like to display the employer right above the job title here so let's do that okay so I will select this and why don't we wrap it it could be a span I'm just going to do a simple div here it's not really a paragraph so I wouldn't do that uh maybe there's an argument for that though and then above it we'll have another div where I Echo the job lawyer so there's our belongs to relationship and then the name of the employer okay let's have a look come back give it a refresh all right next why don't we add a little emphasis so let's make it bold uh I'm going to make it blue it's not a link currently but it it eventually would be wouldn't it so that's okay and at that point it does become a link we'll swap that out with an anchor tag okay so now for every job listing we can see the employer's name the job title and the salary it's looking pretty good okay but now we have introduced a bit of a problem and that problem is called the n+1 problem okay so what's the issue well do you remember an episode or two ago where I mentioned that when you reference the relationship a new SQL query will be performed and I called that lazy loading all right well how does lazy loading work within the context of a loop could we end up in a situation where for each item in the loop you EX another SQL query to load the employer uh could that happen and the answer is 100% yes and that's specifically where the name n +1 comes from okay so now I want to illustrate this and I'll show you two ways to do that all right first up larel debug bar so you can search for it here's the direct URL I'll let you take a look at that and yeah it's going to add a helpful debug bar to the bottom of your browser window and notice it'll have tabs from messages or exceptions or your views or your database queries that are being executed or the models that are being loaded it's incredibly helpful okay so why don't we install this notice I can pull it in through composer and I will paste this in okay so you've learned at this point that composer is a package manager so if I want to pull in some kind of a tool or library or helper I can simply require it using composer and that will pull in all of the necessary files it'll pull in the package cool okay so we can see that larl uses autodiscovery so it doesn't require you to manually do anything it should just work out of the box as long as your app debug setting is set to true all right so where would that be it's going to be within your environment file and that'll be in the root of your project right here and notice at the top app debug is set to true but of course in production it's set to false and that way we can ensure that you never display a debug bar in a production environment okay so let's go back to the browser and have a look give it a refresh and there you go you instantly have a new debug bar all right so I want you to notice queries right here 12 SQL queries are being performed it seems like a bit much doesn't it let's have a look all right so we have one for sessions we can ignore that but notice we have a query to select all from job listings and then right down here yeah this is a dead ringer for an N plus1 issue if you ever see multiple queries that are nearly identical other than a particular ID yep that's an N plus1 problem so notice let's just count these 1 2 3 four five six seven eight is that right it performed eight queries and if we have a look in our database within job listings we have three six eight yep eight records eight SQL queries or if I had 100 records then we'd have a 100 SQL queries so this is precisely where the n plus one problem comes from for every single record we will plus one to the SQL query count it's a problem it's something to be aware of so while lazy loading can be helpful if you're not thoughtful and aware of what's going on sometimes these these performance issues can sneak their way in all right let's fix this return to your routes file and let's extract this into its own variable so I could say jobs equal job all okay but now I want to tweak this I want to implement eager loading I'd like to say give me all jobs with the employer for each one so I will eager load the employer relationship and here's how we do that job with and then we reference the relationship name and that relationship is defined right here so that's where I'm getting that value job with employer get me all of the results okay so keep in mind with get that's select star we are grabbing all of the records so if you had a million records in the database you don't want this you'd want to implement some kind of limiting or pagination and we'll take a look at that soon okay so now if I come back to my browser let's give it a refresh and it's still going to work just like it did before but now if I open up our query count it has been reduced let's have a look here all right so now we only have two relevant queries so we have one query to grab all of the job listings and then a second query that now eager loads all of the employers where the ID uh is referenced from those job listings so yeah compare this to what we had before let's go back real quick job all refresh yeah before we were lazy loading each item within that Loop so here's a query for employer 2 employer 3 employer 5 it'll just keep going on and on but when we tweak it to this we are now eager loading the employer relationship as part of of one single query so even if we fetched 100 records from the database we would still only have two SQL queries and that's what we want so you might decide that for your own projects even though Lacy loading is helpful it might be a bit too risky for your preferences so in these situations if you want you can disable the feature entirely but yeah I want to emphasize this point I'm not leading the witness I'm not suggesting it is too risky and you should disable it I'm just saying it's an option if you prefer it and I think you should make up your own mind on this particular issue uh I find developers somewhat split down the middle uh certain people disable it at the very beginning of the project and others feel like they know what they're doing they know when they should eer load it's not a concern for them so you should decide for yourself so let's imagine that you do want to disable the feature entirely this will bring us to a new directory app providers and we only have one to start app service provider okay so you can think of this as a file for configuring your application however you need to so in our case I want to configure my app by disabling uh lazy loading all right so we're going to do this in the boot method the boot method is triggered after all of the project dependencies have been fully loaded all right so I'm going to reference our model right here illuminate database eloquent model and yeah this is where intellisense is incredibly useful I can now say prevent lazy loading and if you're working along be careful there's also a prevents lazy loading method that's not the one you want that returns a Boolean in our case we want prevent lazy loading all right and that's it so now have a look what happens here let's go back to my routes file and I'm going to return this to a simple job all call that leads to Lazy loading within our view so if I come back to my browser and I refresh it now we get a la loading violation exception and this is specifically because of that one line that we added to app service provider and it's really helpful hey you attempted to Lacy load the employer relationship on the job model and where did you do that well you did it in line9 of your jobs. blade View and yep there it is lazy loading okay so if we want to remove this screen we have to solve the problem so we solve it by eager loading the relationship so once again job with the relationship name get me the results and that's it so we come back give it a refresh and we have solved that problem okay so now we are eager loading our employer relationship we have minimized the number of SQL queries I think we're in really good shape so in the next episode we will move on to day 14 I'll see you then [Music] all right welcome back so today I'd like to have a look at pagination so check this out if I return to my routes file yeah we talked about this a little in the last episode so this get call here is fetching every single record from the jobs table and of course right now we're testing we have 20 25 records it just doesn't matter uh it's a non-issue but of course in real life we could potentially have thousands or tens of thousands of jobs and this query would fetch every single one of them which of course you don't want your memory is going to go through the roof almost immediately so yeah instead in situations like this we defer to pagination and luckily in lelt it's incredibly simple and you have a few different options so I'd like to show you them today instead of running job with employer get I'm going to change this to paginate all right so let's command click to go through to the method definition and you can see for the first argument we can specify how many records do we want to show per page so at least initially I'm going to put a very small number and then we'll we'll bump it up so let's do something like three so that it's immediately obvious that the pnation is taking effect okay so if I go back to the browser now I haven't hit refresh yet so yeah we have 10 records or so let's give it a refresh and now we see only three but notice I I don't see any pagination links and that would make sense we haven't added them to to our view but in fact the pagination is working and I'll prove it to you why don't we update the URI and we'll change it to page two so I want you to notice page one had Forest firefighter and dredge operator if we give this a run now we have landscape artist and human resource director all right so the paging is working the only remaining step is to display the individual links so let's do that now so back to my editor let's go into job . blade. PHP and yeah how about right down here I will render the links for the paginator so I can say jobs Links come on it's so easy it's ridiculous how easy this stuff is all right back to the browser give it a refresh and there we go I mean and it looks great out of the box too and we'll talk about that in just a minute but yeah we're currently on page two so we are showing results 4 through six but I can switch back to page 1 2 three or we can use the arrows it's really cool and yeah it it's just seamless it kind of blows me away how easy this is okay so first why does it look good well it looks good because larell assumes that you're using Tailwind now of course you don't have to but if you are you get some conveniences like this where the formatting is already set up uh and ready to go which is cool but yeah in plenty of situations you're going to be using um a custom Library you've made or something different from tailwind and in those situations you will need to manually edit the patator okay I'll show you how back to the terminal let's run a new command PHP Artisan vendor publish okay so vendor refers to any package that we've pulled in through composer and publish means I want to publish any relevant assets or routes or files or reviews to my application folder so that I can manually uh control and edit them it's a very common practice okay so yeah think about it where is the markup where is the view for these Patron links uh currently it's nowhere in our resources folder it's in one of those vendor packages so I want to publish them so that I can manually edit those files okay so we give this a run and if you don't know what the provider or the tag name is just search for what you want and then we can see yep we want this tag right here larl pagination so I can press the down arrow key to select it okay so now notice it's literally doing a a a copy command it is copying from the vendor folder which is where all of your composer packages are installed and it's going to take that views folder for your pagination and it will publish them to your views vendor pagination folder we should now have a resources views vendor pagination folder and yeah notice we have a bunch of different pagination files here and of course yeah that's because lar ofel supports many different ways of displaying your pattion link as well as many different CSS Frameworks so yes it supports Tailwind but it also supports semantic UI or Twitter bootstrap Twitter bootstrap Twitter bootstrap so is that X bootstrap now is that still a thing I don't know how they have dealt with that anyways it doesn't matter uh the point is you can pick your tool of choice and larl should be smart enough to render those links in a reasonable way so yeah imagine we're not using Tailwind for our project instead we're using saying bootstrap 5 if I want to switch the default view from Tailwind to bootstrap 5 again that requires configuring our application and we've learned a good place to configure your app is within your app providers app service provider and we already have one for preventing lazy loading which again is optional you can turn that on or off depending on uh your preference okay so I want to configure my paginator so I will reference the paginator illuminate pagination pagein Ator and yeah notice there is a method for setting the default view so if you just want to control pnation yourself you could reference a view name here if we want to switch the default view there should be yeah notice we have used bootstrap uh let's see what else we have here use bootstrap use bootstrap 5 of course they are uh different depending upon if you want an older version of bootstrap or a newer version so if I want bootstrap 5 I can call this method and now the default page views will be swapped out let's have a look if I switch back to the browser and refresh it'll be unstyled because I haven't pulled in Twitter bootstrap but sure enough we can see that uh that particular change has been made which is cool so I'm going to come back and I will comment this out just so you can see it in the source code and you don't forget all right so if Tailwind is the default this is the file we should tweak uh if we need to make any relevant changes so let's see let's come back refresh show seven to eight results let's look for showing and there we go now I can say viewing come back give it a refresh and yeah not works uh we can see any of the relevant buttons and yeah notice the API for our paginator you have access to methods like are we on the first page well if so you probably shouldn't display a back button right because there is no back button uh get the previous page URL and we can use that for the href so yeah there there's a lot going on here most of the time you can probably stick with the defaults but it's good to know if you need to tweak things or adjust the layout you have the ability to do so okay so now uh one thing to keep in mind is that there's a small well relatively small relatively big uh performance cost to displaying pagination in this way so imagine a situation where you have a forum with literally millions of Records uh it can actually be relatively costly to calculate all of the page numbers and render them in this case it's it's irrelevant it's Superfluous but yeah for a gigantic Forum these are things you need to be aware of um if you're displaying page 392 um you might find that your SQL query could take a little bit of time so you have a couple options here you could render simple pagination links or you could even reach for cursor based pagination I'll tell you how to do that so we can finish up for the day so instead of calling pagein a I could reach for simple pagein AES okay so you'll notice a slight difference here if I switch back no longer will you have page numbers and keep in mind if we had way more records we'd see page 1 2 3 4 5 6 7even I can't remember what the default is for larell maybe five page numbers on each side of the current page that might be right but yeah we only see three here because we only have a total of eight records anyways we've swapped out to simple pinate if I give it a refresh now it's literally simple pnation where we just have a preve and a next button to go back and forth and yeah often that will be fine you probably don't even need to display those page numbers unless you you have a good argument for why the user would want to switch to page eight from page two uh often it's just not necessary all right so that's an option next we have cursor based pagination and this does come with a caveat so if I switch back if I call cursor paginate yeah this is Far and Away going to be the most performant option but there's a bit of a cost so if I come back and give this a refresh we still get our PR next links but I want you to notice something if I hover over the next button notice what the URL is here jobs and then it's not page two page three page four it's cursor equals and then some random string that represents uh which records need to be fetched from the database so if I click on this and we take a look at the current URL it's not ideal so this is something to consider if you switch to cursor-based pagination you no longer have the ability to say go to my form and visit page 12 in that result list uh so you have to decide is is that a deal breaker so for example for the lus Forum that's probably a deal breaker for me uh I don't want URLs like this but you can imagine for situations like um areas where accessing a direct URL manually isn't as important or infinite scrolling uh these would be perfect scenarios for cursor pagination all right something to be aware of now to finish up I want to show you how the query differs so if I bring this back to simple paginate come back refresh of course we can open up larl debug bar to view the query that's being executed yeah this is the one we care about so notice it's not a simple select star from job listings we also add a limit and an offset so just to make this Crystal Clear if I bring this back to get now it's going to break my page because the links method isn't available if we're not using pagination but still I can see what the query being executed is it's a select star give me everything from that table but for pagination of course we don't want that so if I give it a refresh that works uh if we close this and we switch to page two or three and bring it back up now notice it's select star limit 4 offset 6 so that's how we deal with well we don't want the first handful we want to offset it according to the current page and again Lille takes care of all of that behind the scenes you don't have to perform that calculation yourself which can sometimes be a little bit confusing okay anyways if I switch to cursor-based pagination and I give it a refresh yeah it's a little bit different isn't it so notice with cursor-based patn there is no reference to the offset keyword so for example we're not going to see for page two quote unquote uh offset 3 or offset 6 or offset 9 it doesn't work that way instead if I go to page two and have a look at the URL yeah it uses this encoded value here cursor so this is an encoded string that represents the the starting point the the location for the next set of results that larl should fetch from the jobs table that's effectively what's going on there and again this is Far and Away going to be your most performant option if you're dealing with extremely large data sets this is probably the way to go here's another example imagine you're building a table to display 800,000 customer records for your company in those situations cursor-based patrin would be a great way to go a great way to deal with that all right so yeah busy day right you've learned about pnation and simple pnation and cursor-based pnation and Rend ing pagination links how many times can I keep saying the word pagination by the way uh how about publishing pagination views so that you can edit them yourself or configuring the default pagination view that you want larl to reach for this is going to take you so far this is this is 95% of what you need to know so if you feel comfortable uh let's move on in day 15 we are halfway through and you're doing a great job I'll see you then [Music] all right let's talk about database seating today so imagine that you need to refresh your database you can run migrate fresh all right so that drops all of your tables and builds them up from scratch but if I switch back to the browser now of course we don't see any records at all so think about it what would we have to do at the Point Well we'd have to boot up PHP Artisan tinker and then once again I could say app models job Factory 100 creates we would manually have to run a command to uh build up this table and then I'd have to do it for all of the various tables for my application it's not ideal ideally I'd run PHP Artisan migrate fresh and then seed the database populate all of those tables however I require all right well as it turns out we can do this through database seeders so check this out within my editor let's open up the database and a new folder Cedars and we have a single file to get us started database Cedar and notice they give us some examples do you want to create 10 dummy user records or a single user record all right very cool uh how do we execute this how do we trigger this well from the terminal you can run PHP Artis dbon seed and remember if you ever forget you can just run Artis and then do a command F and just look for the command and then you can find it ah this is the one we want seed the database with records okay so let's run it PHP Artisan DB seed oh it fails what did I do wrong table users has no column named name it's the exact same problem we found ourselves in a couple episodes ago yes once again we changed it to first name and I'm just going to do John and then last last name will be do all right try one more time sorry about that there we go so we seated the database if I now have a look within the users table sure enough we have John Doe great it works so now think about this if I were to run PHP Artisan migrate fresh well we've learned that drops all of the tables and builds them up from scratch but then as a result we lose all of our seated data but check this out if I run it again but I add the help command before it this will show me all of the various options that we can pass and one of them is seed indicates if the seed task should be rerun so this effectively means uh refresh the database and then run PHP Artisan DB seed but we can do that as part of a single command PHP Artisan migrate fresh- D seed so it drops the tables it runs the migrations and then it seeds the database all in one go come back refresh and it works very cool okay so maybe when you SE your database you want a single user and then we want some jobs so I can say job Factory let's do 200 and create all right so let's try this now keep in mind though if I run DB seed it's going to fail so can you can you guess actually before I show you can you guess why did that fail all right well it failed because of a unique constru of course a user's email address has to be unique the problem is we're trying to add a new John Doe with an email of tested example but that already exists so this is something you should be aware of if you're going to run that DB seed command you either need to clear out all of the uh previous records or combine it with migrate fresh something to be aware of phb Artis migrate Fresh Feed okay and now we avoid that problem we have one user and sorry job listings we have 200 uh random jobs it works okay so the last thing I'm going to leave you with is if I run phb artisan make Cedar and we give that a run yeah you may find that in some situations it's advantageous to split these up so you could have one Cedar class just for your users you could have another Cedar class for your jobs and this has two benefits one when you split them up you can now run them or trigger them in isolation so I can run my job Cedar class without running all of the other ones at the same time and that can be helpful in some scenarios and then two you could even create dedicated Cedar classes that have the sole purpose of um helping out with a particular complicated test that you're running so that test could run a single Cedar class that builds up the datab base in the necessary way so that you can perform a test against it and that can be very helpful trust me all right so anyways if I go back to my editor now I have a database seater and a job seater so yeah what I would recommend is initially just keep it all within a single file keep it simple but as it grows and as you you find yourself needing a little more flexibility at that point create dedicated Cedar classes where you can house uh logic like this all right so now we have our root database Cedar and that just builds up a single user and then if I also want to trigger my job seater I can say this call and then I reference the class as you see here yeah it just helps with structure all right and especially for large projects you're going to reach for this so if we give it another run migrate fresh seed you will see it migrates the database and then it runs and completes the job Cedar within our database we now have our default user as well as 200 job listings it it all works just like it did before which is great all right 30 seconds to go the last thing I want to show you is if I once again run help for DBC you will see that there's an option for class set the class name of the root Cedar and again by default it is that database Cedar uh route but if we only want to run the job Cedar instead we could say phb Artisan DB seed class and then we reference the class name in this case job Cedar okay so now notice it's not if I switch back it's not running this file it's exclusively running this file so that means if I switch back to job listings and refresh we should now have 400 records and we do okay so now you've learned about the distinction between database factories and Cedars and I know at least initially that can sometimes be a little bit confusing when do I use this one versus that one okay so as it turns out factories are helpful for quickly holding data they are immensely useful for preparing your tests which you will learn about in the future database seeders give us a class where we can then trigger those factories and keep in mind a cedar doesn't have to trigger a factory it could use the database facade directly it could it could reach for eloquent directly it's just that usually they will reach for factories because they're so incredibly easy uh to prepare so yeah as it turns out we're going to use both of these in tandem which makes them punch far above their weight okay very cool good job in the next chapter starting in day 16 is that right day 16 uh in the next chapter we are going to move on finally to forms please be excited [Music] all right welcome to day 16 now today is a very special day because we finally get to discuss forms but in order to do that we also have to touch upon a number of other topics like uh request data and folder organization and even cross-site request forgery so yeah a lot to cover and worse I want to try to get this all done in 10 minutes or less so wish me luck let's get going let's begin within our routes file and I want you to notice something we're starting to see a bit of a pattern forming all right so I have one route to show all jobs I then have a second route for displaying or showing a single job but now I want a third route to show a page to create a new job so if we're going to stick with conventions this URI will be called jobs SLC create all right but I want to show you something if I simply die and dump and say hello there and we load this in the browser it's not going to work so have a look to the browser I will visit jobs slre and hm it fails it's kind of weird right we expected to die and dump hello there but it seems like it's trying to load a different route so let's see why if I switch back notice that we have a wild card declared above jobcat so think about what this is saying this is saying listen for a request to jobs slash anything including create so even though we declared uh explicitly job create it occurred after this route which means it doesn't take effect so that's something to keep in mind your wild cards should generally go closer to the bottom all right so I'm going to bring this up and now if I come back and give it another try it works all right so that's a common uh Pitfall that you should be aware of okay so next I want to return a view to create a job but at this point I think we need to adjust our folder structure for example do I call the The View create job well you can if you want but again I like to stick to Common conventions if we all stick to them then when I view your project I immediately feel right at home and and the same is true if you view my project all right it's a perk of following conventions so with that in mind we have one view for all jobs another view for a single job and a third view to create to job so let's do this in My Views folder let's Nest all of those under a single jobs directory so create a directory called jobs and then I will take this and this and move it over but now think about it jobsjobs doesn't really work well let's rename this instead of jobs I will call it index and again this is a common convention the The View and the action for displaying all of a resource is typically called index next the view for displaying or showing a single resource or record is called show so I will rename this to show. blade. PHP all right so you're going to repeat this for all of your resources if you have uh tasks then you would have a tasks folder in your view you'd have an index view for displaying all tasks a show view for displaying a single task a create View and I'll create that right now for creating a task or creating a job as we're doing in this example okay so now let's go back and adjust our rounds and you can see because I'm using a plugin called larl idea it immediately notifies me that this view no longer exists all right so I could say jobs SL index and that would work however you can also use do notation uh in place of a forward slash for the directory separator so this is a little bit more common all right this one would be jobs. creates and notice I have autoc completion here which is great and then finally we have jobs. show all right this feels a little better to me okay so now let's go into our create View and we'll update the heading to create job and then we'll say too all right let's have a look in the browser all right so here is the index view to display all jobs here's the show view to show a single job and then we have a new one create uh will display a form to create a new job all right so let's head back over to tail one UI so that I can quickly snatch a form that we can use in our project tailwind ui.com and of course we're only going to grab something that's freely available so within components we'll come down to application UI and and I'm going to look for form and see what we come up with aha here we go so it looks like we have some input groups H why don't we just grab a full layout here and yeah usually with some of these examples the first one is freely available you don't have to purchase so that'll give us a big form layout most of which we're not going to use but that's okay we can delete it pretty quickly so I will copy that and switch back to my editor and I'm going to paste the entire uh Clump right here all right back to the browser and yeah this actually looks pretty good to my eyes okay but yeah most of this we don't need so for example notifications uh personal information cover photo we don't need any of that so let's get rid of it uh I'm going to look for notifications all right and it looks like I can select this entire thing to get rid of it cool uh next I said personal information so let's get rid of that se next I said cover photo so I can get rid of that section come back give it a refresh all right uh next a Avatar Photo let's see photo yep we don't need that one so yeah this is what you will often do with Hillwind you only need to grab uh the sections you require so we have username about and I can repurpose those okay so let's see uh username first this is going to be the title of your job so yeah basically all I'm doing here if I switch back to table plus is uh replicating the fields within the table so the employer ID we're going to automatically assign that but next I need a title and a salary so only two Fields very quick and very easy all right so we will have title and I will use multiple cursors to quickly select some of these so that I can change them all at once all right we'll have title all right next you will see that tail one CHS an example of your username uh preceding the the URL so I don't actually need that in this case so I can get rid of that but then if I give it a refresh we lose some of the padding and that's because uh they automatically uh adjust that so I'm going to bring it back to PX3 so that we have some padding on the left and right now the placeholder right here can be a dummy job title like shift leader okay so do I need a text area actually no in this case so what I will do is duplicate this and then down here I can select the text area entirely and delete it all right so this next one will be uh salary so I'm going to select all of this salary update this here and uh real quick autoc complete that's irrelevant in this case uh it would it would make sense for a username or an email but for title and salary uh it's not useful so I can get rid of that all right next placeholder uh again it's going to be something like 50,000 per year it's whatever the employer wants to add there all right come back give it a refresh and that's looking pretty good we have our buttons the only remaining step is the profile information at the top so I'll say uh create a new job we just need a handful of uh details from you all right I like it so now if I add some dummy data here and I click save well nothing happens and of course that would make sense if I switch back and real quick I can get rid of the comments here because I'm using the CDN but yeah anyways the form is blank so if we have a look it's making a get request to itself and passing through those fields and that's not what we want all right instead I want to make a post request to where well again following a common convention we would make a post request to the resource itself so in this case that would be jobs so if you make a post request to jobs that is our signal that we are going to uh persist a new job to the database okay so let's give this a try but we know we don't even have a route that listens for a post request to slash jobs but yeah nonetheless let's just see what happens we give it a run and larel lets us know hey the post post method is not supported for that route we have a get request but not a post request okay let's fix it by returning to my routes file and yeah once again we are continuing this route URI naming convention so I'm going to listen for Route post to slash jobs and then like we did before sanity check we will die and dump and say hello from the post request don't feel bad about doing this stuff they are sanity checks just to make sure you're actually hitting the r that you expect because often uh it doesn't turn out that way okay so let's come back and give it another shots and I should be able to just hit command or controlr but I bet this won't go the way we expect no we got a 419 page expired and worse we have no clue why all right let's just try it again for sanity job create maybe we did something wrong add a title add a salary submit it 419 what's the problem and if you want me to be honest this is one area where I feel like the framework could be I don't know a bit more clear at least in a local environment as to what the problem is so let's talk about it okay so this 419 error refers to ll's automatic csrf protection or cross site request forgery okay so if you hear that and it just sounds like gibberish gobbly G then I need 2 minutes of your time and I promise at the end of those two minutes you will perfectly understand why this is so important all right so maybe hit pause get yourself some milk get yourself some juice or beer I'm not going to Jet you I like water uh story time okay so imagine think of an example Jeffrey uh imagine that got it okay so imagine that you are a member of a local bank and we'll call it local bank.com or local bank. test just in case that's it's a real uh URL you're a member of this local bank and they offer a page once you sign in to update your password pretty standard Fair stuff right uh visit the URL log in visit the settings area update your password what's the problem well nothing except in this example local bank doesn't know anything about security they don't even know what csrf refers to so if that's the case though I Mr malicious person can take advantage of both local bank as well as you and here's what I do I would send you an email and I would represent that I am from local bank I might even make it look like an automated email uh hey John or Jane do it's time to update your password please click here now you're a programmer and you know to be suspicious of things like that but most people aren't built that way so they click the button and they're taken to a form to update the password they fill out the new password they submit it and they're on their way and here's the cool thing uh at least in a malicious sort of way here's the cool thing they don't even know that something just went down all right but something did so here's what happened when they clicked on that button of course they didn't go to local bank.com or local bank. test instead I sent them to my malicious person website uh.com now you're thinking well wait a minute it looked like like local bank we saw the logos so what happened well I know how to write CSS dude I know how to grab an image uh so I can just make it look like local bank that's the easiest thing in the world and it's one of the the simplest tricks you can do for uh people who aren't overly technically inclined okay so what happens well think about it you thought you were on a local bank but you're not okay you filled out a new password and we tracked it so now I know what you want your password to be and then when you submit it here's the secret sauce that post request still goes to local bank. test all right so wrap your mind around this you're on my malicious site you filled out a form on my site but it's actually making a post request back to local banks site so that's the cross- site portion of the request forgery okay so does that work as what you're probably thinking wait a minute you got to be signed in so that request won't work because you're not signed in well you very likely are though let's say you logged in earlier that day or even the night before to check your account statement or something all right well you're in the session you're still signed in there's a cookie in your browser that says you're signed in so if I make that request to local bank then the cookie will be read and you're signed into to local bank so the post request will complete and your password will be updated all right so isn't that weird from my site I basically replicated the form to update the password the only difference is I was able to intercept your new password while still physically updating the password on local bank's end so now all I have to do is the next day sign in with that password that I captured and I now have access to all of your data so how do we fix this we fix this by leveraging uh what is effectively a token there is a token that will be included as part of the form and we will then compare that token from the form to a token that's in your current session and if those two match we can be pretty sure that you are the person making the request on the current uh domain but if they don't match then we know uh-uh something's going on here and in the case of lell it throws a 419 error and now you know all all right let's fix the problem back to my editor let's return to the create view so I can command click on that and at the top of our form I'm going to add a blade directive called csrf now behind the scenes once this is all compiled down to vanilla PHP this will expand to a hidden input and we can actually inspect the HTML in the browser to review it jobs SLC create let's right click and choose inspect and at the very top of the form here we go so yeah again this directive uh compiles or expands to this hidden input so notice it has a unique token all right so that's what I'm referring to once we submit this form that token will be included along with the request and then laravel behind the scenes you don't even have to have to deal with this yourself larl is going to compare that request token to a token that's in your session and as long as they match up good to go but if they don't match up and I'll show you an example of that in just a second uh it will once again throw a 419 okay so let's do the happy path I will fill it out we now have our token larl will read the token compare it it will match and sure enough we hit that post request it works but let's go back now let's tweak it so once again I will come back and I'm just going to add a bunch of characters here to force a mismatch okay so now if we try it again we should get a 419 because the token from the client does not match the token from your session and so a 419 is thrown okay so I know I was a little verbose there explaining it but it's really important that you understand this concept all right so I'm feeling pretty good here I can now return to my routes file and we can proceed so how do we get the attributes from the form well we can use this request help per function I can say from the request give me all of the attributes so why don't we pass this to die and dump and review the output so let's come back we'll say shift leader and 50,000 that's fine submit it and sure enough here is our request data the title salary and the csrf token cool now further instead of saying request all I could also pass an attribute name here so if I want the title I could say request title I come back give it a refresh now we see shift leader all right I think we have everything we need so we're going to skip validation just for this episode but I promise we're going to return to it but assuming that everything is valid we can now create a new job in the database app models job create and what do we need we need the title of the job we need the salary of the job and we need the employer ID for the job now you might be wondering well why didn't we have an input in the form to set the employer well that's because I would assume that would be fetched from your authenticated account so if you're already registered and signed in as an employer then you don't need to fill in the employer a second time we can grab that off of your account so yeah just for now though while we haven't yet reviewed authentication I will hardcode an employer okay so the title can be request title the salary can be request salary and uh I think that looks good okay so now where do we want to return well assuming that the job was created successfully it would make sense to take the user back to this page to view all of the jobs okay so let's do that now return a redirect to slj jobs all right so I'm going to let you take a look at this now I actually think we're going to see an error if we run this but let's go ahead and work through it so back to the browser we'll say shift leader this one is 30,000 USD and it does fail okay good so we get a query exception not null constraint failed for employer ID so yeah let's take a look at the query title salary no reference to employer ID even though we know that we included it so what's the problem well the problem relates to those fillable fields on your eloquent mod model and we learned about this a few episodes ago if I return to job notice that fillable Fields this refers to fields that can safely be Mass assigned we have title and salary but not employer ID so I could add that here but yeah already I'm noticing that this is kind of annoying but nonetheless let's just keep trying so I will come back and refresh the page and it works so if I return to table plus and refresh there we go we have our new record but now real quick notice I don't see it here and that's probably because of the ordering for all of our jobs so I can fix that let's come back to our routes file and when we fetch all jobs right here yeah the ordering isn't what we want I actually want to see the most recently created job first so we can add a method called latest and this uh behind the scenes just adds an order by Clause to your SQL query and it's basically order by the created at timestamp in descending order so give me the latest records first all right so now if I come back and refresh sure enough I see our new job that's working very cool but yeah if I come back it's just a little bit annoying that every time I I need to uh assign to a new field I have to make sure that it's represented in the fillable Fields so I I'm going to warn you this is an area where programmers very much disagree it It ultimately comes down to how much Safety and Security you want by default now my general View and by the way you are free to disagree with this but yeah my view is that as long as you and anyone on your team understands the potential dangers it's okay to disable this feature entirely mostly I kind of find it annoying more than helpful so there's two ways to disable it for now I will just show you a simple way directly in your model instead of setting the fillable Fields I'm going to going to do what is effectively the opposite the guarded Fields fields that should be guarded from being Mass assigned and if I set this to an empty array I'm basically saying you don't need to guard anything I'm effectively disabling the feature entirely all right so now if I come back and we try it again job SLC create this one will be programmer at uh 100,000 per year submit it and it works and that's because we we disabled that feature entirely so just remember right now for any eloquent model you would need to add this property or of course you can configure your application as a whole to disable it and maybe if you want on your own research that and figure out how to do it and then leave a comment below all right day 16 in the books so I do hope we were able to get that done in 10 minutes or less and by the way if you're thinking well Jeff you recorded the video you know uh the answer is actually no I don't at this point in time uh a little tip the amount of time it takes to record a lesson is much much longer than the edited version that you're watching right now so you know if I pulled it off but I don't you've been close uh so yeah please make sure you understand the concepts from this lesson it's really important understand how to submit a form understand what cross-site request forgery is understand how to fetch uh request data from the form understand the difference between fillable and guarded Fields And if you feel like you're comfortable in the next episode day 17 we move on to request validation I'll see you [Music] then welcome to day 17 okay so in this episode we move on to the topic of validation and I don't want to speak too soon but I think this should be relatively easy to understand so I'm going to predict that we're in and out in 7 minutes let's get going if I check out our jobs website notice at the moment there isn't any link to create the job that means I have to manually open the URL let's solve that really quickly within my editor let's put this in the layout file it'll be available anywhere I'm going to look for header yeah this section right here corresponds to what you see on each page so yeah we're just going to assume the create job button is visible no matter what page you're on maybe that's not appropriate but for a little demo it's fine and I want the button to show up right here okay so within our div we will add an anchor tag and we'll call it create job and of course that's going to go to SL jobs slre okay so if I come back and refresh uh it doesn't look like a button and the alignment is off now we can fix that pretty easily by leveraging Flex box so on the container we'll say for small devices and up set a display of flex and then I'm going to set the alignment to justify between so justify the spacing in between each of these uh direct children so if the spacing is Justified it will be the same which will force the first one all the way to the left and the second one all the way to the right okay next I want this to look like a button so I think yeah why don't we just steal some of the styling here from the pagination so I believe that was in the Tailwind pagination file all right so I'm looking for the next button and I think it's right here okay so yeah I'm just going to steal the CSS classes and then I will switch back to layout and I will paste it in as the class so yeah notice uh real quick is a lot of CSS classes so keep in mind uh Tailwind assumes that you're going to extract these things into reusable components that way you can reduce the amount of duplication so keep that in mind but if I come back to the browser and refresh sure enough we now have our create job button I can click it and we're all set to go okay so if this does represent our default button styling I'll show you how to quickly extract that component create a new file in the component directory I'm going to call it something simple button or link whatever you want I'll call it button all right switch back and I'm going to copy the whole thing move it in all right next uh of course I don't want to hardcode the hre that'll be passed in but I do want a default set of CSS classes so here's what I'll do I'm going to copy those classes and then say attributes merge and set the initial classes to that long string okay and then of course we're not going to hardcode create job this will be our slot and that should do it all right so let's come back to our layout and now this can be swapped out with x button component the herf will be jobs slre create job yeah it should work so come back refresh and click on it and we're all set to go all right now we can move on to validation so if I go into my routes file yeah you'll remember that when we make a post request to/ jobs at the moment we are taking the happy path off all the way we are just assuming whatever you gave us is good to go and we throw it into the database so that means if I were to submit this form it fails so why did it fail though because I thought we were following the happy path well on the PHP end we did but of course on the database end we do have uh restrictions in place and one of those restrictions is uh the title cannot be null but notice we tried to set it to null so we we got all the way to the point of the database query before things failed okay so we'll take two steps to solve this problem and as you'll see one is going to lead to the other all right so first step would be client side validation and luckily browsers makes some some basic validation fairly easy to implement so if I go into our create view jobs create so here is our input for the title and yeah at the very end if I simply add require and yeah this will add a bit of browser based validation so now if I try to submit the form it disallows it it's almost like a guard who is protecting entry into a building hey you got to fill out this field or this form in order to proceed and that's really helpful okay but now if you're a beginner you might be thinking well what else is there to do we've solved the problem we're done why is this only step one of a two-step patented process and the answer is well you can never ass assume the browser uh what we have here this client side validation is great and you should do it uh it's helpful for just simple ux or user feedback but if I wanted to I could bypass the browser completely uh I could submit the post request from the command line in which case we'd be in exactly the same situation as we were just a moment ago so here's what I'm going to do uh it's helpful to bypass this required attribute uh so that we can hit the server side validation so I'm going to delete it just for now and then I will return it at the end of the video okay so back to my routes file and you're going to love this it's so easy I can say request validate and then I provide an array of attributes that need validation so for example we have title and notice my editor is trying to autocomplete it for me kind of a spoiler there uh so we have fields from our form the title and the salary okay so this course responds if I switch back to these inputs title and salary okay that's where those values are coming from so now I can provide one or more validation rules uh what is the minimum length this needs to be should it be a string is it required should it be an image larel provides and I haven't checked this but dozens and dozens and dozens of different validation rules and as always you will generally use you know a small handful of them but when you need those those more exotic rules they are available to you okay so in our case I'm going to say the title is required and the salary is required and yeah maybe in situations where that salary needs to be more specific like a number or something matching a particular format this is where you would specify it okay okay so why don't we say the title is required and it should have a minimum number of three characters um that probably makes sense but also it's helpful for a demo okay so here's the coolest thing about laravel validation what if the validation fails well do you have to do something like check the results and then redirect manually and the answer is no larl is going to take care of that for you automatically if this validation fails it will redirect back to the previous form and send through an errors variable uh that is populated with all of the attributes that failed validation have a look so let's fail this validation in two ways for the title I will provide only two characters instead of the minimum of three and then I'm going to leave the salary blank entirely and don't forget because I removed that required attribute from the HTML it will allow me to submit the form successfully okay so I run it and it's almost like the page just refreshes uh like nothing happened however I assure you something did we made the post request We performed the validation it failed so we never reached this point at all larell immediately redirected back the only issue is it included the errors when it redirected back but we never displayed them anywhere so so it feels as if nothing changed even though something did all right so let's solve the problem by displaying those validation errors I'm going to return to our create View and yeah why don't we say how about where would be a good place so perhaps after our grid I'm not sure maybe tail one has some specific recommendations but I'm just going to throw it right here let's say if errors any uh which is nice and readable but also a quick note this errors variable is always available to you so you don't have to first do something like if is set errors then Loop over it uh no matter what an errors variable is available so now we check well if there are any validation errors let's Loop over them and display each one within a list item so I could say something like for each errors all as error then within a list item Echo the error itself okay and again when I say error I mean validation error all right let's have a look in the browser refresh once again fail the validation and now we see the results the title field must be at least three characters and the salary field is required so yeah what we might do now now is wrap this within a div like so we'll give it maybe some margin top and then the the the error itself will be I don't know red italic something like that it doesn't really matter one more time run it it fails let's make the title validation pass but the salary fail so we run it again and now we see only one uh validation error okay so this is helpful but another option is to display the validation error directly below the input and of course you can do that as well I'll show you let's comment out this example so that you can refer to it uh in the source code and if I scroll up so I'm going to add a new blade directive called error and this is cool I think you're going to like it it's one of my favorites so I'm going to reference the attribute name in this case title and what this is saying is Well if we have a validation error for the title only on that condition should we proceed and in this case we Echo the message itself okay now keep in mind this message variable is only available within this error directive so it's a tiny bit magical at least in terms of what we see in the blade file but if you can get beyond that it ends up being incredibly helpful so what I'll do here is use a paragraph tag and Echo the message and then very quick styling make the text extra small red and maybe semi bold all right good enough enough come back to the browser submit the form and now we have a little validation error perfect I might even add a little margin top above it one more time and that looks good cool so now I could do the exact same thing for all of my inputs paste that in and this time I'm checking for validation errors for the salary itself all right one more time submit it and now we have inline validation that's coming from the server very cool so the the final step is of course I I want some client side validation as well so I want that user experience to be as instant as possible and in client side validation is the best way to do that so the salary is required and the title is required cool so if we come back and give this one more shot now we'll have some instant client uh side validation like so but then we also have some backend validation as well and in this case that will fit very cool okay so here's where I'm going to leave you if you're working along go to lal.com slocs validation within the table of contents if I scroll down you'll find a section for all validation rules and yeah trust me there's a lot and there's too many to remember I can't remember them uh as always you're going to use seven or eight of them most of the time but you when you need to you will refer back here for something a bit more complex maybe something related to a custom regular expression but yeah whether you need a number or a value that exists in the database or a date or a minimum number of digits or a maximum number of digits it's all here should it be a URL should it start with something should it be um the same as something else it's all there and you can refer to it when you need to okay and I'm not going to bore you by going over all of these so that would take way way too long and you don't want to hear it okay so how' we do 7 minutes it probably went longer I can't help it there's so much to cover and so much to explain but I hope it was helpful all right so that wraps up day 17 of our course now for day 18 I'd like to return to our R file and finish scaffolding our jobs resource so yeah think about it right now we can view all jobs we can view a single job I can persist a new job but what about editing updating and deleting a job we still haven't reviewed any of that and we really need to so we will cover that in day 18 I'll see you [Music] then all right everybody for day 18 we will focus on editing updating and deleting and don't worry this should only take 4 minutes tops I mean maybe maybe maybe maybe 5 minutes but but definitely definitely no more than that maybe 20 now if I click on any job listing right at the bottom we should have a button to edit the job let's do that now so let's go into that job slow View and yeah right down here at the bottom uh let's add a little bit of margin top and then I will use my x button component to link to a page to edit the current job and it will say something like edit job okay let's switch back to the browser give it a refresh and that's what we get but actually as I see this notice there's a little bit of padding so maybe on our component oh yeah ml3 that should not be there all right I'm going to command click through to my component SLB button page and yeah let's get rid of that entirely and actually while we're here if I open the sidebar notice that I made the component folder name capital capital c uh I think that's probably fine but you might run into situations uh maybe on Windows it's always windows I can't help it uh but yeah that said it's more common to make it lowercase uh and yeah sorry about that kind of a muscle memory thing okay anyways if I now come back to the browser give it a refresh there we go okay so where should we be directed when I click on this link well let's go back to our routes file and yeah let's start documenting this so this route displays all jobs we can often think of this as the index action all right this one dis plays a form to create a job so I will write create here all right this one displays uh a page to show a job so let's add show for that next this one stores a new job or persists a new job in the database so I will call this one store so now I need one to edit an existing job so here's what we'll do I'm going to grab this route right here and I'll put it down at the bottom and now I'm going to say listen for a get request to jobs SL the ID of a unique job sledit and I think that URI ends up being really nice so this should display a form to edit the job with this ID okay so with that in mind let's make the view edit all right let's switch back to the browser and it's going to be similar to the create form so I will duplicate create and call it edit. blade. PHP and if we have a look here we'll change this to edit job and then I'll expect to have a job object so I will say edit job and then the title of the job and then let's get rid of this section right here and uh yeah we'll have a look in the browser so if I go back to my show view I can update the herf to jobs slash the ID of the job sledit but actually before I do that notice how we're now accessing our attributes in two different ways so here I'm accessing them as properties but up here I'm accessing them as array keys and that's because this example uh was created before we switched over to eloquent now eloquent doesn't care how you access those attributes you can use them uh as array keys or properties it doesn't matter you'll get the exact same thing but of course you want to be consistent so with that in mind I'm going to swap these over this is what you will typically see in the wild all right so let's come back to the browser give it a refresh and now if I click edit job we're brought to a new page to edit uh this secretary position but now of course I would expect these inputs to be populated with their existing values from the database so let's do that now back to edit. Blade and let's see here is our input for the title here's what I'm going to do I generally like to put all of these On Their Own Line like you see here yeah just like that okay so now I'm going to set the value equal to the job's current title and then if we scroll down I'll do the same thing here like so but this time I'll set the value to the jobs salary and that looks good so now if I come back and give it a refresh I can see the existing values from that record in the database table all right so now let's Point our attention to these buttons here cancel and save that's probably fine and by the way I can get rid of this uh little placeholder but yeah rather than save I would rather this be update okay that looks good so let's start with cancel what should happen when I click cancel well maybe it just takes you back to the jobs page so with that in mind that should be an anchor tag so a herf takes us back to jobs slth ID and now if I refresh and click cancel and now it takes us back to the Show view great okay but let's go back to edit job and handle the update click where should this send us well let's go back to our routes file now at this point you've learned about two different request types first we have get so a get request refers to getting a page just like you would normally interact uh with a web page next we have a post request again very common for submitting a form that uh stores some data in the database now as it turns out these two request types are the only ones that your browser supports natively however most common frame Works implicitly understand a few more and we're going to focus on two of those few more those two are patch and delete so to keep it simple think of patch as updating a resource think of delete as destroying or deleting a resource so we're going to keep this really simple and I think you're going to like it because we can reuse the same URI but then swap out the request type to signal to lfl what we expect to happen and I'll show an example so let's copy this right here and I'll bring it right down at the bottom I'll give this a little comment that we will reach for in the next episode this one will be update and I'll paste that in okay so if I want to update a resource I'm going to use the patch request type and notice the URI does not change and that's because it doesn't need to change think about it if we were using a post request well then I would need to distinguish between well are we storing a new job in the database or are we updating an existing job so in those cases we'd have to use kind of an awkward URI like this however because I can swap out the request type to patch now the framework understands what we're doing we're trying to submit an update to this particular job that's cool and I can keep the same URI and while we're here I can also handle a delete request so let's duplicate it and I'm going to call this destroy this is the route we will hit to destroy destroy a record in the database and once again I'm not going to change the URI instead I will tweak the request type to delete yeah I want to be crystal crystal clear here there's no point in adding slash delete at the end because the delete behavior is explicit in the request type itself so we're trying to keep as simple Uris as we can possibly manage all right so I will clear these out and then we will implement the behavior for both real quick now let's think about what would need to happen in order to update a job and I will write it out as comments Well we'd need to validate the request and we learned about that in the last episode never trust the user always validate next we would also need to authorize the request and this is a little bit different this would be our way of saying do you John or Jane Doe have permission to update this job so if you created the job yourself then probably the answer is yes but if Frank over there created the job it wouldn't make sense for you to have permission to update his job but I'm going to put a pin in this just for now so I will say on hold until we learn a little bit more about authentication in future episodes okay so we will skip over that part finally we will update the job uh and persist okay finally once we're done with this action we should probably redirect somewhere where do we redirect why don't we redirect back to the jobs specific page so that you can see your changes in effect all right and yeah this is often helpful I've been doing this for many years and I will still often write out um the the sequence of events that need to take place all right let's get started validate well you know what I'm going to reach for a bit of duplication by scrolling up and we can copy a bunch of this and yeah if that makes you feel icky and you want to combine that logic there are options that we will review in the future but let's keep it simple for now next authorization that's on hold so I will leave that comment next update the job so let's find the job job find by the ID and actually on this note if you'd like a little bit of extra credit as it turns out you don't have to manually fetch these jobs from the database you can let the framework do it for you so if you'd like to learn more about that and get a head start research laravel route model binding all right back to the show so now that we found the job I'll show you two different ways that we can update this first up we could set each property individually so I could say the title equals request title and then the salary equals request salary finally I can save it to the database and that would be fine and you will often reach for this method another option is to leverage job update and this is very similar to the create method pass an array of all of the attributes and their respective values so that would take the shape of this request title and then once again salary all right so this and this are effectively identical now while we are here though I want you to consider the possibility that the ID of the job we're trying to update does not exist in the database or in other words what if I manually make a patch request to jobs1 million well in that case think about it we would find the job with an idea of 1 million that does not exist in the database so this would return null then we would try to call an update method on null and your application would blow up okay so in situations like this you can swap out your find method with find or fail so this says try to find the job with the matching ID but if you couldn't uh abort throw a model not found exception that will Bubble Up and LL the framework will then convert it into the appropriate response so this is is often the appropriate way to go now I don't have to worry about a situation where job is set to null that would never happen all right very cool so let's move on to the next step persist we already did that finally redirect to the job page return a redirect to jobs SL jobid and we're all done so I can delete that entirely and this is your update action all right now let's handle the destroy action as well and this is a little simpler we would authorize the request and I'll say on hold once again delete the job redirect and that's it okay so this is on hold delete the job well let's find it so job find or fail by ID or once again learn about route model binding or I'll show you it in a couple episodes and then finally let's delete it so I can say job delete and then redirect so return redirect and where should you be sent after you delete a job I don't know maybe let's send you back to that index view that shows all of the jobs and that has a URI of SL jobs all right and that'll work now you'll notice here I am storing the response in a variable called job of course if you want to inline these two you can so I could just do something like this and that will do the trick cool so let's switch back to our edit View and that was a little a little bit of work to handle the endpoint but now it should be fairly seamless I want to make a post request and more on that in just a second to [Music] jobsjob ID but yeah remember earlier in the video where I said browsers only natively support get and post so you'll notice in my IDE if I try to set this to patch I get a squiggly line let's have a look yep a wrong attribute value so the browser won't understand this but the framework will so here's how we handle situations like this I'm going to set it to post but then I want to send kind of a hint to the framework that what I really mean is a patch request and blade has a directive for this it's called method so I'm going to set this to patch and yeah this is our way of signaling to larel that well yes we made a post request because we had to but we actually want you to treat and Route this request as if it were a patch and yeah this directive is going to expand to a hidden input that will then be posted to the server and larel will read that hidden input automatically so now it will detect ah you want this to be treated as a patch request so I will hit this route closure instead and that's the way it works all right so we submit the form it'll validate the request it will find the job it will update the job and it will redirect back to the Show view let's give it a shot let's change this to I don't know administrative secretary is that spelled right update it and there we go we redirect back and let's just give it a refresh to make sure it worked and it did we now have updated the title let's tweak this maybe an administrative secretary makes $80,000 a year update it and we're all set if I go back to all jobs I can see it listed here congratulations okay so now the only remaining step is to add a button to delete the job so so maybe we'll handle that within this edit form what I'm imagining is right down here a little red uh link or button that says delete all right let's do that now let's go back to edit. Blade and let's see let's scroll down to this section so this div corresponds to what you see here so it sounds like I will need two different sections one for the left side and one for the right side so what I will have to do let's clean this up is is is once again set flex and item Center and GAP X6 on this wrapper and often when I'm using Flex box um I'm not sure what the actual rules are but I have found that you can sometimes end up with weird button issues if they are direct children of a flex container so I almost always wrap those within divs like I said I'm not sure what the real rule is there but it's just something I've I've encountered more than once uh so yeah I still see that there and that looks good next I will have have a button for delete come back and refresh but now it's all the way over there and that's because on the main container we have justify end I'm going to change that to justify between come back refresh and now it's over here cool so now let's style it let's make it red uh small and bold yep but now notice if I line these up the formatting isn't quite right or the alignment isn't quite right so on this one as well I will set flex and items Center because maybe in the future we will have more than one link there all right if that looks good and yeah if we use a quick ruler here it lines up okay but now think about it this entire page is an edit form so that's going to make the patch request but this button is sort of its own form right it should make a delete request so as you may know you can't put one form within another form so we'll have to get a little bit tricky here's the way I would handle it at the very end below our current form I would create a brand new form and this will be for my delete now I'm going to set this to method and again I have to use post because the browser doesn't understand delete so with that in mind I'm going to send that little hint to laravel that I want you to treat this as a delete request and also we've learned a couple episodes ago that we have to provide a token to guarantee that this request is coming from the current site so I will add the csrf directive and if I scroll up you'll remember we've already done that for this form cool okay so now all we need to do here is set the action and the action would be SL jobsjob ID once again we have the exact same URI but then the request type will determine how larl routes this request okay now the only remaining step is I want to hide this form so I will apply a class of hidden because remember I don't need to see it I just want to see the button way up here but then I want to Target that form from the button and I can do that through a form attribute on the button tag so this would reference the ID of the form that we want this button to correlate to so for example if I gave it the name or ID delete form then I would need to also apply an ID here all right does that make sense so if you're not familiar with the form attrib honestly I wasn't um if you don't have it it is implicitly set to the closest parent form for that button and that would be this but yeah in situations like this where you actually want a different form to handle that button if I scroll down then you can Define it and I can say no I don't want the parent form uh to be associated with you I want the Le form to be Associated all right so let's think about what happens now when I click that button it will submit MIT this form that form will then make a post request to job sln ID but then we send through a signal that we want it to be treated as a delete request so larl will detect that and say all right well let's use that URI but instead of calling the post request I will treat it like a delete request that will then find the job delete it and redirect back let's see if we got it to work come back delete all right and it's gone let's also delete nuclear equipment operation technician delete and it works yeah and again I want to remind you there is currently no authorization yet anyone can delete these jobs or update them and maybe that's okay for what you're building but usually it's not so we will solve and fill in that puzzle piece uh once we reach the authentication chapter and that does it so congratulations you just completed your first round trip for a resource and by trip I mean show all jobs show a single job create a job store a job edit a job update a job delete a job I think that's all of them you did the whole thing and yeah this is the essence of crud create read update and delete okay so in the next episode we will return to our routes file I want to show you a whole bunch of things some nice to have some refactoring ideas and then we will introduce a whole new concept which is dedicated controller classes please be excited I'll see you [Music] then all right folks welcome to day 19 I'm calling this episode routes reloaded like The Matrix but not as cool definitely not as cool all right so let's see I have 1 2 3 four four or five different uh tips or techniques that are uniquely related to your Rouch file so think of it like this we are taking a broom to that Rouch file and you're going to enjoy it so let's get started okay first up is Route model binding so work along open your routes file and scroll down to this show action here all right let's have a look we are listening for a get request to jobs SL some kind of identifier we then capture that ID it is passed to the closure here and we then use that to fetch the corresponding job from the database great but as you can imagine this is something you will do over and over and over within your projects and luckily Lille has a shorthand of sorts uh it can fetch the model instance for you automatically if you follow a common convention so here's what we'll do I'm going to comment this out temporarily and for the wild card I'm going to change it to job something a little more generic fetch me the job uh and you can use an ID and the default is an ID but often it might be a slug or some other kind of unique uh token or string all right so now I'm going to change the ID variable to match that so job job they're the same okay next I'm going to add a type I expect a job instance all right so is it that simple let's get rid of this uncomment this line and see if it works let's have a look at carpet installer this is the show action and yeah it works exactly the way it did before I mean come on how cool is that all right so what is the convention well it's twofold first up your wild card and the parameter name need to be identical so notice job and job next we add a type to the parameter and this is a signal to larl that hey I'm not expecting the string that's the URI I want an actual instance of job okay so now Lille sees that and it goes all right I'm going to give you a job but which one which which identifier from the database well these match so whatever this wild card is represents the ID in the database and of course if you need to you can configure that so for example very quickly uh let's imagine you have a Blog well often the identifier for a post isn't the ID it's some kind kind of unique slug so in these situations you can add a colon and then the name of the column that should be the identifier so if I want you to find the post from the database where the slug equals this value then I would use colon slug or I could do this or this is the default so I could leave it off entirely all right so yeah it's pretty cool next we can update any other references within our R file here's another one so let's do it together all right update the wild card and the parameter to be job next I apply a type and then I can remove this manual fetching there all right next up update the exact same thing job job and then I don't need this anymore and also by the way authorize is actually something you would do at the very beginning and then you validate all right finally we have this one here job job and then this section right here can change to job delete all right let's do a quick run through just to make sure we didn't break anything so we have all jobs have a look at construction manager edit that job uh let's say senior construction manager is that a thing update it that looks good mm let's delete one all right that one's gone yeah everything's working exactly the way it did before good job all right let's switch back and move on to tip number two so what we have here is is just fine and dandy uh for relatively simple projects but as you can imagine if you're building a very large application that has potentially hundreds of rounds pretty quickly this becomes unwieldy I mean we're just dealing with jobs at this point and it's already quite a bit of scrolling so instead what I think you'll find is for for most non-trivial applications developers reach for dedicated controller classes and we'll do that now PHP Artis make a controller and I can then apply a name right here or if I omit it larl will ask me a handful of questions all right what should the controller be named well generally it will be job or jobs whatever convention you want to follow and then controller all right next what kind of controller do you want should it be an empty class should it be a resource we're going to put a pin in that because I'll show you that later a Singleton API or invocable which is like a single single action controller uh that's confusing just add empty for now let's now open app HTTP controllers and there we go and yeah notice it's an empty class because we told it to be empty okay so here's the cool thing I'm going to open up a split pan and then return to my routes file and notice how we applied these action names above every routes an episode or two ago I'm now going to convert those to methods like this method index 1 one for create one for show and yeah I'm just going down the list here one for store one for edit one for update and finally one for uh destroy as you see there cool so now I want to say well listen for a get request to/ jobs but don't run a closure instead call the corresponding action within this controller so here the action is index so I want to trigger this method right here okay what I'm going to do is add die and dump hello for a sanity check and then I will comment this out and replace it with our new version route get jobs and then I will provide an array here the first item will be the controller class so I can say job controller class and yeah of course if you want you can simplify and import that at the top of the file all right the next item will be the name of the action that we want laravel to call in this case it's index and that should do it so yeah if I visit SL jobs if we did everything correctly I should die and dump hello come back refresh and it works pretty cool and not too hard to implement so now think about it let's uncomment this out all I have to do is take the contents of this closure and move it over into this new uh home and then I I can delete this entirely okay next I of course will import the job class all right so now yeah we've done our first successful migration from a route closure to a dedicated controller action and that's the term we would use to describe each one of these they are actions on the controller come back refresh and it works so cool okay now I will go down the list and update all of these and I'll do it a little bit quicker so for the create action I can cut and paste that in for the show action once again cut paste it in but what about this section here can I just move that over and the answer is yep you got it all right get rid of that all right next store action I will cut all of that paste it in what else we have edit add our type and then update a little bit tedious but it's just for demonstration all right job job and then finally we have destroy all right very cool so our controller is looking good I will close that out and then I just want to update all of these other routes so I can say we have job controller class this time we're calling the create action okay and what I'll do here is select all of that so I can save myself some time all right paste it in this one is show this one is store this one is edit and this one is update and finally we have destroy yeah a little bit cleaner don't you think definitely easier to reason about and scroll okay so now I can get rid of all of these comments that's redundant and this is what we get now it's Crystal Clear that these are the routes related to our jobs and also by the way I can get rid of this job import okay number three route view so often you will have situations where you listen for a get request and in response you do nothing else except load a view and yeah this is especially common for uh static Pages like a contact page or an about us page so in these situations has a small short hand I can replace this with route view I provide the URI and then I reference the view it should load like this so this and this are effectively identical it's just it's just a shorthand I can do the exact same thing here route view contact and contact get rid of it and yeah nothing will change here it all still works which is pretty cool but sure sanity check here's your homepage here's your contact page you're set cool that was a short one next number four listing your routes now what we have here is fine and simple but of course for real projects the size of your routes file will grow significantly you'll have dozens and dozens or potentially hundreds of routes so for this reason larl has a helpful Artis command called route list and as you can guess this will list all of the routes in your application but it is unique notice if I scroll up here's all of my jobs here contact but then I also see some routes related to thirdparty packages like ignition and debug bar and yeah this might be helpful but generally you can avoid these or ignore them so if you want you can say route list accept vendor show me all of the routes except the ones that were defined within my vendor folder and this is what I get and this is really what I care about homepage contact and then the jobs resource that consists of seven actions and yeah it's really helpful we have the request type we have the URI and then way over here we have the controller that is responsible for handling it pretty helpful okay so that brings us to our next tip notice here for the resource I keep repeating that controller name job controller job controller job controller and yeah there's no real problem here but if you want to remove just a touch of duplication you can Define it once and then group all of these routes under that single reference and here's how I can say route controller job controller then group and then I provide a closure here so I'm creating a route group where all of them will assume this controller and then I can move all of these within it okay so now the only remaining step is to of course remove the controller reference I will use multiple cursors for this select all of them delete look for the closing array and delete that as well and yeah maybe uh you might decide this is a little cleaner so can we confirm this works well let's switch back to the command line run it again and if we did everything correctly it should look identical to the way it did before and it does notice they all refer to job controller all right very cool but now that brings us to our next technique which is Route resource so yeah multiple times in this video I have used that term resource to represent the collection here of actions so as it turns out Lille has its own dedicated route resource method I'll show you how to use it the first argument will be the resource name uh this will also be the URI in this case jobs the next argument is the controller that is responsible for it job controller okay so check this out if I comment out this line here and I rerun route list notice I get the exact same thing because that's what route resource does it registers all of the routes for a typical restful or resourceful controller and notice the convention that we're following here if I didn't have any of these here and I just had an empty controller if I run route list I still see that it's going to assume and default to these action names and yeah on that note this is specifically why I've tried to be crystal clear about these action names over the last few episodes and it's also why we added a little comment above each route declaration two episodes ago but yeah if you can't if you can't remember them you got to do it just practice close your eyes and say them out loud index show create store edit update destroy index show just do it over and over until it rolls off your tongue okay now I have one final extension to Route resource what we have here is helpful but often you don't need to generate or register all seven resourceful routes instead you only need maybe a handful so for this reason you can pass an array as the third item now you have a couple options here you could specify only the actions that you wanted to generate or register or you could do the inverse except do all of the default ones except such and such so maybe we decide we don't actually need an edit action in this case I could say generate a resource accept edit now notice we have it right here but if I run it again it disappears we have all of the routes except edit on the other hand if I swap this out with only maybe we only need index show create and store but there is no option to delete or update now if I switch back and run it again you can see we have only four uh corresponding actions all right so that's all of the routing specific tips that I have for you at this stage in your learning so now let's get prepped for The Following episode I do want all of these actions so I will simplify it rout controller is very useful but we don't need it in this case so now I will move my route view calls at the top we have one for home one for contact and then a resource for jobs and that resource will be handled by a dedicated controller class all right that's a wrap now before I let you go one final note I really do hope as much as possible you are working along with each of these videos it's one thing to watch me type it out but trust me when you are responsible for each character uh it makes a mountain of difference in terms of what you retain and remember okay that's it in the next episode we will start a new chapter which is authentication I'll see you then [Music] hey there welcome to day 20 which is also the start of a brand new chapter on authentication so we have a lot to cover and keep in mind yeah day 20 that means 10 days to go and at least probably four of those episodes will be dedicated to our final project so that gives us about five or six videos to cover a lot of material so let's get started for many years now larl has provided starter kits to get you up and running as quickly as possible and yeah when I say starter kits I want you to think of initial projects scaffolding for a typical app so here's an example have you ever worked on a project that required users to log in to their account all right well immediately before you can even build something unique to the project you require a registration form you require a login form you need a forgot password form you need a confirmed password reset form you need an edit profile form uh then you need routes and control rollers and Views and logic to orchestrate all of this it's shockingly an immense amount of work and these starter kids specifically lir ofel Breeze automate the entire process let me show you now check this out I'm in my example project route but let's go up one level to herd so that I can scaffold a brand new LEL project just as a demo LEL new I will call it app all right immediately it wants to know do we want to pull in a starter kit I will choose use Breeze and yeah on that note keep in mind starter kits are really meant to be used at the start of a new project so yes even in our example app I could pull it in and I could install it but it's going to be a frustrating process and that's because Breeze assumes certain things it will assume that you have a welcome view that you may have already deleted it's going to overwrite your routes file it's going to overwrite your layout file it's going to pull in a bunch of Blade components that might conflict with components you've already created yeah it's a frustrating process and that's why it's specifically meant to be used at the start of a new application okay what stack do we want to use how are you going to build your app is it a single page app using react are you using view are you using Live Wire that you might not be familiar with yet or is it a traditional serers side blade app with some JavaScript sprinkled in we'll choose that one okay do we want dark mode support no uh what test framework test is fine do we want to get repository no and we'll let that get to work all right next which database will you use site is fine so yeah we fast forwarded of course but a ton just happened we didn't just scaffold a new lville app it set up your node dependencies it installed them it configured your database it copied over all of the breeze specific uh scaffolding like your routes and your controllers and your views and your components and now we have an instruction to CD to the app and we can run PHP Artisan serve or if you're using herd you can just access app. test in the browser I will visit app. test and here we go we have a new layl project but this time it's a little different notice we have login and register Links at the very top all right let's give it a shot we click register and we have a typical registration form let me fill this out really quick and here's my dashboard we're in I mean come on you have to appreciate how mind-blowing this is and I'm not even using that word hyperbolic maybe maybe a little hyperbolic but still it's just so cool think about it within 20 seconds we installed a lell project we registered and we are now viewing our authenticated dashboard and it took again what 20 20 seconds that's ridiculous anyone who has built this functionality in the past will instantly appreciate uh how useful this is so if I come up to my name here of course we can view and edit our profile so let's change it to Jano save it there we go if I refresh the page that has been updated in the database I can update my password I can delete my account and of course I can log out but I do want to show you if I visit my dashboard the URL is app. test/ dashboard okay let's log plug out and try to visit that again app. test/ dasboard and of course it doesn't let me okay so we have some level of authorization in place hey if you want to access this URL you must be signed in otherwise we will automatically redirect you to the login page okay so lot's going on here let's have a look at our editor now we will have a look here but I do want you to keep in mind that initially this might be a little overwhelming and that's because larl pulls in so many files but yeah it's necessary if you were writing this functionality from scratch you would do the exact same thing and if nothing else this is an incredible educational resource to see how larl core the core team would recommend implementing some of this logic let's have a look at registered user how do we create a registered user in our application well they have a controller that shows A View to register all right I can command click to that View and we can see how they would Implement one of their views notice they make heavy use of Blade components they have a layout file just like we created and then they also extracted blade components for the input the label and the validation error very cool and very educational take notes all right let's go back next when we submit that registration form it hits this logic and again it looks very similar to some of the code that we've written notice in this case they added a parameter here called request so larel will automatically resolve and pass that into the controller method but it's effectively no different than how we were handling this it's just a more formal way to inject the dependency that you might prefer but nonetheless this and this uh as I often say are effectively identical okay so we validate the request it looks like to register you need a name an email and a password and if that validation passes then we create a new user all right it hashes the password it fires an event now we haven't yet discussed venting but if you want to head start here you go you can review this helper function you can click through have a look at this and then also take a look at an artisan command called make event but yeah we're not quite there yet so let's switch back finally we log in the user and we redirect them to their dashboard okay so if we're following this idea of using Breeze as an educational resource well how how did how did the core team ensure that if you're not logged in you can't view your dashboard well let's take a look at the r file and see how they implemented it let's go into RS web and here are the RS that breeze created for us and sure enough we have one for dashboard okay so let's inspect this together when the user visits SL dashboard we load a view all right no security there but then I see this section middleware and then keys for off and verified okay even if you don't know what middleware refers to you can sort of gather that it's adding a bit of protection well in order to access this page you need to be authenticated you need to be signed in and also you should have confirmed or verified your email address okay so I find that the term middleware can be a little confusing for newcomers you know what I mean it sounds very low-level and Technical and serious now like the serious developers we are we will Implement some middleware uh but you know what it's not that scary you can think of middleware like layers of an onion like ogres that lead to the core of your application and each of those layers has the opportunity to do something it can record something in the database it can check for a header it can check in the session to make sure you're signed in it could do the opposite it could ensure that you're a guest so a logic like that can all be handled within a middleware so let's confirm our assumptions if I remove this call to middleware entirely and then as a guest I try to view the dashboard what will happen here's the homepage we're not signed in if I visit my dashboard no longer are we redirected to the login page instead it tried to load the dashboard but it did fail because if I scroll down at some point in the view it tried to access the authenticated user and of course there is no authenticated user so we're trying to grab a property called name off of null and can't do that so it blows up but yeah in terms of Education once again if you wanted to know how to grab the authenticated user after you signed in now you know how there is an oth class or facade how we refer to them with a user method that gives you the current user who is signed in to the application so cool okay so if I switch back I will return the call to middleware and let's include just off this time notice if I only have one layer of the onion leading into the core of my ab I can include it as a string but if I have more than one then I would pass an array both of these are supported all right so anyways if I come back to my browser give it a refresh now we are properly redirected to the login page and that makes sense that's what the off middleware does behind the scenes it effectively says all right let's see if you are authenticated let's see if you're signed in if you are then you're clear I can pass you on to the next layer of the onion leading into the core of the app in the core you will load the dashboard page okay but if you're not signed in uh-uh this this is disallowed you're not allowed to continue on to the next layer of the onion instead I'm going to redirect you to somewhere ible and by default that somewhere sensible is of course the login page okay so that's all I'm going to show you in this episode again I just want you to play around so this is your homework go into the controllers and keep in mind nobody expects you to understand all of this so if you're thinking the complexity of this course just took a huge leap no it didn't I don't expect you to understand everything what I do want you to do though is get comfortable just consume it let these files wash over you so you get an idea of how season developers would go about constructing their applications all right then when you're done with controllers come down to resources and you're going to notice yeah how are these organized we have a profile directory we have a dedicated folder for layouts we have one layout for your app one for guests and then one for navigation okay we have a folder for all of our components so in our example project we only cre created a couple but now we have components for drop downs and modals and nav links and if you want to swipe any of these you totally can it's open source all right so that has been your rapid fire introduction to starter kits in larel Breeze and again to reiterate starter kits are meant to be used at the start of a new project okay so in the next episode we will switch back to our little jobs example project and I want to give you some ideas for how you can handle authentication if you're not using a starter kit so I'll see you [Music] then all right so now that you understand that laral breeze is a thing that you can use at the start of any new project in this episode we'll figure out how to manually implement the logic for a registration and lockin system so I'm going to Peg this at 9 minutes let's get going now let's begin within the browser of course I'll need to create the markup for a registration and a login form but luckily we've done some of this work already if I click on create job yeah we have the general layout for a form field so why don't we extract these into a couple blade components and then we can rapidly build some new forms I will go to jobs SLC create all right and let's see what you see right here represents a single form field notice it contains a form label a form input and a form validation error so with that in mind why don't we create a handful of new components one will be called form label. PHP I'll duplicate that the next one will be form error and then one more time this will be form input cool so now think about it if I switch back to our create view we can just move some of these over so I will take that label it's going to be replaced with X form label and then I can move it here okay now the four attribute that can all be merged in from the outside and then this of course can't be hardcoded that could either be a prop itself or it could be the default slot whatever you want okay so let's merge in any attributes by saying attributes merge but set the default uh attributes in this case class to what you see here and let's close that out all right that looks good so now let's switch back this is the label for the title so I will add that here and then we will set the slot so this would be title all right next why don't we do the validation error X form error whoops I'm sorry I forgot to add the blade extension all right switch back one more time form error let's switch over paste in that code all right so it looks like we need to pass in the title why don't we accept that as a prop that will be the name for this error that's now available as a variable within the component so I can reference it here and that looks good all right let's switch back name is title in this case and this can be self closing and then finally I think this whole thing can be our form input so extract that we want X form input and I will move it over here all right so let's see all of the attributes are going to be passed directly to this child input so the default type for an input is text already so I can remove that these will be passed in so let's do that now real quick paste that in all right and then finally we have these long classes I will cut those temporarily and yeah everything else can be passed in cool so let's say attributes merge set the class to um what you see here and everything else yeah once again can be passed in from the outside so let's go back to create and placeholder will be CEO and this will be required okay so now we've cleaned things up just a little bit here's what we had before if I give it a refresh yeah this all seems about the same let's inspect it and make sure all of the attributes are being applied properly so here is our field here's the label for the title does the input also have a name of tit yeah all of this looks pretty good to me why don't we also submit it oh the required attribute is taking effect but if I removed it and we hit the server H oh yeah we have to do that one too let's see let's comment that out for now all right now we are seeing the contents of the form error component and that looks good as well cool so let's do this um should we create a form field uh I'm going to show you because it might be helpful to you but if you want to skip it you can all right so we're going to add one more here called form field. blade. PHP and then if I switch back it's basically everything you see here but everything here the label the input and the error will be passed in from the outside so I'll just say whatever you want to pass in will be deposited here cool so let's come back all right so now this div becomes X form field and I can remove the class okay back to the browser give it a refresh everything works just like it did before okay so now this is going to save us a great amount of time if I come back I want to do another one for the salary so we are reproducing what you see here let's just get rid of it entirely and update it salary I think our placeholder was 50,000 USD and then I will update this come back refresh that works submit it validations in effect yeah this is much cleaner than we had before okay so now we had some example validation um logic I'm going to get rid of that entirely and this is kind of what your form looks like all right and now by the way I know we're spending a lot of time on these blade components but trust me it's going to pay off once we start constructing those other forms so the last thing I'm going to work on is why don't we extract our submit button into a dedicated component so this would become something like X form button do you want it to be a primary button a default button whatever you want whatever you think makes sense okay so let's add this here form button. blade. PHP I'll paste that in and here's what we'll do I'm going to rewrite this whole thing so that I can say attributes merge the default class is what you see here and the default type is submit all right and then this can be your slot all right we have it back to our create view this will now be save in this particular case okay come back give it a refresh I can still uh interact with it like usual but now yeah we've componentized it if that's a word okay so now yeah there's a couple other things we could do here but it's good enough for now so I'm going to copy all of our view here switch back to my routes file and let's prepare some off routes route get register that's our endo and we will call this controller anything you want registration controller register controller uh larl does registered user controller anything that makes sense to you now what is the action well this is the page to create a new registered user so we call it create okay but now of course my editor is squawking because I haven't yet created that controller PHP artisan make controller and I'll paste that in cool so now I can right click and say Import in PHP storm or of course you can manually import it at the top okay so now of course we can go to app HTTP controllers registered user controller and let's add our action to create so if you want let's do sanity check did we hit this endpoint back to the browser let's go to example. test/ Reg and we did okay so let's return a view and why don't we put this all under an O namespace maybe something like that cool so let's go down to views let's have a new directory called off and a new view called register. blade. PHP okay so now I'm going to paste in all of that form code from our job create view let's update a couple things register um we don't need any headings and yeah let's just see how this looks come back give it a refresh and yeah that looks decent so now and actually real quick I see title is duplicated let's fix that real quick come back here salary sorry about that I know you saw that anyways if we switch back if you want to register you need to give us what well we can check our database table if I open users yep we need a first name a last name and an email address as well as a password okay let's do this quickly first name uh and by the way if you don't want to watch feel free to fast forward I will use multiple cursors first name no placeholder on the input is necessary here's an idea for a name Joe and then I'll do the same thing for the next one all right last name last [Music] name and same thing no placeholder necessary okay are we on the right track first name last name looks good let's keep going so I can duplicate at this we need an email address but then on the input itself I will override the type to be email all right and then finally we need actually two fields for the password so one will be what you see here just your standard password now of course in this case I will set the type to password because that would make sense if I come back and refresh there you go first name last name email password and actually on this note just a quick one but from my experiences it would actually be more helpful to make the user repeat their email address rather than the password that's the one people always miss I know it's hard to believe but I have the receipts it happens over and over and over again but anyways we will stick with tradition for now so I will have a password confirmation field password confirmation or why don't we say confirm password and now we're going to follow a convention here which is password uncore confirmation and I'll explain that more shortly all right so switch back and yeah here is our form so just a couple things why don't we reduce the margin here on the parent I can just remove that entirely yep and then finally save doesn't make sense it should probably say register so right down here register and then next this shouldn't be a button this can be a simple Anor tag that takes you back to the homepage all right so finally which of the inputs should be required actually in this case I think everything so here's what I'll do I'm going to select all of these and then go to the end with multiple cursors and set required saves a little bit of time okay so now if I try to register it's going to make me fill out each of the fields as you see here cool okay so now let's once again copy this and I'm going to create another form for uh signing in let's call this one login. blade. PHP I'll paste it in we'll say log in of course we will update the form attributes uh for both of these forms shortly but yeah to log in you don't need a first name you don't need a last name you just need to give us um your email address as well as your password so let's get rid of that as well and then this can become log in so let's close that out I'll go back to register and now let's work through where this form should submit uh you have a couple choices you can you can strictly follow kind of a restful approach uh or or you can change it up remember rarely are there hard rules there's just guidelines or systems that you follow for your team in this case I think it's fine and simple to submit a post request to SL register all right that's our next step go back to our routes file all right let's duplicate listen for a post request to SL register and that will hit the store action again we're just following conventions here come back create our action die and dump too that will all be in the next episode for this episode we're only focused on the HTML logic yeah if I say Jeff Joe blah blah blah add some dummy password register sure enough we hit that endpoint and of course if you quickly want to see all of the attributes from that form you can run request all so if I hit command R there you go okay so now if I come back to my R file let's finish up the login form so we'll say listen for a get request to SL login and yeah once again what do you want this controller to be anything you want login controller session controller login user controller it doesn't matter I often go with session controller that makes sense to me we're creating a new session we're storing a session we're destroying a session but again you can be creative all right so this is going to show the create action on a new session controller let's create it PHP artisan make controller session controller all right import that command click add our action and this will now return a view off. login now we've already created that view so I can click through and this is what we get let's see if it works in the browser let's go to log in and there we go good so now where should this form submit well once again if we're creating a new session then we would make a post request to uh either login or if you want to have a new endpoint like sessions any of that would work but yeah we're going to keep this super simple a post request to SL login will do the trick all right let's create that right now let's duplicate this we're now listening for a post request to/ login and following con ventions that will hit a store action so I can create that one as well store and once again we will die and dump the request as a to-do placeholder come back refresh let's try to log in the validation takes effect we use dummy data we hit that endpoint very cool it works okay so now to wrap up this part one uh we should display some login links maybe right up here I'll get rid of these uh and replace them all right so let's go to our layout component and yeah here's that nav section and many episodes ago we created a nav link component for each of these that you see here so let's just add one to the far right all right so let's see yeah so we have this button that contains an SVG that's this section here we're going to get rid of these and then I'll get rid of the profile as well okay xnav Link login come back refresh and that works okay so this will take us to herf login and if I click on it there we go okay what about registration well we can do another one here like you see and yeah that would work so we now have a register link that looks great but keep in mind once you're signed in it might be weird to see a login and register button in the navigation area you're already logged in you're already registered so in these situations it's helpful to check the authentication status to determine what markup we create and I'll give you a quick tip for how to do that okay so I will introduce two new blade directives that I want you to be aware of the first one is called off and it does exactly what you think it does if you're authenticated then display whatever markup I have within here now of course we can also do the opposite guest if you are a guest of our application then do whatever you see here okay so if you think about it this would make sense only on the condition that you're a guest should we display a login and register link so if I come back and refresh this page sure enough I see them because I have not yet signed in and that would make sense okay last thing I want to do here is if I click on my nav link component we can pass through an active status so yeah just like we did with home and jobs we should provide some additional styling if you are on uh that page so if if I come back for login I can say make this one active if the request is login and then I'll do the same thing for register like so now if I switch back and refresh yeah we just have a little extra feedback which can be helpful okay I think we're making pretty good progress here all right I get it I know what you're thinking I can read your mind this was definitely AB absolutely certainly one of the more boring episodes in the course but folks what do you want me to do it's form code it has to be written my hands are tied here we had to do it uh and we did do it so good job we made it through this lesson and now in the next episode we can focus on what I consider to be some more fun logic so stay tuned for that you're halfway through let's keep going [Music] hi folks welcome to part two why don't we Jump Right In I think this video will take around 7 minutes maybe six okay we will start with registration so assuming that I filled this out properly and I click on the register button what should happen well let's switch to my editor I will visit my routes file and yeah of course we already have an endpoint set up in the previous episode that will hit a store action on the registered user controller all right let's write it out what needs to happen in order to register a user well we have to validate the form always got to validate next we should create the user in the database next of course we should sign them in so log in and then finally redirect them where we want them to go go should it be their dashboard should it be back to the homepage uh whatever would make sense redirect somewhere all right let's get to work so we already know how to validate I can say request validate now if I switch back yeah we need to validate the first name last name email address and password okay so I'll show you a little trick if you happen to be using PHP storm and the Lal idea plugin I can actually hit command in within this array and choose add quent model Fields I referenced the name of the model and it will do its best to automatically generate the validation Fields uh which I think is pretty cool now in this case though it's doing a little too much I don't need a remember token I don't need email verify that all right let's reformat and the only other thing I might want to change here is do you require a minimum number of characters for the first name or last name uh is a last name or first name required maybe it's optional for your system in our case we will say it's required all right so for email it should be required it should be an email and they have set a maximum number of characters uh that's often a good practice to get into but we're going to leave them off for now okay finally for the password uh is there a specific shape that we want the password to take uh we've all signed up for applications where it's got to be you know at least two numbers at least one uppercase character a certain length um generally I find those rules do more harm than good but nonetheless if that's what you want you have the option and because it's complex enough larl has a password helper class so notice it's illuminate validation rules password and you can almost think of this sort of like a fluent API for setting your rules so for example if I want to set a minimum number of characters I could do so like this and notice I can continue chaining so if I want to set a maximum number of characters if I want to and by the way I can command click to to read the documentation here if I want to confirm or require that at least one letter is used then I can call the letters method if I want to do the same but for numbers then I can call the numbers method and again notice how these methods return the instance so that you can chain as much as you need to so I could say you got to give me letters you got to give me numbers the maximum number of characters uh again whatever you want now one thing to keep in mind is if you would be referencing these rules all over the place in your application you can instead put it in your service provider and then that would allow you to Simply reference uh your applications defaults now in this case I want to stay on task so we're not going to review that but yeah if you're interested have a look at level.com dosv validation in our case we'll keep it very simple I will say it needs to be at least six characters and then I will add one more called confirmed I like this one okay so here's how it works when you apply it to a request field laral is going to look for another attribute that has this name password uncore confirmation and it's going to make sure that this attribute and the password confirmation attribute match or are the same now generally it's going to be applied to the password uh attribute but you could do it to email if that would make sense so if I did this then larel is going to look for an attribute or an input with a name of email confirmation that's the way that works so you'll remember if I go back to my register view we have uh a confirm password field and notice what the name is password confirmation so notice I didn't say confirm password because that's not going to work in order for that validation rule to work it needs to be the related attribute uncore confirmation and actually while we're here I noticed a little mistake from the last episode The type here should be set to password okay multiple cursors me know how they are okay so I'll switch back undo this and we are ready to continue on great job so we validated the request the next step is to create the user user creates and I'll show you a little tip yes I could repeat those attributes so I could say first name is well get the first name from the request then do the same for last name then do it for email uh but if you want assuming that this validate method succeeds it's going to return the validated attributes so I'll show you this uh let's comment this out and then I will die and dump the validated attributes let's have a look in the browser so I will do John uh Jacob blah blah blah password we submit it and yeah the validation succeeded and now it returned the validated attributes so notice this is effectively what we want to pass to the user create method okay so with that in mind I could do something like this validated attributes okay so in the wild H validated attributes that works I guess it's a little verbose uh I have seen personally simply attributes I've seen validated uh that sometimes signals a Boolean but I have seen that many times um if you want to do a shorthand it doesn't matter and you could even inline the validation entirely and that would work as well uh and sometimes that's kind of fun but yeah let's just stick with how about um let's do attributes this time cool right all right let's continue on so at this point they have submitted the form they have passed validation we have created a user in our database now we will log them in now larel ships with an off class notice alum eliminate support facades off and there's a method called login now as the first argument to this login method I need to provide the user that I want to log in shocker so after we create the user that will return the new user and I can pass that to off login nice and simple all right final step where do we redirect well maybe I don't know maybe the first thing you want to do is visit your dashboard or your settings page or the jobs page let's stick with that redirect to jobs and that's it that's your basic controller Logic for registering a new user let's try it out in the browser let's fill out the fields and submit ah it fails and yeah once again this is related to fillable fields for the model so you'll remember we solved this problem for the job class but not yet for user so what I can see here is it's allowing the email address and the password but not the first and last name so if I open that user class and again that will be an app models user yeah this is what larell includes by default and notice there's no first name or last name so if you want to fix this either update these like so or of course like we learned if you know what you're doing and you feel confident that you're not going to dump all request data into for example the create method instead you could set protected guarded to an empty array you don't need to guard anything for me I know how to use a sharp knife I can take care of this all right so if I come back I will simply hit refresh to try again and there we go so we don't have any feedback yet it might be useful to have a flash message that we put into the session but we can confirm it works let's visit our database all right let's open the users table and sure enough we have our John Jacobs account it worked now here's kind of a fun thing notice how I used a horrible password password but when it was saved to the database it was actually a hashed version of it now that's interesting because we didn't hash it ourselves in the controller and yet still it worked so what's going on here how did that happen well I'll show you let's open the user model and again this code was provided out of the box by the framework we didn't write any of this but sure enough I see a method called casts get the attributes that should be cast all right so think of this as a way to manipulate a value when you fetch it or when you set it and sure enough I see one called password right here hashed okay so what this means is when we set a password on user I want to automatically hash it all right so let's just try this out from the terminal PHP Artis Tinker let's create a new user app models user let's set a password to password and now notice if I grab that value now that value is is effectively piped through that cast and of course lell provides a bunch out of the box and you can even create your own which is really helpful okay so that's kind of a quick primer maybe we'll touch on that more in the future so we're in good shape but notice right up here I no longer see the login and register links and that would make sense we implemented that logic at the end of the last episode let's return to that I will go to our layout and yeah right here we said well if you're a guest only on that condition should we display these links let's do another one I will duplicate this but this time we will say off so only on the condition that you are authenticated or signed in and in this case I want a log out link now here's one thing to keep in mind um beginners will often use a simple get request for their logout link and yeah it is helpful because then you can set up an anchor tag to instantly log out the user so if I come back and refresh now we see it because we are authenticated however generally this is frowned upon uh ideally we should submit a post request to log out the current user otherwise for example even if you were on facebook.com if they wanted to be malicious they could have a link that sends you to larac cast.com logout and they could call it something else like um view popular posts but then when you click on it it's not showing you popular posts it's actually logging you out of Layar cast which they should shouldn't be allowed to do so that's why a get request for log out is generally frowned upon so with that in mind let's instead use a form we'll have a form button we might have to tweak The Styling here but let's see if we can make it work and we'll say log out all right let's switch back give it a refresh and yeah The Styling is different but you know what it's fine I don't mind all right so where is this going to send us well let's switch back to our Rouch file and again let's keep it really simple if you make a post request to log out that will hit the destroy action on the session controller okay so we have our endpoint let's switch back that will go to log out and the I'll do this at the front the method will be post all right the only remaining step is to add our csrf token and I think we're all set all right so let's go into session controller we're now going to destroy a session and once again sanity check log the user out are we properly hitting this action let's come back refresh press log out and there we go okay so yeah why don't we just take care of this right now because after that we can start working on the login functionality so if we can log in a user by saying login user then we can log out a user by saying log out and in this case I don't have to provide uh a user because it assumes the currently authenticated user all right so let's import that and then finally after we log out a user let's redirect them to the homepage that sounds good to me all right so let's give it a shot come back refresh I'm on the jobs page I click log out I'm redirected to the home page I'm no longer authenticated so now I once again see the login and register links cool so that brings us to the final step I need to log in okay we're going to use those credentials that we provided when re-registered so the email address is John Jacobs and my password is password login we hit that endpoint and we die and dump the values all right a little bit more work to do here I'll show you all right so once again let's get in the habit of writing out what needs to happen first we should validate the form next I should attempt to log in the user remember yeah validation could pass but then when we attempt to sign them in if the password is wrong that step is going to fail all right so try to log them in if it succeeds one little side effect we should do is regenerate the session token uh this is a little lower level but we'll talk about that when we get to it and then finally I think we're all set so we can redirect okay so let's begin I'll do it a little faster this time request validate the email address is required and it should be an actual email address and then the password is required and that's enough okay so validation is complete let's save the validated attributes to a variable next attempt to log in the user so once again we're going to reach for our handy dandy notebook off class and notice there's a method at the top called attempt let's see what the parameter list is include the credentials and then if you want the application or the session to remember the user uh you can set that to True okay so the credentials will be of course the email address and the password which we fetched here let's pass it in now this attempt method will return AB Boolean could it successfully log you in or not let's start with the happy path okay next regenerate the session token let's put a pin in that for one more minute I want to stay on task but yeah I will write it out uh request session regenerates uh but yeah you can imagine it's a security thing that effectively recycles the session token okay finally redirect yeah once again uh if this is all about jobs then I'm going to send you to the jobs page after you sign in but yeah maybe maybe your dashboard maybe a settings page maybe the homepage whatever you want okay so again I said happy path why don't we have a look in the browser so here's the login form let's sign in John Jacobs with that horrible password and it worked and I can tell that I'm signed in because I do see that log out button at the very top cool but let's log out go back to login and this time I will choose John Jacobs but I will provide a password that doesn't match all right let's see what happens in this case log in and hm it redirected me but I'm definitely not signed in all right so so what's the deal this is confusing but actually it makes perfect sense if you think about it we performed form validation and it passed you did include an email and a password next we attemp Ed to sign you in and it failed so false was returned from the attempt method but we didn't do anything with it so we just continued on regenerate the token and redirect and that's how we end up here but not signed in all right so and I promise I'm not going to be long here but it sounds like we need to handle the very real and likely possibility that authentication is going to fail so in that case if you think about it it's almost like a validation error isn't it uh sorry you didn't provide an email sorry you didn't provide a password sorry your credentials do not match so hm let's see if we can treat it like a validation error now back in my controller action let's negate this we'll say well if you could not log in the user then I basically want to throw a validation exception that then gets converted into a validation error within the form that way we provide feedback to the user and luckily outside of the request validate method this is pretty easy I can throw an exception now larel includes a validation exception class and be careful there's a bunch here the one you want is illuminate validation validation exception now it has a method called with messages this would be an array of messages to associate this error with so I want to associate it with the email uh attribute or the email input in our form now the value you can be sorry those credentials do not match and yeah that should do it so why don't we try this out in the browser back to the login page I will sign in John Jacobs using an invalid password and sorry those credentials do not match try again but actually while we're here and by the way that's kind of cool that we solved that problem but while we are here notice that it emptied out those input values and that can sometimes be annoying I now have to start all over just to fix what is possibly just a one character difference so it sounds like I want to display the old values from before the form was submitted that way I don't have to start all over okay I'll show you how to do that super quickly if I go into the login page here's the email input and yeah I could set the value to anything I want and of course that works you already know that but yeah if I want level includes an old helper function I've reference the attribute name in this case email and yeah it's going to give me that old value for the attribute from the session all right so now though I want to show you why this doesn't work because it's often a point of confusion for newcomers so I'm setting value to old email and if I switch back to the browser I see old email and that it makes sense right I'm referencing this as not a function call but a string so this is why we add that colon here we are binding this value to an expression rather than a string so when I have a colon this is treated as an expression when there's no colon It's treated as a string okay so let's bring it back give it a refresh and now it's blank because there is no old value from the session let's try again though submit incorrect password log in now of course the validation fails but I do see the old input value which is great okay so very good now for password it wouldn't make sense to display the old value so we will typically omit that step all right so anyways if I provide a real password we are redirected and we are signed in to the application pretty cool stuff all right so let's wrap up if we switch back to our session controller I want to finish up with two notes here now as you've learned when we call request validate if it fails we don't have to manually redirect back to to the login form larl will do it automatically and that's really helpful so as it turns out the exact same thing is true for validation exception if I throw it I don't have to catch it anywhere it'll Bubble Up and Lille will catch it it will then inspect the exception and it'll see all right validation exception we know these roads we know what to do so it then redirects back to the form and sends through the error messages all right number two session regenerate yeah this does what you think it does it is a security measure that protects against what's known as session hijacking that is an attack where a hacker gains access to your session token and a session token is sort of like a unique identifier that says you are authenticated for this application in that browser so if a hacker could gain access to that token they could then impersonate you which is not good so one way we can protect against that is by always regenerating the token whenever we sign you in that way even if somebody has an old token it's not going to work because we recycled it and that's how that works all right so this is the logic for logging in validate the request attempt to sign you in regenerate the token and redirect you where you need to go congratulations you did it part two is now in the books okay so I would say you now have 85% of the necessary knowledge to begin building your own login and registration system okay so on that note the Reason by the way that I'm not saying 100% is because well there's things we didn't cover obviously we only have so much time in these videos so one thing I would recommend is reviewing rate limiting think about it right now if I log in with incorrect credentials I can just try again and again and again and again and again I could do it hundreds of times I could automate that from the terminal which clearly is a big security concern and then second we didn't yet cover uh resetting your password there's actually a number of steps involved in that and I was worried about it being maybe a bit overwhelming and you know what we haven't even talked about delivering email which of course should come first so yeah let's put a pin in that just for now okay so in the next episode you're going to let this we will move on to authorization which like everything larel makes a CCH I'll see you then [Music] good evening everyone my name is Jeffrey way and this is layer cast news our top story tonight involves day 23 authorization which is a really important episode all right so here's the deal I find that because authorization can be handled in so many different ways in a larl app that can sometimes be a little bit confusing to newcomers so here's what I've done I took some time and I organized the entire process into a series of incremental steps and I even printed it out for the first time I printed a PHP class which felt weird I feel like I work at Twitter um yeah I really do think this is going to help so if you have eight or nine minutes let's get started with step one Now quickly before we begin yeah if we want to perform user authorization for a job well there needs to be a relationship between a job and a user but at the moment there is none I only see an employer and if I open employers the exact same thing there's no connection between one employer and one user so we should fix that now let's go to create employers table the migration and I'm going to add a foreign key for the user ID I can use foreign id4 and then I can reference the model next let's go to our employer Factory and update this now an employer consists of a name as well as a user ID and I can reference user Factory for that all right and I think that should do the trick so let's run migrate fresh start from scratch and then seed the database cool so now if I give this a Reload yeah notice each employer belongs to a user and that's what we want okay now we can begin let's open job controller and yeah most of our energy today will be focused on the edit action okay so Step One is inline authorization have a look within my browser I can currently edit any job even if I'm not signed in which doesn't make any sense okay so a first step might be well to proceed at the very least you need to be signed in we might say well if off guest that's the opposite of off user or off check if you're not signed in you don't belong here brother so let's redirect you to the login page okay so now if I come back and I try to reload this page okay that's definitely an improvement but now what if you are authorized well let's see I will sign in a dummy user that I created behind the scenes and now if he tries to edit a job that he didn't create yeah of course that's now going to work we didn't account for that yet it's sounds like we need a second layer of authorization first up you need to be signed in second well you need to be responsible for that job all right so let's think about it if I go into job a job belongs to an employer and now an employer belongs to a user now I have a shortcut here to quickly build up the relationship but yeah it's the same one we've worked on for many episodes an employer belongs to a user okay so now think about it if I switch back to job controller we could say well if the user who created this job is not the person who is currently signed in then you don't have authorization so here's how we can do that I could say give me the job give me the employer behind the job and then give me the user or manager who is responsible for that employer and I'm going to use a new method here is if that is the currently authenticated user and I can use off user to fetch that then you're authorized okay so is is a method available on your models and it's really helpful for comparisons like this are they the same is this user instance the same as the user who is currently signed in if so you are authorized but in our case I want to guard Clause so I will do the inverse is not so if the user behind the current job is not the user who signed in in right now then you are unauthorized and in cases like this I don't want to redirect I would rather abort so I can say abort and then provide any status code uh common ones might be 403 Forbidden or 404 not found and depending on the scenario you'd probably reach for both in our case 403 is fine okay let's give it a shot let's come back to the browser I'm going to refresh this and now it doesn't work I get a 403 Forbidden okay but now let's switch back to jobs and let's imagine that I created uh a different job how about this one here for credit Checker all right let's do this to table plus let's open users and find my user id it's 202 here I'm John Doe and then we'll go into recent jobs here it is there's credit Checker that belongs to the employer with an ID of three and now we'll say that employer was created by me so yeah I'm just creating a scenario where I am authorized to edit this job okay so now if I try it it works because I am authorized awesome but for the first one I'm not authorized so it doesn't work all right that brings us to step two gates so think about it at the moment we are still displaying this edit job button even though you're not authorized to see it and that doesn't make any sense the only problem is well the logic that determines whether or not you're authorized is stuck inside of this controller action and that's not very helpful okay so let's incrementally fix this I'm going to use a gate facad that laravel ships with out of the box illuminate support facades gate now think of a gate like a real life gate it's a barrier and it conditionally allows entry uh if you meet certain criteria right so if you are authorized that gate will open but if you are unauthorized the gate is locked so let's define a gate and we can give this any name we want how about edit job and we'll pass a function here that will accept the currently signed in user as well as the job that we are authorizing okay so now within here we should return a Boolean that indicates whether or not this user is authorized to edit that job all right well we could take all of this here and move it in but like I said it doesn't need to board it just needs to return a Boolean so I can shorten this and say well return if the job employer user is the currently signed in user and of course I can replace that with user cool so does that make sense we are taking that logic and extracting it into its own gate the gate is called edit job and the logic for whether you can edit a job is well look at the user responsible for the job and see if that user is the same as the user who is currently signed in okay so now I can reference that logic by saying gate authorize we provide the name edit job and then we pass in the job that we are referring to all right let's give it a shot back to the browser edit job and we get a 403 all right so this is important to understand the authorized method will run the logic associated with the name that you reference and if it fails or returns false larl automatically aborts with a 403 now there might be situations where you don't want it to do that in these cases you can manually run a conditional you could run gate allows or gate denies so for example if you have a situation where you don't want to abort but instead do something else log something redirect somewhere you could say if gate denies access to edit a job then I will personally handle that response but yeah otherwise if you're fine with LEL doing it then you run the gate authorize method all right that brings us to step three think about it right now this gate definition will only be created if you're on the edit page so if I switch back to the browser this is the show view for a job and yet at this point that edit job gate does not exist because it hasn't been loaded yet for the request all right so that doesn't make any sense let's do this let's take our gate definition and move it to a place where it's available for every single request a good place for that is your app service provider and I will paste it here cool so now I have a place to Define simple bits of authorization that can be referenced anywhere in my application now one quick note before we move on this is important to remember the user object here that Lille passes into your closure will always reference the currently authenticated user but what about situations where you're a guest you're not signed in well in those cases the gate will always fail you will never be authorized it won't even bother hitting this logic it just immediately returns false now in some situations you may not want that you could either fix it by setting user to null or you can make the type optional in either of these cases it will allow you to trigger this logic even if you're not signed in okay in our case we want a signed in user so check this out if I come back to job controller this logic now that confirms your signed in is irrelevant I can remove it entirely very cool so that brings us to step four can I will comment this out for just a moment now your user model that ships with larl right out of the box includes access to a can and canot Method these methods are important they are unique and specifically for authorization so I can call Ken and then reference the name of one of our gates here in this case edit job so this would be an alternative way that we could perform this logic and I'll show you why we're introducing a second option in just a moment but yeah if you want you could say well if the user can edit the job or if they cannot edit the job then failure you're not allowed redirect return a custom response abort do whatever you need to so I'm going to revert this but make a mental note of can and can not okay let's go into jobs slow and yeah right here is the logic for displaying the edit job button now I'm going to wrap it within a new blade directive called can or it's opposite can not and again these are related to authorization so I could say if you can edit the job and I will pass in the the appropriate job only on that condition should we run uh this code or this markup here makes sense it's nice and readable if the current user can edit the job here then display a button all right back to the browser give it a refresh and it disappears but if I go to a job where I am authorized like credit Checker I do see it because again I am authorized to edit the job okay let's move on to step five middleware authorization so again if I return to job controller I love that this is a oneliner that's nice and readable but the only downside is well I'd have to reference it in every single action where it's appropriate right so if you want to update a job you also have to be authorized if you want to destroy a job you have to be authorized to do so and actually on this note one thing to keep in mind is is we are assuming if you can edit the job then you can also delete it uh but that won't always be the case you can imagine a scenario where people on your team can view and edit jobs but the administrator is the only one who can actually delete them from the database in those cases you would create a separate or different gate okay but anyways yeah this works but a bit of repetition so instead if you prefer you can perform the authorization on the right rout level by using middleware I'll show you let's go to our routes file and yeah right here route resource so let's discuss one downside to this oneliner approach to declaring your routes if I wanted to add middleware well we've already learned about o right this ensures that you're authenticated however when we apply it to Route resource it gets applied to every single route uh that this generates so back to the browser if I log out and I try to visit the jobs page nope now it's not going to work because it's trying to redirect me to the login page now a quick note here uh it's failing because larl is looking for a route that has a name of login so it's not using the URL because for me that URL is slash login but for your application it might be slash login user or something like that or slash off so we can fix this by returning to our routes file and giving this particular route a name and now that'll do the trick if I come back and refresh it works so just a little aside if you want to learn more about that research laravel named routes but anyways if I switch back yeah how do we handle situations where yeah you can view all jobs or single job but you need to be signed in for everything else well using a route resource approach you would have to to do something like this you could call the only method and say Well only generate routes for index and show and for those routes you don't need to be signed in but if we do another one we can do the inverse and say for all routes for a jobs resource that are not index and show I want you to apply the off middleware and yeah that would work but I don't really like it to be honest so in situations like this I think it's an improvement to revert to single route declarations and yeah through the magic of screencasting I'm going to do that right now and now it's done okay so consider this yes it's more lines of code but that's not the end all be all we've also improved Clarity in my mind now I visit this file and I instantly know uh about every single URI that it responds to and yes I understand how a route resource works but again this this just improves Clarity that much more okay the next upside is I can apply middleware on a per route basis so for example I could say well in order to create a job you need to be signed in so I could add that to this route alone to edit a job and this is the main one we're working on I could say yep you also have to be signed in however we also want to authorize that you can edit this particular job okay so we can add that as a second middleware and in cases where you have more than one middleware you can reference an array like this off and we're going to use a new one that larl provides can colon we provide the name of the gate edit job and then we have to pass in the relevant job so if I use job here I know that's a little confusing but that's referring to whatever this wild card is and then larl like always is going to use implicit model binding to fetch that job and pass it to your Gates okay so now within a single route we've declared in order to access it first you need to be signed in second you need to have permission to edit the job okay so if I go back to job controller that would then allow me to remove this line entirely let's have a look I'm not signed in at the moment so let's try to edit this job and I don't even see the button if I manually visit that URL it redirects me to the login page let's sign in and if I try again this time I am authorized to edit the job so it works but let's go to one that does not uh work edit and yeah we get a 403 so this is working as well and many many people prefer to perform their authorization on the route level by using middleware now real quick if I switch back to the routes file it's it's fine but it's a little bit verbose so so if you prefer you can return this to a simple off middleware and then we can use a method called can can you edit the job like so now one thing I like about this other than the fact that it improves readability a bit is we have graduated this term once again can so now I know on my route declarations there is a can method on my user model there is a can method and in my blade views there is a can directive and all of those are specifically for authorization okay so we're not going to do all of this together but generally you would sort these like this where each of them Goes On Their Own Line and then at this point you might want to add a bit of breathing room okay so now you can repeat these calls for any other routes where it makes sense so that would be this one and this one but I'm going to leave that to you you can do that as part of your homework we won't do it together but I will include it as part of the source code for this video so you can have a look at that if you get stumped all right that brings us to our final step which is policies now real quick policy is another one of those terms that for whatever reason can be confusing to people yes I don't get it but it's not confusing think of it like this imagine you're 15 years old and you want to visit a nightclub that is 21 and up all right well you drive down he stand in line and when you get to the gate there's a bouncer who holds his hand out and he says sorry buddy it's our policy that you have to be 21 and up to enter that's all it is it is a policy for the nightclub now in the context of larl policies are connected to your eloquent models so let's generate one phb artisan make policy and it'll ask me what kind of policy do you want well let's make one for a job a policy for a job all right what model is this connected to well it's connected to job all right and that's created in a new policies directory let's have a look let's open the sidebar and sure enough we have our first policy okay so Lille includes a bunch of examples here uh can you edit can you delete can you restore can you update just keep in mind these are ideas uh in plenty of situations a single method will do just fine so if I select all of these I could say well the only one I have at the moment is edit can you edit a job this accepts the user and the job just like before so notice this is almost like a version of a gate it's sort of the same thing just a different interface for it so with that in mind if I open up app service provider let's take this logic here I will comment this out and if I switch back I will paste it in here now once again just like your gate definition this is going to return a Boolean so if you want you can add a return type to it all right so check this out now that we've migrated from a simple gate closure to a dedicated policy now we can update our code let's go to the routes file back to our edit route yeah at this point we no longer have a gate or a policy called edit job ours is called edit so notice we referen the method name on the policy and then we it the corresponding model so now larl is smart enough to know there is a link between your job model and your job policy so now we're just saying all right find the policy for a job and then run the edit authorization on that policy and this will work just like it did before reload the page if I try to hit that edit endpoint of course I get unauthorized very cool now further keep in mind if I go back to the job that we did create this one uh I don't see that button and that's because again we have to update our view let's go to jobs slow and yeah once again we no longer have a gate with this name it's simply called edit and I think that reads just a little bit better so now back to the browser give it a refresh and it works just like it did before all right and that's a wrap so yeah you see what I mean there's so much flexibility in the LL when it comes to authorization that I don't know sometimes it can lead to to decision paralysis do I handle authorization in my routes file or in my controller do I use the gate facade or do I create some policies and as always the answer is it just sort of depends on what you want to do here's my recommendation if you're building something relatively simple the gate facade is fine open your app service provider Define a few Gates and you're good to go for anything a little bit larger I would 100% recommend that you stick with policies and by the way that's what I do for lass okay that's it I will see you tomorrow please be [Music] excited all right welcome back today we will finally figure out how to deliver some mail the first step is to generate what larl calls emailable PHP artisan make mail and what should it be named well let's imagine that you're an employer and after you have published a new job to our website we want to send you a confirmation email all right so why don't we say job posted okay so now notice it's in a new app mail directory let's have a look all right open the sidebar and sure enough app mail job posted okay let's have a look I think you're going to like this it's fairly intuitive now first up if you want to send an email you have to effectively fill out the envelope and this is where you would provide the subject of the email uh potentially who it's to who it's from a reply to uh tags that can be associated with the email provider and you can find a whole list of uh available parameters in the Constructor here but yeah most of the time subject maybe reply to maybe from uh are the fields you will reach for all right next we have content provide the content for the view so notice we return a new instance of this content class and we pass the name of a view all right let's do that now let's go into resources View and let's create a new directory for emails or mail whatever you want I will stick with mail now within here I'm going to create a simple blade View job posted. blade. PHP congrats your job is now live on our website and we'll leave it at that for now but yeah later we we could embellish it provide more specifics about the job itself maybe provide a link to the job page all of that is available here okay so let's go back to our mailable and now I can update this to mail. job posted finally if you have any attachments you can provide them here otherwise this looks pretty good to me right now so I'd like to see how this email looks how do I test it well here's a cool thing if we go back to our routes file while we are still playing around I could create a dummy route I'll do it right up here route get I will call it test and yeah what's cool is all I have to do is return a new instance of our mailable class so if I return new job posted there we go that's it it'll work let's have a look in the browser let's go to example. testtest and there we go we see the body of our email cool all right next up let's send it to send a mailable I can use the mail facade illuminate support facades mail I specify who it's to so why don't we just say Jeffrey l.com and then I'm going to send our mailable so new job posted and then I will say return done just to provide some quick feedback but keep in mind we're still in a local environment and we haven't yet set up any kind of email provider or an SMTP server so that means when I send this email it's not actually going to Jeffrey lc.com it's just being logged to a file all right so back to the browser once again we will visit that test endpoint it says done so now it should be logged to a file I'll show you how to check it open your sidebar and head to theore storage directory logs and you'll see by default a ll. log file and sure enough we can see the the makeup and the body of our email notice it was sent here the from address is the default and I'll show you how to configure that in a moment and then of course we have the body of our email it works very cool now check this out if I go into config mail as you can guess shocker this is where we configure our mail settings so for example uh how are we going to deliver this email do we just log it to a file do we use a specific API is there an SMTP server uh L supports many things here next we can configure how we're going to send it so here are our SMTP settings uh if you want to use a dedicated SAS like postmark by the way that's what I use for lass or you could use send mail or um mail Gun there's so many you can set them here next we have the global from address and notice for most of these they reference an environment variable but then as the second argument we have a default if that environment variable has not been set so notice mail from address but defaults to hello example.com and sure enough if I switch back that's the default email because we didn't override it so you have two choices one if we switch back to our mail configuration file yeah you could just overwrite that directly here so I could say from would be info lc.com or something like that or and this is fine but I would say generally I prefer to configure these things from my environment file so it looks like we have a from address and a from name so let's go to the project Roots at the very bottom I will open. EnV and yeah we've covered this a little bit but again for a quick review this is where you define all the settings and keys for your application in the current environment so keep this in mind we're not going to commit this so when you push your project up to production you will create another environment file where many of these settings will be swapped out so for example in a local environment app EnV is set to local but in my production environment of course it'll be set to production so that's something to keep in mind okay so anyways if we scroll down I can see some settings for mail and sure enough laravel has already defined these so I'm going to overwrite this it's now going to be info at l c.com and from name how about Luke all right that's it so let's switch back to the browser and try to deliver this email a second time back to the browser I will simply command R to refresh okay back to our ll. log file and here's the second one now notice that we have updated the global from address okay but now yeah I just want to make sure this is all clear if I go back to our mailable if you prefer or in situations where you want to to override the from address you can set it here so maybe in this situation I want it to be from admin at lar cast.com and then maybe I want the reply two uh to be different you can override these on a per mailable basis okay so one more time refresh switch back go to level. log here's the third email but this time it didn't use the global default uh it used what we provided in the mailable all right next up let's make this a little a bit more in real life now there's a bunch of different Services we can play around with but one that I really like is called mail trap so mail trap. iio you can sign up for free but I already have an account so I will log in all right let's start testing I'm going to create an inbox and I will call it lass let's open the Inbox now once emails start coming in you will see them here but yeah over to the right we can see Integrations and there should be one for larel and yeah all we have to do is provide these uh configuration settings so I will copy that back to the browser open your environment file and the project route and I can paste these in okay so notice yeah let's review the difference by default the mailer is set to log but now we're changing it to SMTP the host is now sandbox. mail. the port is 2525 no change there we've provided a username and password and then everything else can be the same okay let's try to send that email again and this time it won't be logged it will be sent to mail trap let's open a new tab example. testtest ah and yeah notice it took a second or two and that's because once again it takes a bit of time to deliver this email and that's something you should be aware of okay so if I switch back sure enough we have our email and here's the body congrats your job is now live on our website okay so now let's integrate some real data I want to learn information about the actual job that was created as well as a link to view the job so let's do this within my routes file I'm done testing but I want to reuse the section here so I will cut it for later all right next let's go into job controller and after we publish a new job yeah right down here we can deliver that email so I will paste it in and then of course we will clean up and import those okay mail to but now I'm still hardcoding my own name which doesn't make sense we should send this email to the person who created the job but you'll remember a job belongs to an employer and the employer belongs to a user so if I switch back what we could do is say save this to a variable and then update it to job employer user yeah so notice in this case I could say give me their email address but lille's pretty smart if we feed it a user instance lille's smart enough to grab the email address off of that object all right next I should import this as well and then I will pass in the job instance to the Constructor of our mailable public job like so uh now here's a really important thing to understand inside of your mailable class all public properties are instantly available within your view so here I'm injecting it and setting it into a public property but also I could do something like this Fu equals bar so in this scenario inside of my mail. job hosted view I will now have access to a job variable as well as a Fu variable so if you have situations where you don't want it in your view then of course you would need to make it protected okay so what about situations where you do want to inject uh a job but you don't want to pass the full job instance to your view well again in these situations right down here and as the second parameter I can set with equal to an array of values to pass through so yeah this would be an alternative way to do it uh if I want to send only the title of the job I could say this job title and then I would just make sure right up here that uh when I inject job I make it something that is not public but yeah in our case I'm fine with uh passing job to the view sorry we'll get rid of this entirely and now let's update the view job posted why don't we wrap all of this within a paragraph well will'll have a link here view your job listing and then I will set the href to jobsjob ID but keep in mind when the user receives this email they're not on your website so you need to provide the full URL we actually want example. test/ jobsjob ID so in these situations you can update it to URL to jobs SL job ID yeah if we command click here that will generate a URL for the application and you'll see what shape that takes shortly finally maybe at the top uh it's not going to look super pretty but maybe within an H2 we will have the title of your job all right and I think that's enough for an example let's send the email again all right back to our project I will need to log in all right John will create a new job laracast video producer pays 9 ,000 per year save it that will persist it in the database notice it took a second or so but I can see it here and now if we switch back to mail trap sure enough we have a confirmation email but yeah sure enough we have the title of the job congrats your job is now live view it and if I click on it notice it takes me to that full URL to our project and by the way what's useful about that is URL will work for your local environment as well as your production environment all right so that's a wrap for our male lesson at least mostly now you'll remember I kept bringing up the fact that it does take a bit of time to deliver an email and in a production environment that's even longer so yeah if you think about it it's just not practical to make the user wait 2 3 maybe 4 seconds for an email to send I'm waiting when on top of that they may not even know you're delivering them an email they're just publishing a job they don't know that as part of that request you're also preparing and firing off an email so yeah we don't want to do this so we can improve performance by instead throwing the email onto what's known as a Q and if you don't know what a q is then of course you're in luck because that is the topic of tomorrow's lesson so I'll see you then [Music] all right folks we are officially moving on to day 25 So within job controller if I scroll down to my store action in the last episode we did learn how to send an email which is great but one problem is well at the moment it's all happening synchronously or in other words we are making the user wait for however long it takes to deliver this email so if it takes maybe 2 seconds to deliver that email then the user has to wait 2 seconds for a response and I get it 2 seconds isn't a very long time to wait but on the other hand as it turns out it's an extremely long time to wait so yep this just won't do instead it would be nice if we could take that job and in this case the job is delivering an email to you and we're just going to throw it into the background all right we'll get to that in just a minute but for now I want to immediately respond to the user all right let's figure out how to do that all right so I'm going to close this out and our first step is once again our configuration directory and you can see we have a config file for our cues now as it turns out there are a variety of services and backends to assist with your cues and we can see a list of supported connections here so sync that's synchronous that means run the job as part of the current request sort of like what we've been doing already uh but this can be useful for testing or local development next you can run your cues using the database driver and believe it or not I think this is a good way to go for a long time maybe longer than you think but otherwise if you need something a little more robust you could reach for beanock sqs or redus Okay so let's see right up here the default Q connection is in fact the database driver but notice it's looking for a q connection environment uh variable so if once again you go into environment let's scroll down to q and yeah you could rewrite this to whatever you want to use so if you want to support reddis or sqs you can swap it out here for now though I'm going to stick with database all right let's switch back to config now if we scroll down here are the various uh connection settings for the driver we choose in this case database and you'll learn more about some of these options in the future but for now notice the table section here so of of course if you're going to use a database driver then you need some place to house or contain uh all of your jobs while they're being processed and right now that table is called jobs and a migration for that table comes with the lfl out of the box we've already seen it in table plus all right let's keep going down and uh yeah there's some sections here for Q batching how to handle failed jobs and once again for a database driver it's going to look for a table called failed jobs and again we already have access to that so if I switch back to table plus here is the cued jobs table and then we also have a failed jobs table that comes with larl out of the box as a migration you can review it here let's go into database migrations and it should be this one here create jobs table yep you get this out of the box okay so all of that to say if I return to job controller when it comes to mail it's really easy all I have to do is change this send method to Q so now I'm saying no don't deliver this email as part of the current request instead I want you to throw it onto a queue okay so I'm going to explain that more in just a second but why don't we try this out to the browser I'm signed in as John Doe let's create a brand new job how about lass instructor and this one pays how about 70,000 USD all right let's submit that now we've created that record in the database we can see it here but what about the email the confirmation email well let's switch over to mail trap and my inbox is empty let's do a sanity check refresh do it three times for good measure nope no email hm so what is the problem here all right I'm going to try to explain this in a simple and easy to understand way but in order to do that I got to tell you a story but don't worry I'm not 80 it's not going to take 20 minutes uh it'll only take a moment or so okay so a really long time ago when I was in high school I worked at a copy and printer place called Kinka uh it was eventually bought by FedEx and today it's known as FedEx office but yeah way back then it was known as Kinkos okay so my job was Cas here so a customer would come in and they'd say hey I need 300 copies of this flyer and I would be responsible for that however when that job and that's kind of a key word there the job is making 300 copies of of the flyer when that job would come in yes I could have walked around to the copy machine and performed that job for them but think about it the customer would have had to wait for me to complete that job I go over to the machine maybe somebody's using it before me I wait for them I then perform the copies and then I return to the customer and I say all right here you go a second possibility though is I say okay 300 copies and I hand it to a person who only job is to make copies I hand it to to Stan Stan can you take care of this for me and immediately after I do that I turned back to the customer and I complete their order all right so you know what we did there that was a real life queue a job came on and I threw it to a queue and in this case that Q was the table right behind me where Stan another worker at Kinkos can be exclusively responsible for knocking out those jobs oh and by the way that term worker it's another key word all right so you see what I mean you already know what a que is you already know what a job is you already know what a worker is because you see it in your everyday life so the problem is we've thrown a new job onto this queue hey I need somebody to deliver this email for me but if I turn around there's nobody working in the back there are no workers at the moment so let's fix that open your terminal and run PHP Artisan Q work aha notice processing jobs from the default queue all right and sure enough we had a job to deliver an email all right let's switch back to the browser come back to mail trap and there we go open our email and everything works just like before pretty cool huh so yeah if you intend to use cu's then you also need to have one or more workers to work on the que and that's exactly what this Q work command does all right so that means yeah uh when you push your project up to produ you will need to run this command behind the scenes and don't worry there are dedicated tools and services to help with this for example there's one tool called supervisor that will ensure that no matter what this Q work command never Falls over it's always running behind the scenes all right so let's do this let's switch over to my routes file and once again I'm going to build up a test route just so we can play around with a couple things so when we're done I will return done and I want to play around with dispatching a job because of course in real life you will be doing much more than delivering an email there will likely be a variety of processes and actions you're performing that take a bit of time especially these days when there's so much interaction with AI so first step is the dispatch helper function this is really cool we call this AED closure so why don't we just say for now log to a file hello from the que all right so as we learned in a previous episode log will be added here storage logs l. log and let's clear this out all right so let's give this a run but before I switch to the browser I'm going to close out this qw command just for illustrative purposes I can close it out with contrl C all right so back to our demo project I'm going to go to example. testtest we get return done so now we have dispatched to job but yeah once again if I switch to my editor yeah we don't see anything just like before so I'm drilling this into you that's why I'm doing it two times now think about it we dispatched a job the job was thrown onto a queue and if it helps just think of a queue as a stack of papers and each paper represents some kind of job that needs to be performed the only problem is there's no worker to handle those jobs so nothing happens all right let's get to work think about it you're you're the nasty boss who says get to work get to work and they start working all right so they run this cued closure and if I switch back now we see the log all right so this is really helpful if I come back to my routch file sometimes you want to trigger a bit of logic that happens outside of the current request but it's fairly basic and you want to perform it in line you don't want to complicate things all right so in situations like that the dispatch helper function is a great way to go and you can even do cool things like I can delay this so I could say delay it for 5 seconds all right let's give that a shot I'm going to close this out I already have my Q work command running so I don't have to restart it and if I switch back to the browser let's give it a refresh yeah if I come back notice one two I'm switching away to make it refresh three 4 five there it goes so we dispatched a job that was delayed by 5 Seconds and this can be really helpful uh for example if you want to send a welcome email 15 minutes after the user signs up that would be one way to hand that all right but anyways let's head back to our routes file and discuss dedicated job classes now I'll switch back to the terminal and hit contrl C uh one thing I could imagine doing is What if after an employer publishes a new job we take care of translating it to a dozen different languages and maybe we want to use artificial intelligence to to handle that task well we can definitely do that but once again it takes a bit of time so let's instead throw that job onto a queue I'm going to run make job H what should the job be named well how about translate job okay so now it'll be placed within a new app jobs directory let's have a look let's go into app and sure enough you have a new jobs folder and there we go all right so we see a bunch of traits here uh mostly you can ignore those but of course each one adds just a little bit of behavior to interact with the queue for example or or to serialize your eloquent models when they are um added to the queue and retrieved from the que but anyways for now all you need to know is this handle method is where your job logic will be triggered so for example if I just wanted to once again say logger hello from translate job I could do that and you know what this is a great way to learn so let's give it a shot I'm going to go back to my rout file and this time I'm not going to use a cued closure I will dispatch a dedicated job I'll do that by referencing the name of the class translate job and you'll see that I have a dispatch method so let's run that now we'll give it a refresh and then of course from the terminal I will start my worker get to work and now if I switch to my log file sure enough we do see hello from translate job all right super cool all right so back in my routes file yeah it doesn't really make sense does it to dispatch a job and by the way I will clean that up to dispatch a job but then provide no indication as to which job we are referring to and yeah we're getting a little Inception here didn't get Inception we have two different concepts that have the same name we have a job listing for our application and then we also have a cued job so uh granted a little less than ideal for a tutorial but you get it okay so anyways we're going to fix this by tracking down a job listing from the database and then I will pass that into the dispatch method and let's clean that up okay so now our job listing will be passed to our job class yeah even as I say this it's confusing but um yeah that's just how it turned out all right so I will inject this public job job but as I do this we can see my editor is squawking and again that's because we're colliding a little bit with our cuu job interface so as it turns out if I go up a level it looks like there already is a job property here that refers to the CU job rather than the job listing so why don't we just rename this to job listing here all right so now yeah at this point you would reach for whatever AI service you have maybe if you have an AI class you could call a method like translate and then you would reference your job listing uh we only have a title here but yeah in real life you'd have something like a description and then you'd provide a list of languages that you want to translate that to so for example maybe if we're just trans ating it to Spanish this could be our API but yeah the entire point is this is potentially a long running process that should not take place as part of the current request so instead we locate it within a job and then we dispatch that job onto the queue for now we will simulate that by saying log translating this job listing title to Spanish all right and let's give it a run give it a refresh refesh and now return to level. log and oh actually I forgot to mention this this is a really good uh error that we can discuss so notice it's still displaying the old value hello from translate job instead of our new version uh which you see here all right so what's the problem well keep in mind whenever you run this Q work command it loads everything into memory so since we loaded it into memory we have changed the logic for our job and it's not yet reflected okay so this means whenever you make a significant change you should restart your Q worker and yeah once you push to production you will set that up as part of your your build or your deploy script make sure you restart your worker so run it again and this time if we give it another try back to my editor open l. log and sure enough we can see all right we are translating the lawn service manager job to Spanish it works all right so that has been your introduction to Q's episode so yeah I hope now terms like q and job and worker aren't quite so scary anymore I don't know I I find that in the early stages we we are all Masters at terrifying ourselves when it comes to terminology but yeah if you can just find a real World Cory correlation Cory what's the right word there correlation I don't know if you can find a real world comparison uh it instantly makes sense don't you think all right so let's be done with that in the next episode I want to introduce you to vit I'll see you [Music] then all right let's move on to the front end so the topics of the day are asset bundling and vit okay so asset bundling refers to taking all of the Assets in your application whether they be images or stylesheets or JavaScript files and it will bundle them up in such a way that they are now ready and more importantly optimized for production okay so as it turns out vit at the time of this recording is easily one of the most popular bundlers on the market and of course Lille has support out of the box so I'll give you a crash course within your project head down to your package.json file and yeah very similar to your composer. Json file this is where you can declare dependencies for your front-end tooling and you can see out of the box LL suggests axios vit and the larl vet plugin all right let's go ahead and install those oh and real quick keep in mind you will need to have both node.js and npm installed so if those are new things to you don't worry just visit nodejs.org and and run through the installation steps it shouldn't take long to see if you have these installed of course run node --v as well as npm DV all right let's use npm to install our npm dependencies all right and it looks like it added 23 packages we're all set to go okay so our next stop is V.C config.js so we're pulling in that LL V plugin and we are defining our input and it looks like we have one CSS file and one Javascript file and you'll see that they are located in your Resources directory all right let's have a look at CSS since that's a little bit easier why don't we say for the body I want the background color to be red just something very bold and clear okay now I want to reference this file but notice it's actually not within my public directory that would be accessible from the web it's in the Resources directory so we will need to compile this and here's how if I quickly head back to package.json you'll see that we have two scripts here one called Dev and one called build and they're very simple they just defer to V commands Okay so from the terminal I could run npm run Dev all right and now it's running but real quick notice that the app URL is set to Local Host now it's pulling this from your environment file so here's what I'll do I will hit contrl C to exit out and if I switch back let's go into our environment file and yeah right up here I'm going to update this to our local app URL which is is example. test in this case okay so now if I run it again you'll see the app URL is correct so now if I switch over to the browser yeah I don't see any red here do I well of course not we defined it in that stylesheet but we haven't yet imported it within our blade files so that's the next step so back in our editor let's go up into our views directory and of course we could place this within our layout component I'll do right here at the top now Lille has a v directive that makes this really easy all I have to do is reference that root app.css file and it'll take care of the rest all right and now we get red perfect okay so next I want to show you hot reloading this is just a fun term that means whenever you make a change to uh a script or even your stylesheet the browser will automatically reflect that without needing to manually refresh the page here let's switch layouts to make it a bit more clear background orange save it instantly refreshes background black background green pretty cool isn't it okay so this will work for your style sheets but it also works for your JavaScript back to V.C config we specified an entry point as resources JS app.js so you will find that here all right so this is what larl suggest out of the box maybe import a bootstrap file that um does anything you need to bootstrap your your front end dependencies in this case because making HX requests is so common larl will assume maybe you probably want to pull in axio and provide some initial configuration all right so let's do you know some some Hello World stuff here let's alert hello from the JS save the file all right and now of course we need to reference it right so we can do that once again from our layout file and we can reuse the same beat directive resources Js app.js all right so immediately when I Sav this the browser should update so if I switch back all right and there we go so now we are bundling up both our CSS and our JavaScript files all right so yeah let's talk about Tailwind now up until this point we have been referencing it through the CDN and that's great for demos but yeah for real life uh production deployment you don't want to do that so now that we understand vit or at least a little bit of vit why don't we solve that problem in your browser visit tailwind css.com and let's go into the docs and down to installation and let's choose a framework guide LEL all right so we already have a LEL project next up we need to install Tailwind post CSS and auto prefixer through npm open a new tab and run it all right there we go so when we ran tail one CSS andit that creates yet another configuration file within your project route let's have a look right down here and there we go brand new file all right let's switch back to the docs all right step three configure your template paths yeah so we need to teach Tailwind about our project where can we expect to find uh any Tailwind utility classes well maybe in a blade file maybe in a Javascript file maybe in a view file if you use react then you would update that as well all right so let's switch back and I will paste that in here all right easy enough next we want to add the Tailwind directive to our CSS all right let's do it app.css and I'll swap out that background of green with the Tailwind directives all right finally start our build process and begin using Tailwind in your projects yeah it's as easy as that so in the terminal I will contrl C and start it up again and now if I visit our layout file once again yeah I can remove this script entirely because now tail one will be available through the file here let's head back to our project refresh ignore the alert and uh we get exactly what we had before great so now we can configure Tailwind however you need to and yeah this isn't a Tailwind specific course but of course you can visit their documentation to learn more so maybe I have a custom color for L cast or or something like that I could say extend and add to Colors one called laracast and I will make that equal to this uh blue shade that you see right right here okay so now let's come back to our JavaScript real quick and comment this out so we don't keep seeing an alert every time I refreshes and if we visit anything we want how about Job SL index yeah maybe right here we will take the job title and I will use my new class which is text lass as you see right here all right let's switch back go to jobs and there we go and actually in this case it's a very similar shade to the text blue 500 just slightly different all right so what else uh well something you might want to consider is at the moment in your V.C config file we are providing two inputs um and that works but if you're building an Spa a single page application what you might want to do instead is omit this and instead uh import your CSS directly from your bootstrap file so if I were to come back to javascript. app.js I could then import our stylesheet so let's go up level into the CSS folder and grab app. CSS okay so if you want to take that approach of course return to layout and let's make sure that we uh remove that CSS file okay so now we are exclusively importing the Javascript file that will then import the CSS and yeah this is a very common approach when building a single page application so now if I switch back and refresh yeah we still get the same thing okay so keep in mind one is not necessarily better than the other it just sort of depends on what kind of application you're building if you're working on a fairly traditional server s side app with blade files then I probably would keep those two entry points but yeah if it's instead a full spa keep it all in the Javascript file okay so now to wrap up if I return to our package.json file there is a second script called build this is the script you will run to prepare all of your files and bundle them up for production so if I hit contrl C from the terminal I can say npm run build and yeah notice it doesn't set up a watcher here it's a one-time thing and it builds them for production so notice we have a compiled CSS file and JavaScript file that had been zipped up and and compressed as much as you possibly can now what's cool about this is we don't have to change anything that V directive is smart enough to detect whether we are currently in a local hot reloading environment or if we're in production so now if I switch back and refresh yeah nothing changes except for the fact that now our project is primed and ready for production all right good work and hopefully most of that made sense yeah just keep in mind asset bundling as a whole is a fairly complicated topic and here we've only grazed the surface but you're now on the path right and when you need to learn more you can do so but yeah you know what's funny I think you'll be surprised how what we covered in this video it's going to take you a long way it it'll cover 85% of what you need to know it's pretty surprising and that's a testament to the lirell team and how useful that V plugin ends up being okay so moving on we got to stop somewhere right we're now at episode 26 we've covered a great deal of the framework not nearly all of it but a great deal for a beginning Series so next up is our final project and I'll warn you we're going to go a little bit quicker than usual I'm not going to stop at every single line to explain it you're expected to understand the basic concepts but I hope you'll enjoy it and you'll get to see how I would generally go about starting a brand new project so I'll see you then please be excited [Music] all right everybody the moment is now the time is come we have to start working on our final project oh and by the way you can tell it's the final project because I have a brand new spiffy wallpaper to Mark the occasion okay so before we get started a couple ground rules first up there's no way around this we're going to go much faster than we did in previous videos but hopefully if I did my job properly it's not going to feel that fast because you've already already reviewed each of these Concepts but yeah we can't get around it if I stopped after each line to explain it we'd be here for four or 5 hours and we got to get this done okay ground rule number two with that in mind here's your job if you're watching a video and you didn't understand a particular uh piece or or why I did this or that your job and for the benefit of everyone else your job is to leave a comment Mark the timestamp and then ask your question so it might be like uh hey Jeff at 3 minutes and 52 seconds I didn't understand why you put this return type there can you explain more and I'm going to monitor these comments for a long time and I will do my best to answer each of your questions okay so if you're watching a video and you don't know what's going on well maybe head down to the comments and somebody has already asked your question all right that's it let's get going now we will start like we always do larel new and the name of our fictional jobs platform is called pixel positions so that will be the name all right no starter kit in this case even though Breeze would give us a head start uh it removes some of the learning opportunities so we will start from scratch I will use pest um yes I will initialize git I'm going to use SQ light and let's CD in there all right let's review this in the browser and we're all set all right let's head over to Zeppelin now here's the layout that Adrian whipped up for us it looks pretty good good and should be fairly easy to create the markup for now of course you don't have access to this but I think the only thing we need here is the logo itself so I will make that available within the GitHub repository and I will also link to it within the comments for this video all right I will call it logo and I will save an SVG now you'll see I'm already within my project so I have a couple choices I could create an images directory within my public folder or if I want V to automatically version and hash any images we have have and that would help with cache busting by the way uh in that case I could put it within a Resources directory so let's do that let's open this create a new folder called images and then I will save it here cool so let's switch over to our editor all right so the first thing I'm going to do is set up my general layout So within the views directory I will add a directory called components and this one will be called layout or app layout whatever you want let's do layout all right let's add some initial boiler plate we'll call it pixel positions and then let's see if I switch back to Zeppelin yeah it looks like I have a navigation area at the top and then our main section below it all right so we'll have our wrapper a nav section at the top and then our main section below it and for now I will put our slot there okay so now within the nav it looks like we have three sections right an area for the logo an area for the links and then a section to post a job so let's create three divs first up we'll have our logo then our links and then finally post a job okay so first up if I want to reference this logo.svg file within my resources folder rather than public we have to load it and access it a bit differently here's how open up our image tag but first this should be clickable right so let's add it within an anchor tag and then as the source I will open up PHP and I'm going to reference the V facade now this is the full path but actually it's made available globally as an alias so I can just do this and I'm going to reference an asset okay so now all I have to do is reference the full path to the image in this case resources images logo.svg and that's it okay so with that in mind why don't we go ahead and run npm run def npm run def but right now we're getting V command not found because I haven't yet installed my npm dependencies let's do that now all right one more time there we go it's up and running next I'm going to at the very top reference our resources JS app.js file and now well let's access this in the browser so here's what I'll do I'll go to my routes file and let's open welcome and delete all of this and replace it with our new layout all right let's switch to the browser give it a refresh so sure enough it doesn't look great because of the white background but this is our logo and if we inspect it sure enough we can see it being referenced properly all right but here's one thing to be aware of if I switch to the terminal and I instead build this for production have a look I come back reload and unable to locate file and vit manifest okay here's how we fixed that go into your resources JS app.js file and right here I'm basically going to tell vit about our images directory so I can say import. meet. glob so I'm going to provide a regular expression here so I'm going to say my images are within the go up a level go into the images folder and then grab everything within there and I want that uh made available and ready for versioning okay so if I come back and run this again this time if I come back to the browser and refresh it works okay so that is something to be aware of only on the condition that you need versioning and uh cach busting so take a look at this if I inspect the element notice that it appends a uh unique URL to the logo and again this is entirely for the purposes of cash busting so that your assets can live as long or little as they need to okay just an aside let's head back to our layout for now it's going to link back to the homepage and then let's work on this switch to Zeppelin and I see links for jobs careers salaries and companies so first one is job JS next we have careers next one is salaries and last up is companies and we'll probably change this a little bit later okay finally we need a link to post a job so we'll have post a job and we'll leave it at that all right back to the browser give it a refresh all right but now of course I want to line these up properly I could use Grid or I could use flex box so with that in mind I next want to pull in Tailwind Tailwind css.com docs framework guide laravel and once again we will follow the steps I will copy this run it all right next we will update twin. config and that file should now be available it is paste that in and yeah we're just providing uh paths to files that we want tailin to inspect for uh utility classes this way the compiled CSS file is as small as it can be so we're not using view here I can remove that entirely cool reformat and that looks good next update our entry point and then run npm runev cool so resources app.css paste that in and then finally if I go to my layout file we can reference that as well or like you learned we could alternatively import our CSS uh directly from our app.js file but for now we'll keep them separate cool npm run Dev and now Tailwind is available to us okay so on the nav I'm going to set a display of flex and then I will say justify between and that should push this one all the way to the right this one to the left and this in the middle let's switch back to our project give it a refresh and there we go cool next why don't we align the items to the center items Center all right cool but next everything is right up against the edge of the window so right up here why don't we set some padding on the left and right of 10 and why don't we switch to a two up playout and yeah that'll save us some time all right next on the nap itself yeah if I said a background of red or something let's give it a little padding on the top and bottom a bit of breathing room and next on the body itself I want it to be a black color so I could set class of BG black like so and yeah now we can at least see the logo a bit better we'll also set the text to whites but if I switch over to Zeppelin I believe it's not an act black let's select this and it looks like this is our black color so here's what I'll do I'm going to open up Tailwind Doc config.js and extend our colors and I'll say black should actually be this shade right here now tail one should update behind the scenes so check this out if I were instead to set it to red or something like that you can see now anywhere that I reference text black or background black it will now use this value rather than the default but yeah let's bring it back all right anyways back to layouts and on the nav there should be a border so I'll set border B but that white is a little too strong so I'll show you a little tip you can set a border white but then lower the opacity and this is useful if you don't have a specific color but you want it to be a percentage of a color I could do something like this and that means white but set the opacity uh or the alpha to 10% and that's what I want in this case all right cool next on the nav links themselves why don't we add a bit of breathing room and between them so I can use space X6 to add a bit of space between each of the items next I know I want these links to be bold and then for the main content itself I want to push it down from the nav area so let's add a class of margin top of about 10 and that'll push it down all right next let's switch to Zeppelin and see how long this should be it looks like we have a maximum withd of 986 about a thousand so here's what I'll do uh I'll say maximum width and if I want to use custom value I can type it in here so why don't we say the maximum width you can be is 986 pixels all right cool so I have a little more work to do here for the layout but I think we can switch over to our welcome View and get started on the main section for the homepage now if I switch to Zeppelin have a look here I can see a few blade components we'll need to create for example what you see right here that is a repeating theme where you have a little square it could be a certain color and then a heading so I see it here I see it right up here I see it for all of the headings actually that's something that should probably be a component uh next The Styling for these buttons all seem to be uh the same and then we have styling for a job card and then an alternate styling for like an expanded job card okay so I'm filing these away in my head all right so let's do this I will begin with one section at a time top jobs okay so with that in mind let's wrap it within a section we'll have some kind of heading that I'll say top jobs and then within a div it looks like we're going to have three job cards okay so we'd have something like this ultimately but for now I'm just going to work on the first one so within a card it looks like we'll have three individual sections one for the employer name then a section for the title I'll hard code this for now video producer and the salary fulltime from $60,000 finally the bottom we will have a list of tags something like this and let's create three of those finally I will have an image for the employer's logo but with that in mind I should probably wrap these tags within a div so that I can push them to the left and the logo to the right like you see in the image now temporarily for the image I'm going to use a placeholder service I think there's one called placehold doit and then I provide the dimensions and it should be 42x 42 all right and that should be enough to get us going so let's switch to the two up playout okay so let's start by giving this some padding all around how about P4 and then a background color so if I make it crystal clear you can see what we have here okay but instead I'm going to make it more subtle how about a background color of white at around 5% yeah just very subtle let's make it rounded all right and then I'm going to set a display of flex oh but that doesn't change anything oh you know what I think I have an extra div by accident all right reformat there we go okay so now I want to adjust the direction let's do Flex call so it's top to bottom and then I want to Center almost everything excluding just a couple parts for example the employer should be uh self start so that should be on the far left and while we're here let's make the text just a little bit smaller next for this section let's give it a little bit of padding so py maybe eight uh I want it to be bold and then down here yeah we're going to do the same thing let's set a class of flex and justify between and maybe align the items to the center very good and then just to be safe I'm going to set Marchin top to Auto now I don't think it'll make a difference in this case but uh in situations where maybe there's more margin to be had it'll it'll Force this section to be at the very bottom of the card okay next on the section heading why don't we give it a margin bottom of six something like that just to push it down and then let's do this for our tags so I'll start with just one I'll add a class of background white again I'm just using uh Alpha here to make it a little quicker for us about 10% let's then add some padding on the left and right and the top and bottom let's make it rounded and I want the text to be fairly small so let's use extra small there all right but now what about when we hover over it well we could say well when you hover set the background to 25% maybe that looks good I think and by the way a little tip uh I know we don't have much breathing room here but if you want to transition those colors a bit more cleanly you could say transition colors and then set a duration of about 300 milliseconds so now any colors will have more of a smooth transition and I don't know if you can see that in the video but it's definitely smoother okay so now think about it I could do uh three of those and that looks a little better all right what else how about the employer logo uh that should be rounded and that's a little hard to see right now but later that'll be a full image okay so this is enough to extract a component so let's do this let's open our sidebar and within our views directory let's add a brand new component and I'm going to call this job card all right so now I can select all of this and move it over cool so let's swap it out X job card and let's create three of them okay back to the browser and yeah now we're repeating that but notice there's no spacing in between them let's fix that we'll wrap all of these within a div and then this time I will use a grid we'll say for large devices we want grid calls 3 next I want a nice little Gap in between them so we'll set uh it's basically padding in between each of the job cards yeah it's starting to take shape but now notice how everything is right up against the left Edge I think we can fix that by returning to our layout and on the main section let's make sure the margins are set to Auto and yeah now that pushes it to the center now I know that ultimately we will pass in a specific job uh data but for now we're going to leave those static okay next why don't we update this into a section heading because I know we will reuse it so let's create one and I called it section heading that's good enough for me paste it in and then this will be our slot but now I'm not sure if I can always assume the margin there so maybe that will be applied elsewhere all right so with that in mind I can do margin top six and then remove this entirely okay X section heading and this will be uh what did we call it feature jobs back to the browser and that works okay now I can add our little square and that should be fairly easy uh why don't we do a span here and I'll give it a width of Two and a height two so it's a perfect uh Square maybe a background color of white and then I don't want it to be an inline element let's do inline block and let's see how that looks and yeah that's okay but maybe we should change this up maybe this will be wrapped within its own div and then we'll have a span followed by the H3 yeah if I take that approach then I could do something like inline Flex item Center and I can even add a little bit of a space in between the square and the heading itself let's have a look yeah and I think that looks pretty good actually the only tweak might be the heading should be bold and a little bit larger than the regular text and there we go we have our section headings cool so now if we switch back to welcome yeah we have one section for our feature jobs uh we could have a another section for uh what would this be our tags and then another section for our uh recent jobs switch back and there we go now clearly we need a little bit of space in between each of these sections so in situations like this what you can do is wrap all of it within uh a root and then I could apply something like a space y of 10 and that way there's an equal amount of space in between each of the children as you see here all right next up we have our tags we're going to do this very quick quickly so we've already created a tag so this too should be extracted into its own component tag. blade. PHP paste that in this will be our slot okay so now I can swap these out with X tag now again keep in mind we want these to be configurable so ultimately I would probably pass in a tag but we haven't gotten to that point yet for now I'm keeping this all static all right so now back to welcome yeah right here I could have one of these and then let's say y y9 p let's have around 10 of them all right switch back and yeah that looks okay now once again they need a bit of room to breathe so we'll say once again mt6 and I'd like to add a little space in between each tag so how about space X1 and that's what we get and then yeah these tags probably need to be a bit larger so it sounds like we should have two different sizes of tags maybe extra small and then a base size oh and by the way I put this in the wrong section so let's fix that you were waiting for me to fix that like so all right so I think we made pretty good progress here but we're going a little high on time so in the next episode we will work on the expanded job card and by the way if you want why don't you get a head start and see how your version compares to mine okay so we're going to wrap up there again I know we're going fast but that's the way it's done uh in the next episode we will finish up our layout so that we can then begin working on the architecture itself so I'm going to take a break and I will see you in the next episode [Music] all right welcome back there's no time to waste so I'm going to jump right in if I switch back to Zeppelin yeah we currently have one job card but right down here we have a second version and while we could figure out a way to consolidate both of these Styles within a single blade component often it's just easier to create two separate components and that's what I'm going to do so let's go to job card and if I open up the sidebar here I will duplicate and we'll call this one Whatever you want job card wide how about that all right so let's see we should work left or right so first up on the left is the image itself the employer's logo next we'll have a div that wraps the employer's name and then the title and the salary requirements so I should be able to get rid of this and why don't we change this to some kind of anchor tag and actually we're going to talk more about this at the end of the video uh but basically how can we have multiple anchor tags within a card while still allowing the card itself to be clickable it's a little bit tricky but I'll show you how to do it all right so we have the employer name the job title the salary and then finally on the far right let's just display the tags for now and we can come back later if we have a little more time but I'm trying to be as quick as we can here all right that's the general shape all right so of course there's more to do but let's see this in the browser so here's our main welcome page where we have the tags and then the recent jobs I'm going to grab this div here and we'll have a new one this time for a job card wide all right and why don't we do three but this time we'll have space between them vertically so maybe I don't know space Y3 all right let's have a look so we come back to the browser and whoa we have a gigantic image and this is probably related to uh flexbox it's always flexbox so let's fix it I can command click here and yeah one thing you learn if you've used flexbox for a long time is you want to be careful about things like images or buttons that are direct children of a flex container uh which is what you see here you always end up with weird uh with weird issues so for example if I just wrap this with an a div and switch back yeah we've solved that problem there okay but yeah it still doesn't look great because we are using Flex call this time we want a flex of row and I don't want the text to be centered there we go all right next up let's tweak some of the spacing so I'll start by saying in between each of the flex items let's add a gap of about six and then with that in mind if I switch back to the welcome view I'm going to increase the space uh the vertical space in between each of the wide cards up to six a little more breathing room all right come back and yeah that looks a little better all right next I want this section itself to flex expand as much as it can and that will push the tags to the far right so back to our wide card and we'll say right here Flex One Flex to fill the available space or Shrink uh if it needs to all right good next the employer logo is a little bit wider than 42 pixels I think it's 90 uh let's double check back to Zeppelin and let's see I can click right here and sure enough 90 by 90 save it switch back and yeah that looks better but that blue is killing me so you know what I'm going to do I'd rather reference an actual image or at least a dummy image so I will use a different placeholder surface and let's see if I can remember it it's pixum do photos and I believe once again I can just pass the dimensions here there we go now we have a random image but notice it is repeated for each item there uh ideally I want them to be unique for each job so there is a way to do that I believe we pass seed and then some kind of identifier so then um the the image pick some photos returns will always be unique to that ID so if I come back and refresh well they're all using the same identifier so we see the same photo there so all we have to do is make it unique um once we have actual jobs in the database we will reference the ID of the job for now I'm just going to say give me a random uh number between one and you know a massive number now if we come back yeah we have some Unique Images there and that's fine for a demo all right back to Zeppelin next we have this text now I happen to know the hash is C2 C2 C2 but let's see if Tailwind has something close let's go with gray 600 and yeah it doesn't have to be perfect maybe 700 that's too much how about 400 you know what close enough for me I'm not going to squawk okay so while I'm here notice the font is different from what we see on Zeppelin so as it turns out this pixel positions demo is using the same font that we reference on laracast and that comes directly from fonts. google.com so here's what I'll do I'm going to visit our layout file and at the very top I will save us some time and just paste it in and yeah all of this is again coming from fonts. google.com for this font here hanen grotesque is that how you pronounce it uh and we're getting a handful of Weights if we need them cool so now I want to reference this within Tailwind so here's what I'll do I'll open our Tailwind doc configuration file and I'm going to extend the font family object to include a new one we'll call it hanen grotesque and then I will reference uh a font tree so ideally I want that font we pulled in with a fallback to sans's serif if it didn't load for some reason okay so now yeah once again Tailwind will reload and I can now reference this as a utility class I'll show you let's go into our layout file and let's set it sitewide on the body so I'll say font henen grotesque and let's see it in the browser yeah there we go looking good all right so let's continue with our wide job card job card wide and yeah of course the title itself should be bold it should be large and then for the paragraph yeah this is going to be very similar I also want it to be small and gray okay so if we switch back yeah that's looking fairly good but notice how everything is grouped at the top ideally I want to push the salary to the bottom of this section down here like you see in the image so maybe we should do this maybe once again Flex to the rescue let's set a display of flex but I want it um in in the direction of a column and then for this last item I will set margin Top Auto uh to push it down as much as it can go and now yeah that looks better all right next the title could probably be a little larger and I want to push it down from the salary so how about push it down Marchin top of three maybe and then let's change it to text extra large yeah that's looking reasonable okay now let's move on to some other miscellaneous things uh at the moment we have two different versions of our employer logo but of course we want to consolidate them so this once again sounds like a good use case for a dedicated component so I'm going to copy this and create a brand new one we'll call it employer logo. blade. PHP and I'll paste that in and again don't forget ultimately we will update these components to accept uh for example the the employer object and then we will reference it but for now once again everything is static all right so let's update this with our new component uh employer logo and then I will switch to our standard job card and I can update it here as well employer logo but now we do have one issue you'll remember if I switch back the width in this case should be 42 but within our component it's set to 100 by 100 so now we have messed up our layout as you see there okay so why don't we do this let's accept a prop uh an initial prop for the width and that will default to 90 pixels but if you want to override it you can okay so then I can swap this out with the width and I believe if we just provide a width it will be treated as a square so we wouldn't have to do a height uh or something like that duplicate it we should be able to provide just one and it'll work okay so now back to job card I could say width is uh what was it 42 give that a shot switch back and now we have two different sizes for our job cards all right next up I'd like to do a little more work with the tags they don't look that great if I switch back to Zeppelin let's zoom in a little bit and we can see this text is actually very small if I open the sidebar I can see is set to yeah about 10 pixels what do we have currently I'll go to computed and look for font size ah it's set to 12 okay so that's extra small and I don't think tail one goes below that so why don't we create a custom size back to our Tailwind configuration file and let's override font size and we'll have how about if we already have an extra small let's do two extra small and I want this to be 10 pixel I could hardcode this or I could set it in rims so if I do some math let's take 10 pixels divid by the base font size and we get 625 all right let's use it back to job card actually into to tag and yeah let's see if we can update it to text 2 XS come back and yeah now it's just a little bit smaller all right let's keep going I would like this to be bold and maybe we should give it a little more padding on the left and right all right back to Arc and that's looking pretty good okay now I'm thinking our font might be a little bit too heavy so if I compare this to Zeppelin yeah notice that here even for the navigation area the font is set to bold but it's much softer than what we currently have in Arc so let's do this let's go back to our layout file and yeah why don't we remove both 800 and 700 will stick with 400 500 and 600 weights so if I switch back yeah that's much softer than it was before all right next up you'll see that we have some hover Styles if your mouse is over a card it looks like the title goes blue and the border is blue so let's go into job card and we can say uh well by default we have a border but maybe we hide it let's make it transparent but you hover over the card and we make it border blue and again I'm just going to eyeball it maybe be 800 come back and yeah close enough all right but now I want to make the title blue as well so how do we do that well you can't just add hover styling to the H3 because then you would only see the blue if you hover over the H3 and that's not what we're doing here so a way to solve this with Tailwind is to apply a class of group and then on the H3 you can listen for when an element with that class is hovered over so I could say for example if you hover over the group meaning this parent element then I want to set uh the text for this to also text blue 600 and I think that will solve the problem yeah cool so actually real quick while we're here if I switch back to Zeppelin you'll notice that the salary is pushed down a little bit and much much smaller I want to fix that pretty quickly while we're here so for the title let's make it bigger like XL and yeah then for the salary we will make it may be small and then I will push it down uh a little bit so I'll set some March and top to push it down from the title come back yeah better but H the salary is still too bold let's see oh that's because we applied it to the div okay let's apply it only to the title and then the salary itself can be a base level yeah and that's looking a little better okay but next I would also have to apply those hover those border styles to the wide card as well and that's not IDE deal but yeah let's just see what that would look like notice I'm doing a bit of duplication here which is a sign so let's go to job card wide and I'm going to paste those Styles in here and then for the video producer group hover text blue 8 oh 800 you know what I think I used the wrong ones here yeah notice I have 600 and 800 up here we want those to be consistent okay so now if I hover over it that looks good maybe it's too dark maybe it should be 600 but we're not going to get stuck in the weeds here you get the idea now once again if you want to transition these so it's a nice um smooth transition from uh transparent to Blue do this once again set transition colors duration and let's make it really long so you can clearly see it so come back and well the title isn't quite right but notice the border is definitely transitioning end yeah I guess I forgot the title has to receive the same thing transition colors duration and this time let's make it much quicker a third of a second often seems to be uh a good value to go with a third of a second or 300 milliseconds yeah if you like that it's just a little bit smoother okay so once again we'd have to do the same thing for the job card wide this feels kind of gross doesn't it then right down here the exact same thing and now that works as well it's not the end of the world but H it seems like we could have more than one card well we already do but in a real pixel positions application we could have many cards that have this styling they're almost like panels or or you can call them cards if you want I often call them panels um so with that in mind could this be a candidate for a component let's give it a shot create a component called panel and I'm going to use a split view here let's take the wrapper here and then we can have a slot like so all right let's see how that looks if we took that route I could swap it out with our X panel component so now we've effectively uh consolidated all of those Styles so let's see how job card wide looks yep no difference good next I can go to job card and we're going to do the exact same thing however I want to make sure is there any um unique classes here so did we duplicate the classes here I'm just going to paste this in um yeah we actually have a couple differences and yeah that would be the flex information and the Gap okay so that should be excluded all right let's do this I'm going to change this to X panel there we go and then I'll get rid of everything except for the unique parts so it sounds like the unique parts are that within the panel we want to display a flex so get rid of yeah and then if I click through to panel this is unique to job card wide so I don't want to assume it but everything else should be the same all right so job card wide pass these in and then of course we've learned if we want to merge these well we would have to do something like this and I'll show you a little shortcut so up until this point we've been saying attributes merge and then we set the default class like so and that would do the trick however if we just call attributes as a function it's going to merge it so this is sort of a shorthand for attributes merge and yeah that would work also keep in mind if you want you can do things like this where you could open up PHP blocks uh like this and then you could say default classes or keep it even simpler classes now you can reference that variable within your template here so you could do something like this just to make it a little easier to consume right especially on a low resolution like I have those utility classes go off the screen very quickly so this is an option if you want all right so back to Arc and yeah notice now we have the exact same thing as we had before but we have Consolidated those stylings within a panel component pretty cool so now for example if we go back to welcome if we were to add a new section for something totally different I could open up a panel and say um hello there whatever you want and you'll see it will receive those same Styles and yeah it seems like that's a repeating pattern for this site so it makes sense to extract it into its own component let's get rid of it all right so now uh yeah these tags are way too small they're fine for a job card but if I switch back to Zeppelin yeah you can see they're much larger here okay so it sounds like hm we should make this configurable let's go into tag and yeah let's do this let's accept a prop for the size uh and maybe we'll accept like a base or normal how about base uh but also maybe a small size or something like that okay so then we could do something like this open up a PHP block and we could say well if size is base then use these classes but if the size is small then use these other classes okay so let's figure out what our base classes here we'll do the exact same thing at the top I will have our CSS classes but then yeah the the text size and the padding should be unique based on the size so how about if the size is small then I will append to classes and I'm just going to grab these here all right and then what else uh text to EXs so those are the classes that are unique to a small size at least so far clean that up okay now I just have to figure out what the classes should be for uh the base level and I'm just going to eyeball it uh maybe text small and then I will increase the left and right padding to five and yeah maybe that's enough uh by the way notice I am including a space so that when we concatenate they aren't grouped with the uh the previous class there okay so now I'm going to reference them and yeah that would be one way to handle this all right so our default size is base so if I switch back to Arc uh yeah those look good now but these are now too large so we just switch back to job card and I will update these to say all right set a size of small and then I will uh create three of those all right and let's even update these to look a little more real backend front end manager something like that there you go we have our small tags and our larger tags all right back to Zeppelin last up well we'll still have some form work to do later uh in the series but all I want to do to wrap up this video is add the section at the top let's find you a great job followed by a uh an input back to welcome this will be its own section at the top and it's not a standard section heading so it's more of a banner let's find your next job I already know it's going to be bold and maybe pretty large how about for Excel and then below it I want a form so we will handle the logic for the form later but yeah within it we'll have an input type of text we'll give it a placeholder U to give you an idea of what to search for how about web developer and then for the classes let's see if I zoom in all right so we have a dark uh gray background there's a border it's rounded there's a good bit of padding there all right let's see if we can make this work make it rounded let's set a background color of again let's use Alpha how about background of white but only at 5% and that way I could do a border of white at 10% so just a little bit larger and then we know we want a good bit of padding on the left and right and the top and bottom it's a pretty large input all right let's have a look in Arc and yeah so next let's align it to the center and you know what maybe can I just set text Center to the section itself yeah that looks good uh let's make the input wider so H how about set width to full yeah and actually just in case on your screen you're not seeing this uh overly well let's increase it temporarily so it's Crystal Clear uh where we are all right we want to push it down so let's say class mt6 and then it's a little too wide so we should set a maximum width now tail one includes a handful of Maximum width classes not sure which one to do um typically I would just eyeball it so here's large here's extra large extra large looks pretty good to me okay finally if we check Zeppelin it is pushed down just a little bit um let's do well we already have spacing in between don't we so I can't set margin um let's do this how about padding top of 10 yeah and that pushes it down and then also so we should push uh let's find your next job down from the navigation area a little bit as well so maybe I don't want pt10 maybe a little bit less pt6 and yeah I don't want to spend too much time on this uh because we have a lot of lirl specific work to do although this is LL specific you know we are working with blade components and refactoring things and figuring out how it works with utility classes and stuff like that and yeah I think this is looking pretty good okay so let's bring this back to background white of five and uh yeah clearly there's a lot more tweaking we could do in real life um I'm sure there's a bunch of hover Styles and focus Styles we've missed but again for a demo where you're working along I think this is pretty good all right so very good job yeah I don't know what the deal is but in my head whenever I have videos like this that are almost exclusively HTML and CSS based I feel like the programmers among you are thinking come on come on fast forward this isn't what I signed up to LC cast for move on to the next part um I don't know maybe that's not true maybe some of you enjoy watching it but either way it doesn't matter because we're done in the next video we're going to do a lot we're going to build up the whole architecture for this project so that means we will be generating eloquent models uh we will whip up seed data and factories we'll work with relationships I will introduce you to testing there's a lot to do and I hope we can pull it off um so yeah that's it I will see you in the next video stay [Music] tuned what pull a show [Music] outro all right everybody Welcome to day 29 we're getting close two videos to go and if you want me to be frank I'm getting a little stressed out because we have so much to cover all right so like I said at the end of the last episode we are mostly done with the frontend portion we still have to construct a form later but yeah most of the boring stuff quote un quote uh is all done so in this video we will move on to the architecture of the application now I know already that it's an employer who will publish a job so I'm going to start with a migration to create that table create and employers table all right create employers table and yeah let's see an employer has a name that'll be a string they have a logo so we will store a path to that logo and then also an employer belongs to a user right a user signs up they create an employer and it is the employer who publishes the job all right let's do a foreign ID for a user and of course we can clean this up all right let's migrate the database PHP Artisan migrate all right so we have three tables that Lille ships with out of the box and then our new employers table if I switch to table plus let's open it it's an SQ light connection I'll give it a name and the path so here's our app it's going to go into database database.sql light save it and yeah now we have our new employers table okay so while we are here though yeah jobs and job batches and failed jobs you'll remember throughout the course because larl has a concept of cued jobs that kept interfering with our concept of a job listing so yeah I don't want any interference so what I'm going to do is change these default table names go into your config directory down to q and let's have a look I'm just going to look for table Yeah so for the database connection for our Q driver the default table name is jobs so why don't we change this to cued jobs or again we could store this directly within your environment file all right let's do another table search ah yeah job batches uh we didn't really go over this it's a slightly higher level concept but uh nonetheless I'm going to use the same convention here it will now be called cued job batches and I think there's one more yeah so if a cued job runs but it fails for some reason it needs to be stored right so that we can reference it later and and retry it later so that table is called failed jobs by default now it's going to be cued failed jobs all right so now we just have to update the migration itself so this is the migration that Lille ships with create jobs table and yeah let's start by renaming it to create CED jobs table and then I will update the table names C jobs cued job batches and then finally cued failed jobs okay let's Refresh on my ations PHP Artis migrate fresh and now if I switch back to table plus and give this a refresh all right now yeah there won't be any interference whatsoever with our job model okay so let's do this we did this in two steps didn't we we created a migration for the employer's table and now I'm going to create a model for the employer but don't forget if I do help on make model we can generate these things all in one Go including the Mig including a factory including a controller or if we pass the- a flag it makes a migration the model the cedar the factory the policy the resource controller and a form request yeah there's a lot here but it really does save a bunch of time okay but anyways because we already created the migration this time let's build the model and I will select the ones that I need so- c for controller f for factory - s for a database seeder and then I also want a policy cool so now we get five files with a single command which is pretty cool okay next up let's focus on jobs and this time we'll do it all in one go PHP artisan make model job- all and yeah now we get all of these files for free and yeah keep in mind if it turns out that there's one maybe form request that you're not going to use just hit the delete key no problem there all right so let's go into our migration create jobs table and let's see let's think this through to publish a job we need to provide the title of the job right what's the job title next what is the salary for the job and yeah once again we're going to be pretty generic here I don't want to deal with um with currencies and stuff like that so you can provide whatever you want for that field all right next another string what is the location for this job is it remote or do you have to be in Winter Park Florida uh it just depends so you need to specify that all right next what is the what should we call this the type of work is it full-time or part-time and maybe type isn't the right term maybe schedule that's not quite right either why don't we go schedule though it could be full-time or part-time and we'll set a default of full-time yeah if you want this could be an enum but I don't know sometimes that's a little Annoying to work with on the database level so I will skip that all right next up when you publish a job you need to provide a link to your actual job Details page believe it or not that's how it often works you you publish your job to some kind of aggregate uh platform but then it ultimately directs you to your own website where you provide more details so this will be a URL to the actual job listing and then well here's another thing I don't know if we're going to implement this but yeah you could imagine uh allowing users to pay more to have their job listing featured at the top so we need some way to determine if a job should be featured or not so with that in mind let's make that a Boolean it'll be featured but the default is false and then finally the relationship a job belongs to an employer right so let's set a foreign ID for the employer and then once again I will import that all right that looks good to me let's migrate our database back to table plus give it a refresh now we have users we have jobs and we have employers very cool so now I'm going to set up those relationships let's start with employer an employer belongs to a user so return this is a belongs to relationship and then we reference uh the associated model and if you want you can add a return type or you can omit it just depends on what system you want to follow all right now let's do the inverse so in this case the user is actually like the representative for the employer so it's not a belongs to relationship it's actually a has one relationship ship so a user has one employer like so all right next let's switch over to job so what are the relationships for a job well as we discussed a job belongs to an employer right of course it does all right next yeah once again let's do the inverse if I have an employer instance and I want to see all jobs associated with that one employer and no one else well let's do that jobs and this is going to be a has many relationship an employer has many jobs and again if you want you can add a type here just make sure that you import it uh at the top here now real quick we're making good progress but yeah I do want to introduce testing at least a little bit um it's a tricky thing uh testing is a key component to building applications these days but for a beginner level course it slows things down dramatically but yeah nonetheless we want to discuss it at least a bit so I'm not going to write test for this entire project like I would do in real life but we'll write some to give you the general approach all right let's do that now so let's do this before I can write some tests I first want to flesh out my database factories so let's go into factories and build these out all right so let's see an employer has a fake name it has a fake logo so let's see if there's some kind of image URL yeah I think that'll work and then finally an employer belongs to a user right so let's reference a user Factory all right that's done now into job Factory and a job has a title so I believe Faker has a job title property which is pretty cool they have a salary and here's what I'll do in this case uh this is a cool little tip there is a random element method where you can pass an array and Faker will just choose a random item from that array so for example you could say 50,000 USD like we've been doing uh 90,000 USD or 150,000 USD so now every single item will be one of these three all right next we said location I'm just going to hardcode that to remote and also that's an important thing to realize it doesn't always have to be random fake data if you need to hardcode it that's fine it doesn't matter next we have schedule and we'll set that to fulltime or again if you want it random use random element next we need a URL to the job listing page on the employer website so we'll do fake URL uh is the job featured we're just going to always set it to false unless you override it and then finally yeah the relationship employer ID so we can say employer Factory all right so let's clean that up and we're all set okay so now we can write some tests for this so let's come down into phpunit.xml so keep in mind even though we're using a test framework called pest pest is a wrapper around PHP unit so that's why we can visit a phpunit.xml file to configure how pest is going to behave because pest is just deferring to PHP unit it's a wrapper anyways you can see some of these environment variables that are set these are like overrides when you're in a testing environment so I'm going to set up the database connection to also be SQ light but I can set the database itself to not be a file but instead memory and yeah you won't always reach for this uh but for small little projects like this it's going to be perfect and super fast next notice other things like sending mail or dealing with cues yeah all of that is effectively turned off we don't actually want to deliver an email when we are performing a test we just want to assert that an email was sent so in these situations we use the array driver rather than SMTP or or postmark or something like that all right let's create a test PHP artisan make test I am testing my jobs and now what kind feature or unit uh this can often be confusing think of a feature test as testing a wide spectrum of your application like this when I visit such and such page I expect to see that or when I make a post request to this controller then validation should occur and I should see such and such in the database think about it that's testing a very wide range of your project versus a unit test Which is far more narrow when I instantiate this class and I call that method then I expect such and such in response and yeah how narrow that ends up being differs based on the community so for example uh would testing an eloquent model that hits the database is that a unit test some people say absolutely not I say sure who cares uh but again just make up your own mind in our case we are working with quote unquote unit tests okay so let's open that up it will be within your test directory inunit and now we have our new job test now we already have an example here expect true to be true nice and readable let's run it PHP Artisan test okay so we have the example tests that Lille ships with and if we want we can go ahead and delete those or just the one for unit for now and yeah the one we care about here is our job test and of course it passes but if we uh change this expect true to be false of course that's going to fail so if I run it again now we get red all right let's review a few examples let's say a job belongs to an employer so I could say test it belongs to an employer but as it turns out with pest we can use this function name of test or we can use an alternative Alias which is it and you can switch between those based upon how you want to uh write out your tests so notice I'm saying test that it belongs to an employer that's great or I could say it belongs to an employer both do the exact same thing so how would I check this well and this is usually a three-step process we often call it arrange act assert AAA like this Begin by arranging the world create the world in order to run your test next ACT perform some kind of action finally assert what did you expect to happen as a result of that assertion all right so I'll show you an example it belongs to an employer how do I arrange the world here well if it belongs to an employer then I probably need an employer to perform this action right let's use a factory for that employer Factory create all right next we are using it it refers to a job but I don't have a job currently so let's do that as well let's say job equals job Factory create now when I run this it is true it'll set up its own relationship to an employer but for this particular test I want to be a little more explicit so if I ever want to override anything declared within the factory then I pass that as an array to the create method so in our case I went to over ride employer like so okay and while we're here let's clean things up all right so now step one arrange is complete next up perform an action so this is where I interact with the codebase in the way that I want in our case job employer okay so often your action and your assertion will be separate but in this particular case we can group them into one arrange or I'm sorry act and assert all right so I could say expect job employer to be this like you see here so here's what we could do job employer is employer we learned about that method many episodes ago I expect that to be true so yeah if the is method is new to you it's checking if what you pass here is the current instance so that will either return true or false in our case we expect it to be true all right let's run our test PHP Artisan test but it fails for a confusing reason a facade route has not been set all right so ultimately What's Happening Here is the LEL framework hasn't really loaded because this is being treated as a sort of raw naked unit test but I I do want to interact with laravel and eloquent in the database so if I go into the pest. PHP file this is sort of like the configuration file for your test and right at the top you can see use this uh root parent class in the feature directory now you can think of test case almost like larl it makes and bootstraps larl for you and you'll also see this commented line refresh database and what this means is after every test completes larl will refresh and reset the database so that you can start with a clean slate all right so these things will be active in the feature folder right here but I also want them in my unit folder and yeah this goes back to how different people have different ideas uh for what a unit test should Encompass in my case I'm pretty loose with it so I'm going to use these two parent classes or traits within the unit and the feature folder all right now if I run it again it passes perfect so it passed if I switch back because we have already set up these relationships so if I go into job and we hadn't yet written this we would run the test it would fail and at that point we could write the code in order to make it work and this is referred to as test driven development yeah I find that test driven development can be a little confusing to newcomers but it's actually not so bad especially with Flavel these days uh think of it like this you start by writing a test where you interact with the world and in this case the world is your code base uh you interact with the world in a way that is ideal to you next you run the test but of course the test is going to fail right you haven't written any of this code uh in real life you're in la la land you're saying wouldn't it be great if this worked but of course it doesn't so the test returns red it fails so the final step is write the code to make the test pass and then rerun the test it Returns Green and you rinse and recycle it's a nice way to build applications it's not for everything but in certain scenarios you're really going to love it anyways if we return this code and run the test again it passes now I do want to show you at least one example of this tdd approach so how about a post can have tags that can be useful so how about it can have tags all right let's follow arrange act assert create the world well to start I want a job so job Factory create all right next act so interact with the world in the way that would be ideal so if I want to attach a tag to my job maybe I could even call a method like tag job tag it with front end or something like that finally assert assert that this worked the way I would expect maybe something like this uh I would assume on my job model I would have a tags collection and maybe I could say well I expect that collection to have one item so I could say two have count one and I'll reformat yeah why don't we start with that all right so let's come back and run our tests and of course it fails there is no method called tag all right let's Implement that job tag all right so we fixed that particular error it said No Tag method exists so we run it again and now we have changed the error and this is a key part of test driven development make the error change and that is a signal that you are in fact making progress okay so now we tried to grab a collection but of course that returns null and it's not working okay let's do that now we will have a tag relationship and why don't we just stub it out for now let's return an empty array all right it fails the error changes and now ah job tags must return an eloquent relationship instance okay now we can get to work let's make a model for a tag and I don't know if we're going to get around to building a controller for it but I do want a factory and a migration all right so let's go into create tags table and this is very simple a tag consists of a unique name like front end backend manager Project Lead and actually for now I think that's fine all right now let's go into tag Factory and set this up a tag Factory has a name of any kind of fake and unique so I will add that uh classifier uh name and that will be fine all right so now I can go into job and yeah let's update this relationship so does a a job belong to a tag well that would signal that the tag owns the job right and no that doesn't really make sense uh what about the inverse does the tag belong to the job well sort of right if I had a tag called front end that could belong to this job the only thing is it could belong to more than one job it could belong to 10 different jobs so it's not exclusive okay so in these situations we want a belongs to many relationship and we'll create a pivot table to allow for that all right so our relationship is belongs to many a job can belong to and have many tags all right so we have a tag eloquent model we have a job eloquent model next we need an intermediate table and this table will include the job ID and the tag ID and it'll do that over and over that way one job could potentially have a hundred different tags that it is associated with let's create a migration phb Artis make migration create job tag table all right all right so we want a foreign ID for the job right and then we want another one for the tag and for both of these why don't we say constraint uh create a forign key constraint and then Cascade on delete and we've already reviewed both of these this just means if uh in this example if the tag is deleted then Cascade and also delete the record within this pivot table as well okay PHP Artisan migrate so now I have a new tags table and a job tag pivot table all right so we've done some work I'm now going to return to job test and let's see how we're doing PHP Artisan test and it still fails failed asserting that actual size zero matches expected size of one well at least we are making progress let's go back into job and let's see that relationship is working but right now the tag method doesn't do anything at all so let's update this if I accept a tag name here we'll call it name now there's a couple ways to do this uh I'm going to reference the tag model so I'm going to say give me the first tag uh from the database table that has this name or if you couldn't find one with that name create or persist one in that table so I'm going to say the name is name all right does that make sense give me the tag from that table and if you couldn't find the tag with that name create one and then give me the tag all right next I'm going to interact with my pivot table I can say this tags and attach a new tag here just like that all right finally these squiggly lines my editor just wants return types again these are optional depending on how you like to build your applications but we could import these and simplify all right let's run our tests again and it fails but I want you to notice right here yeah check this out add name to the fillable property to allow Mass assignment on tag yeah so notice when we take this approach it almost feels like the tests are telling you what the next thing you need to do is and that's one of the huge benefits to this approach all right let's go on to tag and we could update the fillable property or I'm going to go into app service provider and I'm going to disable that feature entirely like we've learned about in past videos so I can say model ungard all right run it again and now we get green how cool is that we haven't yet opened a browser but now we know that a job belongs to an employer and it can be associated with any number of tags all right let's be done with tests that's all we can get done here let's go to our routes file and yeah all we have right now is the homepage route let's update this when you visit the homepage that will load our new job controller and an index action on it all right let's open that up and this can still load our welcome view though we should probably change that shouldn't we so let's go into resources views I'm going to have a directory called jobs and then a view called index. blade. PHP and what I'll do is I'll take everything here and migrate it over and then I can delete welcome entirely all right back to job controller now as you can imagine and let's update this we would need to pass jobs to our job listing page and I'm also imagining that we need to pass a list of tags so let's do that one as well all right let's keep it very simple we can now reference our job model and say give me all of them though of course as we've learned in a real project we would want to patate them but for now a select star is fine we'll do the exact same thing for our tags okay let's go into our view and you'll remember that yeah in the last episode everything was static we're just hard coding all of these but now we can swap them out let's begin with how about tags we can say for each tags as tag then render this blade component but now I want to pass in uh the associated tag like this tag equals tag or a little tip in situations like this where your parameter name and the variable name are the same if you prefer you can actually do this this is just sort of syntactic sugar uh that achieves the exact same result all right so now within tag I also need to accept the tag and now I will swap out the text here with the name of the tag itself next we haven't set up an endpoint but the herf would probably be something like tags slash tag name to lowercase maybe yeah but we haven't set that up yet okay let's go back to jobs . index so we've updated this one here but also we reference tags within the job cards don't we this should be easy now we know a job can have tags for each job tags as tag then reference the tag all right let's copy this and then also switch back to job card Y and yeah we have this one right here get rid of this and the size can be the default all right let's view this in the browser ah yeah of course I jumped ahead of myself so within job card we're referencing a variable called job that was not defined of course each of these need to be updated to now accept the job so here's job card wide I will then go into job card and paste that in and then within our job /index view we can pass these in in the exact same way for each jobs as job pass it in all right and then I'm going to do the same thing up here but do note this is the feature jobs so we will need to tweak this in just a little bit but yeah let's just get to a point where the page loads all right come back cross our fingers and the page is loading now you'll notice of course we don't see any tags or jobs because we don't have any yet so this is where database ceders come into play we'll go into database seeders job Cedar and let's do this now so yeah this is sort of like a whirlwind tour of the entire course up until this point job Factory let's create I don't know 20 of them create now keep in mind this will work but it doesn't account for tags so here's what we'll do I'm also going to say tag Factory 3 create so I'm going to create a collection of three random tags and now I'm going to call a new method you haven't seen called has a tag Ed and of course this is for uh belongs to many relationships I want to attach these tags to each of these jobs we generate so now every single job will consist of these three tags all right let's go to database Cedar I will create our dummy user that's fine and then we will call our job Cedar all right let's give it a shot PHP Artis DB seed if I come back to table plus yeah now we have a bunch of employers we have a bunch of jobs and we have three tags and whoops I accidentally did a person's name instead of a word I'll fix that but anyways three tags that each of these jobs are associated with and we can see those uh references here all right let's fix that real quick tag Factory and let's use a dummy word here all right PHP Artis migrate fresh- D seed reset my migrations rerun them and then seed the database let's go to Arc give it a refresh and now we have actual live data coming from our database pretty cool and then we have three tags and notice every single job is associated with them okay so just a couple final things I'm going to go into job card and make all of these Dynamic so we'll say job employer name we want job title job salary and then tag we no longer have to pass this in and then employer logo we're going to come back to that okay now let's go to the wide version of the card and I'm going to do the exact same thing job employer so notice we do have an n+1 issue uh right now because we haven't eer loaded the employer relationship so for each item in this Loop we have to perform a new query to fetch the employer so keep that in mind job job title job salary and same thing here all right back to Arc and now these are unique the way we'd expect okay so the last thing I can fit in here is feature jobs right now we're getting the exact same collection so notice the first one is psychiatric technician and then if I come down here to recent jobs we see the exact same thing there's no distinction between a featured job and a non or unfeatured job job let's do this I'm going to come back to our job theer and we know that in some cases we could set featured to false and other cases featured to true so I could run two separate uh queries or this is a slightly more advanced concept but we could create a sequence instead and it takes this shape new sequence and notice that full import there I'm going to provide a sequence of um parameters that I want LEL to filter through or better iterate through for example sometimes featured will be set to false and why don't we set schedule to fulltime all right but then in the next iteration featured will be set to true and schedule uh will be set to part-time all right so let's reformat and if we did everything correctly we should now have for a total of 20 10 of them with these attribute overrides set and another 10 with these attributes let's give it a shot I will run migrate Fresh Feed and now check this out I'm going to go into job controller and let's extract this call IT jobs all right and I'm going to say job all but after we fetch them I want to group them according to whether or not they are featured so check this out I'm going to return this uh from the controller so that we can review the Json and and let's see let's do pretty print all right so notice we have a collection of collections now so for the first array in every case featured is set to zero but after we get to 10 or so we get a new array or a new collection and for this one featured is set to one for all of the items so we' have grouped these into um collections based upon whether or not they are featured cool so now here's what we could do we could uh let's do this we'll have feature jobs as well so that's the first item from this collection here and the second item is the unfeatured jobs so if we want yeah we could do something like that all right so let's go into our view and now I can Loop over featured jobs instead okay so now down here this will be standard jobs and you know what this probably isn't quite right because presumably you would want featured jobs included with your recent jobs but yeah for now we're just drawing a distinction between promoted jobs and non-promoted jobs uh so so so as to avoid duplication okay so back to Arc all right so now we have our 10 feature jobs beginning with human resource director 3 six 9 10 then our tags and then unfeatured jobs and this one is human resources assistant it's a different collection entirely very cool all right that's a wrap and I'm not even joking I am literally tired right now there's just so much to cover and oh my gosh we only have one more video to do it so wish me luck tomorrow is day 30 and we're going to wrap up this entire course I'll see you then what put your arms in the air you'll never take me alone [Music] [Applause] [Music] okay all right is this thing running recording we're good I don't know how much time we have oh I need to close those curtains too they could be here any minute but I didn't want to leave you hang in we can't have a 30 days course with only 29 days so here's the deal if anybody knocks on your door we never met you don't know lass okay we may have to go quick but let's get started now I do have one compromise we need to make in order to fit all of this in to a single video and I'll show you now here is my larl herd route directory and yeah you can see pixel positions but I also have a backup version where I've been working behind the scenes to save us just a little bit of time so so we're going to go into resources views components and just this once I'm going to ask forgiveness for copying a bunch of form related components so that I don't have to manually type them out trust me we'll quickly go over it but you've seen this before you're already familiar with it let's skip over this process so I will copy this directory switch back to our real project in resources views components and I will paste it in and yeah we'll talk about this more in a moment cool so now let's start with authentication I'm going to go into my routes file and let's set up our endpoints and I'm going to do these all at once again to save a bit of time so register we'll hit a how about registered user controller again this is a recap of the authentication episodes and this will hit a create action next when you post that endpoint that will hit a store so we are storing a new registered user and of course ignore the squiggly lens just for a minute uh next login so if you make a get request to login this will hit uh again off controller login controller session controller whatever you want uh this will hit a create action because we are creating a new session that's how I think of it next when you post to that endpoint that will hit a store action and then finally let's do a delete request to SL log out and yeah that will hit a destroy action all right let's create these controllers now PHP artist make me a controller called session controller and let's set up a full resource for it and then let's do another one but this time for registered user controller all right so yeah let's import these and let's start with registration all right and later of course we will remove any actions that we don't make use of all right so this is going to load how about off. register in this case I'm going to use a different directory name and that's fine and also again in the spirit of saving time I'm going to make use of my editor a bit more so in this case I can option click and create the view all at once and you'll see it automatically creates the auth directory and that file and that's going to help us a lot all right so let's create a layout and yeah let's start with a page heading we'll call it register and yeah how about font bold let's Center the text I want it pretty big so how about text for excel and a little margin below it okay so I can imagine that this is a standard page heading which means why don't we move it into its own component like this page heading. blade. PHP and paste it in all right now this will be our slot cool so now if I switch back we can swap it out with page heading okay now I'm going to use some of these form components so again yeah if you take a look at them you've done these before right this is what a button looks like and mostly we're just uh extracting in ta one classes but we do have a couple of things that might be nice so I have one component called form and this will create a form it adds some default classes and then it also handles uh figuring out whether to add the csrf hidden field and the method field so notice it defaults to a method of get but if we change that to post or put or patch as long as it's not get it knows that we always need to include these two things which you learned about in the forms lesson but yeah other than that here's an input so I create a field and a field is just a wrapper for an input it contains a label it contains the input itself and it contains an error you've seen this a million times and if you want visit GitHub and you can inspect it and copy it over to your project okay yeah once again it's going to save us so much time just give me this one all right so let's build up our forms and do note whenever you have a component within a directory you need to do the directory name Dot and then the component name all right so the method in this case is going to be post and the action is going to be register all right so first step I'm going to need an input and for my inputs I accept a label and a name and it takes care of the rest so the label is going to be your name and then also the name for the input which just happens to be name in this case all right let me show you what this looks like in the browser if I visit slash register yeah there we go looks good to me all right back to PHP storm all right next actually real quick let's just stick with name that way this one can be email now in this case the type for the input should not be uh text it should be email all right next I want two more so we will have one for the password and then also you have to confirm your password so password confirmation all right password and type for the input is also password and this is password confirmation and make sure it takes the the same shape all right next down at the bottom we could have a form button and this could say create account and let's have a look yeah name email password and create account but notice there's no padding at the bottom maybe I could add a little padding to the body here I think that's okay pb10 just to push it down a little bit and that's fine maybe even a little more actually yeah that's good now think about it when you register you also need to create an employer so I have a divider component and that just creates a little line uh as you can see right here yeah just a little divider and then we're going to have a section for the employer details for example let's copy this I need a name for your employer so how about employer name and the name for this input will be employer and then also we need one for the logo so I will call that logo and this is a file input so I'm going to set type to file in this case so yeah notice any attributes I provide here of course will be uh passed through here and that's how attributes Works in this case I'm just extracting the defaults into its own array so that it's easier to consume and that's a good approach you might want to take all right back to Arc so we have all of this and then the employer name and logo all right next as you probably know anytime you have a form that will accept a file upload on the form tag itself you need to set the ink type to uh multiart SL form-data and that's just how it will be encoded in this situation pretty standard HTML stuff there all right so let's go to registered user controller and when we submit that form we will now hit this endpoint so let's die and dump all of the request data all right magic I'm going to fill out this form all right let's create the account and there we go we have our attributes while we're here notice that logo is actually an instance of a larl class called uploaded file and you're going to love this it's going to make it as easy as possible to store this image wherever it needs to go whether it's publicly available or even uploaded to Amazon S3 or something like that all right let's get to work so this time why don't we use request not as a helper function but instead using an object instance like this so we're going to validate and by the way the API is identical okay uh let's see if my editor can help help me a little bit with the rules we want to save time anywhere that we can yeah it's not perfect but it'll get us going okay so validate the name the email email verified at is not required nor is remember token password is required and it should be confirmed and then I'm going to use the password validation rule make sure you don't accidentally grab the password facade you want to illuminate validation rules password and I'll set the only requirement is it needs to be at least six characters next what else uh email Let's ignore the maximum for now uh and it should be unique on the user's table and specifically on the email uh column this is actually automatic because it will fetch that from the name but if you want to be explicit yeah this is just saying hey look in the users table and see if there's any email field that has the current uh email and if there is that's a noo we can't have two users in the system with the exact same email address it needs to be unique okay but next you remember we also have employer specific validation so we have a couple options we could group them all together or what if we tried this let's say user attributes and then I will do another one for the employer like this employer attributes and this can change to and actually let's get uh PHP storm to do it some rules for the employer and yeah we just need this here all right so you have to give us a name and you have to give us a logo we'll make that required for now but also I want to ensure that this logo is in fact an image for that I can use a file rule illuminate validation rules file and let's set the available types and yeah you can give us a PNG whatever you want here jpg webp anything you want to add there maybe webp too and that'll be enough now here's why we split it up I can now do things like this user create user attributes whereas otherwise I'd have to do something like uh array accept or something like that to Omit these from being passed to user create and the same for uh updating the employer so this just makes it a little bit easier create a new user then log in the user off log in the user and then yeah let's create the employer yeah we'll do that right here so we'll say user employer create and yeah because we are accessing the create method in this way it will automat Al assign the user ID uh to the employee record that way I don't have to manually set it it happens automatically now we could do something like this where we set employer attributes but in this case we need to do a bit of work first for the logo I need to store the logo in the proper location and then wherever that path is I want that to be referenced within the employer's uh table record so here's what we'll do now you'll remember that the uh request logo field when we we saw it in the browser actually was an instance of ll's uploaded file class and that's really cool because now we have some behavior on that class to store the image wherever it needs to go I'm going to put it in a folder called logos okay let's talk about this uh if I go up into my config directory there is a file systems configuration file so this is for storage do we want to store files locally or with FTP or S3 uh it just depends on what you want to do and I can see the setting for each of those discs or drivers here so yeah in our case these will be publicly accessible avatars so I want to use the public disk by default so I can set that within my environment file and yeah notice file system disk I will update this to public all right and that's it believe it or not you're really going to love this so when we upload the image it will be saved within the storage app public and it will create a new logos folder and then we will create a symbolic link from here to uh the public directory so that any person can access these images that's the way that works all right now once it uploads the image it will save a path to where that logo is located so I can then pass that uh to our create Method All right so the employer's name will be employer attributes name or of course you can grab it right off the request and then the logo will be uh assuming we did everything properly the logo path all right so validate all of the attributes create a user store the logo create a new employer and then how about redirect to the homepage all right let me take a look at this good good good good and create oh actually no employer attributes should be employer that was the name of the input we assigned within the view other than that I think that looks pretty good all right so it looks like we have only two actions here so I can get rid of this and this and yeah from now on I will do this behind the scenes after the video again to save us a little time let's give it a shot all right create the account and it fails so maybe it wasn't called employer let's have a look let's go to register employer name yeah employer logo all right let's go back to registered user controller ah yes I bet you saw that all right so of course that key wasn't available all right try it one more time all right and there go so yeah I'd like to see a little more feedback and we can do that through flash messaging but if I switch to users sure enough I have a new joho account the password is hashed and we also have an employer who uh belongs to that user so I think we're all set for registration next I will switch over to login and log out so let's go into session controller for create this will hit off. login and let's create that all right so let's steal a little bit of the code here so this will say login and this time we will post to login and there is no uh file input there okay I think all we need is uh an email address and a password all right how's that look I think that's right all right back to session controller that will now hit a store action and you know what we already wrote this functionality in the authentication episode so if I switch to GitHub where we have the source code for the entire series if I go into app HTTP session controller I bet yeah let's take a look at this it's all the same stuff right show the login view validate the request so let's take the raw data here copy it and see if we can just paste it in here all right so yeah that looks pretty good we try to log the user in if we couldn't then we attach a validation error to email we regenerate the session token as we learned that's a good practice and then we redirect again to the homepage in this case and then finally for destroy yeah you just do off logout and redirect and you're done so that saves us a bit of time which we needed let's have a look let's go to SL login let's try to log in John example.com and we're in all right very cool but yeah notice how if I visit SL login I still see that form which doesn't make sense so let's do a little bit of authorization if you think about it to access this page you should be a guest same for this one but not for this one actually in this case you need to be signed in so let's say middleware off and then for these two and actually also for these two you need to be a guest if you're signed in it doesn't make sense to visit a register page so I'm going to use a route group but first add a middleware and we'll say you got to be a guest in order for this to work okay so now any route nested within this closure will receive the guest middleware and this is a wrapper or instead for each of these routes we could do something like this and that would do the same thing all right very good next let's go into our layout file and here is our nav section so yeah right here why don't we tweak this I only want to see this post- a Job Link if you're signed in so I'm going to use this oth directive like so and then I'm going to add another one here called guest now I could do o else and O but sometimes I think this reads a little bit better if you're a guest show this if you're signed in show that and actually while we're here why don't we say job SLC create uh for the posted Job Link because we know that's what it's going to be ultimately okay now if you're instead a guest let's repeat some of this here all right so we will have two links to sign up or log in all right so sign up would be SL register and login would be SL login let's have a look okay so if I refresh yeah I still see post a job because of course I'm signed in but let's open up an incognito window and yeah now because we're not signed in I do see sign up and log in and those do work perfect all right so let's close those out and I'm back to the view where I'm signed in all right 5-second breather real quick I get it I know I'm going really fast sorry it's got to be that way it's day 30 we got to wrap up okay back to work what should we work on next uh how about this big search bar here yeah okay let's go into job SL index and let's see what we have yeah right now we have standard form tags but I'm going to replace this with our new X forms. form tag and this will make a get request which is the default but I want to send it to how about search and we will Implement that rout all right next within here let's add an input the name will be Q for query that's really common the placeholder can be something like web developer and let's have a look in the browser ah I get undefined variable label yeah so my input component is expecting a label but in this case we don't actually want one so if I switch through we can see that the uh label is passed to this field component and the field component checks whether label is truy okay so if I switch back all I need to do is set label to false all right switch back and that solves that problem okay I think I need a little more Breathing Room below the title so why don't we say class of mt6 and yeah we kind of reproduced what we had before cool so now yeah take a look if I search for how about laracast and I hit submit I do get a 404 because I haven't yet implemented that route all right let's do it now let's duplicate this if you visit SL search again keep it very simple let's load uh a search controller and actually this time I'm going to show you invocable controllers so every once in a while you will have a controller that will only ever have one action in these es rather than passing an array and the action name you can just pass uh the the path to the class itself and then an invoke magic method will be called on that class it's pretty cool let's do that now PHP artisan make me a controller called search controller and oh you know what that's interfering with my route declaration so let's do that first and then uncomment this okay now I can import it and I will command click through and yeah if I create a MAG icore uncore invoke method now this will be called and yeah this is this is great for situations where a controller only ever needs to have one action so I'll show you come back give it a refresh and we now have hit that invoke uh method okay so there should be a q um query within the request refresh and now that is set to lass and of course we can control that here cool so now we have everything we need to search our jobs table and this will be fairly primitive we're not going to use full text search or anything special uh we'll just say look for any job where the title is like uh this search uh pram and that should be enough so let's say job where the title is like the request query but then I'm going to say yeah any number of characters can come before that query and any number of characters can come after it so as long as this search query exists somewhere within the title I want it included in the result set so we will fetch that and then why don't we return that as Json so we can have a look in the browser let's start from scratch let's look for something related to how about teacher all right we run it let's do pretty print and we get one result all right so now we just need to render A View to display those results and that should be pretty easy let's return a view and this could be like a generic view like results anytime you you want to show jobs we can use this View and I'll pass through our list of jobs nice and easy all right let's have my editor create the view we'll have our layout we will have a page heading results and then let's do this let's go into job SL index and yeah we want this right here so I'm going to copy this and paste it in and I don't think we need that mt6 in this case all right uh yeah let's have a look back to the browser refresh and we have only one result but it does seem to be working let's try one more time uh something related to tax and once again we have one result but yeah that's working cool search is now done at least the Primitive form of search is now complete we should also look for tags and things like that uh but you can work on that on your own so now think about it if we go back to our routes file let's set up another route for tagging so I could say visit tags slash and then some kind of tag name that will hit a tag controller and I will create that so make me a controller called tag controller cool and let's import that and yeah this will be the exact same thing so in fact if I go to search controller let's just copy that switch back to tag paste it in and now we aren't searching the database we are finding all jobs associated with a given tag something like that okay so let's go to our tag model and we don't yet have a relationship between a tag and a job but I think we do in Reverse yes so let's copy this bring it over to tag paste it in and now if I have a tag and I want to find all jobs it's also a belongs to relationship we just have to reverse it like that all all right back to tag controller all right well now I'm going to ask for the tag and you learned about this through route model binding just as a 5-second recap yeah right here because we have this wild card here that's called tag and then we have a parameter name also a tag Lille is going to try to track down this tag for us but by default it's going to expect this wild card to be an ID so I can add a colon and say no actually the identifier here is name so if I visit tag slf front end yeah I I basically want Lille to say select star from tags where name equals front end yeah without that it would default to this and yeah we already reviewed this so that should be a recap all right so now I should have the tag I should be able to get the jobs for the tag right so why don't we just do this load the results and pass through all of the jobs associated with this particular tag all right let's clean up up and it's so easy isn't it it kind of blows me away it's so simple all right back to the browser and let's visit some random tag how about UT oot all right and here are all of the jobs that are associated with that particular tag yeah cool so now yeah all of these tags should be clickable so if I click here that will show me all the jobs so that I can further filter things down that's great okay final thing and then I promise we're going to done of course we need to implement the form to post a job so let's do that now let go to my R file and we'll say right up here how about this let's duplicate this uh job SLC create we'll hit job controller at create and then I'll do another one here when you make a post request to SL jobs that should store a new job in the database and of course these need to have the proper middleware in order to post a job you need to be signed in all right let's take care of it so we have our create action that will return jobs. create let's have my editor create the view X layout notice how quick we can be um when we when we have our systems in order right let's do a page heading new job and Sanity check let's load the page job slre that works and further if I click right here it should load it cool let's build our form now this is going to make a post request to SL jobs and let's do this again I'm going to save ourselves some time you've already seen the basic process of creating a form input so I will paste in a few at once so we have one input for the title and a salary and a location next we need one for the URL so this is the URL to view the actual job page on your company's website next when you create a job you can optionally add a number of tags so I'm going to keep this very simple it's just an input and if you provide a comma separated list we will turn those into tags maybe not ideal but it'll get the job done in this case next I'm going to have a button to publish the job and then I'm going to introduce a new one which is a select uh field so if I have a look at it real quick yeah notice it's just deferring to an HTML select all right so our options are part-time and full-time and this is where you specify what the schedule for the job is next right down here let's add it uh I'm going to add a checkbox once again input and type equals checkbox very basic stuff okay so the label for the checkbox is feature and cost extra yeah presumably if you built this on your own in order to feature a job you're going to be charged $100 or $20 whatever it is um we would want to note that but yeah we're not going to deal with billing or stripe in this series it's far beyond uh the scope of this course anyways I think that's it so the only thing I might do is add a divider to separate the main fields from the optional tags all right let's have a look in the browser and here we go to create a new job you got to give us all of this junk here and then you can publish it all right so that's going to make a post request to/ jobs that will hit our job controller and that will load this action now you can see here we have a form request I actually didn't review that uh in this course some people like them some people don't uh I would encourage you to take a look at them but for now I'm not going to dig into anything new so let's stick with the standard illuminate HTTP request all right let's get to work we will validate the request let's see what my editor can do for me I'm going to add a new job yeah pretty good I will take care of the employer ID so you need to give us a title a salary a location a schedule and then for our demo at least we're saying well the schedule needs to be either part-time or full-time so one way we can do that is through the illuminate validation rule class and I can say it needs to be the attribute value needs to be included in one of these and we can also set this up as an enum if we want but I'm not going to all right Next Step the URL is required and it should be a URL or if you want to make sure it's an active URL you could do that as well which is cool and then featured I will handle that a little differently finally we have tags and we'll keep it here and let's say tags actually can be nullable all right next I will save that to attributes and then I will manually handle the featured status so I could say Okay attributes add a new one called featured and that will be true or false depending on whether the request has a value for that featured checkbox remember if that input isn't checked I don't think anything gets passed right but if it is checked it's set to on or something like that all I want in this case is a Boolean so we will use that all right this looks good to me so let's go through the authenticated user let's grab the employer we'll reference the jobs relationship and create a new one there and again to be Crystal Clear when we take this pathway when we create the job the employer ID will automatically be set in the process and further when we access the employer through the authenticated user we remove any opportunity to to fake who the current user is unless you're signed in you have no ability to create a job under a different employer okay so it sounds like we just need all of these attributes maybe accept the tags so here's what I'll do this time array accept and I'll provide the attributes and then the one that I want to exclude we could do that or we could access it through the request I think there's a request unless or request accept method as well so either of those would work all right now we have a new job record the final step is tags so why don't we do this let's see do we have any tags at all and what we'll say is if we don't have anything there let's just assume false I'm not sure if that's necessary we might be able to remove that but I'm going to keep it then what I'm going to do is basically explode that list of tags using a comma as a separator something like this so now LEL backend front end that will turn into an array right of LEL backend you get the idea let's then Loop over it so for each of those as tag then let's create a new tag so I need a job instance we got it here and I can say job tag and yeah you'll remember using tdd we implemented this tag method and this will try to find a tag with the name and attach it otherwise it'll create a brand new tag in the database with that name so yeah on this note keep in mind this is fairly primitive we could end up in situations where for example you have a tag called front ends in the table but then this uh as well and and we should consolidate that as much as we can but we're going to take a shortcut where we can find it all right let's pass it in and I think we're done so let's redirect to the home page when we're done okay let's get rid of all of these and this is our let's clean this up this is our job controller all right let's go post the job I'll fill this out like magic like so all right so we have a position for a laracast video editor pays 90 grand here's the link to the work page and here are some optional tags let's publish it all right I would expect to see it right here right let's see where is it ah it's at the end of recent jobs here's what I think I did wrong let's go into job controller and maybe I got the order wrong maybe uh recent Jobs is actually first and featured is second yeah I bet that's what I did okay back to Arc give it a refresh and again I don't see it here but I do see it at the end okay so we just need to reverse the order why don't we say the newest jobs show up top job I want the latest ones and give me the results and group them uh according to whether they are featured or not and that should do it come back refresh and there we go we have our brand new job so let's see can I view all jobs associated with that tag yes I can now I should be able to click on the job and it will take me to the job listing page let's fix that and then I promise we are done all right so here is the H3 it's now going to be an anchor tag that links to the jobs URL like so so let's do the same thing for job card wide like so and cross your fingers refresh click on this and it loads the layer cast page where you can view more details the only thing you might want to do is set a target of blank uh for both of these switch over to this one as well and that way some people don't like this but in this scenario I think it's okay that way the user doesn't completely abandon your jobs page it instead opens the job within a new tab so again imagine you're looking for jobs related to video work all right here we go click on it and now we can review more and ladies and gentlemen that is all I'm going to cover today oh wait actually no no no I have two more things sorry two more things to show you we have to update the job card to show the new employer logo and then I also want to display a logout link and make a couple tweaks to make our query performance better all right let's go into employer logo and yeah right now we are hardcoding the path but now we can swap it out with the employer logo okay so now let's ask for an employer when you load this component okay I believe we referenced it in job card yeah let's pass through the employer job employer and then I think we do the exact same thing in job card wide so I will paste that in and remove the width okay so now let's switch into our component and I'm going to pass pass this to laravel's asset function and that will prepare a full URL to the asset and remember when you upload a logo it goes into the storage app public logos directory so here's one of the logos I uploaded and now all you have to do is Sim link it into your public folder which is globally accessible so for that you can say PHP Artis storage link all right so now notice we have a symbolic link right here yeah there it is and now they're accessible all right let's go to Arc and we see it but the size is wrong all right let's go into employer logo and yep we accept a width but we never used it so let's do that now come back and that looks good to me all right next let's go into job controller and remember to always optimize your queries if we have a job and we're going to access tags and employer information off it if we're not careful that's going to lead to an plus one problem as we learned about so let's always use the wi method to eer load any relationships we require such as Employer and tags and yeah you would also do the same thing for example in uh search controller so make sure you say with employer and tags and whatever else you happen to reference and when these queries get a little long yeah make sure you can put them on their own line and if you want you can even call this query method to start a new query and that allows you to keep all of your uh your your primary filter methods on their own lines and that does the same thing all right last thing and then I promise this time I'm letting you go uh if we switch to Arc yes we have sign up and log in but if I log in as John there's no link to log out so that's my final step if you're signed in I'm going to add a form to log out that'll hit the logout endpoint and and it's going to make a post request but of course we need to add the csrf and Method tags and yeah we're not using the form component because that has some styling for the form itself and the button and we don't need that in this case Okay so yeah now let's do a display of flex and yeah it looks good to me so I can post a job or I can log out and this time ladies and gentlemen I'm done I can't do any more in this course well I can't believe it but we are now officially positively undeniably indisputably irreversibly done with 30 days to learn LL it has been a massive effort for both you and me so if you have made it through all of these 30 days trust me I've watched a lot of courses myself and rarely do I complete them so whether you intended it or not I'm going to take that as a compliment all right so let's talk about this come here [Music] I have recorded iterations of this course for about 10 years now it goes all the way back to 2013 with larel 3 from scratch if you can believe it and yeah it never fails every single time people will complain that we didn't cover such and such topic you know there's there's nothing here about package development what about apis what about events you didn't talk about live wire or inertia how come and I'm going to tell you the answer to that question right now the reason is because we didn't well okay you know as the saying goes your learning doesn't conclude the moment you finish a beginner related course I'm sorry to say it has only just begun so yes I would encourage you to learn more about lifewire and we have a course for that on lass yes you should learn more about API development and we have a course for that yes you should learn more about inertia JS and we have a course for that but do they belong in a beginner specific course well that's up for you to decide but I chose no there is such a thing as giving people too much all at once and I would rather you complete a course and then move on versus become overwhelmed by the material in one course okay so this is somewhat of a Bittersweet moment for me because I know most of you are watching this as a free course maybe even on YouTube and you're never going to sign up for l erast even though did you know that you can sign up for lar cast for $15 a month 15 bucks I went to Subway yesterday and it was 15 bucks you could access everything we have ever created for 15 bucks a month but I already know most of you won't some of you will and I immensely appreciate it but most of you won't you'll finish this video you're probably already done you're probably not even listening to me at this point you've already moved on to something else and we'll never see each other again and that is a Bittersweet moment so I'm going to finish up with a song to show you how I feel when you don't sign up for lass let me show you [Applause] [Music] a [Music] the [Music] [Music] l [Music] [Music] [Music] [Music] d [Music] [Music] Henry there's oh my God they're here P me on [Applause] [Music] y