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
05. Ordering and eager loading

Transcript

00:00
So I want this comment component to be easily droppable into any model that we have comments enabled for.
00:08
We've pretty much already established that. But at the moment, we've got a bit of a problem. And that is that if, for example, we go over to our comments page just here,
00:20
or the comments component, we're iterating through our comments, which is fine. But at this point, we're accessing the comments relationship on the model,
00:29
which for us at the moment is this article, but we can't order this or eager load within this. So what do we do here? Do we go ahead and add in the scope
00:40
directly on the relationship itself? Well, no, I don't really tend to do this because I like to keep the relationships here nice and clean, and then only eager load
00:51
and go ahead and order where I need. So what we need to do here is get around doing this. Instead, we want to do something like this comments or something like that within the component.
01:02
So we can grab these out really easily. So what we're going to do is we're going to head over to the actual comments component in itself. And we're going to come back
01:11
to where we originally added that model within our constructor when it broke. I think I know why it broke. So we'll check that out in just a second.
01:18
But the first thing I'm going to do is get rid of this model prop within the component. Now, if we give that a refresh, that's going to have broken this
01:25
because it's unaware of this prop. But if we come over to the comments component, let's add this back in. So let's say public model, pull that in and say model.
01:35
Now, I think this is not going to work until we go ahead and say phpArt and view clear. Now, when we come over, that does work. So you can see now we've got access to the model,
01:44
we've got access to the relationship and everything is working as we would expect. So just something that you need to experiment with when you're tweaking around components,
01:53
bear in mind that there is caching involved here. So if something's not working, you want to go ahead and clear out your views. So what we can do this,
02:00
now that this is a model within here, is we can create helper methods. So let's go ahead and create our method in here to grab the comments.
02:09
Rather than directly access the model, we'll just create a comments relationship here. So let's say this model comments, we'll just keep it super simple for now.
02:18
So we'll just leave it as it is for now. And let's see how we switch this over. Now, do we do this? And again, I'm going to go ahead and view clear on that
02:26
and give that a refresh. And yeah, we do. So we've now got a variable called comment available, which is that method just here.
02:33
I'm not sure if we can do this. I don't know if that actually works. That would be sort of similar to the way that LiveWire works.
02:40
And yeah, it doesn't work because we're not in the context of an object. So it's comment count, and this will be comments comment. So clear our view cache again, and there we go.
02:49
So this is working now. And what this enables us to do, there is a slight drawback to that in that we're going to be adding an extra query here,
02:58
but it means that anywhere we drop these comments now, we don't need to egoload at the controller level. Now, let me just show you what I mean by that before we go on.
03:06
So what I'd normally have to do here, if I weren't egoloading within that component, which is what we want, because we want this component to be super easy to use,
03:14
we would have to do something like this, article load, then we would have to load in comments, and we would have to load the user as part of them comments. We would have to order these at this point here.
03:27
It just gets really messy. And then that means if we wanted to output a bunch of comments for an episode, we would have to replicate what we'd done here
03:35
over in that controller as well. What I want to do is just pass the article down, the episode down, the course down, whatever we are allowing comments for.
03:43
And I just want this comments component to work, and I want it to egoload everything and order stuff for me, all that stuff. So what are we doing here?
03:50
Well, let's go back over to the comments component here. We're not doing this because from the model, just remember a model instance, we want to extract the comments out,
03:59
but we want to start loading these, loading any egoloading. And of course we want to order. So what do we do?
04:07
Well, we access this as in the actual relationship, and we say something like get. So now when I refresh, we get exactly the same thing. Obviously, if we clear our view here,
04:18
we should get exactly the same thing, like so. We are introducing an additional query here, but we can egoload here as well. So let's just go through the whole process of doing this.
04:28
So I'm going to say latest, because I want the latest to be at the top. And let's just pull this down a little bit here. We're going to say comments with user.
04:43
And let's go ahead and clear our view here, give that a refresh. Okay, so we have got seven queries here. Now it looks like we do have a duplicate.
04:52
So we've got comments and comments for both of these. Let's just have a look at what we're doing here. Okay, so let's go over to comments. And yeah, that's because we're using this twice.
05:06
So you can see we've got comments count here, and then we're iterating over the comments. So whenever we access this comments variable, what it's doing is it's going ahead
05:14
and running an additional query here for this. So if we just go over and have a look here, yeah. So we've basically got a duplicate of this. Now there's a bunch of ways that we can get around this,
05:25
but actually what I'm going to do is I'm going to use the once helper within Laravel. What this will do is it will return to us the value that we give,
05:34
but it will cache it so we can use it multiple times. Now, if you're used to working with something like Livewire, this is pretty much a computed property, cached computed property.
05:45
So we're going to create a closure in here, and we're going to return this model comments with user latest and get. Now, if we come over, we've got five queries.
05:55
So we're only running that query once. Now, it does look like we've got this twice here. So let's just have a look at where these are coming from. So comments.php there,
06:04
comments.blade.php, so I think we just have a look at this. Yes, and model comments count, we're doing the same thing. So let's get rid of that one. And we should be down to five queries.
06:17
And yeah, we're still out of date. I think we just need to clear our views here. Okay, so we're still at five queries. So let's have a look.
06:25
So we've got this query here, and then still running comments.blade.php. So where is that coming from? Ah, there we go.
06:33
Okay, right. We'll get there eventually. So just all instances of this now are using this, which is cached once, or returned,
06:43
but cached for an unlimited amount of times we can use this within one request cycle. So let's just go and do a clear cache on that. And yeah, there we go.
06:52
We're down to four queries, which is perfect. But most of these are not related to the comments itself. We've really just got one query here for all of our comments.
07:01
So that's perfect. So now we're ordering these in the right way. And just to prove that, let's go ahead and set this another comment
07:11
to the latest comment. There we go. So that one's at the very top now. And we know that we're egoloading stuff
07:18
because you can see it in the query. We're fetching the users here, where user is in the list of IDs of the users who have commented,
07:25
which is just one for now. Everything's looking good. So there we go. Probably we'll adjust this a little bit later,
07:33
but at least now what we've got is the control at the level of the component. So we don't need to mess around egoloading stuff in here. We don't need to think about it.
07:42
That's the goal here. We want to take whatever we are outputting. We want to pass it down, use it as we normally would. But then what we want to do
07:50
is we want to chuck in the comments component, passing in the model, and not have to think about egoloading, ordering, or any other stuff.

Episode summary

In this episode, we focus on making our comments component really easy to use and reusable across any model in the app that supports comments. The goal is to ensure you can just drop the comments component in, pass a model to it, and have it handle ordering and eager loading all by itself — without having to clutter your controllers or worry about duplicate queries.

You'll see the pitfalls of eager loading and ordering directly on Eloquent relationships and why it's better to keep things messy out of your relationships. Instead, we move the logic into the component itself, creating a helper to fetch the relevant comments ordered by newest first, and eager loaded with their users. We then introduce Laravel's once helper to cache this query within the request, so you aren’t making duplicate database hits if you reference the comments multiple times in your template.

You'll also see some troubleshooting around view cache and query counts, with a few examples showing how everything is working as expected (the latest comments bubble up to the top, eager loading works, and the query count stays efficient). The end result is a really neat and maintainable way to handle comments across your app: just pass in a model, let the component take care of the rest, and forget about loading, ordering, or eager loading anywhere else!

Episode discussion

No comments, yet. Be the first!