This episode is for members only

Sign up to access "Eloquent Relationships By Example" right now.

Get started
Already a member? Sign in to continue
Playing
29. Defining and using has many through relationships

Episodes

0%
Your progress
  • Total: 4h 18m
  • Played: 0m
  • Remaining: 4h 18m
Join or sign in to track your progress

Transcript

00:00
So let's talk about the has many through relationship type, which allows you to access distant models that are related through another model that are not directly related to that original model. Now, that might sound really confusing, but we're going to come up with an example here that will demonstrate this really nicely.
00:19
And then once you've got the hang of this relationship type and it's in the back of your head, you can relate this to a similar situation, even if the models are different. So just to kind of demonstrate this, writing this out, let's imagine that we had users in our application, which is pretty straightforward. An app is always going to have users. Now, let's imagine that users could create projects within their applications and they can create many projects.
00:45
So we could have Project A, Project B and Project C, for example. Now, inside of each of these projects, the user is allowed to upload files. So let's say in here we have File 1, File 2, down here we have File 3 and File 4. Now, if we wanted to at a base level access all of the files that we have ever uploaded, the problem here is that a user has many projects, but a user does not have many files.
01:19
A project has many files. We need a way to, from a user, access these distant models and we can do exactly that with a has many through relationship. So let's use this example. We'll build this out completely from scratch, demonstrate it and see where we end up.
01:38
OK, so I've gone ahead and created a fresh project here and I've run my migrations, but we're going to go ahead and use our tinker session to generate out a fake user that we can use to demonstrate with this. So let's go ahead and create a user out here and quit out of tinker. So we know that user has many projects. So let's start out by creating out a model in here called project.
02:00
And of course, we'll create a migration alongside of that as well. And let's go ahead and open up the create projects table. We'll keep this really simple, but we know that a project relates to a user. So we're going to go ahead and create out a foreign ID in here for the user ID that we've already seen.
02:16
We can go ahead and constrain this. And that's pretty much what we need. It's just add one piece of information that will differentiate each of these projects. That's just going to be a project title.
02:26
OK, so let's go ahead and run PHP artisan migrate here and let's fill in some example data here really quickly. So I'm going to go ahead and hook this up to this user and we're going to say project one. And let's fill in a created and updated timestamp. Let's save these changes out, go ahead and duplicate this down to project two.
02:46
And we'll just use two projects for now, because that's pretty much all we need to demonstrate this out. OK, so the next thing are the files that belong to these projects. So let's again go ahead and make out a model here called file and we'll go ahead and create a migration here as well. Let's go and open up the create files table migration and fill this in.
03:07
So let's go ahead and add in a foreign key in here. And we know that a file belongs to a project. So we're going to relate this back to the project ID and for the file. Let's just again create out a string in here with some sort of data that we would normally have associated with the file.
03:23
And we'll just choose a file name. So again, we'll go ahead and run PHP artisan migrate. We're done with our migrations. Now we can go ahead and set up the relationships here.
03:32
So we'll start out with the top level with the user. We know that a user can have many projects. So let's go ahead and create that relationship out. This is a really simple relationship type that we've already looked at.
03:43
It's just has many. So a user has many projects and we're done. The next thing is going to be on the project model itself. We need to say that a project has many files.
03:56
So let's go ahead and do that. Remember, the goal here is for a individual user get all of the files that they have ever uploaded via each of these projects. So a project has many. And we'll use our file model like so.
04:11
OK, so we're all set up. Let's just go ahead and create a few example files in here that relate to each of these projects. And we should be good to start dumping out some data. So I'm going to say file 1.png.
04:23
Again, just fill in some information in here and we'll go ahead and duplicate this down. We'll create file 2 here for the same project, and then we'll go ahead and create file 3 here for the second project. And we'll do one more. In fact, we could just leave it at that, because that's, again, enough data to demonstrate that this works.
04:43
OK, so over in our web routes, let's go and just create out a view in here just so we can start to iterate through some data. And we're just going to say projects.index. And if we just go and create out a resource here under views, let's create out a project folder and an index.blade.php file. And we're going to go ahead and return some data from here.
05:07
And that's just going to be all of the current user's projects. Again, because we don't have authentication, we're just going to go ahead and manually grab that user out of the database by their ID. OK, so we're going to go ahead and list the projects here. So let's go ahead and pass down some projects to our view.
05:23
And that will just be user and project. So pretty much everything that we've already covered. OK, so if we head over to the home page, of course, we don't see anything at the moment. So let's go ahead and just iterate through each of these projects for each projects as project.
05:38
And we'll go ahead and end that for each down there. And in here we will go and output a project in an H3. So that's going to be the project. And I think we call that title.
05:50
There we go. So we've got project one and two. Now, underneath each of these projects, these have files. So we can now go ahead and create another for each loop inside of here and say project files as file.
06:02
And that for each here. And go ahead and output the files underneath each of these projects. So that's going to be file and file name. OK, let's give that a refresh.
06:13
And there we go. So project one has two files. Project two has one file. And now the goal of this is to create another page which lists all of the files, regardless of which project they belong to.
06:25
We still can get that information, but let's take a look. Now, we do need to egoload here. I'm not going to do that just yet. We'll do that at the end to examine how we would do this.
06:33
But let's go ahead and create a new endpoint for just them files. So let's go ahead and create out a files endpoint here, which will list all of our files. And we're going to go ahead and grab that user out again. So we'll find that user by the ID.
06:47
And let's go ahead and just return a view in here. And it's a files index. And we're going to pass some files down, but we're not quite sure how to access this just yet. So let's go ahead and just create out a files folder, index.blade.php.
07:05
And this is where our files will live. So if we keep this open, but also duplicate this over, head over to our files. Let's look at how we grab these. So let's go over to our user, because this is where we need to define this relationship.
07:20
And let's create out this files relationship inside of here. So to use this relationship, we're going to go ahead and return and use the hasManyThrough relationship type. And you can see here, just as we define this, we have related, through. And then we have a bunch of arguments that we can pass through here if the keys don't quite match up with Laravel's conventions.
07:43
So if by the time you implement this, you have slightly different keys, you can go ahead and define these if you need to. So this relationship type is very simple. We just read it through like we would say it. So we're going to say it has many files.
08:00
So we provide the fully qualified namespace to the model, and it has them through the projects that this user has, like so. And that's pretty much what we need to do, with the exception of if you have slightly different keys. OK, so let's go ahead and see what this files gives us. So I'm going to go ahead and die dump here on user and files, and let's go over and take a look.
08:24
OK, so we know that we have three files in our projects, two in one project and one in another project. But as you can see here, they are now all coming through. So that is pretty much the hasManyThrough relationship. So we can now go ahead and iterate over these files and use them.
08:42
So let's just go ahead and do that really quickly. And then we're going to explore some alternative syntax that you can use if you want to use that. OK, so we're going to pass them user files down here and we're going to go down to files index and just go ahead and do a for each over our files. As file and end the for each there.
09:03
And then we can just dump out the file name, so file and file name. And sure enough, we get all of the files, regardless of which project they're from. Now, let's just explore this relationship type in a little bit more detail. Now, technically, what we don't need to have if we were to do something like this is over on a project, we wouldn't necessarily need to have this files relationship.
09:28
So go ahead and just comment this out really quickly. Head over to this page specifically and give it a refresh. You can see that this still works, even though on the project model, we don't have the files relationship. That's because this is done at the database level rather than going through the models.
09:44
However, obviously, this page here would now break because we don't have this relationship in here. So it's pretty common to have the relationship defined in here anyway for you to do something like this. But this does not depend on the methods that have been defined on the models that you're working with. However, if you do have the methods defined, there's a slightly more readable syntax if you wanted to use that.
10:09
Let's go ahead and see what that looks like. So we're going to go ahead and say return this and we're going to say through instead of has many through. And we're going to give the name and the string name of the relationship. So through our projects.
10:26
So we're going to give user projects that this will now relate to this specific method. And we're going to say has and then we're going to give the files within that project. So files. So as long as we have a project method here, we can use this.
10:41
And as long as our projects have a files method, we can do this. So if we just head over and give this a refresh, this works and this still works. So that's a slightly different syntax that you might want to use, depending on which one you find more readable. And if you have the methods defined.
10:58
Now, you can also use dynamic syntax, which I wouldn't normally do. But that looks something like this. So you can say return this and you can say through and then the name of the thing. So this is a dynamic method, which will take the second half of this and map it up to what you would usually pass in here.
11:15
So through projects has and then you guessed it files. So this might be a little bit more readable to you. You can choose and you can see that still works. And this page here still works as well.
11:28
So you've got three different options from defining this. The only key difference is this will be done at the database level. But this will utilize the methods that you already have to work out how to build up this kind of relationship type. So this doesn't actually invoke the methods.
11:44
It just goes ahead and detects what this has and puts it into something like this. So I prefer probably out of all of these, this middle one. But again, it's entirely up to you what you choose. I'll go ahead and keep that one in there as the final solution.
11:58
Now, obviously, as you are doing something like this and iterating through all of the files that exist within that user or for that user through projects, you might also want to add on to this the actual project that these come from, just so you have a little bit of context. And there's nothing stopping you from doing this. So if we go into the files index.play.php file and we head over to our file itself,
12:22
we can actually define a slightly different relationship type on here and relate this back to a project. So we can use the belongs to relationship type and say this belongs to a project. And that means that what we can do is as we're iterating through each file, independent of knowing which project it's from, we can still access this. So if we just head over here, we can say something like from and then we can say file project and title.
12:51
So let's go over, give this a refresh. And there we go. For the all the files that we're now listing, we can see which project they come from. Let's finally go ahead and install Aravel Debug Bar again, just so we can see what is going on here and how we can egoload this stuff in. Because, again, that's really important.
13:08
So I'm going to go ahead and pull Aravel Debug Bar in. And specifically for this page here, let's give this a refresh and see how many queries we've got. Already five seems quite high for what we're doing here. So let's go back and just add in our egoloading to make sure this works nicely.
13:22
So for this files page here, let's think about the kind of data that we're working with. Over in files and index, we are accessing our file, which is fine, but we're also accessing that project. So we're going to need to go ahead and egoload these in. Now, we're going to assume that this user comes from an authenticated user.
13:40
So that would come from our request somewhere. Let's go ahead and add that in really quickly over in our auth service provider or our app service provider. So we're going to say auth login using ID and we'll say one. And let's just make sure we put in the auth facade here and we can get rid of this user here now.
13:59
And we can also get rid of this user just here. We can swap these out for the request or use the auth helper. So let's just pull the namespace in for our request in here. And we're going to say request and user projects.
14:15
OK, let's do the same thing down here, request user and files, and both of these should still work. Let's just make sure we put our request into here as well. And let's head over and that works and that works. So now that we are working in a structure like we would usually find, we can egoload directly from the user or more like egoload after the user has already been pulled in.
14:38
So we can say request user load and we can load within files the project for that particular file. So remember, for each of these files, we're going back and accessing the project. So we need to egoload the project in the context of them files within that nested relationship. So let's go over, give this a refresh.
14:59
There we go. We've got two queries, regardless of how many files or projects we have. Let's go over to our homepage, give this a refresh really quickly and just make sure we are egoloading these in as well. So we're going to come up to here and for the user, once again, we're going to go and say request user and load.
15:19
And we're going to load in our projects, but we're going to load the files as part of them projects as well. Let's go over, refresh that. And there we go. So that is the has many through relationship, which can be really useful when you're trying to access a distant model through something that you already have defined, but has no knowledge of who it actually belongs to or which initial model it relates to.
33 episodes4 hrs 18 mins

Overview

Eloquent is Laravel's ORM (Object Relational Mapper). In simple terms, it's how your models work with the database.

The good news? There's a bunch of powerful relationship types available. Our task is to learn when and where to use each one.

In this course, we'll cover each basic relationship type, how to access related models, and then insert, sync, update and delete related data. Oh, and we'll build a practical example for each relationship type, to really make it stick.

Alex Garrett-Smith
Alex Garrett-Smith
Hey, I'm the founder of Codecourse!

Episode discussion

No comments, yet. Be the first!