Laravel "clean" architecture - episode 1

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hello everyone and thanks for coming today um i've had a bit of a break been i took a week off and i'm back and i've completely different layouts i'm a little bit confused where everything's going when streaming i've now got my big monitor over here a monitor here which i'm going to be you know sharing and looking at when i'm coding which has got my camera above it and i've got a little monitor down here so i can listen to music at the same time fantastic my wife is very good to me isn't she thanks yeah thanks i'm very happy to be back and today we're talking about clean architecture in laravel um we're going to find a balance between um the right way to do things and good developer experience we're used to now i'm not gonna go into yes she's very very good to me it's my wife she's very good to me too good to me sometimes she spoils me um yeah so i'm not going to go too much into like detail i'm not going to go into like any theoretical this is you should why you should do things i'm going to kind of basically go off best practice and we're going to see what we can do with a laravel application we're going to start with your standard level application we're just going to kind of quickly bootstrap something up and then we're just gonna you know refactor it along the way hey all right so clean architecture the idea here is that you have your entities you have your use cases your controllers and then you've got your web so the idea here is that everything's kind of really segregated this is also like the onion architecture as well uh similar to um hexagonal the screen reads so many different architectures you could possibly use the right one to use is always very it's kind of up to you really what's going to suit your use case most and what we're going to do is we're going to build a um a basic kind of api i suppose it's going to be a why is the music paused keep playing um it's gonna be a api focus on the application i've not built anything yet i've not started a laravel application yet so before i do anything we'll just get started with let's get a laravel application on the go so um let's just zoom in there is a fix coming out for warp which is going to fix this actually it's coming out the next couple of days i was talking to um one of the people who work at warp today actually and they assured me that it's coming to be fixed so it's gonna be cool gonna be fun uh i'm basically gonna build like a multi-blogging platform so you can log in you can write a blog um how about what have we got in here anything useful not really so i'll just go live out new let's call it php online for now um um what we're going to do we're going to make this uh jet stream compatible but when we build i'll build the front end eventually but when i build the front end i'm not going to build it using um inertia or live wire so for back end app it's going to maybe going to have a few live wire components we're not going to have teams we're using it more for the sake of using it right now and we are pretty much done so what i'm going to do i'll also open up table plus we create a new database quickly we've got a patreon like yes i've got a php online um php online api let's call it that there we go so let's just go to um there's the api i'm just gonna close that connection because we don't need it and then over here we're just gonna start to get this all loaded so code sites php online finish all right let that load a second in the background it's appeared over here on a different screen so here we go we have a laravel application i'm actually using a laravel valet valet is fantastic and it just works really well for how i need it i do have docker available um but mostly what i use docker for is actually uh workbench believe it or not um so if i i don't know if you've seen workbench but basically i can come over to this project i've just created and say okay i want to make sure everything is psr 12 but before i do that i will um get in it add everything let's say that's the default install yeah for windows use laragon's best thing if you're on windows to be honest um so his docker docker is running it's analyzing the project it's just going to psr-12 everything for me in the background and i don't have to worry about it so now i can say okay did you actually have to change anything yep these are all the things that's changed and what you can do is if you go you can go view the non-white space changes as well and it will just show you but i can go through and do um things like hype hints this is one that i like to run i like to run this every time i start on your live project to be honest um i download workbent uh i've got workbench to download my project and then i just run all of these things and it just it does everything for me it's great what more could i need um you know i'm now adopting you know tight pins everywhere with very little effort and there a lot all of those type hinted now perfect no no worries no pressure no no nothing and this is where we've created a new commit and we'll just say something like a workbench to the rescue because it saves my butt a lot so let's api test for laravel what do you mean by best api test the best way to test apis or the best api you can test against there are two different things yeah i i'm quite a fan of um using docker if i've got to have like loads of weird very specific requirements as well api testing well i'm actually going to be covering some of that today so that's quite handy what i'm going to do is i'm going to make my code full screen i'm just going to focus on the code so let's get diving in oh and by the way lara con t-shirt is awesome it is the coolest design yet and it arrived the other day i'm super happy and it fits it's quite nice which is you know when you're just 32 year old man and you start to put on a better weight finding a t-shirt that fits is always always nice so let's enter in our details here quickly and this is basic basic laravel stuff now so what i'm going to do i'm going to bring notion over because i need notion more um i don't need much more than that then where is everything am i organized now i'm organized right so if i go to php online dot test perfect the first thing i need to do is session driver i'm just going to stick that to file now we've got laravel yeah we can only say 32 for two more weeks i am almost almost 33 i'm getting old aren't i um it's painful beam it's old all right so the first thing i do in any layer of our project is make my basic changes and my basic changes is always okay do i need to do anything to that user model and typically yes i do i like to edit the user model slightly so i'm going to start by coming to the migrations here's a user's table and the first thing i like to do is probably if you've seen my streams before you'll notice that i like to declare strict types i'm hoping they create a shift for this soon because that would be amazing i also like to make these anonymous which is also really simple to do i'm just going to close that terminal because i won't need it and i can drop the comment because it's not needed and there we go and the first step on here is i don't want the team id not useful for me um i'm going to add unique string on here which is kind of i use for like model keys i've got a specific package i use yeah we've got us we definitely got to start a strict type flying club and then we'll just start here we'll add the first name i like to split these out because you can start to be a little bit more personal in the ui um if you've got the opportunity to it's great you know some people who've got double-barreled names or um so anything like that or maybe they signed up and you know you signed up with twitter and they had a different name and you also pulled it in it's if you don't like assuming people's name sometimes it can be a complete pain um stricter types are better exactly um and then also what i'm gonna do is um just down here i'm just gonna add and one more thing i'm gonna set this to be nullable and i'm just gonna set a theme for the user that's like um not dark mode like mode it's not their preferred mode that they want to see it in it's going to be just something for the front end later on that i've thought about but i'd like to do and then obviously i like to make sure things are soft deleted that's it so now i can a bit of a user model let's start to tidy this one up so we can declare likes what i'll probably do i will obviously work on the stubs for for laravel stuff as well is when i'm wanting to generate a lot of things and then at the very beginning work number scrubs is always always useful um so what we need to add in here we've got the first name and we've also got the last name as fillable and we have the theme and we have a key isn't like an api key and what that will be it'll be like um random key like that basically for that specific model so nothing else we need to change on that um anything up here that isn't being used must verify email i'm not going to worry about right now i'll come back to that that's looking pretty good there's our users all ready to rock and roll i i i'm i've always been a fillable sort of person um i you know validate my requests i'd validate all along the way but i still i can't do you know guarded is nothing i've gotta do something and i've got a um i do have an alias set up for artisan i've got a migrate and there we go that is everything up we've got my users and there we go that is our database setup um the next step is another thing that bugs me is these i for me these have to be in high order it's just one of those things um just keeping my code clean um then we've got soft deletes which needs to go above the api tokens um and then let me a packages so i have got one somewhere where is it it is laravel something or other there we go my packages um none of these one of these um it is re there you go key factory this is what i need i use this all the time simple that is now installed um i can obviously then publish some config with my config and then using the key factory on the string helper what i can do is on a model i can just say this has a key so up here i'll show you i need that anymore another key and all we're doing this is basically where we're booting the trait and when we are creating this model we're going to tap into that and we're gonna get the class based name for the model push it all to lowercase and get the first three characters of it prefix it with an underscore and then we're gonna pass that all off to the string key which is a macro for this package which all that does is takes this string and then prefixes on a random amount of characters on the end super simple super simple stuff um a really easy way to add something other than like uuid that aren't as friendly so what you can do is and the config in the key factory you can set the length of that key to be like 12 for example um so what we will do to see is come to that user factory let's just clean some of this up while we're here again let's uh ask quick types um clean that up a return pipe on there that's returning itself good personal team don't need because i'm not using teams then if that's verified we can do that i always remove that and use the hash facade for this part and we say we want to make the password like that um and we can set that first name over here the main purpose for the declaring strict types is um it's for those occasional cases where php can get a little bit of type confusion um it catches those and enforces you to do you think properly basically it's like nope can't do that it's like a almost by inbuilt static analysis almost it's not but it's almost so there's a user factory and what we'll do we will create a seeder my my general rule with laravel is um every time i touch a file is i add street heights and i try to make the file better in some way so i'm just going to quickly make a seeder called default user seeder this is something i do in every layer of our project which then i can say this call we're gonna because we're php eight we're gonna say class and we're gonna say um default user seeder class leave that anymore come to here avoid zooming a little bit let's what we do here is we say use a victory create and specifics that i want to pass through so the first name is going to be me oh can't spell today steve then the last name is going to be my last name then the email [Music] is going to be my email i'm not going to worry about passwords i want my password to be the default here as well and everything else i just want to be default so now i should be able to i'm in the right place cd php online a db seed run database seeded so come back over to our database here we go we have got a user with a random randomly generated string and it's all just set up nicely nice and simple nice and clean done users sorted that's our bit done so that is our user's setup and running from a date perspective so this is where i typically add another commit and say usually modeling done i always start with like that data modeling aspect and it just makes it really easy to do anything so that's my users the next thing is i'm going to want like posts because i'm doing this multi blogging style platform so i'm just gonna a make a model and i'm going to make a post model and i want a migration um and a factory so minus m make the migration minus f makes the factory you can you can go really in depth with some of the flags that you add on some of these commands by the way if you ever get chance have a look through them it's really cool so first thing come over to here and we can first thing is just okay let's return a new new class a new anonymous class add some declare strict types and return types because this is more of a way project i probably won't get around to doing everything i want to do that's off the loops because i like softer loops yeah i i do i always like to in the so i see what you're saying there mark so typically what i would do within the cedars here is um sorry in this part here is i would only usually do this is if app environment and that um like local for example so if we're in my local environment run the default database c user if i'm in staging i should have already run it don't run this so i can really control the environments a little bit more so posts we've got a key again so let's just go through it this way nice and simple and clean so table string unique key yeah so very very um oh the benefits of using anonymous logo yeah okay question answered thank you very much people listening okay so um kaikou needs to be unique yep and nick is again with slugs um now what i'm gonna do with this i don't know i don't really want that many uniques on the table but i know title maybe not we'll have a look at this so we'll talk about the reasons behind it as well so we've got title slug let's get the body in there so table medium text of uh body and that's not nullable because we always need some content no because how i want to build it i want it to be nullable then we're going to have people text description and nullable and then finally we've got the table boolean for published default is false and right at the end we're going to have a table or an id user id explained on delete aids i'm pretty sure before constrain i can also say next effect um so what i'm doing here is uh creating a user id hey isaac um [Music] i want to create a user id i want it to be indexed i want to constrain back to the user table so let's have a look at that constrained table it's going to pull the table based on like the name for yeah create a fine key concentrate on this column reference and the idea column of a conventionally related table so users for example and then when we're deleting this we want to cascade that simple so what i do typically in my um migrations is i group things reference referencing so that's the database referencing for the id and api referencing civic key but identifiable columns content columns booleans um i grouped together if i've got any json columns i'll group them together um and then obviously at the very end before the date stamp time and date stamps that is where i add all my foreign keys so i'm grouping things very specifically i'm not going to do scheduled publishing um this isn't really about how to create a publishing platform it's more about going to be about clean laravel but i'm creating that base level first so this is how you create a laravel application and then we're going to look at how we can clean a laravel application so here's um my posts and then we will come up we'll come to our model we'll get the post model here and what i typically do is i usually put these kind of side by side airstrike types we've got a factory we're going to say use soft elites we're also going to say use has e that's all we need for this what's the use and need for psr12 so psl12 it's the code formatting currently it's psr2 psr 12 has extra rules so what you'll notice in a lot of laravel applications is we will chain our traits like this and that is perfectly valid syntax for php and it is psr too compliant however psr 12 will change this so if i um come back to here and just delete all that and code format psr 12 and run it this should in theory set everything back as an example and there we go we are back so that is one of the things for psr 12. it it's it's an enhanced code style psr that's all yeah i i'm not sure about the foreign four yet um i haven't used it it's still new i'm still getting used to the foreign idea if i'm really honest um i like things quite declarative um i like the fact that i can do that right now um that's the limit for me for the moment i think and we're gonna have protected um fillable the only thing that bugs me currently is that i can't do that but we'll get there laravel 9 should allow us so we add in our key add in our title we add in our slug our body our description list and user id so what we need now we need slug so we need to create a use has slug well so that is our next next portal call basically but before i get there i will add the quick uh casts so casts are just a nice way to say this is actually um an array or this is an integer or this is a brilliant for example pretty sure you just like billion out of full that's what i've done in the past um nothing else needed no that is all good i probably might look at custom cast later for the body section here where i might look at doing custom casts from markdown to html of some description but so that is that next step so the first thing i do is i create a inside models i create a new namespace called concerns now this is following the laravel convention laravel called traits concerns so has factory if we click through to that this is a concern it is a trait on and off for eloquent so what we will do is we will grab the has slug and we're going to create a new class we're going to set this within the app models concerns has slug this is a tricks and go and that's it that's the start of it so we'll declare strict types and the first thing we want to do is public static function boot then followed by the name of the trait itself so what you what this does is it will tell let me import that now sorry it would tell the eloquent model okay i want to be i want you to run this method when a model is being booted which allows us to create multiple static instances so within here we will get eloquent model as model and then we will set the model slug to be okay so model model slug so let's see if i can if i drop this down onto a line will it make a lot more sense for you uh i should do so when we are booting run this call back we want to automatically pull in the model because we are um sorry that's not boot um creating isn't it my bad um creating we want to get the model slug and we want to make that equal to be this logified version of the title basically very simple oh sorry you wonder how that bit works so that is um bravo shift shift workbench it is a desktop application uh download for free there's lots of free shifts you can run and then there is cloud-based ones there's um some premium ones in there as well and it's basically just a really great way to well i'm even i'm on there as well um it's it's a great way just to manage bulk actions on your code bases basically and if you're working more than one project super super useful all right back to this part so that is how we're going to do that uh has slug that's working has key that's working um one thing i'm going to do is i'm also going to make the title unique too because otherwise we're going to get issues slug doesn't actually need to be unique if a title is but i'm going to keep them both unique for now um again i'm not going about perfect database design i'm just going about clean architecture within laravel so here's our basics we have got a user who can have many models so i've got the database ready to go migrate next step let's go look at this model but at the same time we're gonna have to look at the factory as well so replace factory so let's put the post over here there's some script types let's start working on this definition so have a title so we can say this faker um we'll just go for something like words and we you know we want our title to be x amount of words we'll just for now we'll say five words long and we want it to be as text i'm not going to bother adding um different namings within their slug we don't need to do body so our body is um the content itself so this faker can we do markdown we're trying some random html see how that comes out and then this scription [Music] doing steve don't try to think too far ahead faker and then this is we're just going to have like uh like two sentences of text for that realistically i would usually cap this out at maxine at 120 because the description is what i would use for meta information as well but for now it's fine and then we'll just say something like this faker you want a boolean a chance of getting um actually just leave this boolean i'm gonna make it balanced it doesn't matter coding like a designer yeah a little bit um so the user id so [Music] laravel factories have got a really cool oh model factories what we're going to do let's zoom in so here's a user model factory there's a definition you can create one there's a model factory states you can create current state callbacks user factory after making after creating instantiating models applying states overriding attributes connecting persisting to do there was something here here we go factory relationships um yeah i i usually would go for a published attribute um but for now i'm just gonna i'm gonna do things slightly differently which you'll probably see in a little while um belongs to relationships oh you can do like a four that's kind of cool magic methods pivot tables okay so we'll stick with this for now user id um wouldn't worry about just yet and what we'll do is uh there's a factory and for cedar so we're going to ignore this for now and we're just going to say that's how we'd like to do things but how we're going to do it is we're just going to say for this stream we're just going to do something really simple like post factory um we are going to create let's say 20 for go back up to that before i'll see how that works nicely um so like for user user factory create that's kind of cool i like that i do like that let's just grab that default user so just going to create 20 for me see how this works hey fine line here between being useful and not being useful and then we'll just say create so this in theory should allow me to create 20 factories for this user so we will migrate fresh and seed and it's failed for [Music] post model user okay so relationship time so our user needs relationships so user has any so this is where we can say this return this has many where the related class is the post yes and the foreign key is user id that we're going to be looking for we'll see the local id is the user id you don't need to change that um especially if it has many and on the post we will set this one as public function author and this will be a belongs to and then we will return this belongs to the related is the user class and the foreign key is use that id again there we go problem solved [Music] query okay so because as author let's swap that over to user let's see that's failing too for some reason let's see why it's complaining slug doesn't have a default value insert into posts so that is telling me that that is not executing as expected so way to get around this because i've bumped into this before is you've got to do it like this sometimes i i don't know whether it's a burger whether it's by design but in some sometimes in factories if you've got um breaks that tap into that boot part of the model it's it doesn't always execute the way you want it to [Music] so what i would do for now i would just do it that way and we'll just run it again and now we're good so if we come back here we refresh we've got user and posts all for that same user and they're all some are published some aren't that's cool that's fine got some random html in there for now that's good that's that's all i wanted for now so hit add git commit i'm just gonna say post data modeled and that's all we need for that so now we can close all of those tabs and now we can start looking at the interesting stuff so that's basic laravel the first step in to me in creating clean laravel um is you can look at service classes repository classes you can look at you know abstractions on abstractions on abstractions they're useful don't get me wrong but the first step is always let's look at our structure how we're doing things and the first thing i want to do is um let's create a couple of basic routes that we can then test against so we're going to create some api routes because we're building an api so what i typically do let's save that this is how i build an api i come down to the service provider do that we will drop that i need any uh that and we don't want that so we've got this web that's fine that bits okay this i don't do this this is not what i like to do so i put this after web first thing i do is i will go route with creating a group within here this is going to contain everything the first thing we want to worry about is okay let's put the main prefix okay yep everything within here is going to have the api middleware i can live with that not important right now not important and then okay i want naming to be done as well so api colon done right great now i can start so e1 weeks this is where i would say root prefix b1 we want the name sorry that as could be now be b1 whereby that in the post model factory would this work for the slug it might do i'm not i'm not too sure i don't play around them too much to be honest yeah definitely something to look into further down the line i think um so this is our api roots we go uh v1 for our api we give it the name we don't need anything else so we can now just group and then we can say base pass just like down below say that the base path is roots api v1.php which means we can just drop that so if we want to see that as an example let's come over to here list and find it perfect we knew that would happen first thing to do is in our roots we can create a new directory it's called api and we're going to move this quite simple refactor move that into there and then it's going to quickly rename this as well we're going to name that v1 and v1 loaded so if you want v2 you'd literally just copy that block over so now if we come over to here we list we got it done done done nice just what i wanted and it's nice and clean so it's also very understandable you know here's my web roots my api roots all within here is version one of my api here's version two of my api hey roberto um and it keeps things clean it clean things organized so here's v1 so let's say we just want to get all um posts so we will add a prefix posts we set a name for it so posts go on and then we'll just for now we'll just group eventually we'll be doing something like authorization and authentication and that sort of thing but right now let's just look at this so we are root prefix posts given the name here's our post roots so the first one we want to get requests to get all posts so we can set a name on this one and we can say just call it index so what this is going to transfer to name wise is we can say root api v1 posts index like it's quite simple that is how you would then display that it's quite nice no i i really don't like um api resources personally i like to i like to be declarative in code um but also i like get as much control fine grain control where possible so what i'm going to do first is we're going to make the controller so a make controller missing the api i'm going to put this in v1 hosts index controller and so what we will then do is um app app http uh controllers api if i capitalize the api now i don't usually know so api b1 hosts next controller done and if i save that now what i'm going to do is let's see what psr12 makes of that line because psr12 and psr2 complain about character lengths on a line in php it'd be cool if i could run this for a very specific one he changes no he's just got rid of a gap that's fine if it if it's if that's psr 12 compliant that is fine so we're literally just going through here so we can click through we can declare strict types um extend controller invoke and we will get the request in here we might not need the request but we will keep your requests so what i should be able to do now is api v1 there we go sorry basic laravel [Music] is to do it this way here are all my posts why index controller instead of post controller so that because we are in the post namespace we are versioning our resources through the api so um if i want to then create i i'm setting a standard i know it's going to be restore controller while i'm storing and persisting um just convention that i've found really works well and once everything follows this pattern it's very easy to find your way around an application so here's the basic turn post all our next step beyond this is let's um let's look at um making this better so a make we are going to um make a request we're going to make a form request for api under v1 uh posts no making a resource sorry not a request i make v1 resources and we'll create a first resource now come down to resources down here we return something usually an array the next step is just to return like that so instead of returning this you can return a fixed resource collection and the post all like that and that's not much better yeah it's okay so i'm doing something very very slightly different but i'm not doing anything that's you know not doing anything useful oh sorry i was having a drink there forgot you couldn't see me um so we need to level this up right so the first step on leveling these parts up is to control how they return so is that we're not bothered about that and i automatically just jump straight into json api at this point i say okay so the id for this specific resource which i want to keep to the api is going to be this key um type is going to be a post and we start to get into attributes and so if we have a look at a post itself we know that we're going to have a title which is going to be um this title and body is this for the description it's again this description [Music] and then just published is it's nothing nothing crazy going on here no we're just controlling a little bit yeah so your internet didn't die it was me having a drink and i forgot to mention it and you know we'll start um relationships we'll add our relationships within there and then links a link to self we can if we go look at this we can hopefully grab that that is what we'd want at that point so now if i come over and refresh um that's not quite what i want um eventually that'll be show and then that would have this key within there so to do that i need to come over to here quickly and we just need to say that the public can get rich key name let's just clean this up quickly it's a string we're just going to return key now that's simple isn't type you are correct i do apologize i showed it's not exist that is fine because i can make a resource not a resource a controller and then i can quickly come through and say create the show controller now here let's zoom so we want basically that but instead we are going to use key show controller okay refresh uh invalid reaction okay so i need to come through and just quickly invoke i'm gonna take in the requests we go okay that one that would show it it's not nice easy thing there we go and then what we can do also in here if you really want to i think it's like a parent which is where you would have the index so when you're viewing that one you can see the apparently you can go back uh yes so the reason i'm using key over id is that id's internal reference key is external reference key is um this is for foreign keys this is for referencing uh in the database this is for api referencing some people would use uuid in this this part i'm using keys because i prefer it to be this way it just looks and works for me um but that's just that um okay so that part's kind of super simple let me close safari why did you open up um okay so we've now getting posts which means we can look at testing okay how are we going to test this let's get a press php obviously i'm going to use pest because i like pests and we like to his best they're gonna be quicker to do it on this screen let's just compose or acquire pests um on laravel require that one and then we can just do like a pest install but to do that i am going to delete them and delete them quickly yes obviously using warp i have i've been non-stop using warp it is fantastic i like how um everything instead of like um like on a normal terminal everything goes down the screen and that's fine and we're used to that but this makes a lot more sense to me keeping that flat to the bottom and just seeing things scrolling up the page it feels like you're doing something more probably just me i will disturb you so there we go so pest installed so button test unit not sound that's fine we can create that next so new directory unit test if you're not found it's fine i can do that too um wait a minute wait a minute pp unit is doing it because of this exists make sure i can vendor bin test in it cool i know it kind of like a shortcut there there we go oh yeah i i'm loving loving warp at the moment it just it works for me i just love the fact that i can go to this i can say share this share this block generate the link and it will just share that exactly as it is a screenshot it's fantastic that it just does that um i was actually talking some today about some of the features that they're working on and it's super exciting to see what we're going to be doing so i'm just going to create a api v1 [Music] and we'll just go for like um equip file my bad and then moving here we can do something like um test test case target um api don't need that use that that's fine using using these there so we should be able to test it correct because code for example a very simple basic test for now um get it the iv one hosts index status and i'm going to set the status in a second but first i want to uh composer require that one not that one that one there we go which means i can now come to say here and say http not the facade but my package i could say okay that one and it gets killing status codes done so let me just delete that example test because it's not needed uh simplify that one too that's a very basic test here yeah warp it's in closed beta so um i give out invites every now and then i don't know if i've got any i've okay request more i i've asked for more request more invites i can invite more people uh please be patient um so there's a basic test this is just so that i can refactor for now um you know i'm not doing a a stream on testing there's enough people streaming about testing right now um yeah i just want as i'm refactoring be able to work with this so step one in creating what i call clean laravel is i create a source directory this is where most of my code will go my custom code and what i need to do is in my um [Music] create a domain there and we will create a [Music] blogging domain a models we will also have a shared domain that's things that don't have a specific domain for it it's like like users or anything any sort of meta models that you've got going around for like type this or type that um then we can come over to composer and what i typically do at this point is come down to my auto load we want to autoload that but we also want to load in domain so that means that um we're autoloading the domain namespace from there basically and then if i want to create another one within there i can create another namespace within there and i can start just pulling things in the way that i want to yeah it's it's a little bit um domain driven design yeah no share your twitter tag um if you've if you've got invites share share away more people who use warp the better it's going to be in general so that is that part so first step is this is why i use php storm by the way i can come to here i can come to a refactor move class i want to move that to domain logging models which is somewhere source domain blogging models open effector do refactor that has now moved that blog so there we go that model user will eventually be moved as well so let's now move this one so we can now refactor move class shared models which is going to be source domain shared models once you've moved a couple they start to kind of know that where they're going so and this can we factor or a slug can move class probably easier so move class we're going to move this to domain chad models and sons come down to source domain shared models contents protector do the refactor jobs are good and come back to here you can see domains have been split out so if i run again we are still passing so that is step one start to move things to this nice domain approach which means we don't actually need this i will keep that because i have i don't update the migrate command creating the make commands so they always auto populate there something i should probably do i should probably make a package which does laravel the way i want it to but we'll get there we will get let's close all of these so next step is our posts are going to have various queries available for it so our models are also going to have builders within here we will have a new class called a list builder namespace is going to be domain involves blogging models builders and this is going to extend the eloquent builder class there we go looking good simplify and if we come back to this i always put this at the bottom at the very bottom new eloquent builder instead of returning a new eloquent builder i can return a new boost builder that is going to take various arguments allows me to do that nice and simple you all can be added not interested um so what this allows me to do is instead of putting scopes in my model it means i can move them all to this dedicated class here um so publish for example if this was on the model i'd have to say published this would return a builder instance it would do this it would do that and then within here we'd do a query but because it's on the build a build custom builder class we're going to say published we're going to return self then we can just say like this return this where first and what i like to do here is if this doesn't work yet last time i tried it so function not published um i will call it graft which is basically where we're doing this there we go very simple um we've got published and we've got draft all lined up all queued up all good to go so now if we come back to our app http controllers api for index controllers we can swap that to a get and we can say when you get published perfect hey what i'll do i will um i'll paginate as well yeah we'll paginate to three so as you can see with total 12. um and if we just dropped that you can see 20. lurking again rich thanks for thanks for coming buddy um so that's that's like level two way to do things i'd call it collection that is gonna take the um resource and that is you know the next level of nice clean laravel code um the next step is to move on to you know uh we will return a [Music] response use json and this is where we will have the data as this this is how i actually build api's um i don't go much further than this the status to be okay because i can delete that there we go nice and clean yeah scopes and models get really busy really horrible really quick um one of my quotes that i made up is at some point your laravel app will turn you know your model will get more scopes in the game of call of duty and it's true the more different queries you want to create no helper for response i i i like doing it this way at the minute um and then i obviously it's a response that's it to me that is clean you know but there's not much more i'd want to do with this um other than user package getaway calendar um my mouse has got a mind of its own so let's try this composer require rc avail builder this is a package i typically use when building apis because it allows me to say posts pre-builder for this subject is the post model and we will allow concludes that accepts an array or a string of some description so you say okay we're going to allow user and that's it and then we can say published as an h c and then instead of doing that we can just say that's it and then obviously at this point we can say include user currently not hooked up to anything so that's my next step it's not a bad way to do it i i'm looking at better ways i can do some of some of this let me go and a um okay resource user resource it's going to create that user resource quickly uh resources down here here's my user resource i'm going to keep it standard for now obviously relationships is going to be um the author is or that user is going to be this then loaded user we will return a new user resource this user there we go if that's not included okay that is just ignoring me this is loaded relationship user this one loaded blah blah blah this user that is being extremely strange let's have a look um at the docs make sure i'm not doing anything slightly wrong api resources make resource resource collections to an array collection keys writing resources relationships resource collections i did but i've also removed it so um it's a chasing resource wrapping nested resources wrapping pagination pagination conditional attributes um conditional relationships this is it okay so other way around you get this long every single time so basically we say this um basically this we're going to create a new user resource this then loaded there we go and then if we come here and say include user we include the user this is why i like this package because then i can do things like filters and sorting um can you add no no i i did so what that is doing is let me explain this part maybe a little bit better for you is we're allowing includes which basically what this is saying is anything anything here is going to be a relationship name so for example if i say include something we're getting requested includes are not allowed allowed includes our user and user count so we're only allowing users and the count of users for example so it's it's a way to include relationships using the uri parameters instead of um manually forcing them or doing any sort of messy code like um you know doing that later and then say the way i did before this package was is if request has um includes then i would i'd have my query at this point and add query with and then i would explode my comma and like request get um include that's the way i used to do it and it was it was fine it worked but sorting i'd have to do you know three to five lines again filtering three to five lines and it all adds up when i can use this package and it just does it for me and it doesn't make my life harder it makes it easier you know to me that is the right use case for a package it makes your life much easier and obviously sparsi is well tested and it works well so let's switch that back to user i've now got my user uh nice and clean nice and easy obviously eventually i'd polish that resource and make that the way i want it yeah it's a great package when you're building apis you can do things like so beds allow includes allow sorts so um i don't know sorts i drop this published for example allowed filters say filters basic filters is we will have on published example i i how do i document my api i actually use open api unknown names parameters okay so um i'll see ravel query builder let's just quickly go to docs and let's go filtering basic usage allow filters so we're just gonna do that published it's true [Music] done yeah maybe you want to you know an easier way would be to like do some sort of search for the filter where you know you're doing a can will contain all users with john in the name um disallow filters exact filters partial filters scoping filters so i could do something like this instead i could go import that class and we say published then we could actually do the exact same thing and say actually we also want the draft to be included so so let's come back and see how this works published and draft working something to play with but i don't use filters often if i'm completely honest um i use sorting and include mostly if i need to filter resources i do that client side typically but if i really need to i can go through that so um that is that step uh so this is an api um if i was to build this in any other framework um slim php or something without eloquent and the power that eloquent has given me i would create a service class i would create a repository i would add those abstractions so that i can switch between database drivers and providers really easily uh but eloquent's done that for me you know i'm swatching swapping from postgres to my sql laravel handles that i don't have to worry about creating my sql interface or a postgres interface and then in my dependency injection controlling which one's being loaded um i don't have to worry about that at all um which is nice so clean laravel is the cheating statement i suppose is laravel is clean anyway um it starts off very clean so you don't need to do much with it um if your application doesn't get bigger you can start following different patterns like i do here um i've got source domain over here yeah i can finish with some crud let's do some crud okay back that'll explain things nicely so roots api v1 so let's look at how we can create a post i'm not going to worry about authentication every stage it'll just slow things down so we'll do a post do that home route now let's have a name could be it's full and what we would do is a make a controller and we're going to create a store controller which is going to be nice it's full controller you get our functioning break pull in our request it's all set up yep cool so here is where we'll create something you want that is all hooked up so what i am going to do is um let's insomnia quite quickly see if this will look nice on the screen for you wow no it looks crazy for me um it is gone super super oh full screen on my massive screen over there so uh bear with me a second while i get this onto the actual screen that i'm using did you there we go let's bring you over here let's just get a dashboard and let's just create a new one a new request collection and we're just going to call this um hp online for now because that's what we're using for calling things then here right so a new request um create a new post hp online dot test api v1 posts and the headers we are going to say accept you want to accept application json back and the content type we're going to send over is application button and then the body is going to be jason so let's say that our title is going to be test post our body we'll just sit with title to start with this request send it perfect we are hitting it we know we're hitting that so store controller first thing validation super important so eight make best this is api validation for version one is for posts this is a story store request done it means that here i can swap that to be a store request for that class and we can quickly validate so if we come over and try and run that now action isn't authorized let's clean up our code here we want to allow this action and here are our validation rules so all we want start with a title is required must be a string and it's got to be unique on posts under the title we are passing that so let's say something like um maybe an integer something silly yeah the title must be an integer so that's not going to work so keep that as a string that's fine um but we also need to because we're using string now database we go to our database quickly here post structure title got a limit of two five five we're going to make sure we've got that yeah certain things can get added to the php storm hub but you need to add things to your laravel stubs as well so title we know we need the title so let's come here and let's just um i don't know the post over there so title is required all the time um body is nullable when it is required it's got to be a string that's all the validation i'm doing for now description also nullable gonna be a string and because we want to use it as a meta we want the max be 120. uh published not needed at this stage i'm going to publish slightly differently so that's it you know if i send that request that is working i can then send over the body which you know will eventually be something like markdown and it will be um and then we'll pass over like the description meta description for example i would pass that and that's fine that will pass as validation as expected so then we are here oh that's a hard question berno it can show a spinning wheel for many different reasons typically what i do here is authorize you know we've authenticated at this point we would then do can this user create posts basically uh but because i'm not doing the authentication section right now i'm not going to go through that but typically i'd authorize and that would be this authorize and this user eight just basically then you do something like uh you do stuff like that can this user create a post or can this user with api token which i will work on api token specifics later so can can we do this action then we want to actually create the resource itself then we want to return so let's practice with laravel and best practices with apis in general authorizing the class why not root level to keep the controller a bit cleaner that's a good question so i don't do it in uh i don't like cluttering up my roots my roots should be for rooting only so putting extra things in there beyond just middleware doesn't make sense but it is a good question um but here is where i would do a um like a um a null response say something like um jason data null status is http it basically we've accepted your request because we're going to look at creating it basically hey there we go accepted we've no data to come back at this stage so creating the resource this is where i do things slightly differently so i'm quitting here's blogging within here i will then create um i don't call them dtos i cover them value objects what they're traditionally called so kind of what i stick with and within that we will create something like a a post value object really clean really simple um and we'll come back to that in a moment and also within here we will create the factory for how we can create them agrees and this is where we will create a new um post factory again we will come back to that and then within here we will also create actions so step one the the value object first thing let's add the namespace and main blogging value objects again in here name space domain logging breeze so public function construct this is our object we're going to have a public spring title we're gonna have a public nullable string for the body which is gonna default no and we are gonna have a description which is also going to default to known that's it this factory is this is in charge of creating that so public function pick function 8 we're going to get an array of attributes and we're going to return a post value object then new post value object where the title is the attribute title then the body this is where php looks it looks amazing because it just looks it's smooth doing it this way here we go we can now create a post value object so create the resource it's going to work pretty well actions so we need a classroom in here and we can do something like a create post this is going to have domain blogging actions and then what i would do here is a public static function handle oh this needs to do something basically this is our action we are going to x this create post is going to accept a value object which is going to be the listvalue object and it is going to return a post and this is this would usually be a service class but yeah it's specific it's an action classes i only want it to do this create a post only that's all i need so i can say return host yet um come on steve what are you playing at uh the cycle is going to be x circle uh the body is going to be object body of a description is the is object description and that's simple that's going to return a post create the resource i usually if this is an api that's going to get a bit of scale i'd push this to a background job but typically what you can do is um just say okay level one post is create post handle this is gonna accept an object and the object it's gonna accept is gonna be the factory v8 and that is going to accept attributes and that will be the request validated it means i can now accept post within there created done that is how i do it two array method in value object i can do yeah um so attributes is uh to to do i would typically do something like um do an array so turn this and then i can do um i call this title body this body description and then down in the action itself objects to array done it's a little bit cleaner so then all i need to do let's say um okay i also want to pass published status so this is nullable is a billion value that's all i need nullable and boolean then to extend to accept this public um we might pass nothing or we might pass a boolean say published and we're going to default to false so we can also go here and we can say published it's published done and then suddenly we're auto accepting it so now if we come back here field slug doesn't have a default value and certain posts okay so we are seeing this error again and that is because we've got the key and the slug on the same thing so what we can do is [Music] gonna merge two erase here [Music] this one it's fun right slug spr slug object cycle [Music] done um [Music] again use like these now in the default value like this for now so in theory this would be the authenticated user so but for now i'm just going to do that there we go we've got it and it works um and it's nothing clean i mean realistically i'd work on getting that to work and i'd work on getting that to go in nicely i'll keep that there for now just while i'm building because i've been going for almost two hours i want to make sure that i don't do too long with it um update was kind of the same um similar process so what i'll do i'll quickly do the delete and what i'll do here i'll just do this route it's going to be api v1 posts store and then delete to a delete request for boost on the key name is meet leaks click leaks show leaks and we were to grab that then we'd have a delete controller or destroy controller depending what you wanted to name it so make a controller i'm going to call it delete controller for now there we go i can then do that delete controller come up here declare respect heights anonymous delete controller for the public function invokes requesting don't need any validation on this one there's a json response um delete the resource then i will return a response where the arguments are content and status so null this is http put that one because we're actually doing a normal response json response we should be able to still do null and then we would just also accept into root model binding we would say um post post this what i'd usually do is move this to up let's say we've accepted the job and we will work on deleting it basically super simple um so what we're going to do is get the key for that a new one delete a post and say we are going to do a delete request on hp online api v1 posts there's a key um accept creation jason jason and accepted now we're getting a 404 because it's been deleted and that's fine i'm expecting that so super simple super clean super easy and someone's asked for update why not why not which i like to see patch requests typically view how you do it and name is a bit and we can grab that and we just create a bit controller run that out for now and we just go update controller and add the invokable flag just make life easier right then i'll be that and that would be update have an argument passed to it update controller so now we don't need these so basic types remove that so a make best make an update request there's my update request there's two that's boolean this is an array declare strict types and that is going to be similar to store request however the only difference is everything nullable and i'm going to ignore that for now usually what you do is um like this okay yeah you get the unique identifier basically at that point to check the uniqueness and say update it but don't worry about me i won't do that right now stated something usually you use no it's something i always use uh if if i'm accepting a request i'm not you know if i'm do yeah i'm creating something i return the http created if i'm deleting or updating it's accepted i've accepted your request basically um so there's my update request and then what i would do is typically authorize baked and then return so what we also get in here is the post we get our post to work with straight away so when we're updating what we can do is come down to here actions we can do a php class called post and again we'll have a handle we don't really we're going to have a post value object again here so we're going to turn the same instance of post back so we'll have a post blue object let's zoom in and then we will um have that but we're also going to have post coming in as well so what we can do is return post update object to array basically update updates i'll just be a full value i suppose yeah we'll keep at that that's fine um so factory is hit up post factory here's how we create it so uh um so client has to poll in case it's maiden job or how does one know if operation is actually done so that's a good question if if i'm building something i'm trying to scale i don't worry about that you know if i'm accepting you know hundreds of thousands of requests a minute to update posts um making the front end client make another request to get stuff back and you know stop any slow right operations on while using the api that is more advantageous to me so what i'm going to do is just something simple like created and update post handle and do do function handle then this is good to have the object and the post so object is summon and then and the post is the post so this is going to be the post factory create their attributes are a request validated and sphinx sphinx is just a search client um that's super useful in this case so this is where we'll just return a response um now we're just using like json where the data is a new post resource where the resource is a post and then we will do the status is http codes we'll say that accepted not that we go that's more like it so typically i'd push that to a background job um so now we just like post fresh really care about that part there we go that would typically be a background job i'd usually just do a another response here if i'm really honest so i'm just gonna do that content null status http update uh jason interested in that if i do a background job then we would return a box and it means we can also clean up that need all of those for now cool so yeah there is our update basically [Music] so then let's say we want to create a quick um update post request just create a new one again that was already been taken okay so let's just come back to here later and let's just is that and we're going to grab the key um update post and we're going to do a patch request to php online dot test api v1 posts there header we are going to accept application json and the contents type is application json and the body is jason so what we want to update is title for now and we're just going to update the title as test title updated done right a key body okay to do this is where we need to reassess things uh so maybe this is yeah this is where we need to be sensible because typically what i'd do is um i'd be using the client side to update this so have an updated body i'd be sending the entire object back we'll have the updated description to we'd send it like that and that's accepted at that point then if we refresh it's body everything's updated okay eventually that would be pushed to a background job um and if this was like a if this was an api designed for integrations external integrations instead of internal integrations i would build this slightly differently but this is pretty clean laravel you know um if we zoom out a second uh if we zoom in we you know if we look at this code block here we know these are our post endpoints very simple very easy to access index controller nice and simple store controller this is where we start to see the cleanliness we you know let's say we make a job you know this point we can do something like um i just grab that delete that post job dispatch that's how i do this and then this quick post here um spit kites with psr12 this sort the height order out because i'm very specific about art then would uh drop that move this over to here pull this up would have a public this value object as the object right there void and then this would be a post action handle where the object is the um this object uh import classes alias post action handle done yeah it's hey hey craig um that is that simple you know if i want to create one now i can come over to create um another test post or undivided variable post store controller that's fine so at this point we would just say um accepting a response and we're going to return response the content is null and the status is http okay so let's just fix that yet another test post accepted we were using sync it's already created it it's done good so then if we just go get all of them we would see all of these again and nice and clean nice and simple laravel lovely lovely stuff all published um there we go um yeah me rearranging you statements is uh one of my bad habits uh obviously we'd also lie still creating a post and this is really handy because if we're running a cli job to do the same thing all we got to do is pass it this object we have to pass it a million values um i wouldn't return the created resource typically um so rhian asks how do you return the created resources resource if you use it in a job like this you wouldn't you would just say okay i've accepted that i'm going to work on it in the background because the idea is doing it this approach means that you're worrying more about you know the rate of people hitting your api you're scaling your products you know people are sending these requests and write write operations for my sequel are slower so i'd much rather write it quickly write it in the background return a response and say call i've accepted this and then allow my front end client to then paul get the new one and just update his internal record of okay these are the posts that i've got allow it just to do it asynchronously that way basically that's how i typically do it and it keeps it clean um i am going to probably call it day there because that is two hours and 12 minutes my wife will think of falling into my computer um i will be picking this up again on thursday we will carry on with some of uh some of this we're probably going to start looking at um the authentication side as well how can authenticate with laravel through the api in a nice clean architectural way um well obviously when laravel 9 comes out the clean architecture approach is going to change because we're going to have a a query builder interface which we can use to start to do things differently but for now this is what i call clean laravel everything's got its own little piece lots of objects all working in unison to achieve a goal and everything along the way is testable which is the idea but for now i would like to say thank you very much and good night thank you
Info
Channel: JustSteveKing
Views: 18,311
Rating: undefined out of 5
Keywords: php, laravel, clean code, api, clean laravel, clean architecture
Id: THrqUvVLecM
Channel Id: undefined
Length: 133min 14sec (7994 seconds)
Published: Tue Aug 24 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.