Skip to content

Commit 2d1aeef

Browse files
committed
Support proper generic Collection
We incorrectly supported `Collection<Foo>`, while Doctrine collections should actually be `Collection<int, Foo>`. All type hints in user code must be adapted accordingly.
1 parent cb92bc5 commit 2d1aeef

File tree

6 files changed

+20
-9
lines changed

6 files changed

+20
-9
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ Supported syntaxes (PHP style or GraphQL style) are:
213213
- `'?Application\MyType[]'`
214214
- `'null|Application\MyType[]'`
215215
- `'Application\MyType[]|null'`
216-
- `'Collection<Application\MyType>'`
216+
- `'Collection<int, Application\MyType>'`
217217

218218
This attribute can be used to override other things, such as `name`, `description`
219219
and `args`.
@@ -231,7 +231,7 @@ use GraphQL\Doctrine\Attribute as API;
231231
*
232232
* @param string $status the status of posts as defined in \GraphQLTests\Doctrine\Blog\Model\Post
233233
*
234-
* @return Collection
234+
* @return Collection<int, Post>
235235
*/
236236
public function getPosts(
237237
#[API\Argument(type: '?GraphQLTests\Doctrine\Blog\Types\PostStatusType')]

src/DocBlockReader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public function getParameterType(ReflectionParameter $param): ?string
7070
*/
7171
public function getReturnType(): ?string
7272
{
73-
if (preg_match('~@return\h+(\H+)(\h|\n)~', $this->comment, $m)) {
73+
if (preg_match('~@return\h+([^<]+<.*>|\H+)(\h|\n)~', $this->comment, $m)) {
7474
return trim($m[1]);
7575
}
7676

src/Factory/AbstractFactory.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ final protected function isPropertyExcluded(ReflectionProperty $property): bool
4747
* - `?MyType[]`
4848
* - `null|MyType[]`
4949
* - `MyType[]|null`
50-
* - `Collection<MyType>`
50+
* - `Collection<int, MyType>`
5151
*/
5252
final protected function getTypeFromPhpDeclaration(ReflectionClass $class, null|string|Type $typeDeclaration, bool $isEntityId = false): null|Type
5353
{
@@ -56,10 +56,15 @@ final protected function getTypeFromPhpDeclaration(ReflectionClass $class, null|
5656
}
5757

5858
$isNullable = 0;
59-
$name = preg_replace('~(^\?|^null\||\|null$)~', '', $typeDeclaration, -1, $isNullable);
59+
$name = preg_replace('~(^\?|^null\||\|null$)~', '', $typeDeclaration, count: $isNullable);
6060

6161
$isList = 0;
62-
$name = preg_replace('~^([^<]*)\[]$|^Collection<(.*)>$~', '$1$2', $name, -1, $isList);
62+
$name = preg_replace_callback(
63+
'~^([^<]*)\[]$|^Collection<(.*),(.*)>$~',
64+
fn (array $m) => $m[1] . trim($m[3] ?? ''),
65+
$name ?? '',
66+
count: $isList,
67+
);
6368
$name = $this->adjustNamespace($class, $name);
6469
$type = $this->getTypeFromRegistry($name, $isEntityId);
6570

tests/Blog/Model/Special/ArrayOfEntity.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public function getUsers(): array
2121
}
2222

2323
/**
24-
* @return Collection<\GraphQLTests\Doctrine\Blog\Model\User>
24+
* @return Collection<int, \GraphQLTests\Doctrine\Blog\Model\User>
2525
*/
2626
public function getOtherUsers(): Collection
2727
{

tests/Blog/Model/User.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ final class User extends AbstractModel
3030
private bool $isAdministrator = false;
3131

3232
/**
33-
* @var Collection<Post>
33+
* @var Collection<int, Post>
3434
*/
3535
#[ORM\OneToMany(targetEntity: Post::class, mappedBy: 'user')]
3636
private Collection $posts;
3737

3838
/**
39-
* @var Collection<Post>
39+
* @var Collection<int, Post>
4040
*/
4141
#[ORM\ManyToMany(targetEntity: Post::class)]
4242
private Collection $favoritePosts;

tests/DocBlockReaderTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ class DocBlockReaderTest extends TestCase
3030
* @return bool
3131
*/';
3232

33+
private const COMMENT_GENERIC = '
34+
/**
35+
* @return Collection<int, Foo>
36+
*/';
37+
3338
#[DataProvider('providerGetMethodDescription')]
3439
public function testGetMethodDescription(string|false $comment, ?string $expected): void
3540
{
@@ -106,6 +111,7 @@ public static function providerGetReturnType(): array
106111
[false, null],
107112
[self::EMPTY_COMMENT, null],
108113
[self::COMMENT, 'bool'],
114+
[self::COMMENT_GENERIC, 'Collection<int, Foo>'],
109115
];
110116
}
111117

0 commit comments

Comments
 (0)