تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Introducing Polymorphic Relations0:00

All right, we're making pretty good progress. We've now reached polymorphic relations, and this actually splits into two different types. Our standard polymorphic, and then we have another one for many-to-many polymorphic. We'll start with this first option here. So yeah, a bit of a scary word, don't worry, as with many things, it's not that complicated once you understand it. So think of this almost as a variant, or at the very least, it's connected to a standard single association. It still allows for a belongsTo relationship, but it can belong to any number of associations or related models.

Creating Video and Series0:31

It still allows for a belongsTo relationship, but it can belong to any number of associations or related models. Still, admittedly, it sounds a bit confusing, so I'll show you an example using something from Laracasts. So imagine that we have a Video. Let's create one. php artisan make:model Video -m -f. And let's take a look at the migration. A Video, the simplest form of this, we'll need a title, then maybe text for the body,

Okay, so let's take a look at the migration. A Video, the simplest form of this, we'll need a title, then maybe text for the body, the description. We'll do description there. And then maybe let's do a string for, I don't know, the embed URL, whatever you want there. That looks good to me, and I will php artisan migrate my database. Okay, so if we switch back, give this a refresh, we now have a videos table. However, think about it. On Laracast, any Video, well, there is a belongsTo relationship there. It could belong to an associated Series.

On Laracast, any video, well, there is a belongsTo relationship there. It could belong to an associated Series. And in reverse, a Series consists of many videos. Okay, so it sounds like we need to make another model for a Series. All right, so if we take a look at create_series_table, once again, I'm going to keep this very simple. A Series has a title, and it also has a description as well. So this would be, you know, Laravel from scratch. And this would be, in this Series, we're going to learn Laravel from scratch. Then if each Series consists of a video, well, it sounds like we need to return to our migration.

And this would be, in this series, we're going to learn Laravel from scratch. Then if each series consists of a video, well, it sounds like we need to return to our migration to specify that a video is connected to and belongs to a series. So let's do that now. We want an unsigned integer for the associated series_id. Oh, and by the way, I was recently asked why I do unsigned instead of integer. That's because we're not interested in negative numbers. We only want a positive number. Okay, so does this all make sense now? If we go and do a php artisan migrate:fresh, let's come back to SQL Pro, we now have a

Okay, so does this all make sense now? If we go and do a php artisan migrate:fresh, let's come back to SQL Pro, we now have a series on our site, and each Video belongs to a Series. So I could say maybe if we are learning migrations, I could say learnMigrations, and that belongs to the Series with an ID of 1. And that Series might be Laravel from scratch or something like that, okay? So that means if we were to represent this, this should all be a recap at this point of basic hasMany and belongsTo relationships. So if I want to get the videos in that Series or the lessons in that Series, whatever you want, we could say the relationship is a Series hasMany Videos.

So if I want to get the videos in that series or the lessons in that series, whatever you want, we could say the relationship is a Series hasMany Videos. And you know, maybe you need to order those according to their position, so order by position or something like that to make sure you get your videos in the proper sequence. Nonetheless, that's our relationship. In reverse, a Video belongs to a Series. We're getting good at this, right? This all makes perfect sense. But we're about to throw a wrench into the mix here. So yes, a Video can belong to a Series, but maybe sometimes we have videos that aren't

Why Polymorphism Is Needed3:39

But we're about to throw a wrench into the mix here. So yes, a Video can belong to a Series, but maybe sometimes we have Videos that aren't connected to Series. Maybe they belong to something else entirely, like a generic collection of isolated lessons. Well, that's not really a Series. It's not an ordered Series. It's just a grouping of lessons. So how do we represent that? Because we've already said a Video belongs to a Series, but now we're starting to realize, well, sometimes it belongs to a Series, but other times it kind of morphs and it belongs

Because we've already said a Video belongs to a Series, but now we're starting to realize, well, sometimes it belongs to a Series, but other times it kind of morphs and it belongs to something else, like a Collection, or maybe an AdCampaign, or maybe anything that is not specifically a Series. Okay, this is where polymorphic relations come into play. It allows a model, like Video, to belong to something else without being specific about what that something else is. Sometimes it could be a Series, sometimes it could be a Collection, and sometimes it could be something you haven't even created yet. And that's why we can use this term polymorphism.

could be something you haven't even created yet. And that's why we can use this term polymorphism. Polymorphism literally means to have many forms. So what we're saying here is the relationship between a Video and what it belongs to can have many forms. Once again, sometimes a Series, sometimes a Collection, sometimes something else. So if we want to make this work, let's add this other type. We called it Collection. And again, I need a migration for that. Okay, so a Collection has a string for the name, and that's it.

Adding Morph Columns5:04

And again, I need a migration for that. Okay, so a collection has a string for the name, and that's it. So now, if we come back to our migration to create the videos table, yeah, we got to change it up because no longer can a Video exclusively belong to a Series. We don't have that one-to-one relationship anymore. Instead, the specifics about what it belongs to, well, it's going to change. So we need to be fairly generic. Now if we take a look at the Blueprint class, you'll see that there is a helper method called morphs. So that means within here, if I were to say table morphs, let's see what happens behind

morphs. So that means within here, if I were to say table morphs, let's see what happens behind the scenes. And we need a fun name here, maybe something like watchable, all right? If we give it the term watchable, it's going to create a string called watchable type and watchable ID. So these two, and it also adds an index, by the way, but these two will take the place of the series ID. So no longer are we saying a video belongs to a series. Instead, we're saying, well, we need to record the type of thing that can be watched, and

So no longer are we saying a Video belongs to a Series. Instead, we're saying, well, we need to record the type of thing that can be watched, and we also need to record the ID of the thing that can be watched. So in some cases, we will store the Series there. And often, this will translate directly to an Eloquent class. You can override this if you want, but it might be something like this, Laracast Series will be the type, and then the ID will be 5 or 4. So now we're saying if we want to grab the thing that this Video belongs to, well, in this particular instance, it's going to belong to the Series with an ID of 4. But another time, it's going to belong to the Collection with an ID of 10.

this particular instance, it's going to belong to the Series with an ID of 4. But another time, it's going to belong to the Collection with an ID of 10. See what we're doing here? It's allowing the model to belong to any number of things, but still on a single association. Okay, so let's come back, and yet again, we're going to do a fresh migration from scratch. We come back, give it a refresh. We now have our videos table, but rather than it belonging to a series_id, we're just going to store the model, the type, as well as the ID. And like I said, sometimes it will be something just like this, video in a series, and then the URL.

And like I said, sometimes it will be something just like this, video in a series, and then the URL. All right, this clearly is a video that's going to belong to a series. But now let's make another video, like an isolated video that belongs to some collection or some ad campaign. You have a bunch of videos for ads, you know, whatever makes sense. This next one will be the watchable type is a collection. And once again, maybe we'll say the collection with an ID of 1. Okay, so let's switch over to our series. We could use our database factory to quickly whip this up, but let's just do it all in

Okay, so let's switch over to our Series. We could use our database factory to quickly whip this up, but let's just do it all in line here. Some seriesName. All right, so we have a Video that belongs to the Series with an ID of 1. Next we need a Collection. So let's say some collectionName. All right, next we have a Video that belongs to a Collection. So now let's try to get this through Eloquent. We'll start with our Series.

Eloquent morphMany and morphTo8:22

So now let's try to get this through Eloquent. We'll start with our Series. And we still want to grab the Videos, but we can no longer use a hasMany relationship. Because remember, behind the scenes Eloquent's going to try to trigger a query that says something along the lines of select all from videos where the series_id is 1. But there is no series_id anymore. Instead we need to use the morph relationship. So rather than hasMany, we're going to say morphMany. Exact same thing. It's a hasMany relationship still, in effect.

Exact same thing. It's a hasMany relationship still, in effect. But we're using polymorphic relations. So we'll swap that to morphMany. Now we need one more argument here. We need the name. So this is going to be, in our case, watchable. It's whatever you've decided to be the unique string here, watchable_type or watchable_id. You could have named that anything you want, if you want it to be of a viewable. Well in that case you would update this, and then the columns would be viewable_type and

You could have named that anything you want, if you want it to be of a viewable. Well in that case you would update this, and then the columns would be viewable_type and viewable_id. All right? So now let's give this a shot. php artisan tinker. I'm going to fetch the series. We'll just grab that first one. And then I want to grab the videos or episodes within the series. And we get an empty string.

And then I want to grab the videos or episodes within the series. And we get an empty string. Let's see why. Oh, sorry. I'm still using my, this is what I have for Laracasts. But in our example app, we just have an app namespace. Okay. Control C, bring it back. I'll hit up a couple times to try it all again. And there we go.

I'll hit up a couple times to try it all again. And there we go. Now we've fetched only the videos that are actually part of this series. And to determine that, we're going to check, effectively, the seriesId, but we now call it watchableId. And we also want to make sure it is of type series. Now let's do the same thing for a Collection, a Collection model. So we'll say if we want to grab the videos within the collection, well, yeah, it's kind of the same thing here. So we can just grab that and paste it in.

of the same thing here. So we can just grab that and paste it in. Okay. Let's do it again. Give me the collection. Now give me all of the videos within the collection with an ID of 1. And once again, we get a single entry there. But now what about in reverse? So let's say we have the video and we want to grab the owning model, the owning association. All right.

So let's say we have the video and we want to grab the owning model, the owning association. All right. Well now, in this case, we can't say Series, well, we could if we want, but we don't know if this Video belongs to a Series or not. So instead, we will often just use that same term, watchable or viewable, whatever you've named it. But now here, we're not going to say belongsTo, because again, the query that would be executed behind the scenes won't line up anymore because we are using those polymorphic column names. So instead, I'm going to say morphTo.

names. So instead, I'm going to say morphTo. And this is an easy way to understand it. I bet you've seen morphTo and morphMany, and you instantly get confused where you think, I don't know what morphTo is. Just think belongsTo, but for polymorphic relations. Same thing. And now because we don't know whether it belongs to a series or a collection, we leave that blank entirely. Okay.

Let's do another one. Let's grab, let's do find two. Okay. So this is a video associated with a collection of some kind. So now give me the owning model and it's the Collection. Now one final note on this. If you don't like the name watchable, like maybe you want to get the, um, I don't know, the parent. Maybe you want to call it parent. Well this is no longer going to work because the name of the method is actually being used.

Maybe you want to call it parent. Well this is no longer going to work because the name of the method is actually being used as a default. So let's give that a shot. Save the video again and then get the parent, the owning model, and we get null. So here's the rule. If you want the method name to be unique compared to what the actual polymorphic name was, then you got to be explicit here. So now if we give that another shot, we will grab the associated parent. Okay.

Customizing Morph Type Mapping12:34

So now if we give that another shot, we will grab the associated parent. Okay. One final thing and then we'll call it a day. Here you can see we are referencing a php class basically that's pointing to the class. Some people don't like the idea. They think that strongly couples their database table to Eloquent and things like that. Honestly, I don't worry about it too much, but if this is an issue for you, you can override it. I'll show you how. Let's go to our AppServiceProvider and within our boot method, we're going to use the relationship.

I'll show you how. Let's go to our AppServiceProvider and within our boot method, we're going to use the relationship class, this long path here, and we're going to create a mapping, basically a lookup table for these polymorphic associations. So now what can we add here? Let's see what we currently have. We have series and collection. So if we just want to do series instead and collection, all right, well, we have to tell Laravel how to connect those. We need a little lookup table basically, a little mapping.

Laravel how to connect those. We need a little lookup table basically, a little mapping. So if we have series, that's going to refer to App\Series. We're just reproducing it here within our php. If we then have collection, that would point to App\Collection. Okay. So now take a look. We're using these terms instead, but if we run through the exact same flow, we still grab the associated record, whereas if we did not do this, let's see what would happen. It blows up because it's trying to find, it's literally trying to find a class called series,

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟