Skip to content

Commit e1471bb

Browse files
authored
Merge pull request #16 from calebdw/collection_template_types
fix: collection template types being overwritten
2 parents 163dea5 + 2c25543 commit e1471bb

File tree

3 files changed

+37
-9
lines changed

3 files changed

+37
-9
lines changed

src/Support/CollectionHelper.php

+12-9
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,10 @@ public function determineCollectionClassName(string $modelClassName): string
8686
}
8787
}
8888

89-
public function determineCollectionClass(string $modelClassName): Type
89+
public function determineCollectionClass(string $modelClassName, Type|null $modelType = null): Type
9090
{
91+
$modelType ??= new ObjectType($modelClassName);
92+
9193
$collectionClassName = $this->determineCollectionClassName($modelClassName);
9294
$collectionReflection = $this->reflectionProvider->getClass($collectionClassName);
9395

@@ -96,12 +98,12 @@ public function determineCollectionClass(string $modelClassName): Type
9698

9799
// Specifies key and value
98100
if ($typeMap->count() === 2) {
99-
return new GenericObjectType($collectionClassName, [new IntegerType(), new ObjectType($modelClassName)]);
101+
return new GenericObjectType($collectionClassName, [new IntegerType(), $modelType]);
100102
}
101103

102104
// Specifies only value
103105
if (($typeMap->count() === 1) && $typeMap->hasType('TModel')) {
104-
return new GenericObjectType($collectionClassName, [new ObjectType($modelClassName)]);
106+
return new GenericObjectType($collectionClassName, [$modelType]);
105107
}
106108
}
107109

@@ -124,13 +126,14 @@ public function replaceCollectionsInType(Type $type): Type
124126
return $traverse($type);
125127
}
126128

127-
$models = $type->getTemplateType(EloquentCollection::class, 'TModel')->getObjectClassNames();
128-
129-
if (count($models) === 0) {
130-
return $type;
131-
}
129+
$templateType = $type->getTemplateType(EloquentCollection::class, 'TModel');
130+
$models = $templateType->getObjectClassNames();
132131

133-
return TypeCombinator::union(...array_map([$this, 'determineCollectionClass'], $models));
132+
return match (count($models)) {
133+
0 => $type,
134+
1 => $this->determineCollectionClass($models[0], $templateType),
135+
default => TypeCombinator::union(...array_map(fn ($m) => $this->determineCollectionClass($m), $models)),
136+
};
134137
});
135138
}
136139

tests/Type/GeneralTypeTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public static function dataFileAsserts(): iterable
2323
yield from self::gatherAssertTypes(__DIR__ . '/data/bug-1565.php');
2424
yield from self::gatherAssertTypes(__DIR__ . '/data/bug-1760.php');
2525
yield from self::gatherAssertTypes(__DIR__ . '/data/bug-1830.php');
26+
yield from self::gatherAssertTypes(__DIR__ . '/data/bug-2044.php');
2627
yield from self::gatherAssertTypes(__DIR__ . '/data/carbon.php');
2728
yield from self::gatherAssertTypes(__DIR__ . '/data/conditionable.php');
2829
yield from self::gatherAssertTypes(__DIR__ . '/data/container-array-access.php');

tests/Type/data/bug-2044.php

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Bug2044;
4+
5+
use Illuminate\Database\Eloquent\Builder;
6+
use Illuminate\Database\Eloquent\Collection;
7+
8+
use function PHPStan\Testing\assertType;
9+
10+
/** @template TModel of \Illuminate\Database\Eloquent\Model */
11+
class Repository
12+
{
13+
/** @var Builder<TModel> */
14+
private Builder $query;
15+
16+
/** @return Collection<int, TModel> */
17+
public function all(): Collection
18+
{
19+
$models = $this->query->get();
20+
assertType('Illuminate\Database\Eloquent\Collection<int, TModel of Illuminate\Database\Eloquent\Model (class Bug2044\Repository, argument)>', $models);
21+
22+
return $models;
23+
}
24+
}

0 commit comments

Comments
 (0)