-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathEnumPostLoadEntityListener.php
122 lines (103 loc) · 3.16 KB
/
EnumPostLoadEntityListener.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<?php
declare(strict_types = 1);
namespace Consistence\Doctrine\Enum;
use Consistence\Enum\Enum;
use Doctrine\Common\Annotations\Reader;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Cache;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Mapping\ClassMetadata;
class EnumPostLoadEntityListener
{
/** @var \Doctrine\Common\Annotations\Reader */
private $annotationReader;
/** @var \Doctrine\Common\Cache\Cache */
private $enumFieldsCache;
public function __construct(
Reader $annotationReader,
?Cache $enumFieldsCache = null
)
{
$this->annotationReader = $annotationReader;
$this->enumFieldsCache = $enumFieldsCache !== null ? $enumFieldsCache : new ArrayCache();
}
public function postLoad(LifecycleEventArgs $event): void
{
$entity = $event->getEntity();
$entityManager = $event->getEntityManager();
foreach ($this->getEnumFields($entityManager, get_class($entity)) as $fieldName => $enumClassName) {
$this->processField($entityManager, $entity, $fieldName, $enumClassName);
}
}
public function warmUpCache(
EntityManager $entityManager,
string $className
): void
{
$this->getEnumFields($entityManager, $className);
}
/**
* @param \Doctrine\ORM\EntityManager $entityManager
* @param string $className
* @return string[] format: enum field name (string) => enum class name for field (string)
*/
private function getEnumFields(
EntityManager $entityManager,
string $className
): array
{
$enumFields = $this->enumFieldsCache->fetch($className);
if ($enumFields !== false) {
return $enumFields;
}
$enumFields = [];
$metadata = $this->getClassMetadata($entityManager, $className);
foreach ($metadata->getFieldNames() as $fieldName) {
$annotation = $this->annotationReader->getPropertyAnnotation(
$metadata->getReflectionProperty($fieldName),
EnumAnnotation::class
);
if ($annotation !== null) {
$enumClassName = $metadata->fullyQualifiedClassName($annotation->class);
if (!is_a($enumClassName, Enum::class, true)) {
throw new \Consistence\Doctrine\Enum\NotEnumException($enumClassName);
}
$enumFields[$fieldName] = $enumClassName;
}
}
$this->enumFieldsCache->save($className, $enumFields);
return $enumFields;
}
private function processField(
EntityManager $entityManager,
object $entity,
string $fieldName,
string $enumClassName
): void
{
$metadata = $this->getClassMetadata($entityManager, get_class($entity));
$enumValue = $metadata->getFieldValue($entity, $fieldName);
if ($enumValue === null) {
return;
}
$enum = $enumClassName::get(($enumValue instanceof Enum) ? $enumValue->getValue() : $enumValue);
$metadata->setFieldValue($entity, $fieldName, $enum);
$entityManager->getUnitOfWork()->setOriginalEntityProperty(
spl_object_hash($entity),
$fieldName,
$enum
);
}
private function getClassMetadata(
EntityManager $entityManager,
string $class
): ClassMetadata
{
$metadata = $entityManager->getClassMetadata($class);
if (!($metadata instanceof ClassMetadata)) {
throw new \Consistence\Doctrine\Enum\UnsupportedClassMetadataException(get_class($metadata));
}
return $metadata;
}
}