This episode is for members only

Sign up to access "Mastering Polymorphic Relationships" right now.

Get started
Already a member? Sign in to continue
Playing
07. One to Many: Parent relationships

Transcript

00:00
Okay, so we're going to dive a little bit deeper into polymorphic relationships and what we can actually retrieve from these, just so that when you go away from the course,
00:09
you've got a well-rounded set of techniques that you can use to extract as much information as you need out of these relationships. So what we're going to do here is we're going to build up within the browser a really simple example of just grabbing all comments within the system, regardless of whether they're
00:27
attached to episodes or whether they're attached to articles. We're going to list through them comments, but we're going to say what these relate to and we're potentially going to link back to the article or episode that they're on. So think of this as like a dashboard of comments where we can see all comments that have been
00:43
posted and we know where they've come from. So this is a pretty common thing within systems that have comments. Let's go ahead and build this out now, see what it looks like. So the first thing I'm going to do is get rid of this in the database, and we're just
00:56
going to manually build up a few. So I'm going to say comment one. Let's attach that to the article, but let's also pull in the episode here that we want to attach this to.
01:06
So let's say episode, we basically just want a couple of comments for each of these types. So episode and save that comment to that article. So let's go back over, not the easiest way of doing stuff, but we will get there. Let's save comment two to that article as well, and then let's save comment three to
01:27
that episode. So let's say episode, comments, save, comment, and there we go. I think that's enough for now because we'll pretty much get the idea of what we're trying to do here.
01:39
Okay, so now what we're going to do over on this homepage, we are going to return a view and that is going to be something like home, doesn't really matter, obviously it's going to be a bunch of comments, but we're going to say comments and we're basically just going to fetch all comments from our database.
01:58
So let's say comment latest and get. So like I said, imagine that we're building a little dashboard that shows us all of the comments within our system. Okay, let's go ahead and just make that view out, so make view home, and let's go over
02:14
to home.blade.php and let's just start to iterate over each of these comments. And we know that each comment has a body. Of course, it's probably going to be attached to a user, you can add that in, but let's just add in a div in here with the comment body, we'll just keep it super simple for
02:35
now. Okay, so let's go over and give that a refresh, there we go, not really anything groundbreaking. So what we now want to do is, because we know that two of these belong to an article and one belongs to an episode, we want to show what they belong to here and then potentially
02:55
link over to them so we can, you know, link over to where these came from. So how do we do this? Well, when we went ahead and defined out the comment model, there's a good reason why, or there are a couple of reasons why we define this commentable relationship.
03:09
One is so behind the scenes Laravel can use this relationship chip to fetch and store the polymorphic relationship, but there's nothing to stop us from accessing this relationship as well. So we can directly access this inside of here.
03:25
So let's say from, and let's say commentable. And now comes the sort of tricky part, we need to have really either a getter or a common attribute shared between the two polymorphic things. So in our case, we have got, let's have a look here, we've got articles, which has a
03:46
title, and we've got episodes, which has a title. So both of these things have a title, which means that we can just access the commentable title and either way we will get the title for each, either the episode or the articles. Let's do that first.
04:01
And I'm going to show you a better way to do this, which is a little less brittle, just in case I need to change it. Okay, so let's just, I'm going to do this really badly here. So let's just say strong, and I'm going to put this within some strong tags since we're
04:14
not sliding anything. Give that a refresh. And oh, okay, yes, we need to go comment, commentable, of course, give that a refresh. There we go.
04:24
So what this has now done is it's fetched for us the commentable thing that this is attached to. So we can still extract that information from each of these comments. Now what if these two things vary?
04:35
Now they don't at the moment, but if they did, there's a couple of options that you have, depending on how complex your project is. So the first one that I would recommend, if things are very, very basic, is just to do a quick check within your template.
04:51
Now it's not always the best solution, but what we could do is we could get rid of this and we could build out our strong tags down here. Of course, you could bring this all in line and you could just do an if statement. So we could just do an if statement here for the, if it's an article, and we could
05:05
do an if statement here if it is a episode. So in here, of course, what we can do is say if comment, commentable. Now remember, we don't need to use class names here. We don't need to use get type or get class or anything like that within PHP because over
05:23
in our comments, our commentable type is mapped up to that morph map. So we can just do a really simple string comparison here to check this. So we're going to say commentable, commentable type, and we're going to compare that to say article.
05:39
Now we'll do the same thing. I'll just copy and paste this to save a little bit of time. We'll do the same thing here for the episode. And now what we've got is, even though this is not ideal for reusing this between lots
05:52
of templates, we've got a solution where we can include some custom logic. So let's say, for example, that we wanted to link through to the item here. So we're going to say comment, commentable and title. Now if the episode here didn't have a title attribute, we could change that over.
06:13
Maybe it had a name or something like that instead, let's just pull this in, then you could change that around. It does have a title. And let's go over and give that a refresh.
06:21
And yeah, let's just double check this here, commentable at, so it's commentable type, isn't it? Yeah, we don't even need to access that commentable relationship. So there we go.
06:32
So now we've got the opportunity because we've got these two if statements within our blade file or wherever we're building, we can now make a comparison and we can now drill down and link through to a very specific place if we need to. Now the other option that you could include is a common interface between the two things,
06:52
the two models that where you have to implement a method like a getter, which normalizes the title that you want to fetch and all that kind of stuff. So in this case, what I would do, let's just get rid of this and we'll try that option out here.
07:06
This is better really for the long term, but there's nothing wrong with the solution that we've just looked at. We want to be able to do something like this, comment, commentable and title like a method. Now we need to know that the actual model itself has a title method.
07:22
Now it doesn't at the moment. So of course we're going to get an error, but let's go over and implement just a common interface to get this to work. So I'm just going to keep things super simple here and let's go over into our app once this
07:33
finishes and we will create our directory called contracts. You can put this absolutely anywhere. And what are we going to call this? Let's go ahead and create our interface here called commentable.
07:46
I think that should be fine. We'll go ahead and choose interface here and let's build this out. So we know that we want this to have a method called title, which returns to us a string. So we'll just define that out in there.
08:00
What we can do with this commentable interface now is on anything that is commentable like our article. So we can go ahead and say implements commentable. That's going to require that we go ahead and add in a title method and then we know that
08:15
that's going to return a title. So it's basically just normalizing that data. Now it happens to be an attribute called title, but if it didn't, then this would be something like name.
08:24
And of course it would still match up because we're going to use that method. So let's do the same thing for the episode. And then we've pretty much done that, but we've tucked everything behind the scenes and now we can access them values anywhere, not just in Blade templates.
08:37
We don't really want to get into the habit of doing all of this logic everywhere in our app, just in one place. So let's go ahead and implement commentable here. We'll go ahead and add in that title method stub and let's go ahead and return this title
08:50
and we should be back to the start. So that's my preferred solution to doing this. But if you just have one instance of this where you just need to output it in a list in a Blade template, feel free to go ahead and add if statements within Blade.
09:03
Now you can do exactly the same thing here. So let's head over to our commentable interface with the URL for this. If you need to link through and you can just add anything in here that you need. So the URL would then go ahead and use the route helper to return the URL for this.
09:17
Now I'm not going to do that because we don't have any route set up, but it would look something like this. So let's go ahead and add in URL and you could just use the route helper directly in here and it would be something like episodes.show.
09:31
And obviously you'd pass a slug in here, but with Laravel, you could just pass this and that would infer that and it would fetch out whatever you had within route model binding. So I'll just leave this as the title for now and we'll go over to commentable and get rid of the URL, but that would be the best solution going forward.
09:47
So there we go. That's how we access the parent commentable thing. We're going to talk in the next episode about N plus one problems and how to get around and solve these.

Episode summary

In this episode, we take a practical deep dive into working with polymorphic relationships in Laravel, specifically focusing on how to handle and display parent relationships for a typical "comments on articles and episodes" setup.

We build a simple dashboard in the browser that lists all comments, no matter if they're attached to an episode or an article. As we work through this, you'll see how to display what each comment is related to (either an article or an episode) and even how you might link back to the parent item from the comment list.

You'll see different ways to access data through the polymorphic commentable relationship. First, we show the quick-and-dirty way, grabbing shared attributes when they happen to exist (like a title on both models). But since real projects often get messy, we explore more robust solutions, like using conditionals in your Blade templates to check which type of model a comment belongs to and display info accordingly.

Finally, we level up and build a common interface that both the Article and Episode models implement. This lets you nicely normalize things like title or even a custom url method across both models, so your templates can be much cleaner and your code easier to manage long-term.

You'll finish the episode having seen practical, real-world ways of handling polymorphic relationships in your Laravel app, and you'll be ready to avoid mess as your app grows. Next up, we'll deal with the dreaded N+1 problem and optimize how we query related data!

Episode discussion

No comments, yet. Be the first!