Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b7c93f3

Browse files
committedAug 18, 2018
Use real object managers to know repository type
Based on the class metadata we can easily fetch data from any configuration format.
1 parent af7bb42 commit b7c93f3

11 files changed

+249
-9
lines changed
 

‎extension.neon

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
parameters:
22
doctrine:
3-
repositoryClass: Doctrine\ORM\EntityRepository
3+
objectManagerLoader: ~
44

55
services:
66
-
@@ -17,8 +17,6 @@ services:
1717
- phpstan.broker.dynamicMethodReturnTypeExtension
1818
-
1919
class: PHPStan\Type\Doctrine\ObjectManagerGetRepositoryDynamicReturnTypeExtension
20-
arguments:
21-
repositoryClass: %doctrine.repositoryClass%
2220
tags:
2321
- phpstan.broker.dynamicMethodReturnTypeExtension
2422
-
@@ -29,3 +27,7 @@ services:
2927
class: PHPStan\Type\Doctrine\ObjectRepositoryDynamicReturnTypeExtension
3028
tags:
3129
- phpstan.broker.dynamicMethodReturnTypeExtension
30+
-
31+
class: PHPStan\Type\Doctrine\ObjectMetadataResolver
32+
arguments:
33+
objectManagerLoader: %doctrine.objectManagerLoader%

‎src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
class ObjectManagerGetRepositoryDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension
1414
{
1515

16-
/** @var string */
17-
private $repositoryClass;
16+
/** @var ObjectMetadataResolver */
17+
private $metadataResolver;
1818

19-
public function __construct(string $repositoryClass)
19+
public function __construct(ObjectMetadataResolver $metadataResolver)
2020
{
21-
$this->repositoryClass = $repositoryClass;
21+
$this->metadataResolver = $metadataResolver;
2222
}
2323

2424
public function getClass(): string
@@ -47,7 +47,14 @@ public function getTypeFromMethodCall(
4747
return new MixedType();
4848
}
4949

50-
return new ObjectRepositoryType($argType->getValue(), $this->repositoryClass);
50+
$objectName = $argType->getValue();
51+
$repositoryClass = $this->metadataResolver->getRepositoryClass($objectName);
52+
53+
if ($repositoryClass === null) {
54+
return new MixedType();
55+
}
56+
57+
return new ObjectRepositoryType($objectName, $repositoryClass);
5158
}
5259

5360
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Doctrine;
4+
5+
use Doctrine\Common\Persistence\ObjectManager;
6+
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata as ODMMetadata;
7+
use Doctrine\ORM\Mapping\ClassMetadata as ORMMetadata;
8+
use RuntimeException;
9+
use function file_exists;
10+
use function is_readable;
11+
12+
final class ObjectMetadataResolver
13+
{
14+
15+
/** @var ObjectManager */
16+
private $objectManager;
17+
18+
public function __construct(string $objectManagerLoader)
19+
{
20+
$this->objectManager = $this->getObjectManager($objectManagerLoader);
21+
}
22+
23+
private function getObjectManager(string $objectManagerLoader): ObjectManager
24+
{
25+
if (! file_exists($objectManagerLoader) && ! is_readable($objectManagerLoader)) {
26+
throw new RuntimeException('Object manager could not be loaded');
27+
}
28+
29+
return require $objectManagerLoader;
30+
}
31+
32+
public function getRepositoryClass(string $className): ?string
33+
{
34+
$metatada = $this->objectManager->getClassMetadata($className);
35+
36+
if ($metatada instanceof ORMMetadata) {
37+
return $metatada->customRepositoryClassName ?? 'Doctrine\ORM\EntityRepository';
38+
}
39+
40+
if ($metatada instanceof ODMMetadata) {
41+
return $metatada->customRepositoryClassName ?? 'Doctrine\ODM\MongoDB\DocumentRepository';
42+
}
43+
44+
return null;
45+
}
46+
47+
}

‎tests/DoctrineIntegration/ODM/DocumentManagerIntegrationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public function dataTopics(): array
1616
['documentManagerDynamicReturn'],
1717
['documentRepositoryDynamicReturn'],
1818
['documentManagerMergeReturn'],
19+
['customRepositoryUsage'],
1920
];
2021
}
2122

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\DoctrineIntegration\ODM\CustomRepositoryUsage;
4+
5+
use Doctrine\ODM\MongoDB\DocumentManager;
6+
use Doctrine\ODM\MongoDB\DocumentRepository;
7+
use Doctrine\ODM\MongoDB\Mapping\Annotations\Document;
8+
use Doctrine\ODM\MongoDB\Mapping\Annotations\Id;
9+
use RuntimeException;
10+
11+
class Example
12+
{
13+
/**
14+
* @var MyRepository
15+
*/
16+
private $repository;
17+
18+
public function __construct(DocumentManager $documentManager)
19+
{
20+
$this->repository = $documentManager->getRepository(MyDocument::class);
21+
}
22+
23+
public function get(): void
24+
{
25+
$test = $this->repository->get('testing');
26+
$test->doSomethingElse();
27+
}
28+
}
29+
30+
/**
31+
* @Document(repositoryClass=MyRepository::class)
32+
*/
33+
class MyDocument
34+
{
35+
/**
36+
* @Id(strategy="NONE", type="string")
37+
*
38+
* @var string
39+
*/
40+
private $id;
41+
42+
public function doSomethingElse(): void
43+
{
44+
}
45+
}
46+
47+
class MyRepository extends DocumentRepository
48+
{
49+
public function get(string $id): MyDocument
50+
{
51+
$document = $this->find($id);
52+
53+
if ($document === null) {
54+
throw new RuntimeException('Not found...');
55+
}
56+
57+
return $document;
58+
}
59+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php declare(strict_types = 1);
2+
3+
use Doctrine\Common\Annotations\AnnotationReader;
4+
use Doctrine\Common\Annotations\AnnotationRegistry;
5+
use Doctrine\Common\Cache\ArrayCache;
6+
use Doctrine\ODM\MongoDB\Configuration;
7+
use Doctrine\ODM\MongoDB\DocumentManager;
8+
use Doctrine\ODM\MongoDB\Mapping\Driver\AnnotationDriver;
9+
10+
AnnotationRegistry::registerUniqueLoader('class_exists');
11+
12+
$config = new Configuration();
13+
$config->setProxyDir(__DIR__);
14+
$config->setProxyNamespace('PHPstan\Doctrine\OdmProxies');
15+
$config->setMetadataCacheImpl(new ArrayCache());
16+
$config->setHydratorDir(__DIR__);
17+
$config->setHydratorNamespace('PHPstan\Doctrine\OdmHydrators');
18+
19+
$config->setMetadataDriverImpl(
20+
new AnnotationDriver(
21+
new AnnotationReader(),
22+
[__DIR__ . '/data']
23+
)
24+
);
25+
26+
return DocumentManager::create(
27+
null,
28+
$config
29+
);

‎tests/DoctrineIntegration/ODM/phpstan.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ includes:
33

44
parameters:
55
doctrine:
6-
repositoryClass: Doctrine\ODM\MongoDB\DocumentRepository
6+
objectManagerLoader: tests/DoctrineIntegration/ODM/document-manager.php

‎tests/DoctrineIntegration/ORM/EntityManagerIntegrationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public function dataTopics(): array
1616
['entityManagerDynamicReturn'],
1717
['entityRepositoryDynamicReturn'],
1818
['entityManagerMergeReturn'],
19+
['customRepositoryUsage'],
1920
];
2021
}
2122

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\DoctrineIntegration\ORM\CustomRepositoryUsage;
4+
5+
use Doctrine\ORM\EntityManagerInterface;
6+
use Doctrine\ORM\EntityRepository;
7+
use Doctrine\ORM\Mapping as ORM;
8+
use RuntimeException;
9+
10+
class Example
11+
{
12+
/**
13+
* @var MyRepository
14+
*/
15+
private $repository;
16+
17+
public function __construct(EntityManagerInterface $entityManager)
18+
{
19+
$this->repository = $entityManager->getRepository(MyEntity::class);
20+
}
21+
22+
public function get(): void
23+
{
24+
$test = $this->repository->get(1);
25+
$test->doSomethingElse();
26+
}
27+
}
28+
29+
/**
30+
* @ORM\Entity(repositoryClass=MyRepository::class)
31+
*/
32+
class MyEntity
33+
{
34+
/**
35+
* @ORM\Id()
36+
* @ORM\GeneratedValue()
37+
* @ORM\Column(type="integer")
38+
*
39+
* @var int
40+
*/
41+
private $id;
42+
43+
public function doSomethingElse(): void
44+
{
45+
}
46+
}
47+
48+
class MyRepository extends EntityRepository
49+
{
50+
public function get(int $id): MyEntity
51+
{
52+
$entity = $this->find($id);
53+
54+
if ($entity === null) {
55+
throw new RuntimeException('Not found...');
56+
}
57+
58+
return $entity;
59+
}
60+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types = 1);
2+
3+
use Doctrine\Common\Annotations\AnnotationReader;
4+
use Doctrine\Common\Annotations\AnnotationRegistry;
5+
use Doctrine\Common\Cache\ArrayCache;
6+
use Doctrine\ORM\Configuration;
7+
use Doctrine\ORM\EntityManager;
8+
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
9+
10+
AnnotationRegistry::registerUniqueLoader('class_exists');
11+
12+
$config = new Configuration();
13+
$config->setProxyDir(__DIR__);
14+
$config->setProxyNamespace('PHPstan\Doctrine\OrmProxies');
15+
$config->setMetadataCacheImpl(new ArrayCache());
16+
17+
$config->setMetadataDriverImpl(
18+
new AnnotationDriver(
19+
new AnnotationReader(),
20+
[__DIR__ . '/data']
21+
)
22+
);
23+
24+
return EntityManager::create(
25+
[
26+
'driver' => 'pdo_sqlite',
27+
'memory' => true,
28+
],
29+
$config
30+
);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
includes:
22
- ../../../extension.neon
3+
4+
parameters:
5+
doctrine:
6+
objectManagerLoader: tests/DoctrineIntegration/ORM/entity-manager.php

0 commit comments

Comments
 (0)
Please sign in to comment.