From af1298c2b8639fbb52656bd49623d2367cdfe46c Mon Sep 17 00:00:00 2001 From: Caleb White Date: Fri, 5 Jul 2024 16:26:54 -0500 Subject: [PATCH] fix: findOr and firstOr generics (#52037) --- src/Illuminate/Database/Eloquent/Builder.php | 16 ++++++++-------- .../Eloquent/Relations/BelongsToMany.php | 18 +++++++++--------- .../Eloquent/Relations/HasOneOrManyThrough.php | 18 +++++++++--------- src/Illuminate/Database/Query/Builder.php | 10 ++++++---- types/Database/Eloquent/Builder.php | 4 ++-- types/Database/Eloquent/Relations.php | 14 ++++++++------ types/Database/Query/Builder.php | 3 +++ 7 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 89ee41e19dc5..a7a2a0d6b266 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -530,15 +530,15 @@ public function findOrNew($id, $columns = ['*']) /** * Find a model by its primary key or call a callback. * - * @template TFindOrValue + * @template TValue * * @param mixed $id - * @param \Closure|array|string $columns - * @param (\Closure(): TFindOrValue)|null $callback + * @param (\Closure(): TValue)|list|string $columns + * @param (\Closure(): TValue)|null $callback * @return ( * $id is (\Illuminate\Contracts\Support\Arrayable|array) * ? \Illuminate\Database\Eloquent\Collection - * : ($callback is null ? TModel|null : TModel|TFindOrValue) + * : TModel|TValue * ) */ public function findOr($id, $columns = ['*'], ?Closure $callback = null) @@ -640,11 +640,11 @@ public function firstOrFail($columns = ['*']) /** * Execute the query and get the first result or call a callback. * - * @template TFirstOrValue + * @template TValue * - * @param \Closure|array|string $columns - * @param (\Closure(): TFirstOrValue)|null $callback - * @return ($callback is null ? TModel|null : TModel|TFirstOrValue) + * @param (\Closure(): TValue)|list $columns + * @param (\Closure(): TValue)|null $callback + * @return TModel|TValue */ public function firstOr($columns = ['*'], ?Closure $callback = null) { diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index e2067b4cd864..121abb5b026c 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -737,15 +737,15 @@ public function findOrFail($id, $columns = ['*']) /** * Find a related model by its primary key or call a callback. * - * @template TFindOrValue + * @template TValue * * @param mixed $id - * @param \Closure|array $columns - * @param (\Closure(): TFindOrValue)|null $callback + * @param (\Closure(): TValue)|list|string $columns + * @param (\Closure(): TValue)|null $callback * @return ( * $id is (\Illuminate\Contracts\Support\Arrayable|array) - * ? \Illuminate\Database\Eloquent\Collection - * : ($callback is null ? TRelatedModel|null : TRelatedModel|TFindOrValue) + * ? \Illuminate\Database\Eloquent\Collection|TValue + * : TRelatedModel|TValue * ) */ public function findOr($id, $columns = ['*'], ?Closure $callback = null) @@ -818,11 +818,11 @@ public function firstOrFail($columns = ['*']) /** * Execute the query and get the first result or call a callback. * - * @template TFirstOrValue + * @template TValue * - * @param \Closure|array $columns - * @param (\Closure(): TFirstOrValue)|null $callback - * @return ($callback is null ? TRelatedModel|null : TRelatedModel|TFirstOrValue) + * @param (\Closure(): TValue)|list $columns + * @param (\Closure(): TValue)|null $callback + * @return TRelatedModel|TValue */ public function firstOr($columns = ['*'], ?Closure $callback = null) { diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php index c0d87dec4a3e..f17152613121 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrManyThrough.php @@ -303,11 +303,11 @@ public function firstOrFail($columns = ['*']) /** * Execute the query and get the first result or call a callback. * - * @template TFirstOrValue + * @template TValue * - * @param \Closure|array $columns - * @param (\Closure(): TFirstOrValue)|null $callback - * @return ($callback is null ? TRelatedModel|null : TRelatedModel|TFirstOrValue) + * @param (\Closure(): TValue)|list $columns + * @param (\Closure(): TValue)|null $callback + * @return TRelatedModel|TValue */ public function firstOr($columns = ['*'], ?Closure $callback = null) { @@ -391,15 +391,15 @@ public function findOrFail($id, $columns = ['*']) /** * Find a related model by its primary key or call a callback. * - * @template TFindOrValue + * @template TValue * * @param mixed $id - * @param \Closure|array $columns - * @param (\Closure(): TFindOrValue)|null $callback + * @param (\Closure(): TValue)|list|string $columns + * @param (\Closure(): TValue)|null $callback * @return ( * $id is (\Illuminate\Contracts\Support\Arrayable|array) - * ? \Illuminate\Database\Eloquent\Collection - * : ($callback is null ? TRelatedModel|null : TRelatedModel|TFindOrValue) + * ? \Illuminate\Database\Eloquent\Collection|TValue + * : TRelatedModel|TValue * ) */ public function findOr($id, $columns = ['*'], ?Closure $callback = null) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index c2bd73c63398..84e7eca0ae85 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2894,7 +2894,7 @@ public function toRawSql() * * @param int|string $id * @param array|string $columns - * @return mixed|static + * @return object|null */ public function find($id, $columns = ['*']) { @@ -2904,10 +2904,12 @@ public function find($id, $columns = ['*']) /** * Execute a query for a single record by ID or call a callback. * + * @template TValue + * * @param mixed $id - * @param \Closure|array|string $columns - * @param \Closure|null $callback - * @return mixed|static + * @param (\Closure(): TValue)|list|string $columns + * @param (\Closure(): TValue)|null $callback + * @return object|TValue */ public function findOr($id, $columns = ['*'], ?Closure $callback = null) { diff --git a/types/Database/Eloquent/Builder.php b/types/Database/Eloquent/Builder.php index d5678898005f..dd49fea533e3 100644 --- a/types/Database/Eloquent/Builder.php +++ b/types/Database/Eloquent/Builder.php @@ -38,10 +38,10 @@ function test( assertType('Illuminate\Database\Eloquent\Collection', $query->findOr([1], callback: fn () => 42)); assertType('User', $query->findOrFail(1)); assertType('User|null', $query->find(1)); - assertType('User|null', $query->findOr(1)); + assertType('int|User', $query->findOr(1, fn () => 42)); assertType('int|User', $query->findOr(1, callback: fn () => 42)); assertType('User|null', $query->first()); - assertType('User|null', $query->firstOr()); + assertType('int|User', $query->firstOr(fn () => 42)); assertType('int|User', $query->firstOr(callback: fn () => 42)); assertType('User', $query->firstOrNew(['id' => 1])); assertType('User', $query->findOrNew(1)); diff --git a/types/Database/Eloquent/Relations.php b/types/Database/Eloquent/Relations.php index 9c109a129bf0..412e0c07cdfa 100644 --- a/types/Database/Eloquent/Relations.php +++ b/types/Database/Eloquent/Relations.php @@ -46,14 +46,15 @@ function test(User $user, Post $post, Comment $comment, ChildUser $child): void assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->findMany([1, 2, 3])); assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->findOrNew([1])); assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->findOrFail([1])); - assertType('Illuminate\Database\Eloquent\Collection', $user->roles()->findOr([1], callback: fn () => 42)); + assertType('Illuminate\Database\Eloquent\Collection|int', $user->roles()->findOr([1], fn () => 42)); + assertType('Illuminate\Database\Eloquent\Collection|int', $user->roles()->findOr([1], callback: fn () => 42)); assertType('Illuminate\Types\Relations\Role', $user->roles()->findOrNew(1)); assertType('Illuminate\Types\Relations\Role', $user->roles()->findOrFail(1)); assertType('Illuminate\Types\Relations\Role|null', $user->roles()->find(1)); - assertType('Illuminate\Types\Relations\Role|null', $user->roles()->findOr(1)); + assertType('Illuminate\Types\Relations\Role|int', $user->roles()->findOr(1, fn () => 42)); assertType('Illuminate\Types\Relations\Role|int', $user->roles()->findOr(1, callback: fn () => 42)); assertType('Illuminate\Types\Relations\Role|null', $user->roles()->first()); - assertType('Illuminate\Types\Relations\Role|null', $user->roles()->firstOr()); + assertType('Illuminate\Types\Relations\Role|int', $user->roles()->firstOr(fn () => 42)); assertType('Illuminate\Types\Relations\Role|int', $user->roles()->firstOr(callback: fn () => 42)); assertType('Illuminate\Types\Relations\Role|null', $user->roles()->firstWhere('foo')); assertType('Illuminate\Types\Relations\Role', $user->roles()->firstOrNew()); @@ -77,12 +78,13 @@ function test(User $user, Post $post, Comment $comment, ChildUser $child): void assertType('Illuminate\Database\Eloquent\Relations\HasOneThrough', $user->car()); assertType('Illuminate\Types\Relations\Car|null', $user->car()->getResults()); assertType('Illuminate\Database\Eloquent\Collection', $user->car()->find([1])); - assertType('Illuminate\Database\Eloquent\Collection', $user->car()->findOr([1], callback: fn () => 42)); + assertType('Illuminate\Database\Eloquent\Collection|int', $user->car()->findOr([1], fn () => 42)); + assertType('Illuminate\Database\Eloquent\Collection|int', $user->car()->findOr([1], callback: fn () => 42)); assertType('Illuminate\Types\Relations\Car|null', $user->car()->find(1)); - assertType('Illuminate\Types\Relations\Car|null', $user->car()->findOr(1)); + assertType('Illuminate\Types\Relations\Car|int', $user->car()->findOr(1, fn () => 42)); assertType('Illuminate\Types\Relations\Car|int', $user->car()->findOr(1, callback: fn () => 42)); assertType('Illuminate\Types\Relations\Car|null', $user->car()->first()); - assertType('Illuminate\Types\Relations\Car|null', $user->car()->firstOr()); + assertType('Illuminate\Types\Relations\Car|int', $user->car()->firstOr(fn () => 42)); assertType('Illuminate\Types\Relations\Car|int', $user->car()->firstOr(callback: fn () => 42)); assertType('Illuminate\Support\LazyCollection', $user->car()->lazy()); assertType('Illuminate\Support\LazyCollection', $user->car()->lazyById()); diff --git a/types/Database/Query/Builder.php b/types/Database/Query/Builder.php index 09a8f441bb8d..55ae1c28edc0 100644 --- a/types/Database/Query/Builder.php +++ b/types/Database/Query/Builder.php @@ -11,6 +11,9 @@ function test(Builder $query, EloquentBuilder $userQuery): void { assertType('object|null', $query->first()); + assertType('object|null', $query->find(1)); + assertType('int|object', $query->findOr(1, fn () => 42)); + assertType('int|object', $query->findOr(1, callback: fn () => 42)); assertType('Illuminate\Database\Query\Builder', $query->selectSub($userQuery, 'alias')); assertType('Illuminate\Database\Query\Builder', $query->fromSub($userQuery, 'alias')); assertType('Illuminate\Database\Query\Builder', $query->from($userQuery, 'alias'));