- Notifications
You must be signed in to change notification settings - Fork11.4k
[12.x] allow for custom builders in QueriesRelationships closures#55362
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:12.x
Are you sure you want to change the base?
[12.x] allow for custom builders in QueriesRelationships closures#55362
Conversation
calebdw commentedApr 11, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Thanks for attempting this---however, what you are trying to do is not possible with PHPDocs alone. Given the following example: /** * Add a relationship count / exists condition to the query with where clauses. * * @template TRelatedModel of \Illuminate\Database\Eloquent\Model+ * @template TRelatedModelBuilder of \Illuminate\Database\Eloquent\Builder<TRelatedModel> * * @param \Illuminate\Database\Eloquent\Relations\Relation<TRelatedModel, *, *>|string $relation- * @param (\Closure(\Illuminate\Database\Eloquent\Builder<TRelatedModel>): mixed)|null $callback+ * @param (\Closure(TRelatedModelBuilder): mixed)|null $callback * @param string $operator * @param int $count * @return $this */ public function whereHas($relation, ?Closure $callback = null, $operator = '>=', $count = 1) method templates can only be usedto extract type information from the given parameters. Meaning that:
Also, the existing template type ( $query->whereHas($user->posts(),function ($query) {// Knows that it's a Post Builder!assertType('Illuminate\Database\Eloquent\Builder<Illuminate\Types\Builder\Post>',$query);}); When using mypublished Larastan fork, Larastanis able to correctly determine what the builder type is and it handles custom builders (including nested relations). Here's some examples from the test suite: User::query()->whereHas('accounts',function (Builder$query) {assertType('Illuminate\Database\Eloquent\Builder<App\Account>',$query);});User::query()->withWhereHas('accounts.posts',function (Builder|Relation$query) {assertType('App\PostBuilder<App\Post>|Illuminate\Database\Eloquent\Relations\BelongsToMany<App\Post, App\Account, Illuminate\Database\Eloquent\Relations\Pivot,\'pivot\'>',$query);}); Iupstreamed a PR with this functionality, however, the PR was closed because there's still somelimitations with PHPStan...I guess it's a matter of if you want no support at all until it's fully supported or mostly supported with somequirks. In the meantime, if you want your editor and phpstan to know the builder type (without using my fork), you cannarrow the type: OrderItem::query()->whereHas('order',function ($q) {assert($qinstanceof OrderBuilder);return$q->shipped();}); Best, |
Uh oh!
There was an error while loading.Please reload this page.
The closure types added in#54452 are not accounting for custom query builders, and therefore the following code is triggering a
argument.type
error because the closure expectsBuilder<Order>