Skip to content

Commit ef9c81c

Browse files
committed
Add EntityData value object for types
1 parent 3d9394f commit ef9c81c

File tree

5 files changed

+91
-46
lines changed

5 files changed

+91
-46
lines changed

extension.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ services:
4949
class: mglaman\PHPStanDrupal\Drupal\EntityDataRepository
5050
arguments:
5151
reflectionProvider: @reflectionProvider
52-
entityData: %drupal.entityMapping%
52+
entityMapping: %drupal.entityMapping%
5353

5454
-
5555
class: mglaman\PHPStanDrupal\Type\EntityTypeManagerGetStorageDynamicReturnTypeExtension

src/Drupal/EntityData.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace mglaman\PHPStanDrupal\Drupal;
4+
5+
use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
6+
use Drupal\Core\Entity\ContentEntityStorageInterface;
7+
use mglaman\PHPStanDrupal\Type\EntityStorage\ConfigEntityStorageType;
8+
use mglaman\PHPStanDrupal\Type\EntityStorage\ContentEntityStorageType;
9+
use mglaman\PHPStanDrupal\Type\EntityStorage\EntityStorageType;
10+
use PHPStan\Reflection\ReflectionProvider;
11+
use PHPStan\Reflection\ReflectionProviderStaticAccessor;
12+
use PHPStan\Type\ObjectType;
13+
14+
final class EntityData
15+
{
16+
17+
/**
18+
* @var string
19+
*/
20+
private $entityTypeId;
21+
22+
/**
23+
* @var string|null
24+
*/
25+
private $className;
26+
27+
/**
28+
* @var string|null
29+
*/
30+
private $storageClassName;
31+
32+
/**
33+
* @var ReflectionProvider
34+
*/
35+
private $reflectionProvider;
36+
37+
public function __construct(string $entityTypeId, array $definition, ReflectionProvider $reflectionProvider)
38+
{
39+
$this->entityTypeId = $entityTypeId;
40+
$this->className = $definition['class'] ?? null;
41+
$this->storageClassName = $definition['storage'] ?? null;
42+
// \PHPStan\Reflection\ReflectionProviderStaticAccessor::getInstance is not covered by the backward
43+
// compatibility promise of PHPStan, so we must add it to our value object.
44+
$this->reflectionProvider = $reflectionProvider;
45+
}
46+
47+
public function getClassType(): ?ObjectType
48+
{
49+
return $this->className === null ? null : new ObjectType($this->className);
50+
}
51+
52+
public function getStorageType(): ?ObjectType
53+
{
54+
if ($this->storageClassName === null) {
55+
// @todo get entity type class reflection and return proper storage for entity type
56+
// example: config storage, sqlcontententitystorage, etc.
57+
// $className = reflectedDecision.
58+
return null;
59+
}
60+
if (!$this->reflectionProvider->hasClass($this->storageClassName)) {
61+
return null;
62+
}
63+
64+
// @todo drop reflectionProvider for ObjectType isSuperTypeOf
65+
$reflection = $this->reflectionProvider->getClass($this->storageClassName);
66+
if ($reflection->implementsInterface(ConfigEntityStorageInterface::class)) {
67+
return new ConfigEntityStorageType($this->entityTypeId, $this->storageClassName);
68+
}
69+
if ($reflection->implementsInterface(ContentEntityStorageInterface::class)) {
70+
return new ContentEntityStorageType($this->entityTypeId, $this->storageClassName);
71+
}
72+
return new EntityStorageType($this->entityTypeId, $this->storageClassName);
73+
}
74+
}

src/Drupal/EntityDataRepository.php

Lines changed: 14 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@
22

33
namespace mglaman\PHPStanDrupal\Drupal;
44

5-
use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
6-
use Drupal\Core\Entity\ContentEntityStorageInterface;
7-
use mglaman\PHPStanDrupal\Type\EntityStorage\ConfigEntityStorageType;
8-
use mglaman\PHPStanDrupal\Type\EntityStorage\ContentEntityStorageType;
9-
use mglaman\PHPStanDrupal\Type\EntityStorage\EntityStorageType;
105
use PHPStan\Reflection\ReflectionProvider;
11-
use PHPStan\Type\ObjectType;
126

137
final class EntityDataRepository
148
{
@@ -20,50 +14,27 @@ final class EntityDataRepository
2014
/**
2115
* @var array<string, array<string, string>>
2216
*/
17+
private $entityMapping;
18+
/**
19+
* @var array<string, EntityData|null>
20+
*/
2321
private $entityData;
2422

25-
public function __construct(ReflectionProvider $reflectionProvider, array $entityData)
23+
public function __construct(ReflectionProvider $reflectionProvider, array $entityMapping)
2624
{
2725
$this->reflectionProvider = $reflectionProvider;
28-
$this->entityData = $entityData;
26+
$this->entityMapping = $entityMapping;
2927
}
3028

31-
public function get(string $entityTypeId): ?array
29+
public function get(string $entityTypeId): EntityData
3230
{
33-
return $this->entityData[$entityTypeId] ?? null;
34-
}
35-
36-
public function getClassType(string $entityTypeId): ?ObjectType
37-
{
38-
$data = $this->get($entityTypeId);
39-
$className = $data['class'] ?? null;
40-
if ($className === null) {
41-
return null;
42-
}
43-
return new ObjectType($className);
44-
}
45-
46-
public function getStorageType(string $entityTypeId): ?ObjectType
47-
{
48-
$data = $this->get($entityTypeId);
49-
$className = $data['storage'] ?? null;
50-
if ($className === null) {
51-
// @todo get entity type class reflection and return proper storage for entity type
52-
// example: config storage, sqlcontententitystorage, etc.
53-
// $className = reflectedDecision.
54-
return null;
55-
}
56-
if (!$this->reflectionProvider->hasClass($className)) {
57-
return null;
58-
}
59-
60-
$reflection = $this->reflectionProvider->getClass($className);
61-
if ($reflection->implementsInterface(ConfigEntityStorageInterface::class)) {
62-
return new ConfigEntityStorageType($entityTypeId, $className);
63-
}
64-
if ($reflection->implementsInterface(ContentEntityStorageInterface::class)) {
65-
return new ContentEntityStorageType($entityTypeId, $className);
31+
if (!isset($this->entityData[$entityTypeId])) {
32+
$this->entityData[$entityTypeId] = new EntityData(
33+
$entityTypeId,
34+
$this->entityMapping[$entityTypeId] ?? [],
35+
$this->reflectionProvider
36+
);
6637
}
67-
return new EntityStorageType($entityTypeId, $className);
38+
return $this->entityData[$entityTypeId];
6839
}
6940
}

src/Type/EntityStorage/EntityStorageDynamicReturnTypeExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function getTypeFromMethodCall(
5959
return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
6060
}
6161

62-
$type = $this->entityDataRepository->getClassType($callerType->getEntityTypeId());
62+
$type = $this->entityDataRepository->get($callerType->getEntityTypeId())->getClassType();
6363
if ($type === null) {
6464
return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
6565
}

src/Type/EntityTypeManagerGetStorageDynamicReturnTypeExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public function getTypeFromMethodCall(
8181

8282
$entityTypeId = $arg1->value;
8383

84-
$storageType = $this->entityDataRepository->getStorageType($entityTypeId);
84+
$storageType = $this->entityDataRepository->get($entityTypeId)->getStorageType();
8585
if ($storageType !== null) {
8686
return $storageType;
8787
}

0 commit comments

Comments
 (0)