This episode is for members only

Sign up to access "Custom Laravel Query Builders" right now.

Get started
Already a member? Sign in to continue
Playing
02. Creating a custom query builder

Transcript

00:00
OK, let's start things off really simply
00:02
and create a custom query builder for our user model that just replaces this has verified email scope. Now, the key thing is this is going to look exactly the same.
00:12
We're not going to need to change any of the code that we actually use to call this. The underlying implementation will change. Plus, in the next episode, we will
00:22
talk about IDE autocompletion, which means we will get autocompletion for all of these kind of scopes that we're creating. OK, so let's go over to the user model
00:32
and just remind ourselves what we're doing at the moment. We're just creating our scope in here, which is a method prefixed with scope. We're going to go ahead and comment that out just
00:41
for reference. And down here, we're going to go ahead and override the default eloquent builder that's used when we go ahead and work with a query
00:51
builder on a model. Now, to do this is very, very simple. We just go ahead and call or override new eloquent builder. And of course, my IDE autocompleted that.
01:02
But if it didn't for you, you can go ahead and create this out. Now, we get query passed through. Let's go ahead and just die dump on query
01:10
and just see what we get here. So I'm actually going to get rid of this hasVerifiedEmail. And I'm just going to invoke query here, which will defer to this.
01:17
And you can see, sure enough, we get a query builder. So basically, all we need to do now is pass that query builder through to a custom query builder, which we can return from here.
01:28
And remember, because we're overriding this, this actually expects a query builder or a builder within Laravel to be returned. So don't worry if that doesn't make too much sense
01:37
at the moment. When we piece everything together, it will do. OK, so we want to return some sort of user builder. It's really up to you what you call these.
01:47
But really crucially, we want to pass through the builder that we get into this so we can continue to chain on those methods that are going to act like scopes.
01:57
So we need a place to create this user builder. It really doesn't matter where you do this. Of course, it just depends on the structure of your project. But I tend to create a builders directory in the root.
02:08
So let's go ahead and create out a user builder file in here. Let's, of course, go ahead and give this a namespace, which is now under App and Builders. And of course, this is now called our user builder.
02:21
Now, like I said, this is going to need to extend the base query builder. So let's go ahead and pull this in from database and Eloquent just here.
02:30
And that's pretty much it for now. We don't actually need to create a constructor in here because by default, the Eloquent builder, we just go ahead and open this up under the constructor,
02:41
except in, you guessed it, a query builder. So we don't need to do really much in here apart from create the methods that we need. OK, so now we have a dedicated class.
02:51
What we can actually do is just start to rip out any scopes that we've previously created or create new scopes and just implement them as normal methods.
03:01
So by that, I mean, let's just grab the query part that we have here so we don't have to repeat ourselves. I'm just going to implement this as a normal method, hasVerifiedEmail.
03:11
So let's call it hasVerifiedEmail. Now, let's think about the context that we're working in now. We're not going to get a query builder passed through to here
03:20
because we're working within a query builder. So rather than say query, we're not null, we're going to say this, we're not null. And also, we're going to need to return this
03:32
so it can be continued to chain on and be used. Because remember, we are not being passed a query builder. We want to return this so the next time we call something, it's going to have access to that builder.
03:45
So let's go ahead and just try this out. Let's go back over to our user model, make sure everything here looks good, it does. Let's go back over to web
03:54
and let's just run this and see what happens. So I'm going to go ahead and give this a refresh and yeah, sure enough, this has worked in exactly the same way.
04:02
What we've done though is got away from scopes and we've tidied this up into its own builder with its own dedicated methods, very clearly defined of what we want to do.
04:13
So you can now go ahead and create as many of these as you want. Of course, you're going to end up with a huge list inside of your user builder,
04:22
but they're much more clearly defined now rather than polluting your user model. Now, if we just head back over here, let's try and write this line out
04:31
and see what our IDE gives us. So I'm going to go ahead and use query to return specifically a new builder. And let's go ahead and say has verified email.
04:42
Now it doesn't look like, although my editor has suggested something, it doesn't look like it's giving us an actual method in here.
04:48
It's kind of guessing this from what we've written before. So IDE auto-completion isn't quite there yet. And there's a very good reason for that. So let's bring this back to our working example.
05:00
And in the next episode, we're going to touch on how to make sure our editor auto-completes all of our query builder methods for us.

Episode summary

In this episode, we kick things off by building a custom query builder for our User model. Instead of using Laravel's typical scope methods (like scopeHasVerifiedEmail), we move this logic into a dedicated builder class. The good news? The way you actually call these methods in your code remains exactly the same—nobody using your models will even notice the difference.

We go through the process step-by-step: overriding the newEloquentBuilder method in the User model, creating a dedicated UserBuilder class, and moving the scope logic into regular methods there. This results in a cleaner and more organized codebase, with all your user-related query logic grouped together, rather than cluttering up the model itself.

Finally, we test it out to make sure everything works just as before. One thing we notice, though: IDE autocompletion isn't giving us our custom methods yet. Stay tuned, because in the next episode, we'll tackle editor autocompletion so you get all the nice suggestions for your custom query builder methods!

Episode discussion

No comments, yet. Be the first!