30 Days to Learn Laravel, Ep 29 - Jobs, Tags, TDD, Oh My!

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] 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 front end portion we still have to construct a form later but yeah most of the boring stuff quote unquote uh is all done so in this video we will move on to the architecture of the 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 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 .sq 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 larel 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 nonetheless I'm going to use the same convention here it will now be called CED 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 cued 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 our migrations PHP Artisan 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 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 migration 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 seater and then I also want a policy cool so now we get five files uh 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 winterart 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 uh 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 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 990,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's website so we'll do fake URL uh is the job featured we're just going to always set it to false unless you overwrite 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 rapper 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 in unit 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 Artis 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 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 want to override 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 sep 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 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 configuration file for your tests 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 uh 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 relationship 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 flal 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 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 inner 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 tags 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 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 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 non 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 a 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 constru 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 a 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 the quickly 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 yes 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 unguard 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 ALS so switch back to job card wide 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 not 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 your fingers and the page is loading now you'll notice of course we 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 seaters job seater 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 three three 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 attached 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 choose 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 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 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 let's do this I'm going to come back to our job theater and we know that in some cases we could set featured to false in 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 takes this shape new sequence and notice that full import there I'm going to provide a sequence of um parameters that I want lell 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 override 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 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 to 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 Three 6 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] 43 [Applause] [Music]
Info
Channel: Laracasts
Views: 3,849
Rating: undefined out of 5
Keywords: web development, php, programming, laravel, laracasts, jeffrey way, coding
Id: NGB1sIvM4Ec
Channel Id: undefined
Length: 34min 45sec (2085 seconds)
Published: Mon May 27 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.