Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
fix: add TPivotModel default and define pivot property in {Belongs,Mo…
…rph}ToMany
  • Loading branch information
calebdw committed Mar 19, 2025
commit bd08fa6ef7c848b9b6037d7dcf5a8a2345b92d04
87 changes: 55 additions & 32 deletions src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@
/**
* @template TRelatedModel of \Illuminate\Database\Eloquent\Model
* @template TDeclaringModel of \Illuminate\Database\Eloquent\Model
* @template TPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot
* @template TPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot = \Illuminate\Database\Eloquent\Relations\Pivot
Copy link
Member

@crynobone crynobone Mar 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are use cases where project using \Illuminate\Database\Eloquent\Relations\Concerns\AsPivot&\Illuminate\Database\Eloquent\Model instead of \Illuminate\Database\Eloquent\Relations\Pivot

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be necessary to have an interface for this

Copy link
Contributor Author

@calebdw calebdw Mar 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

\Illuminate\Database\Eloquent\Relations\Concerns\AsPivot&\Illuminate\Database\Eloquent\Model is not a correct type because you can't have a trait in a intersection type:

The user just needs to extend from Pivot/MorphPivot

* @template TAccessor of string = 'pivot'
*
* @extends \Illuminate\Database\Eloquent\Relations\Relation<TRelatedModel, TDeclaringModel, \Illuminate\Database\Eloquent\Collection<int, TRelatedModel>>
* @extends \Illuminate\Database\Eloquent\Relations\Relation<TRelatedModel, TDeclaringModel, \Illuminate\Database\Eloquent\Collection<int, TRelatedModel&object{pivot: TPivotModel}>>
*
* @todo use TAccessor when PHPStan bug is fixed: https://github.com/phpstan/phpstan/issues/12756
*/
class BelongsToMany extends Relation
{
Expand Down Expand Up @@ -136,7 +139,7 @@ class BelongsToMany extends Relation
/**
* The name of the accessor to use for the "pivot" relationship.
*
* @var string
* @var TAccessor
*/
protected $accessor = 'pivot';

Expand Down Expand Up @@ -327,8 +330,12 @@ public function getPivotClass()
/**
* Specify the custom pivot model to use for the relationship.
*
* @param class-string<TPivotModel> $class
* @template TNewPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot
*
* @param class-string<TNewPivotModel> $class
* @return $this
*
* @phpstan-this-out static<TRelatedModel, TDeclaringModel, TNewPivotModel, TAccessor>
*/
public function using($class)
{
Expand All @@ -340,8 +347,12 @@ public function using($class)
/**
* Specify the custom pivot accessor to use for the relationship.
*
* @param string $accessor
* @template TNewAccessor of string
*
* @param TNewAccessor $accessor
* @return $this
*
* @phpstan-this-out static<TRelatedModel, TDeclaringModel, TPivotModel, TNewAccessor>
*/
public function as($accessor)
{
Expand Down Expand Up @@ -580,7 +591,11 @@ public function orderByPivot($column, $direction = 'asc')
*
* @param mixed $id
* @param array $columns
* @return ($id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>) ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel> : TRelatedModel)
* @return (
* $id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>)
* ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel&object{pivot: TPivotModel}>
* : TRelatedModel&object{pivot: TPivotModel}
* )
*/
public function findOrNew($id, $columns = ['*'])
{
Expand All @@ -596,7 +611,7 @@ public function findOrNew($id, $columns = ['*'])
*
* @param array $attributes
* @param array $values
* @return TRelatedModel
* @return TRelatedModel&object{pivot: TPivotModel}
*/
public function firstOrNew(array $attributes = [], array $values = [])
{
Expand All @@ -614,7 +629,7 @@ public function firstOrNew(array $attributes = [], array $values = [])
* @param array $values
* @param array $joining
* @param bool $touch
* @return TRelatedModel
* @return TRelatedModel&object{pivot: TPivotModel}
*/
public function firstOrCreate(array $attributes = [], array $values = [], array $joining = [], $touch = true)
{
Expand All @@ -640,7 +655,7 @@ public function firstOrCreate(array $attributes = [], array $values = [], array
* @param array $values
* @param array $joining
* @param bool $touch
* @return TRelatedModel
* @return TRelatedModel&object{pivot: TPivotModel}
*/
public function createOrFirst(array $attributes = [], array $values = [], array $joining = [], $touch = true)
{
Expand All @@ -666,7 +681,7 @@ public function createOrFirst(array $attributes = [], array $values = [], array
* @param array $values
* @param array $joining
* @param bool $touch
* @return TRelatedModel
* @return TRelatedModel&object{pivot: TPivotModel}
*/
public function updateOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true)
{
Expand All @@ -684,7 +699,11 @@ public function updateOrCreate(array $attributes, array $values = [], array $joi
*
* @param mixed $id
* @param array $columns
* @return ($id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>) ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel> : TRelatedModel|null)
* @return (
* $id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>)
* ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel&object{pivot: TPivotModel}>
* : (TRelatedModel&object{pivot: TPivotModel})|null
* )
*/
public function find($id, $columns = ['*'])
{
Expand All @@ -702,7 +721,7 @@ public function find($id, $columns = ['*'])
*
* @param mixed $id
* @param array $columns
* @return TRelatedModel
* @return TRelatedModel&object{pivot: TPivotModel}
*
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException<TRelatedModel>
* @throws \Illuminate\Database\MultipleRecordsFoundException
Expand All @@ -719,7 +738,7 @@ public function findSole($id, $columns = ['*'])
*
* @param \Illuminate\Contracts\Support\Arrayable|array $ids
* @param array $columns
* @return \Illuminate\Database\Eloquent\Collection<int, TRelatedModel>
* @return \Illuminate\Database\Eloquent\Collection<int, TRelatedModel&object{pivot: TPivotModel}>
*/
public function findMany($ids, $columns = ['*'])
{
Expand All @@ -739,7 +758,11 @@ public function findMany($ids, $columns = ['*'])
*
* @param mixed $id
* @param array $columns
* @return ($id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>) ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel> : TRelatedModel)
* @return (
* $id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>)
* ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel&object{pivot: TPivotModel}>
* : TRelatedModel&object{pivot: TPivotModel}
* )
*
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException<TRelatedModel>
*/
Expand Down Expand Up @@ -770,8 +793,8 @@ public function findOrFail($id, $columns = ['*'])
* @param (\Closure(): TValue)|null $callback
* @return (
* $id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>)
* ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel>|TValue
* : TRelatedModel|TValue
* ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel&object{pivot: TPivotModel}>|TValue
* : (TRelatedModel&object{pivot: TPivotModel})|TValue
* )
*/
public function findOr($id, $columns = ['*'], ?Closure $callback = null)
Expand Down Expand Up @@ -804,7 +827,7 @@ public function findOr($id, $columns = ['*'], ?Closure $callback = null)
* @param mixed $operator
* @param mixed $value
* @param string $boolean
* @return TRelatedModel|null
* @return (TRelatedModel&object{pivot: TPivotModel})|null
*/
public function firstWhere($column, $operator = null, $value = null, $boolean = 'and')
{
Expand All @@ -815,7 +838,7 @@ public function firstWhere($column, $operator = null, $value = null, $boolean =
* Execute the query and get the first result.
*
* @param array $columns
* @return TRelatedModel|null
* @return (TRelatedModel&object{pivot: TPivotModel})|null
*/
public function first($columns = ['*'])
{
Expand All @@ -828,7 +851,7 @@ public function first($columns = ['*'])
* Execute the query and get the first result or throw an exception.
*
* @param array $columns
* @return TRelatedModel
* @return TRelatedModel&object{pivot: TPivotModel}
*
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException<TRelatedModel>
*/
Expand All @@ -848,7 +871,7 @@ public function firstOrFail($columns = ['*'])
*
* @param (\Closure(): TValue)|list<string> $columns
* @param (\Closure(): TValue)|null $callback
* @return TRelatedModel|TValue
* @return (TRelatedModel&object{pivot: TPivotModel})|TValue
*/
public function firstOr($columns = ['*'], ?Closure $callback = null)
{
Expand Down Expand Up @@ -942,7 +965,7 @@ protected function aliasedPivotColumns()
* @param array $columns
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Pagination\LengthAwarePaginator
* @return \Illuminate\Pagination\LengthAwarePaginator<int, TRelatedModel&object{pivot: TPivotModel}>
*/
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{
Expand All @@ -960,7 +983,7 @@ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page',
* @param array $columns
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Contracts\Pagination\Paginator
* @return \Illuminate\Contracts\Pagination\Paginator<int, TRelatedModel&object{pivot: TPivotModel}>
*/
public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{
Expand All @@ -978,7 +1001,7 @@ public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'p
* @param array $columns
* @param string $cursorName
* @param string|null $cursor
* @return \Illuminate\Contracts\Pagination\CursorPaginator
* @return \Illuminate\Contracts\Pagination\CursorPaginator<int, TRelatedModel&object{pivot: TPivotModel}>
*/
public function cursorPaginate($perPage = null, $columns = ['*'], $cursorName = 'cursor', $cursor = null)
{
Expand Down Expand Up @@ -1100,7 +1123,7 @@ public function each(callable $callback, $count = 1000)
* Query lazily, by chunks of the given size.
*
* @param int $chunkSize
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel>
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel&object{pivot: TPivotModel}>
*/
public function lazy($chunkSize = 1000)
{
Expand All @@ -1117,7 +1140,7 @@ public function lazy($chunkSize = 1000)
* @param int $chunkSize
* @param string|null $column
* @param string|null $alias
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel>
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel&object{pivot: TPivotModel}>
*/
public function lazyById($chunkSize = 1000, $column = null, $alias = null)
{
Expand All @@ -1140,7 +1163,7 @@ public function lazyById($chunkSize = 1000, $column = null, $alias = null)
* @param int $chunkSize
* @param string|null $column
* @param string|null $alias
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel>
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel&object{pivot: TPivotModel}>
*/
public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null)
{
Expand All @@ -1160,7 +1183,7 @@ public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null)
/**
* Get a lazy collection for the given query.
*
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel>
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel&object{pivot: TPivotModel}>
*/
public function cursor()
{
Expand Down Expand Up @@ -1300,7 +1323,7 @@ public function allRelatedIds()
* @param TRelatedModel $model
* @param array $pivotAttributes
* @param bool $touch
* @return TRelatedModel
* @return TRelatedModel&object{pivot: TPivotModel}
*/
public function save(Model $model, array $pivotAttributes = [], $touch = true)
{
Expand All @@ -1317,7 +1340,7 @@ public function save(Model $model, array $pivotAttributes = [], $touch = true)
* @param TRelatedModel $model
* @param array $pivotAttributes
* @param bool $touch
* @return TRelatedModel
* @return TRelatedModel&object{pivot: TPivotModel}
*/
public function saveQuietly(Model $model, array $pivotAttributes = [], $touch = true)
{
Expand Down Expand Up @@ -1368,7 +1391,7 @@ public function saveManyQuietly($models, array $pivotAttributes = [])
* @param array $attributes
* @param array $joining
* @param bool $touch
* @return TRelatedModel
* @return TRelatedModel&object{pivot: TPivotModel}
*/
public function create(array $attributes = [], array $joining = [], $touch = true)
{
Expand All @@ -1391,7 +1414,7 @@ public function create(array $attributes = [], array $joining = [], $touch = tru
*
* @param iterable $records
* @param array $joinings
* @return array<int, TRelatedModel>
* @return array<int, TRelatedModel&object{pivot: TPivotModel}>
*/
public function createMany(iterable $records, array $joinings = [])
{
Expand Down Expand Up @@ -1625,7 +1648,7 @@ public function getRelationName()
/**
* Get the name of the pivot accessor for this relationship.
*
* @return string
* @return TAccessor
*/
public function getPivotAccessor()
{
Expand Down
8 changes: 5 additions & 3 deletions src/Illuminate/Database/Eloquent/Relations/MorphToMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
/**
* @template TRelatedModel of \Illuminate\Database\Eloquent\Model
* @template TDeclaringModel of \Illuminate\Database\Eloquent\Model
* @template TPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot = \Illuminate\Database\Eloquent\Relations\MorphPivot
* @template TAccessor of string = 'pivot'
*
* @extends \Illuminate\Database\Eloquent\Relations\BelongsToMany<TRelatedModel, TDeclaringModel, \Illuminate\Database\Eloquent\Relations\Pivot>
* @extends \Illuminate\Database\Eloquent\Relations\BelongsToMany<TRelatedModel, TDeclaringModel, TPivotModel, TAccessor>
*/
class MorphToMany extends BelongsToMany
{
Expand Down Expand Up @@ -122,7 +124,7 @@ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery,
/**
* Get the pivot models that are currently attached.
*
* @return \Illuminate\Support\Collection<int, \Illuminate\Database\Eloquent\Relations\Pivot|\Illuminate\Database\Eloquent\Relations\MorphPivot>
* @return \Illuminate\Support\Collection<int, TPivotModel>
*/
protected function getCurrentlyAttachedPivots()
{
Expand All @@ -149,7 +151,7 @@ public function newPivotQuery()
*
* @param array $attributes
* @param bool $exists
* @return \Illuminate\Database\Eloquent\Relations\Pivot
* @return TPivotModel
*/
public function newPivot(array $attributes = [], $exists = false)
{
Expand Down
Loading
Loading