Skip to content

Commit bd08fa6

Browse files
committed
fix: add TPivotModel default and define pivot property in {Belongs,Morph}ToMany
1 parent d7b5366 commit bd08fa6

File tree

3 files changed

+99
-74
lines changed

3 files changed

+99
-74
lines changed

src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@
2020
/**
2121
* @template TRelatedModel of \Illuminate\Database\Eloquent\Model
2222
* @template TDeclaringModel of \Illuminate\Database\Eloquent\Model
23-
* @template TPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot
23+
* @template TPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot = \Illuminate\Database\Eloquent\Relations\Pivot
24+
* @template TAccessor of string = 'pivot'
2425
*
25-
* @extends \Illuminate\Database\Eloquent\Relations\Relation<TRelatedModel, TDeclaringModel, \Illuminate\Database\Eloquent\Collection<int, TRelatedModel>>
26+
* @extends \Illuminate\Database\Eloquent\Relations\Relation<TRelatedModel, TDeclaringModel, \Illuminate\Database\Eloquent\Collection<int, TRelatedModel&object{pivot: TPivotModel}>>
27+
*
28+
* @todo use TAccessor when PHPStan bug is fixed: https://github.com/phpstan/phpstan/issues/12756
2629
*/
2730
class BelongsToMany extends Relation
2831
{
@@ -136,7 +139,7 @@ class BelongsToMany extends Relation
136139
/**
137140
* The name of the accessor to use for the "pivot" relationship.
138141
*
139-
* @var string
142+
* @var TAccessor
140143
*/
141144
protected $accessor = 'pivot';
142145

@@ -327,8 +330,12 @@ public function getPivotClass()
327330
/**
328331
* Specify the custom pivot model to use for the relationship.
329332
*
330-
* @param class-string<TPivotModel> $class
333+
* @template TNewPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot
334+
*
335+
* @param class-string<TNewPivotModel> $class
331336
* @return $this
337+
*
338+
* @phpstan-this-out static<TRelatedModel, TDeclaringModel, TNewPivotModel, TAccessor>
332339
*/
333340
public function using($class)
334341
{
@@ -340,8 +347,12 @@ public function using($class)
340347
/**
341348
* Specify the custom pivot accessor to use for the relationship.
342349
*
343-
* @param string $accessor
350+
* @template TNewAccessor of string
351+
*
352+
* @param TNewAccessor $accessor
344353
* @return $this
354+
*
355+
* @phpstan-this-out static<TRelatedModel, TDeclaringModel, TPivotModel, TNewAccessor>
345356
*/
346357
public function as($accessor)
347358
{
@@ -580,7 +591,11 @@ public function orderByPivot($column, $direction = 'asc')
580591
*
581592
* @param mixed $id
582593
* @param array $columns
583-
* @return ($id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>) ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel> : TRelatedModel)
594+
* @return (
595+
* $id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>)
596+
* ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel&object{pivot: TPivotModel}>
597+
* : TRelatedModel&object{pivot: TPivotModel}
598+
* )
584599
*/
585600
public function findOrNew($id, $columns = ['*'])
586601
{
@@ -596,7 +611,7 @@ public function findOrNew($id, $columns = ['*'])
596611
*
597612
* @param array $attributes
598613
* @param array $values
599-
* @return TRelatedModel
614+
* @return TRelatedModel&object{pivot: TPivotModel}
600615
*/
601616
public function firstOrNew(array $attributes = [], array $values = [])
602617
{
@@ -614,7 +629,7 @@ public function firstOrNew(array $attributes = [], array $values = [])
614629
* @param array $values
615630
* @param array $joining
616631
* @param bool $touch
617-
* @return TRelatedModel
632+
* @return TRelatedModel&object{pivot: TPivotModel}
618633
*/
619634
public function firstOrCreate(array $attributes = [], array $values = [], array $joining = [], $touch = true)
620635
{
@@ -640,7 +655,7 @@ public function firstOrCreate(array $attributes = [], array $values = [], array
640655
* @param array $values
641656
* @param array $joining
642657
* @param bool $touch
643-
* @return TRelatedModel
658+
* @return TRelatedModel&object{pivot: TPivotModel}
644659
*/
645660
public function createOrFirst(array $attributes = [], array $values = [], array $joining = [], $touch = true)
646661
{
@@ -666,7 +681,7 @@ public function createOrFirst(array $attributes = [], array $values = [], array
666681
* @param array $values
667682
* @param array $joining
668683
* @param bool $touch
669-
* @return TRelatedModel
684+
* @return TRelatedModel&object{pivot: TPivotModel}
670685
*/
671686
public function updateOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true)
672687
{
@@ -684,7 +699,11 @@ public function updateOrCreate(array $attributes, array $values = [], array $joi
684699
*
685700
* @param mixed $id
686701
* @param array $columns
687-
* @return ($id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>) ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel> : TRelatedModel|null)
702+
* @return (
703+
* $id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>)
704+
* ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel&object{pivot: TPivotModel}>
705+
* : (TRelatedModel&object{pivot: TPivotModel})|null
706+
* )
688707
*/
689708
public function find($id, $columns = ['*'])
690709
{
@@ -702,7 +721,7 @@ public function find($id, $columns = ['*'])
702721
*
703722
* @param mixed $id
704723
* @param array $columns
705-
* @return TRelatedModel
724+
* @return TRelatedModel&object{pivot: TPivotModel}
706725
*
707726
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException<TRelatedModel>
708727
* @throws \Illuminate\Database\MultipleRecordsFoundException
@@ -719,7 +738,7 @@ public function findSole($id, $columns = ['*'])
719738
*
720739
* @param \Illuminate\Contracts\Support\Arrayable|array $ids
721740
* @param array $columns
722-
* @return \Illuminate\Database\Eloquent\Collection<int, TRelatedModel>
741+
* @return \Illuminate\Database\Eloquent\Collection<int, TRelatedModel&object{pivot: TPivotModel}>
723742
*/
724743
public function findMany($ids, $columns = ['*'])
725744
{
@@ -739,7 +758,11 @@ public function findMany($ids, $columns = ['*'])
739758
*
740759
* @param mixed $id
741760
* @param array $columns
742-
* @return ($id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>) ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel> : TRelatedModel)
761+
* @return (
762+
* $id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>)
763+
* ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel&object{pivot: TPivotModel}>
764+
* : TRelatedModel&object{pivot: TPivotModel}
765+
* )
743766
*
744767
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException<TRelatedModel>
745768
*/
@@ -770,8 +793,8 @@ public function findOrFail($id, $columns = ['*'])
770793
* @param (\Closure(): TValue)|null $callback
771794
* @return (
772795
* $id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>)
773-
* ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel>|TValue
774-
* : TRelatedModel|TValue
796+
* ? \Illuminate\Database\Eloquent\Collection<int, TRelatedModel&object{pivot: TPivotModel}>|TValue
797+
* : (TRelatedModel&object{pivot: TPivotModel})|TValue
775798
* )
776799
*/
777800
public function findOr($id, $columns = ['*'], ?Closure $callback = null)
@@ -804,7 +827,7 @@ public function findOr($id, $columns = ['*'], ?Closure $callback = null)
804827
* @param mixed $operator
805828
* @param mixed $value
806829
* @param string $boolean
807-
* @return TRelatedModel|null
830+
* @return (TRelatedModel&object{pivot: TPivotModel})|null
808831
*/
809832
public function firstWhere($column, $operator = null, $value = null, $boolean = 'and')
810833
{
@@ -815,7 +838,7 @@ public function firstWhere($column, $operator = null, $value = null, $boolean =
815838
* Execute the query and get the first result.
816839
*
817840
* @param array $columns
818-
* @return TRelatedModel|null
841+
* @return (TRelatedModel&object{pivot: TPivotModel})|null
819842
*/
820843
public function first($columns = ['*'])
821844
{
@@ -828,7 +851,7 @@ public function first($columns = ['*'])
828851
* Execute the query and get the first result or throw an exception.
829852
*
830853
* @param array $columns
831-
* @return TRelatedModel
854+
* @return TRelatedModel&object{pivot: TPivotModel}
832855
*
833856
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException<TRelatedModel>
834857
*/
@@ -848,7 +871,7 @@ public function firstOrFail($columns = ['*'])
848871
*
849872
* @param (\Closure(): TValue)|list<string> $columns
850873
* @param (\Closure(): TValue)|null $callback
851-
* @return TRelatedModel|TValue
874+
* @return (TRelatedModel&object{pivot: TPivotModel})|TValue
852875
*/
853876
public function firstOr($columns = ['*'], ?Closure $callback = null)
854877
{
@@ -942,7 +965,7 @@ protected function aliasedPivotColumns()
942965
* @param array $columns
943966
* @param string $pageName
944967
* @param int|null $page
945-
* @return \Illuminate\Pagination\LengthAwarePaginator
968+
* @return \Illuminate\Pagination\LengthAwarePaginator<int, TRelatedModel&object{pivot: TPivotModel}>
946969
*/
947970
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
948971
{
@@ -960,7 +983,7 @@ public function paginate($perPage = null, $columns = ['*'], $pageName = 'page',
960983
* @param array $columns
961984
* @param string $pageName
962985
* @param int|null $page
963-
* @return \Illuminate\Contracts\Pagination\Paginator
986+
* @return \Illuminate\Contracts\Pagination\Paginator<int, TRelatedModel&object{pivot: TPivotModel}>
964987
*/
965988
public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
966989
{
@@ -978,7 +1001,7 @@ public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'p
9781001
* @param array $columns
9791002
* @param string $cursorName
9801003
* @param string|null $cursor
981-
* @return \Illuminate\Contracts\Pagination\CursorPaginator
1004+
* @return \Illuminate\Contracts\Pagination\CursorPaginator<int, TRelatedModel&object{pivot: TPivotModel}>
9821005
*/
9831006
public function cursorPaginate($perPage = null, $columns = ['*'], $cursorName = 'cursor', $cursor = null)
9841007
{
@@ -1100,7 +1123,7 @@ public function each(callable $callback, $count = 1000)
11001123
* Query lazily, by chunks of the given size.
11011124
*
11021125
* @param int $chunkSize
1103-
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel>
1126+
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel&object{pivot: TPivotModel}>
11041127
*/
11051128
public function lazy($chunkSize = 1000)
11061129
{
@@ -1117,7 +1140,7 @@ public function lazy($chunkSize = 1000)
11171140
* @param int $chunkSize
11181141
* @param string|null $column
11191142
* @param string|null $alias
1120-
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel>
1143+
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel&object{pivot: TPivotModel}>
11211144
*/
11221145
public function lazyById($chunkSize = 1000, $column = null, $alias = null)
11231146
{
@@ -1140,7 +1163,7 @@ public function lazyById($chunkSize = 1000, $column = null, $alias = null)
11401163
* @param int $chunkSize
11411164
* @param string|null $column
11421165
* @param string|null $alias
1143-
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel>
1166+
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel&object{pivot: TPivotModel}>
11441167
*/
11451168
public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null)
11461169
{
@@ -1160,7 +1183,7 @@ public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null)
11601183
/**
11611184
* Get a lazy collection for the given query.
11621185
*
1163-
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel>
1186+
* @return \Illuminate\Support\LazyCollection<int, TRelatedModel&object{pivot: TPivotModel}>
11641187
*/
11651188
public function cursor()
11661189
{
@@ -1300,7 +1323,7 @@ public function allRelatedIds()
13001323
* @param TRelatedModel $model
13011324
* @param array $pivotAttributes
13021325
* @param bool $touch
1303-
* @return TRelatedModel
1326+
* @return TRelatedModel&object{pivot: TPivotModel}
13041327
*/
13051328
public function save(Model $model, array $pivotAttributes = [], $touch = true)
13061329
{
@@ -1317,7 +1340,7 @@ public function save(Model $model, array $pivotAttributes = [], $touch = true)
13171340
* @param TRelatedModel $model
13181341
* @param array $pivotAttributes
13191342
* @param bool $touch
1320-
* @return TRelatedModel
1343+
* @return TRelatedModel&object{pivot: TPivotModel}
13211344
*/
13221345
public function saveQuietly(Model $model, array $pivotAttributes = [], $touch = true)
13231346
{
@@ -1368,7 +1391,7 @@ public function saveManyQuietly($models, array $pivotAttributes = [])
13681391
* @param array $attributes
13691392
* @param array $joining
13701393
* @param bool $touch
1371-
* @return TRelatedModel
1394+
* @return TRelatedModel&object{pivot: TPivotModel}
13721395
*/
13731396
public function create(array $attributes = [], array $joining = [], $touch = true)
13741397
{
@@ -1391,7 +1414,7 @@ public function create(array $attributes = [], array $joining = [], $touch = tru
13911414
*
13921415
* @param iterable $records
13931416
* @param array $joinings
1394-
* @return array<int, TRelatedModel>
1417+
* @return array<int, TRelatedModel&object{pivot: TPivotModel}>
13951418
*/
13961419
public function createMany(iterable $records, array $joinings = [])
13971420
{
@@ -1625,7 +1648,7 @@ public function getRelationName()
16251648
/**
16261649
* Get the name of the pivot accessor for this relationship.
16271650
*
1628-
* @return string
1651+
* @return TAccessor
16291652
*/
16301653
public function getPivotAccessor()
16311654
{

src/Illuminate/Database/Eloquent/Relations/MorphToMany.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
/**
1111
* @template TRelatedModel of \Illuminate\Database\Eloquent\Model
1212
* @template TDeclaringModel of \Illuminate\Database\Eloquent\Model
13+
* @template TPivotModel of \Illuminate\Database\Eloquent\Relations\Pivot = \Illuminate\Database\Eloquent\Relations\MorphPivot
14+
* @template TAccessor of string = 'pivot'
1315
*
14-
* @extends \Illuminate\Database\Eloquent\Relations\BelongsToMany<TRelatedModel, TDeclaringModel, \Illuminate\Database\Eloquent\Relations\Pivot>
16+
* @extends \Illuminate\Database\Eloquent\Relations\BelongsToMany<TRelatedModel, TDeclaringModel, TPivotModel, TAccessor>
1517
*/
1618
class MorphToMany extends BelongsToMany
1719
{
@@ -122,7 +124,7 @@ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery,
122124
/**
123125
* Get the pivot models that are currently attached.
124126
*
125-
* @return \Illuminate\Support\Collection<int, \Illuminate\Database\Eloquent\Relations\Pivot|\Illuminate\Database\Eloquent\Relations\MorphPivot>
127+
* @return \Illuminate\Support\Collection<int, TPivotModel>
126128
*/
127129
protected function getCurrentlyAttachedPivots()
128130
{
@@ -149,7 +151,7 @@ public function newPivotQuery()
149151
*
150152
* @param array $attributes
151153
* @param bool $exists
152-
* @return \Illuminate\Database\Eloquent\Relations\Pivot
154+
* @return TPivotModel
153155
*/
154156
public function newPivot(array $attributes = [], $exists = false)
155157
{

0 commit comments

Comments
 (0)