diff --git a/stubs/6/EloquentBuilder.stubphp b/stubs/6/EloquentBuilder.stubphp new file mode 100644 index 00000000..637e07e5 --- /dev/null +++ b/stubs/6/EloquentBuilder.stubphp @@ -0,0 +1,25 @@ + +* @mixin \Illuminate\Database\Eloquent\Builder +*/ +abstract class HasOneOrMany extends Relation +{ + /** + * @param array $attributes + * @param array $values + * @return \Illuminate\Database\Eloquent\Model + * @psalm-return TRelatedModel + */ + public function firstOrNew(array $attributes, array $values = []) { } + + /** + * @param array $attributes + * @param array $values + * @return \Illuminate\Database\Eloquent\Model + * @psalm-return TRelatedModel + */ + public function firstOrCreate(array $attributes, array $values = []) { } +} diff --git a/stubs/8/EloquentBuilder.stubphp b/stubs/8/EloquentBuilder.stubphp new file mode 100644 index 00000000..0f4b4ab2 --- /dev/null +++ b/stubs/8/EloquentBuilder.stubphp @@ -0,0 +1,26 @@ + +* @mixin \Illuminate\Database\Eloquent\Builder +*/ +abstract class HasOneOrMany extends Relation +{ + /** + * @param array $attributes + * @param array $values + * @return \Illuminate\Database\Eloquent\Model + * @psalm-return TRelatedModel + */ + public function firstOrNew(array $attributes = [], array $values = []) { } + + /** + * @param array $attributes + * @param array $values + * @return \Illuminate\Database\Eloquent\Model + * @psalm-return TRelatedModel + */ + public function firstOrCreate(array $attributes = [], array $values = []) { } +} diff --git a/stubs/EloquentBuilder.stubphp b/stubs/EloquentBuilder.stubphp index c7db1cc9..5991af50 100644 --- a/stubs/EloquentBuilder.stubphp +++ b/stubs/EloquentBuilder.stubphp @@ -136,20 +136,6 @@ class Builder */ public function findOrNew($id, $columns = ['*']) { } - /** - * @param array $attributes - * @param array $values - * @return TModel - */ - public function firstOrNew(array $attributes, array $values = []) { } - - /** - * @param array $attributes - * @param array $values - * @return TModel - */ - public function firstOrCreate(array $attributes, array $values = []) { } - /** * @param array $attributes * @param array $values diff --git a/stubs/HasOneOrMany.stubphp b/stubs/HasOneOrMany.stubphp index 2dd65bf7..13463c13 100644 --- a/stubs/HasOneOrMany.stubphp +++ b/stubs/HasOneOrMany.stubphp @@ -4,7 +4,6 @@ namespace Illuminate\Database\Eloquent\Relations; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\Collection; /** * @template TRelatedModel of Model @@ -46,22 +45,6 @@ abstract class HasOneOrMany extends Relation */ public function findOrNew($id, $columns = ['*']) { } - /** - * @param array $attributes - * @param array $values - * @return \Illuminate\Database\Eloquent\Model - * @psalm-return TRelatedModel - */ - public function firstOrNew(array $attributes, array $values = []) { } - - /** - * @param array $attributes - * @param array $values - * @return \Illuminate\Database\Eloquent\Model - * @psalm-return TRelatedModel - */ - public function firstOrCreate(array $attributes, array $values = []) { } - /** * @param array $attributes * @param array $values diff --git a/tests/acceptance/EloquentBuilderTypes.feature b/tests/acceptance/EloquentBuilderTypes.feature index 3eedf72f..12daf5a0 100644 --- a/tests/acceptance/EloquentBuilderTypes.feature +++ b/tests/acceptance/EloquentBuilderTypes.feature @@ -15,73 +15,78 @@ Feature: Eloquent Builder types """ + And I have the following code preamble + """ + + * @return Builder */ - public function getNewQuery(): \Illuminate\Database\Eloquent\Builder + public function getNewQuery(): Builder { return User::query(); } /** - * @return \Illuminate\Database\Eloquent\Builder + * @return Builder */ - public function getNewModelQuery(): \Illuminate\Database\Eloquent\Builder + public function getNewModelQuery(): Builder { return (new User())->newModelQuery(); } /** - * @param \Illuminate\Database\Eloquent\Builder $builder + * @param Builder $builder */ - public function firstOrFailFromBuilderInstance(\Illuminate\Database\Eloquent\Builder $builder): User { + public function firstOrFailFromBuilderInstance(Builder $builder): User { return $builder->firstOrFail(); } /** - * @param \Illuminate\Database\Eloquent\Builder $builder + * @param Builder $builder */ - public function findOrFailFromBuilderInstance(\Illuminate\Database\Eloquent\Builder $builder): User { + public function findOrFailFromBuilderInstance(Builder $builder): User { return $builder->findOrFail(1); } /** - * @param \Illuminate\Database\Eloquent\Builder $builder - * @return \Illuminate\Database\Eloquent\Collection + * @param Builder $builder + * @return Collection */ - public function findMultipleOrFailFromBuilderInstance(\Illuminate\Database\Eloquent\Builder $builder): \Illuminate\Database\Eloquent\Collection { + public function findMultipleOrFailFromBuilderInstance(Builder $builder): Collection { return $builder->findOrFail([1, 2]); } /** - * @param \Illuminate\Database\Eloquent\Builder $builder + * @param Builder $builder */ - public function findOne(\Illuminate\Database\Eloquent\Builder $builder): ?User { + public function findOne(Builder $builder): ?User { return $builder->find(1); } /** - * @param \Illuminate\Database\Eloquent\Builder $builder + * @param Builder $builder */ - public function findViaArray(\Illuminate\Database\Eloquent\Builder $builder): \Illuminate\Database\Eloquent\Collection { + public function findViaArray(Builder $builder): Collection { return $builder->find([1]); } /** - * @return \Illuminate\Database\Eloquent\Builder + * @return Builder */ - public function getWhereBuilderViaInstance(array $attributes): \Illuminate\Database\Eloquent\Builder { + public function getWhereBuilderViaInstance(array $attributes): Builder { return (new User())->where($attributes); } } @@ -90,10 +95,16 @@ Feature: Eloquent Builder types Then I see no errors Scenario: can call static methods on model - Given I have the following code + Given I have the following code preamble """ + * @return Builder */ - public function getWhereBuilderViaStatic(array $attributes): \Illuminate\Database\Eloquent\Builder + public function getWhereBuilderViaStatic(array $attributes): Builder { return User::where($attributes); } /** - * @psalm-return \Illuminate\Database\Eloquent\Collection + * @psalm-return Collection */ - public function getWhereViaStatic(array $attributes): \Illuminate\Database\Eloquent\Collection + public function getWhereViaStatic(array $attributes): Collection { return User::where($attributes)->get(); } @@ -122,20 +133,25 @@ Feature: Eloquent Builder types Then I see no errors Scenario: - Given I have the following code + Given I have the following code preamble """ + * @return Builder */ - public function test_failure(): \Illuminate\Database\Eloquent\Builder + public function test_failure(): Builder { return User::fakeQueryMethodThatDoesntExist(); } @@ -150,11 +166,6 @@ Feature: Eloquent Builder types Scenario: can call methods on underlying query builder Given I have the following code """ - $builder * @psalm-return Builder @@ -165,3 +176,52 @@ Feature: Eloquent Builder types """ When I run Psalm Then I see no errors + + Scenario: cannot call firstOrNew and firstOrCreate without parameters in Laravel 6.x + Given I have the "laravel/framework" package satisfying the "6.*" + And I have the following code + """ + /** + * @psalm-param Builder $builder + * @psalm-return User + */ + function test_firstOrCreate(Builder $builder): User { + return $builder->firstOrCreate(); + } + + /** + * @psalm-param Builder $builder + * @psalm-return User + */ + function test_firstOrNew(Builder $builder): User { + return $builder->firstOrNew(); + } + """ + When I run Psalm + Then I see these errors + | Type | Message | + | TooFewArguments | Too few arguments for method Illuminate\Database\Eloquent\Builder::firstorcreate saw 0 | + | TooFewArguments | Too few arguments for method Illuminate\Database\Eloquent\Builder::firstornew saw 0 | + + Scenario: can call firstOrNew and firstOrCreate without parameters in Laravel 8.x + Given I have the "laravel/framework" package satisfying the ">= 8.0" + And I have the following code + """ + /** + * @psalm-param Builder $builder + * @psalm-return User + */ + function test_firstOrCreate(Builder $builder): User { + return $builder->firstOrCreate(); + } + + /** + * @psalm-param Builder $builder + * @psalm-return User + */ + function test_firstOrNew(Builder $builder): User { + return $builder->firstOrNew(); + } + """ + When I run Psalm + Then I see no errors diff --git a/tests/acceptance/EloquentRelationTypes.feature b/tests/acceptance/EloquentRelationTypes.feature index 97cf047f..e36764f0 100644 --- a/tests/acceptance/EloquentRelationTypes.feature +++ b/tests/acceptance/EloquentRelationTypes.feature @@ -356,3 +356,56 @@ Feature: Eloquent Relation types """ When I run Psalm Then I see no errors + + Scenario: cannot call firstOrNew and firstOrCreate without parameters in Laravel 6.x + Given I have the "laravel/framework" package satisfying the "6.*" + And I have the following code + """ + function test_hasOne_firstOrCreate(User $user): Phone { + return $user->phone()->firstOrCreate(); + } + + function test_hasOne_firstOrNew(User $user): Phone { + return $user->phone()->firstOrNew(); + } + + function test_hasMany_firstOrCreate(Post $post): Comment { + return $post->comments()->firstOrCreate(); + } + + function test_hasMany_firstOrNew(Post $post): Comment { + return $post->comments()->firstOrNew(); + } + """ + When I run Psalm + Then I see these errors + | Type | Message | + | TooFewArguments | Too few arguments for method Illuminate\Database\Eloquent\Relations\HasOneOrMany::firstorcreate saw 0 | + | TooFewArguments | Too few arguments for method Illuminate\Database\Eloquent\Relations\HasOneOrMany::firstornew saw 0 | + | TooFewArguments | Too few arguments for method Illuminate\Database\Eloquent\Relations\HasOneOrMany::firstorcreate saw 0 | + | TooFewArguments | Too few arguments for method Illuminate\Database\Eloquent\Relations\HasOneOrMany::firstornew saw 0 | + + + Scenario: can call firstOrNew and firstOrCreate without parameters in Laravel 8.x + Given I have the "laravel/framework" package satisfying the ">= 8.0" + And I have the following code + """ + function test_hasOne_firstOrCreate(User $user): Phone { + return $user->phone()->firstOrCreate(); + } + + function test_hasOne_firstOrNew(User $user): Phone { + return $user->phone()->firstOrNew(); + } + + function test_hasMany_firstOrCreate(Post $post): Comment { + return $post->comments()->firstOrCreate(); + } + + function test_hasMany_firstOrNew(Post $post): Comment { + return $post->comments()->firstOrNew(); + } + """ + When I run Psalm + Then I see no errors +