PHPORM-492 Fix PHPDoc return and param types for raw() methods - #3526
Merged
Conversation
The @PARAM type for the Closure argument was missing the \MongoDB\Collection parameter that is passed at runtime. The @return type for the null case incorrectly referenced Illuminate Collection classes instead of \MongoDB\Collection. For Eloquent\Builder::raw(), the Closure case was also missing TModel and Collection<int, TModel> as possible return types, which caused static analysis tools to report false positives when the result was used as a model.
There was a problem hiding this comment.
Pull request overview
This PR updates PHPDoc for raw() methods in the MongoDB Laravel query and Eloquent builders to better align with runtime behavior and improve static analysis (PHPStan/Psalm) accuracy.
Changes:
- Adjust
raw()PHPDoc so Closure parameters reflect that a\MongoDB\Collectionis passed at runtime. - Correct
raw()PHPDoc return types for thenullcase to indicate\MongoDB\Collectionis returned. - Add PHPStan type-level tests to validate
raw()param/return typing.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| tests/PHPStan/BuilderRawTypes.php | Adds PHPStan assertType() checks for Query\Builder::raw() and Eloquent\Builder::raw() behaviors. |
| src/Query/Builder.php | Updates raw() PHPDoc Closure parameter type and null return type to \MongoDB\Collection. |
| src/Eloquent/Builder.php | Updates raw() PHPDoc Closure parameter type and expands Closure return types; also touches the null return type. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+226
to
229
| * @param (Closure(\MongoDB\Collection):T)|Expression|null $value | ||
| * | ||
| * @return ($value is Closure ? T : ($value is null ? Collection : Expression)) | ||
| * @return ($value is Closure ? T|TModel|Collection<int, TModel> : ($value is null ? \MongoDB\Collection : Expression)) | ||
| * |
Contributor
There was a problem hiding this comment.
What this guy said I guess 😅
Member
Author
There was a problem hiding this comment.
Good catch! Both points fixed:
Expressionreturn type now uses\Illuminate\Contracts\Database\Query\Expression(the interface actually returned by$this->query->raw()).- For the
CursorInterfacecase, I added a nested conditional:T is CursorInterface ? Collection<int, TModel> : T|TModel|Collection<int, TModel>— PHPStan now correctly infersCollection<int, TModel>and no longer includesCursorInterfacein the union.
Comment on lines
+45
to
+48
| assertType( | ||
| 'Illuminate\Database\Eloquent\Collection<int, MongoDB\Laravel\Tests\Models\User>|MongoDB\Driver\CursorInterface|MongoDB\Laravel\Tests\Models\User', | ||
| $builder->raw(fn (MongoDBCollection $c) => $c->find([])), | ||
| ); |
…ion tests The @return PHPDoc for the non-Closure/non-null case referenced MongoDB\Builder\Expression (the local import) but the method delegates to Query\Builder::raw() which wraps the value in a new Illuminate\Database\Query\Expression.
paulinevos
approved these changes
Jun 17, 2026
…r::raw() return type $this->query is declared as Illuminate\Database\Query\Builder, whose raw() returns the Illuminate\Contracts\Database\Query\Expression interface, not the concrete class.
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes https://jira.mongodb.org/browse/PHPORM-492
Summary
The
@paramand@returnPHPDoc types onraw()had several issues.@param— Closure argument type:Both
Query\Builder::raw()andEloquent\Builder::raw()declared the Closure asClosure():T(no arguments), but the Closure actually receives a\MongoDB\Collectioninstance at runtime.@return— null case:Both builders declared returning
Collection(eitherIlluminate\Support\CollectionorIlluminate\Database\Eloquent\Collection) when$valueisnull. The method actually returns the raw\MongoDB\Collectionobject.@return— Expression case (Eloquent\Builderonly):ExpressioninEloquent\Builderresolves toMongoDB\Builder\Expression(the local import), but the method delegates toQuery\Builder::raw()which returns anIlluminate\Contracts\Database\Query\Expression.@return— Closure case (Eloquent\Builderonly):The return type was declared as
T(the Closure's return type), butEloquent\Builder::raw()post-processes the result:Tis aCursorInterface, it is always hydrated intoCollection<int, TModel>— the cursor is never returned._idorid), it is converted to aTModelinstance.A nested conditional type fixes the
CursorInterfacecase:PHPStan type tests are added in
tests/PHPStan/BuilderRawTypes.phpto validate all cases.