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
03. Typehinting the builder

Transcript

00:00
Let's think about why, at the moment, our IDE isn't auto-completing this hasVerifiedEmail method for us.
00:06
Now, when we use the QueryBuilder, as we've seen before, I can start typing things like WHERE, and my IDE can auto-complete this and give me all of the information about the arguments that we need. So that's really good, but why is that?
00:19
Well, that's because if we open up the base model, so inside of Eloquent, and we look for QUERY, this goes ahead and explicitly returns something. Now, my IDE can work out what that is, because eventually,
00:31
when we return this new query, if we follow this down, we get a builder instance. And those methods are defined on the builder. However, when we are over in our user model,
00:43
and we have this UserBuilder, my IDE doesn't quite know what's going on, because NewEloquentBuilder, we're not using directly. So let's go ahead and tidy this up by also overriding the Query method, which we are using.
00:57
So we're going to go ahead and create our static function QUERY, because we always call this statically, and we're going to go ahead and return ParentQuery. Now, that's not quite going to be enough,
01:08
because in here, we'd think, well, we could just return a new UserBuilder, surely. Not quite, just because of the way that Larafeld passes this through. Let's go over to web and just see what happens here.
01:19
So we're going to go ahead and say QUERY, and let's say HasVerifiedEmail, still not quite working. Now, we can make this work, if we just pull this back again to a working example,
01:30
by type hinting the return value of QUERY, which we know is eventually going to be a UserBuilder. So let's go ahead and type in the return value of this to UserBuilder. And while we're here, we may as well also type in this as well.
01:46
So now, my IDE will know that we're returning a UserBuilder. Let's try this again. So QUERY, HasVerifiedEmail, and there we go. We got an auto-completed method for that HasVerifiedEmail scope.
02:01
And I say scope, but of course, it isn't a scope, it's a method on our custom QueryBuilder. So now, that's much more convenient, and we can continue to chain on any of the methods that we have within our builder,
02:14
or of course, we can go and continue to chain on other methods that we have inside of our builder. For this though, of course, I'm just going to go ahead and say Get, give that a refresh, and we get the results that we've seen already.
02:26
To finish things up in the next episode, let's look at a slightly more complex example with using two different models, two different builders, and kind of combining these together.

Episode summary

In this episode, we're digging into why our IDE isn't auto-completing custom methods like hasVerifiedEmail on our query builder. We start by looking at the default Eloquent builder and notice that things like where are auto-completed, and that's mainly due to Laravel's base model typehinting its return values properly.

But when we switch over to our custom UserBuilder, the IDE loses track because it doesn't know we're actually returning our own builder. So, to fix this, we override the query method in our model, make sure it calls parent::query() and, most importantly, we add a return typehint to indicate that this returns a UserBuilder.

After doing this, our IDE starts playing nice—now when we call query()->hasVerifiedEmail(), we get proper auto-complete suggestions, which makes working with these kinds of custom builders way smoother.

We wrap things up by pointing out the opposite: before typehinting, the auto-completion just wasn't there, but now it recognizes all custom methods on our builder (even though they technically aren't scopes). In the next episode, we’ll go a bit deeper and see what happens when we have multiple models each with their own builders.

Episode discussion

No comments, yet. Be the first!