How Laravel Eloquent Models work behind the scenes

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

I was about to share this here. Thanks, man!

👍︎︎ 3 👤︎︎ u/lyotox 📅︎︎ Jul 11 2022 🗫︎ replies

Nice video.

On another note, what the fuck is that font?!?!

👍︎︎ 3 👤︎︎ u/DragonCz 📅︎︎ Jul 11 2022 🗫︎ replies
Captions
eloquent is definitely one of laravel's most important features and it's also usually the feature that people either really really like or really really dislike it is curious because it is an active record implementation so it works both on the database layer as well as on the application layer so not only does it accesses your database and fetch and write records but it also represents database records all in one class this isn't a problem but rather a design decision on active record the pad in which eloqua implements and on this video we're going to dig down a little bit into eloquence internal implementation and see how it does all the magic that's necessary to provide such a good developer experience and allow us developers to do all the things that we do with it i apologize for my voice on this video i'm a little bit sick and also got a little bit of a brain fog so i'm just not on my prime but i hope you guys enjoyed the video and of course any suggestions or complaints leave it on the comments and see you on the coding area or rather the rest of the video see ya all right so i'm using the same application that we've used on the last test driven development video i only made one slight change so we have users which comes with larval and we have a post table which has a title a body and it belongs to users so basically users can create posts that's the schema that we have right now for the examples i'm going to show you to make things easier i've created a couple of fake records on the database so we have about 20 posts and one user that's going to be useful when i want to show you relationships and queries and whatnot but we're not going to use that right now i've written this doc which we're going to use to support the explanation like i said eloquent does a couple of things it accesses the database we've all done it for instance when you call post all or post uh query get you're doing a read operation on the database you're interacting with the database and after that you're getting a collection of records each instance of a model also represents a record from the database okay there might be situations where it doesn't for instance an unsaved record but what we have in memory is usually in sync with the database if you have an unsaved model on your application you're probably going to save it at some point eloquent also persists objects into the database when we call say for instance we're doing a write operation on the database and it also queries relationships so when you have an instance of a model that is a record from the database you can query its relationship so you go back into the database layer now eloquent is much more than this but we're not gonna touch all of all it does on this video we're gonna focus on those four things here are some examples of what we can do with eloquent we can fetch all the posts that's pretty standard we can query something on the database for instance we could fetch all the posts where the title is let's say complain something like this and this returns a query builder instance we're going to talk about this a little bit later now you can also omit this query method and call word directly or or you know you can actually call any query builder method directly and you can also use queryscope so if we go into the post model we have the squarescope iscomplain which just matches the title to the complaint string we can call this as well now here's what's interesting this looks fine this looks fine we have auto completion now this one the my ide is complaining it says that the method wasn't found and indeed it isn't uh this method doesn't exist either on the post class or the model class that both extends from same thing for the qr for the i'm sorry same thing for the query scope we don't have this method it is actually called scope is complaint and it is written slightly different we have an uppercase i here and we have a lowercase i here so how does eloquent works internally to allow us to do this well let's start with the database layer how does eloquent query stuff how does it know when you should query stuff and what does it do internally to do this we need to jump into the laravel's code base a little bit i'm going to hover over this and i'm going to press shift f12 which on my keybinding goes the definition so let's see how this function is defined you can see it is a static function so we cannot call it from an object context and here's what it does it calls the query method and then calls get so this is the same thing as doing post query get it is just practicing the call so you can get that all the way now what this query does that's that's i mean that's what's being called so it must be important if we jump to the definition well it instantiates the model so in this case we would be doing you know uh sorry we're doing new post query something like this and then that's it that's all it does now if we go back to new query it does a couple things um it registered global scopes to a given query builder we're not gonna cover global scopes now uh if you wanna take a look at the code you can see it's pretty simple uh it just iterates through the global scopes and applies them but we're not we're not gonna change this now if we go to the new model query method you can see that it returns an instance of element database eloquent builder now this is interesting let's go back to this document we have a couple classes that we're going to leverage here the first one is the model class extended by the models the second one is the base query builder when you call for instance db table post get this is on the query builder instance we also have the eloquent query builder which is what we're talking about and then we have relation classes so when you return uh a has many or it belongs to they extend this relation class okay so in this example you can see that we are passing a base query builder as an argument to this new our computer if we see the code you can see that new elo computer returns an eloquent um query builder right if we take a look you can see that we're talking about database eloquent builder uh let me go back to the method we were looking for which is new model query and it passes a base query builder as an argument if we take a look at this class you can see that it accepts a query builder as an argument it does not extend the base square computer instead it implements disputed contracts so it uses composition to bring in the methods available on the base computer and you can see that we also have a mixing dock block here to indicate that we have these classes methods available on this class if we check the constructor sure enough we have a base computer instance being expected here so that so that already gives us a clue of what's going on eloquent has its own query builder which is built on top of the base query builder and we don't know what it does exactly but if there is a class specific to eloquent it must do certain things that eloquent needs without having to rewrite or overload the existing the base coordinator methods well to sum it up we call this set model method and it is available on the ello computer class so it just sets the model that we pass in this case we're passing the actual object we would be passing post in this case an instance of pose the reason it does this is because as you can see the query builder stuff is not actually on the model class it isn't a separate eloquent theater class and we need this class to be aware of which model we are talking about so if we go all the way back and we go back to this method call query we're just returning this new query which is an eloquent booter so the magic happens on this class now i might be thinking okay but how can i write this and okay the id is complaining but we know this works we know for a fact this works well that's one of the magic one of the well quite a lot of magic that eloquent's doing for us if we scroll all the way down and look for the magic methods on this class let's take a look at the call and as well and the call static as well which is right here so call statics just practicing this call to call [Music] actually it is instantiating the model and calling the method now if the method doesn't exist on the object and you have a magic call method it is going to go into this block and you can see that we're going to ignore this but at the end of the day it is forwarding the call to a query builder instance so if we're calling a method that doesn't exist on the model itself what eloquent does is okay so this isn't available here this must be a query video method and then it forwards the call to the queer computer forward call 2 is a trade available in laravel this isn't the only piece that uses it but like i said it just process the call to a given object and if the method is not available then it throws a bad method called exception i'm sure you guys probably assembled upon this exception at some point especially when dealing with model methods but this is what it does so the important stuff is actually here and on the eloquent builder class we can see the same thing happening if we go all the way down to the call magic method this is what we are interested in so remember we talked about scopes right here we have a scope example this method doesn't exist but it still works and this happens on this block first we have a method to determine whether a scope exists remember that what this magic method is getting on the method name isn't actually his complaint i'm sorry isn't actually uh scope is complained it is getting let's see if we can edit this the method in this case would be um his complaint but the method that exists on the model is scope is complaint so not only do we have scope at the beginning we also have an uppercase i how does laravel determine whether we have that scope well let's take a look it defers it to this has named scope method on the model remember that the l computer is aware of the model we're talking about if we take a look at this method well here's the magic it checks whether a method it starts with scope and also has an uppercase for slider where the actual scope may exist so you would be checking whether scope is complaint exists so here's how the magic happens if we go back to the column method uh you can see that we if the scope exists then we want to call it and then eloquent applies the scope now we're not going to worry about the pass-through methods here but basically there are certain methods that we just want to defer a straight into the query builder but on this case this is what we want so if we call a method on the allo computer class remember this class doesn't extend the base computer it doesn't use inheritance so let's just double check it so you can see it just implements disputed contract what it does is if the method isn't available on this class then it must be available on the class it extends not directly with inheritance but uh the one we the base computer so it forwards the call to the base computer as well just like the model does using the same trade which is forwards calls and then once it happens then okay then we're talking about the computer class find it uh this is eloquent so this is where it is being uh deferred to being proxied to and this is the base coordinator class that we use when we call like i said this here we're using the base computer so at the end of the day everything is just being passed uh through objects when we call press oh it is actually post call impose query get uh when we call post query it is actually returning an eloquent filter when we call something directly it is actually passing that call to a query viewer as well and when we call a query scope it is also being processed to the query builder in this case we already have a query in this instance from this point moving forward but it still has some logic to intercept that method call it knows it doesn't exist on the model because it it was given to the magic sorry the call magic method and then it checked whether the scopex is following laravel patterns so that's basically what's going on we have model which sends it to the allo computer which then defers what's needed to the base query builder okay so now we know how eloquent query is stuff but how does the model aspect of it the representation of a record from the database work well that's that's much simpler there is a lot of magic here so when we have an instance of model we're talking about this class and we have access to all the methods on this class now there are some database operations which are projected to the query builder but what i wanted to talk about is relationships so what do we call for instance let's let me give you an example we have a post right when we call post user this is a property this isn't a method we do have a user method but we're calling the property and if i run this it fetches the user right now one more thing if i have a post and i'm gonna enable the query log and i call the user through that property and then i check the query log you can see that a query was made however if i do this again well no query was made what's going on so if you've worked with level a little bit you know how this works what we're doing is something called lazy loading um we call a relationship laravel detects that it isn't stored in memory and then it fetches from the database once it fetches the relationship from the database it saves it to the memory so that if if we happen to request a relationship again it is already cached and we don't have to hit the database more than once i'm going to show you guys how that is implemented well the first thing we're going to look for is the model method we're talking about a property so we're not going to look for the call magic method but the get magic method here it is and you can see that on the gad magic method it is simply practicing the call to this get attribute method let's take a look at it okay so we have an attribute to get which is the key and let's see what it does so the first block of code checks for attribute mutators and casts so we're not going to touch on those now but if you've ever used level you probably use those as well especially with dates then we have a block to make sure that the base class notice that it used self class instead of a static class here has the method in this case we don't want to do anything and then it gets the relation value so level already knows that if we're calling for a property that isn't on the attributes and we have this check here that isn't being casted and that isn't available on the base class then it is we're talking about a relationship so this is the last possible scenario it checks for a bunch of stuff first if none of them match then well this must be a relationship and when we go into the gap relation class notice this if block if the relation is loaded we're not going to look into the underlying implementation otherwise this video might get long and confusing but if the relation is loaded then well we just need to return it from memory it is cached if it isn't a relation then we want to return now we have this prevents lazy loading block which is interesting if i think this was introduced either in late level 8 or on level 9 i can remember but basically when we do remember what i told you about lazy loading um let's say you have a for each block and you're iterating through hundreds of users and then you're grabbing their posts if your laser load is you're gonna make hundreds of queries that's caused the n plus one problem and in our phone you can eager load stuff so for instance if i want to get all the users with all their posts i can say user with posts get and you can see that it already came with the post so those are already loaded with a single query in this case requires one for the user and one for the posts and i don't have to load this dynamically as the loop goes and then i can avoid the the query problem now those are a little bit tricky to spot and larval releases feature where you can disable lazy loading you can say hey laravel if something tries to be lazy loaded if something tries to be loaded and it isn't in memory then just throw an exception and that helps the developer know where they're things up if they don't want lazy loading to be present so that's a very nice addition and we can see here how it is handled uh this method throws an exception well if nothing goes wrong and you can actually get a relationship it goes the get relationship from method let's take a look at it so first it calls the relation on this post case it would be calling the user method and this returns an instance of belongs to now belongs to extends relation which is this class we talked about so what level does is if the instance if the object that we got here isn't an instance of a relation then something is wrong and it is in a relationship instance so you might have stumbled upon this exception at some point it isn't that common but it happens now if it is an instance of relation then we can get results we're not going to look into the underlying implementations but it fetches the results and then it sets the relation results on the model it caches those those results so if we call something twice we only query the database once and this is where it happens so i'm gonna test this and show you guys how this works let's create a new relationship here uh we're gonna call this i don't know owner and it is going to return an instance of post subscription which is available um i think this one required yeah it requires an argument so we're going to pass the current instance so if i try to access as a property wherever i was going to think we're talking about a relationship but it is going to stumble upon this if block and throw us an exception let's take a look we refresh tinker i'm going to grab the first post i'm going to say post owner and okay my color scheme isn't helping but it says logic exception all i always return a relationship instance so laravel is very smart and it can let you know when you're doing things wrong and helps you avoid those scenarios so at the end of the day we have this we have the data access layer which is proxy to the eloquent query filter which product system calls the base graduator we have the representation of a record which is the model itself and we can call methods within the model just fine they're not going to go through any magic methods relationships well those are approximate to the relation class i mean the object that we get on this point so we use it to get the results one interesting thing to notice is if we go into the relation class you can see that it also implements the builder contract and it also accepts a allo computer instance as well as a model so the relation class is aware of the model we're talking about and it is aware of the computer so it acts as a computer in its own so like i was saying uh relationships goes through the relation object oh i think i i think this is what i want and that's pretty much it now one interesting thing is since on the model if we go to the call magic method we're not going to look much into it but you can see that it also forwards the calls into the nuclear builder so one thing that you can do with eloquent even though you shouldn't but that design allow this design allows is you could fetch the first post and you can get a query video instance from that you can say both square id three get see that i'm calling this on a post instance on an object and syntax error okay this was my mistake and i can get that instance so you shouldn't do this but you can do this and the reason why you can't do this is because calls are forwarded to the query builder a good way to think of the whole eloquent ordeal is from a class level from a static level you're talking about a query filter you're talking about database access from an object level you're talking about a record representation even though you can call relationships which do query the database but in general a good way to think is if you're talking about it on the static level if you're calling static methods you're probably querying the database if you're talking about a model instance you're probably talking about a record from the database now you can use for instance dependency injection with models you can do stuff like on your controllers or any class that you have a function you know something expects a post and other posts you can query stuff you can say you wear something blah something like that and it will work because of why what i just showed um i don't have it open anymore we have the call magic method proxy staff through the query builder so here we are actually talking about an instance of post the container is going to resolve this for you even then i would still think of it as query builder on the class level and record representation on the object level even though you can create things on the object level as well that was the video i hope you guys managed to learn something with it i hope it wasn't too fast or too confusing uh there's a lot going on behind the scenes on eloquent and not only do i not know all of it i wouldn't have time to show it on a video especially a short one like this one but i hope you guys enjoyed it and i hope you guys managed to understand how it works behind the scenes a little bit and i think it's very important you don't have to know the entire underlying implementation but it's certainly good to know at least how things are processed behind the scenes so you can properly understand your code and understand how things should be done for instance you might still do things like this but it is important for you to understand why the ide is complaining about this word method or why it is complaining about this query scope or why you can leverage custom query scopes which i have a tweet about this and alex from code course has a course about this as well i'm going to link them in the description how could some query videos can help you still have query scopes would avoid this kind of problem anyway i think this video is long enough i hope you guys enjoyed it and see you in the next video you
Info
Channel: Mateus Guimarães
Views: 3,246
Rating: undefined out of 5
Keywords: php, laravel, tdd, test driven development, clean code
Id: dhaPri-7QCE
Channel Id: undefined
Length: 24min 51sec (1491 seconds)
Published: Sun Jul 10 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.