Out of the box Laravel is configured for you to be productive immediately without thinking about much. In this snippet we're going to take things a step further and I'm going to show you
00:10
four things that I tend to add to every single project I create. These are pretty opinionated so I'm not saying you have to include them but in my opinion if you do add them to your projects you're going to end up with a much better developer experience
00:27
while working with Laravel. So let's jump straight in with the first one which is probably the most controversial and that is setting up unguarded models. Now to demonstrate this you might not know how this works. I've created a fresh
00:44
Laravel project here and all I have is a post model and a user model and you can see that these are related to each other. Now this post model by default when we create it it's going to look something like the following. So there isn't really much in here.
00:59
Now you've probably come across this if you've worked with Laravel for any length of time. Let's just go over to our web routes and let's go ahead and create out a new post. So to do this we're going to obviously reference the post model and we're going to say create and at the
01:14
moment I just have a title in here so I'm going to say post one. Now you can probably guess if you've worked with Laravel before what is going to happen here. Let's head over to the browser and give this a refresh and we get the add column to fillable
01:28
property to allow mass assignment on and then the name of the model. Now this is pretty standard because by default we are guarding all of the properties of a model so they can't be accidentally filled when we are taking user input
01:44
and creating a model. What we would normally do in our code of course we wouldn't do this and actually create this with hardcoded content we would take in the request data so we would have a request coming in here then we would go ahead and validate
01:59
this so we would say something like request and validate and let's just pull this in so we get our type hints here this will come from eliminate HTTP and request and then we would just pass in all the validation rules so for example a title here
02:15
we might say required etc. Now when we do go ahead and do this what we're going to get back is the validated data so we would typically just name this variable data and then we would create this with the data that we validated so we would just specify the data we wanted to put into a
02:35
model. An alternative way of doing this is validating as normal but then going ahead and saying request only and then just choosing the columns you want to fill in and this is either an array or a single or multiple argument.
02:50
Now the reason that we have guarded models is that for example we could do something like this request all now this is a really really bad approach and mass assignment is there to protect us against us doing something like this
03:06
so it is a kind of sensible default but once you've worked with Laravel for a while and you're pretty sure you're always validating and only passing in the columns that you want to fill you could pretty much ignore guarding within models.
03:21
So let's take a look at how this works so let's go ahead and just bring this back to the example we saw before with the title so just passing in a hard-coded title hopefully that makes sense we'll get rid of this validation here of course because we're not actually sending a
03:35
real request through and we'll go back to the point where we see this error. So how do we usually get rid of this? Well let's go over to our post model and what we would normally do is add this in a fillable array directly within here.
03:50
Now this gets a little bit annoying and if you're working on a project and you are changing models a lot and you're adding columns you have to remember to come over to fillable and add these in. Now what I typically do on almost every single project is I
04:04
either set guarded so I ignore fillable completely to false or I'll set guarded to the id because that's one thing that we don't want to manually fill in but typically I would just set this to false like so. What setting guarded to false will do
04:20
is just completely unguard this particular model. So now if we go to the browser and give that a refresh you can see sure enough that does work. Now it's not working at the moment because we're not filling in a user id we'll ignore that for now
04:33
but if we were to create this via a user it would work. So let's actually set this up so we're creating this via a user and in fact we'll just fill in we'll fill in the user id manually I wouldn't normally do that but let's go ahead and just do that for now
04:47
to demonstrate that this does actually work and you can see that's been filled in there. Okay so this is okay but there's a much better way and this is what I mean when you start another project you just want one simple command to unguard everything
05:02
so you can just get on with creating models and filling your database with data. So I'm going to get rid of guarded false from here we're going to come over to our app service provider or you could create a specific service provider for this we're going to reference the model
05:19
from database and eloquent and we're going to say unguard that is it that is one thing I would add to every new Laravel project. So by doing this this will take every single model you create have created and every single model
05:35
you're going to create in the future and it will do exactly what we just did over in that post model by setting guarded to false. So now if we head back over to web and we create another one here you can see sure enough it just works. So this is a controversial one because
05:50
you have to make sure that when you are accepting user input first of all you're validating it and you also need to make sure that when you're creating this out using request data you're not doing something like request and all that is a very bad idea it means
06:07
that any data can be posted through to your forms and it can be inserted directly into your database. So that is the first thing that I would do in every new Laravel project I would go ahead and unguard all models. Now with most of the things that we're
06:23
going to discuss we have the ability to set a state so what you can do is you can change this around per environment. Now for unguarding it doesn't really make sense to do this but what you can do is do something like is production or
06:37
it's not production so you can go ahead and control whether this actually gets set or not. Okay so we've looked at model unguarding the next thing that we're going to take a look at also relates to models and this is model
06:51
should be strict. So we use exactly the same thing model should be strict. Once again we can pass into here whether it should be strict or not based on some sort of condition. So for example you could add this
07:04
only in production or whether it's not in production so let's go over here and say not app is production. We'll talk about why we would do this in a minute when we go through each of the methods that should be strict actually calls.
07:20
So let's take a look at this let's open the should be strict method over here on the model and you can see that this does three things so it calls three different methods within here which you can use individually so if you wanted to chop and change out what you did enable
07:34
and what you didn't enable you can go ahead and do this. So we're going to go through each one of these because it's really important that we actually understand when we call a method what this is actually doing. So the first one is preventing
07:48
lazy loading. So what is preventing lazy loading and again you could call this specifically if you wanted to just to do that on its own but we're using this as part of should be strict. So let's take a look at preventing lazy loading so let's get rid of the example that we have over here
08:05
now we saw from earlier over on this post we have this relationship to the user so we've got a couple of posts in the database. I'm going to go ahead and rename this to post two and what we're going to do is we're going to fetch
08:18
all of the posts so let's grab each of our posts here and we'll say post and we'll just say get we don't really care what we're doing let's go ahead and create out a view really quickly so let's make out a view here called posts
08:32
and let's go ahead and return render that post view and let's pass down those posts. Now what we're going to do inside of this post view is iterate over each of the posts so let's say for each post as post and we're going to go
08:50
ahead and in here probably as part of our application output our post title but then we want to say who this post is by so we would access the user then we would access the name so we're accessing that relationship directly through the post. Now over in
09:05
app service provider I'm just going to go ahead and comment out should be strict and let's go over to our app and see what we get what we get here so we've got post one by Alex post two by Alex now what is actually happening behind the scenes here is we are executing an
09:19
mplus one query because for every post we are then performing a query to fetch the user of this post we can demonstrate this by just coming over and requiring in something like Laravel debug bar on our development environment
09:33
and if we just open this up back in the browser once this is finished we should see our query list in here and you can see we've got two duplicate queries for every single post and if we create another post we would have another duplicated query
09:47
now the command that we just uncommented here should be strict so let's just uncomment that here prevent lazy loading will do exactly what it says it will prevent us from lazy loading data which is exactly what we've done over here
10:04
when we've gone ahead and lazily fetched the user out we've not specifically loaded this up front let's go over to the browser now and give this a refresh and now we get an error now the reason that we chose not to have strict models on production
10:21
is because in a production environment you would rather see extra queries than receive an error you don't want your users to have an error if you have forgotten to egoload something so it's best to disable this in production and you can change that
10:35
around if you really want to that's just the way that I would do it so you can see here we've got an exception thrown a lazy loading violation exception thrown and it says exactly what we need to do so we need to go over to
10:48
our web root or our controller wherever we do this and we now know that we have forgotten to egoload this so we can specifically go ahead and egoload in the user sure enough when we come back back over to the browser this has been
11:02
fixed we don't have any duplicate queries this has done a where lookup for all of the potential users that we would see within this list and behind the scenes eloquent has pieced it together okay great so that is what the first thing does and once again you can use
11:18
this in isolation if you want to so we've looked at preventing lazy loading what about prevent silently discarding attributes what on earth does this do well to demonstrate this we're going to go ahead and cancel off the model unguard that we've already used
11:34
and let's go ahead and fetch a post out of the database and go ahead and update it so let's say post find one and let's go ahead and do something to update this so i'm going to go ahead and say fill so or i could either set the
11:47
attribute or i could use fill here and i'm going to say user id 2 then i'm going to go ahead and save this out now if we head back over to our post model if we had guarded enabled or disabled here so if we'd set guard it to false this would go ahead and work because we'd
12:06
be allowed to set this user id but if we are using fillable fields and we have say just the title set and not the user id we know that this fill is going to fail now i'm going to just go over to the browser and give this a refresh and you can see that this actually
12:23
looked like it worked although it didn't update it in the database now what has happened here is it's silently discarded as the method name that we are now using implies the attribute that couldn't be filled
12:37
now if we head back over to app service provider and enable this it's going to let us know that we can't fill in that user id now you may if you've been working with rfl for a while been attempting at some point to update a property on a model
12:52
and you've wondered why it's not updating why is this user id not being set here and it almost looks like it's working in the browser but it's not behind the scenes this command will help you out figure out straight away that this is the reason why so it's a really useful
13:09
method just to save yourself a bit of time okay so now you can see that hasn't been updated in the database because we've seen that error let's look at the last one of our strict models and then we'll move on so let's head
13:23
back over to our app service provider let's go ahead and unguard everything and let's go over to should be strict this last one is pretty straightforward prevent accessing missing attributes now this again will save you a lot of time if you make a spelling mistake somewhere
13:39
or you're trying to access an attribute of a model that you think exists but actually doesn't so let's leave should be strict on and let's go over to our web just here let's try and access something on this post that just doesn't exist so let's
13:52
echo out and well let's say post abc let's head over to the browser there we go so we've got the attribute abc either does not exist or was not retrieved for the model that could be for any reason is not being returned but you can see that that now goes ahead
14:09
and fails now if we didn't have that turned on we would just get a null output so this either wouldn't be output in a template or you would just not see the result in the browser or your api if you're building one so there we go again super helpful for when you're
14:23
spending a long time trying to figure out why something is not being output when in actual fact it could be that you have just gone ahead and misspelled something and that's the most common reason for not seeing a value being output
14:38
you've just spelled something wrong the next thing we're going to talk about is carbon's immutable date functionality and changing this to save ourselves huge headaches when we're working with dates and times now let's go ahead and not quite
14:54
enable this or disable this just yet we'll go ahead and look at an example of the problem that we have here and how we can address this so to change this we're going to go over and use the date facade within laravel
15:08
and we're going to say use carbon immutable and that comes from the carbon package which is included with laravel now i'm going to go ahead and comment this out for now while i demonstrate this let's come over to our web routes
15:21
and see what the problem is now by default any dates that we work with within carbon are mutable by default so let's go ahead and demonstrate this i'm going to use now which returns to us a carbon instance let's just die dump on now or on the date and let's give this a
15:38
refresh and you can see we get a carbon object back this is showing as part of laravel's support here but behind the scenes this is actually the carbon php package okay so what happens when we add a couple of hours to this date so we've
15:54
got an original date here and we're going to say let's say future and we'll say date add hours to now really ideally what we would expect here is this is the current date and time and this is
16:12
the current date and time add two hours but what has actually happened here is because carbon is mutable by default this will this future date will be two hours in the future but this will have changed the date that we originally had set so to demonstrate this let's say
16:28
to date time string and let's also dump the future and we'll say to date time string as well so let's go over to the browser and give that a refresh you can see that both of these dates are now the same so what has happened is and this can get really confusing when
16:47
you're working with dates particularly things like booking systems is we have a reference to the current date and time which we kind of expect to stay at the current date and time but we also now have this future now there's a couple of ways to get around this and that is the first way is to use
17:01
the copy method within carbon so this will create a immutable copy of the original date that we're referencing so it'll create a new instance of it and then you when you use something like add hours it will only deal with that
17:14
instance so that solves the problem you can see i'm recording at 11 52 here that's the current date and time and of course in two hours it's 152 so that is one solution but do you want to rely on always copying these values within
17:31
your code it's very unlikely that you're ever going to want to mutate an original value like this so we've already seen how to solve this and that is by going ahead and using date use carbon immutable and that will work with this by default so let's make sure
17:48
we go ahead and don't copy this so we just don't want to think about having to do that at all let's go over and give that a refresh and there we go you can see the difference without having to manually use copy so this is a tricky one because you don't
18:03
necessarily need to add this to your project unless you are working a lot with dates and times but if you are this is a really really useful one okay so the last thing that i would add to every single laravel project is prohibiting destructive database
18:19
commands specifically in production how do we do this well we use the db facade so let's go ahead and reference that within our app service provider and let's say prohibit destructive commands and we're not going to do this when the
18:35
app is or we are going to do this sorry only when the app is in production so what does this do well let's go ahead and just comment this out for now and we'll just talk about what the commands here do so we have a set of destructive
18:50
commands that when we run in production could cause data to be lost that is things like php artisan and db wipe and we also have things like migrate and rollback we have migrate reset all of these things
19:08
can potentially cause data loss you do not want to be rolling back migrations in production because if you have created a column in production using a migration when you migrate the database that has been filled with data perhaps from your users or some
19:24
other process when you go ahead and roll this back that's going to go ahead and remove them columns and basically get rid of the data so ideally you never want to run any of these production commands or these commands in production
19:38
now laravel does have safeguards for this so i'm just going to go over to the appenv and i'm going to set the appenv to production here let's go over and run php artisan and let's say d wipe so a really destructive command you'll notice that what this will do is
19:53
it will warn us first and say are you sure you want to run this command and by default we have no selected so we can just hit enter command cancelled but if you really want to safeguard things it's a good idea to prohibit destructive commands
20:08
entirely let's look at the difference that this makes and it will be exactly the same thing for migrate rollback migrate reset all that kind of stuff so i'm going to run db wipe again now that prohibit destructive commands is enabled and there we go we don't even get the
20:22
option to go ahead and run this this command is prohibited from running in this environment so that is one i would add specifically for production to stop anyone including ourselves running any of the destructive commands here and of course you can go ahead and see which
20:37
destructive commands this applies to as well so if you wanted to go over to this you can see exactly which commands each of these relate to and very recently rollback was added in laravel 11 it wasn't initially in there but rollback has
20:52
recently been added to this okay there we go there are probably more but these are the main things that i would do in any new laravel project just to either help protect ourselves speed up development in terms of any mistakes we might be making
21:09
and also stopping us from doing really silly things like not eager loading any of our relations we've gone through each of these in quite a lot of detail so hopefully you can pick and choose which you'd like to add to your own laravel projects
1 episode• 21 mins•2 months ago
Overview
Out of the box, Laravel is configured for you to be productive immediately without thinking about much. Let's take it a step further and add some opinionated configuration to improve developer experience.