This episode is for members only

Sign up to access "Winging A Laravel Comment System" right now.

Get started
Already a member? Sign in to continue
Playing
03. Comment polymorphism

Transcript

00:00
The goal of this episode is to adjust comments so they work polymorphically across any other models. Now that sounds more complicated than it is, particularly if you're new to Laravel.
00:12
Basically, like I said at the end of the last episode, we want multiple types of things in our application that we can comment on, and we just need to modify our comments model slightly for this to happen. But there's also a couple of additional tweaks we want to do just to make sure this works nicely. Okay, so to get started, we need at least one example
00:32
of a page or something or an item where comments are going to be allowed on. Let's just start with one and we'll add more a little bit later. So let's say make model article. So we'll create a migration and a factory alongside of that. We don't really care about articles at the moment. These could contain anything. So let's just add a string here for the title.
00:55
Let's add a string here for the slug. And we'll make this unique. And we will add a should we add a body at the moment? Let's leave this. So I'm just going to keep this super simple for now. So let's go ahead and run migrate on our articles table. And we are good. So for the article factory, let's just fill this in. So we can just generate
01:24
out some fake ones. We've got a title here, which we'll use sentence for again. And let's make this five. Now what I tend to do if I'm working with a factory that has a slug is I assign the title the point that is assigned within this array. And then for the slug, we can just say string slug on that title. So we end up with an exact match here. So
01:49
if we now go over to tinker, we are going to say app models and article. Grab out the factory instance, we'll just create one here. And there we go. So now you can see that the slug matches the title exactly. Okay, so now what we're going to do if we exit out of here, we're going to build up a route for this. So we are going to build a controller. First of all,
02:16
this is going to be article show controller. And let's go ahead and say route get articles, as we said in the last episode and article that's going to use root model binding. Let's say article show controller, hook that up. And we'll give this a name as well. So articles dot show is a convention I usually take. So now over an article show controller, again, this is invocable,
02:44
we will get through an article model directly into here. And we'll call that article. Now one thing that we do want to do is make sure we pluck that out by the slug. So the slug is going to be the thing that we're going to have in the URL. And let's just dump the article title here just to make sure that this is working. And over in the database, we'll grab the slug for this,
03:06
we'll come over to our application, we'll go over to articles, the slug, and there we go. Great. So that is working really nicely. And then on this page that we're going to eventually build, we will just dump the comments, which will eventually be within its own component or well, we'll see, we don't really know at this point. So let's return a view called articles dot show. And we
03:27
will pass the article down to that that will allow us to extract the specific comments from the article. So let's pass the article down. And let's generate out the view for this. So make view articles dot show. There we go. So over in show, the first thing that we want to do is use our layout that we created earlier. And then I'm just going to dump out the article inside of there.
03:51
And there we go. Okay, so at this point, we need to start to think about the polymorphism. So we've got the setup here that allows us to do this. Now, ideally, what we want is for any kind of model like an article that we have, we want to be able to create out a comments relationship, because we need to be able to create comments for a particular model. So if we render out the comment system on
04:15
this article page, when a user creates a comment for that article, it needs to be assigned to that article. And if it was a episode, it would do the same exactly what happens on code course. But how do we set up this relationship? Well, let's go to the Laravel doc, just to sort of remind myself of how we're going to set up a polymorphic relationship here. Now, the reason
04:35
we want a polymorphic relationship set up is if we didn't, in the comment structure, we would have something like the following article ID. Now, we don't want we could do if comments were just for an article, but in our case, we want to be for any model type. So that's where the polymorphism comes in. So over in the documentation here, we want a polymorphic type. So let's just find these.
05:01
And we want a one to many. So one to many means that we have a table structure that would look like this. And in fact, there's an exact comments example in the docs, which for us is obviously going to be super helpful. So we've got two examples here, posts, and videos, which don't have any sort of link to the comments. But then on the comments model, we have a commentable ID
05:23
and a commentable type. So the type is going to be something like the videos model, and the post model, depending on which one we've commented on, and the ID will be the ID of either of these. If this doesn't make sense at the moment, don't worry, as we go through this, and we start to create some example data, it will do. So how do we do this? Well, let's go and make out a migration.
05:43
And of course, we could have done this when we set up the comments table, but we're just working through this slowly. So add, let's say add commentable to comments table, you can call that whatever you want, add commentable to comments table. So what we do here, we're going to modify the schema, we're not going to add commentable type and commentable ID,
06:07
we're going to use the morphs helper here over on the blueprint for building up the table. Now for polymorphic relationships, we give this a name like the following. So it's comment, so the singular version of whatever we're doing, able. So imagine if you were allowed to upload videos on any models, as an example, this would be videoable. Now, sometimes it doesn't make sense,
06:30
but that's fine. So if we use table morphs commentable, and I go ahead and say phpr to migrate, what that's going to do is it's going to add, if we head over to the database, the commentable type and the commentable ID. So over in data, let's get rid of all of these but one. And I'm going to show you what this comment would look like by default, if we were assigning
06:52
it to article with an ID of one, it would look like this by default, app models article. So that's the commentable type, the model type that we are saving this article to, and commentable ID would be one. Now, before we do anything, we want to talk about building up a morph map. And there's a good reason for this. Now, we might move the location of the article model around in our
07:18
application at some point. So we don't really want the database to reflect our application structure. It's not great to do because you're just going to have to update things, your database in the future. What we want is we want this to say article, we just want to say article and then wherever the model is, it doesn't matter. So how do we map this up? Well, over in
07:38
app service provider, let's come down here and let's build this out. So I think it's relation and morph map. Yeah, there we go. So we've got morph map here. In an array here, we just say article and then we assign this the value that we would normally see in the database, which is the full path to the article. So we can just use the fully qualified namespace here with the scope resolution
08:03
operator and class and that will map this up for us. We'll see this in action later when we're creating comments and when we're retrieving comments. But for now, that should hook this up really nicely. Okay, so what about these relationships? Well, let's go over and look at the example in the documentation here. So the comment itself is going to have this commentable relationship
08:23
with morph2 returned from this. So let's go ahead and do that first of all. Over in comment, let's create out a commentable which returns morph2. Of course, you don't need to type in this if you don't want to. And we're going to say this morph2. Now, this is helpful because if we're accessing a comment or a collection of comments, what we can do by commentable, commentable
08:47
is going to return the thing that has been commented on. We know that can be either an article, an episode, whatever we are applying comments to. So this is helpful not only for creating things via comment or reading things via comments, but Laravel uses this in the back end as well. So the next thing we want to do is on either of the models that we're working with, comment here
09:11
on a post or comment here on a video, we want a morph many on the actual thing itself. So the comment with the commentable type that we added earlier. So we've only got articles at the moment, but we can add them to the others later. And we're going to say comment. And of course, this relationship is then going to allow us to create comments via this article. So we're going to say morph many,
09:36
return this and morph many. And that's going to relate to a comment. So that's the thing that this relates to. And the second argument here is commentable. Okay, that's it. So hopefully that makes sense. But if not, let's go ahead and just start to fake creating an article or a comment through an article just to test things out. So where should we do this? I don't, again, I don't
10:01
think writing a test for this is particularly useful, but should we? No, no, let's not write a test because it's too, it's too sort of narrowed down. I'm just going to create a route out to demonstrate this for you so you know what's going on. So let's say comments and let's just create a closure in here. Okay, so let's assume that we're on this articles page and we want to add a comment
10:25
to this article. Let's fetch the article first of all. So let's say article find one. Let's go over to the database and just make sure that that is an ID of one. Yep. So now we're going to say die dump article comments just to verify that this relationship is there. So let's come over to comments and yeah, there we go. We've got a collection of comments. Of course, there aren't
10:49
any at the moment. Let's run through the polymorphic process of creating a comment via this relationship. So we're going to say article comments and what do we need to do? Well, we need to create a comment here with the necessary data that we need to fill. In our case, it's going to be body. So I'm just going to say hey there. Now what this will do behind the scenes, it will create out the comment. Now, of
11:15
course, we need to attach a user as well. We'll get to that in just a second. It will fill the body in but it will fill commentable type and commentable ID because we're doing it via this comment relationship which is a polymorphic relationship. So actually, because we need to assign a user ID as well, what we're going to do is we're going to create out and say set. I think we can say save.
11:39
Let's just try this out. So let's say comment equals comment. Let's say make or no, let's say user. Now, we don't have a user at the moment so I'm going to go ahead and find that first user but normally that would come from the user who is currently authenticated. So find one, make and then we're going to pass in the body. So comments make and let's just say hey there and then we're
12:09
going to save. I think we can do this comment. Okay, let's try it out and then if we can't, we'll see. Okay, yeah. Let's just make sure we pull that user in and let's try that out. Okay, let's have a look in the database and that should have worked nicely. Okay, so I did this twice. That's fine and you can see. So it's assigned to a user, it has a body, it's a basic relationship stuff but then the
12:30
commentable type now is article which remember we added that to our morph map and the commentable ID is one. So now this article, this article has two comments. Now if we went and commented on another article, this would be article two. If we went and commented on an episode, that would be episode and then the thing. That is the polymorphic relationship. So hopefully now that makes a little bit more
12:53
sense. Now of course we will get to actually creating these properly later. I just wanted to demonstrate it out there just so you knew and of course let's return back to what we did a little bit earlier. Article comments and that is now going to give us a collection of comments for that particular article. I've just deleted them out the database but that would be a collection
13:17
of them comment models. So polymorphic relationships are now set up. What do we need to do next? Well to be honest we are just going to start building out the ability to see a list of comments on this page and then of course get to the point where we can create comments via this as well. So let's go over and take a look at that next.

Episode summary

In this episode, we're taking our comments system to the next level by making it polymorphic—that means comments will be able to belong to any model type in our Laravel app (not just one specific thing like articles). This might sound a bit technical if you're new to Laravel, but we'll walk through it step by step and it starts to make sense as we go along.

We kick things off by setting up a quick example: we make an Article model, migration, and factory, keep things simple, and generate some sample articles. Then, we tie this into our routes and controller, wiring up article pages using route model binding so we can view them by their slug.

Once that's in place, we get into the core of polymorphism. Instead of tying comments directly to articles (using something like article_id), we update our comments table using Laravel's morphs helper. This gives us two new columns: commentable_type and commentable_id, letting comments reference any type of model, not just articles.

To clean up the way these types are stored, we use a morph map so our database only says "article" rather than a full namespace path. This futureproofs our DB if we end up moving models around later.

After wiring up the relationships in our models (using morphTo and morphMany), we test everything out by faking the creation of comments—showing how a comment ends up linked to the right article or anything else in the future. We even go over assigning the right user to a comment and make sure the relationships are all behaving as expected.

By the end, we've got a fully polymorphic comments system ready for use across different parts of our app. Next up, we'll work on displaying those comments and fleshing out the front end!

Episode discussion

No comments, yet. Be the first!