|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* @file |
|
4
|
|
|
* Contains \TheSportsDb\Entity\EntityManager. |
|
5
|
|
|
*/ |
|
6
|
|
|
|
|
7
|
|
|
namespace TheSportsDb\Entity; |
|
8
|
|
|
|
|
9
|
|
|
use FastNorth\PropertyMapper\Map; |
|
10
|
|
|
use FastNorth\PropertyMapper\MapperInterface; |
|
11
|
|
|
use TheSportsDb\Entity\Factory\FactoryContainerInterface; |
|
12
|
|
|
use TheSportsDb\Entity\Repository\RepositoryContainerInterface; |
|
13
|
|
|
use TheSportsDb\PropertyMapper\Transformer\Callback; |
|
14
|
|
|
|
|
15
|
|
|
/** |
|
16
|
|
|
* Default implementation for entity managers. |
|
17
|
|
|
* |
|
18
|
|
|
* @author Jelle Sebreghts |
|
19
|
|
|
*/ |
|
20
|
|
|
class EntityManager implements EntityManagerInterface { |
|
21
|
|
|
|
|
22
|
|
|
/** |
|
23
|
|
|
* The factory container. |
|
24
|
|
|
* |
|
25
|
|
|
* @var \TheSportsDb\Entity\Factory\FactoryContainerInterface |
|
26
|
|
|
*/ |
|
27
|
|
|
protected $factoryContainer; |
|
28
|
|
|
|
|
29
|
|
|
/** |
|
30
|
|
|
* The repository container. |
|
31
|
|
|
* |
|
32
|
|
|
* @var \TheSportsDb\Entity\Repository\RepositoryContainerInterface |
|
33
|
|
|
*/ |
|
34
|
|
|
protected $repositoryContainer; |
|
35
|
|
|
|
|
36
|
|
|
/** |
|
37
|
|
|
* Map entity types to classes. |
|
38
|
|
|
* |
|
39
|
|
|
* @var array |
|
40
|
|
|
*/ |
|
41
|
|
|
protected $classes = array(); |
|
42
|
|
|
|
|
43
|
|
|
/** |
|
44
|
|
|
* Property map definitions. |
|
45
|
|
|
* |
|
46
|
|
|
* @var array |
|
47
|
|
|
*/ |
|
48
|
|
|
protected $propertyMapDefinitions = array(); |
|
49
|
|
|
|
|
50
|
|
|
/** |
|
51
|
|
|
* Property map definitions. |
|
52
|
|
|
* |
|
53
|
|
|
* @var array |
|
54
|
|
|
*/ |
|
55
|
|
|
protected $propertyMaps = array(); |
|
56
|
|
|
|
|
57
|
|
|
protected $propertyMapper; |
|
58
|
|
|
|
|
59
|
|
|
|
|
60
|
|
|
const EMPTYPROPERTYPLACEHOLDER = '__EMPTY_PROPERTY_PLACEHOLDER__'; |
|
61
|
|
|
|
|
62
|
|
|
|
|
63
|
|
|
public function __construct(MapperInterface $propertyMapper, FactoryContainerInterface $factoryContainer = NULL, RepositoryContainerInterface $repositoryContainer = NULL) { |
|
64
|
|
|
if ($factoryContainer instanceof FactoryContainerInterface) { |
|
65
|
|
|
$this->factoryContainer = $factoryContainer; |
|
66
|
|
|
} |
|
67
|
|
|
if ($repositoryContainer instanceof RepositoryContainerInterface) { |
|
68
|
|
|
$this->repositoryContainer = $repositoryContainer; |
|
69
|
|
|
} |
|
70
|
|
|
$this->propertyMapper = $propertyMapper; |
|
71
|
|
|
} |
|
72
|
|
|
|
|
73
|
|
|
public function setFactoryContainer(FactoryContainerInterface $factoryContainer) { |
|
74
|
|
|
if ($this->factoryContainer instanceof FactoryContainerInterface) { |
|
75
|
|
|
throw new \Exception('Factory container already set.'); |
|
76
|
|
|
} |
|
77
|
|
|
$this->factoryContainer = $factoryContainer; |
|
78
|
|
|
} |
|
79
|
|
|
|
|
80
|
|
|
public function setRepositoryContainer(RepositoryContainerInterface $repositoryContainer) { |
|
81
|
|
|
if ($this->repositoryContainer instanceof RepositoryContainerInterface) { |
|
82
|
|
|
throw new \Exception('Repository container already set.'); |
|
83
|
|
|
} |
|
84
|
|
|
$this->repositoryContainer = $repositoryContainer; |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
|
|
88
|
|
|
/** |
|
89
|
|
|
* {@inheritdoc} |
|
90
|
|
|
*/ |
|
91
|
|
|
public function repository($entityType) { |
|
92
|
|
|
if ($this->repositoryContainer instanceof RepositoryContainerInterface) { |
|
93
|
|
|
return $this->repositoryContainer->getRepository($entityType); |
|
94
|
|
|
} |
|
95
|
|
|
throw new \Exception('No repository container set.'); |
|
96
|
|
|
} |
|
97
|
|
|
|
|
98
|
|
|
/** |
|
99
|
|
|
* {@inheritdoc} |
|
100
|
|
|
*/ |
|
101
|
|
|
public function factory($entityType) { |
|
102
|
|
|
if ($this->factoryContainer instanceof FactoryContainerInterface) { |
|
103
|
|
|
return $this->factoryContainer->getFactory($entityType); |
|
104
|
|
|
} |
|
105
|
|
|
throw new \Exception('No factory container set.'); |
|
106
|
|
|
} |
|
107
|
|
|
|
|
108
|
|
|
/** |
|
109
|
|
|
* {@inheritdoc} |
|
110
|
|
|
*/ |
|
111
|
|
|
public function registerClass($entityType, $realClass = NULL, $proxyClass = NULL) { |
|
112
|
|
View Code Duplication |
if (is_null($realClass)) { |
|
|
|
|
|
|
113
|
|
|
$realClass = (new \ReflectionClass(static::class))->getNamespaceName() . '\\' . ucfirst($entityType); |
|
114
|
|
|
} |
|
115
|
|
View Code Duplication |
if (is_null($proxyClass)) { |
|
|
|
|
|
|
116
|
|
|
$proxyClass = (new \ReflectionClass($realClass))->getNamespaceName() . '\\Proxy\\' . ucfirst($entityType) . 'Proxy'; |
|
117
|
|
|
} |
|
118
|
|
|
if (!class_exists($realClass)) { |
|
119
|
|
|
throw new \Exception('Class ' . $realClass . 'not found.'); |
|
120
|
|
|
} |
|
121
|
|
|
if (!class_exists($proxyClass)) { |
|
122
|
|
|
throw new \Exception('Class ' . $proxyClass . 'not found.'); |
|
123
|
|
|
} |
|
124
|
|
|
$this->classes[$entityType] = array( |
|
125
|
|
|
'real' => $realClass, |
|
126
|
|
|
'proxy' => $proxyClass |
|
127
|
|
|
); |
|
128
|
|
|
return $this->classes[$entityType]; |
|
129
|
|
|
} |
|
130
|
|
|
|
|
131
|
|
|
/** |
|
132
|
|
|
* {@inheritdoc} |
|
133
|
|
|
*/ |
|
134
|
|
|
public function getPropertyMapDefinition($entityType) { |
|
|
|
|
|
|
135
|
|
|
if (!isset($this->propertyMapDefinitions[$entityType])) { |
|
136
|
|
|
$propertyMapDefinition = new \ReflectionMethod($this->getClass($entityType), 'getPropertyMapDefinition'); |
|
|
|
|
|
|
137
|
|
|
$this->propertyMapDefinitions[$entityType] = $propertyMapDefinition->invoke(NULL); |
|
138
|
|
|
} |
|
139
|
|
|
return $this->propertyMapDefinitions[$entityType]; |
|
140
|
|
|
} |
|
141
|
|
|
|
|
142
|
|
|
/** |
|
143
|
|
|
* {@inheritdoc} |
|
144
|
|
|
*/ |
|
145
|
|
|
public function getClass($entityType, $type = 'real') { |
|
146
|
|
|
if (!isset($this->classes[$entityType][$type])) { |
|
147
|
|
|
throw new \Exception(ucfirst($type) . ' class for ' . $entityType . ' not registered.'); |
|
148
|
|
|
} |
|
149
|
|
|
return $this->classes[$entityType][$type]; |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
|
/** |
|
153
|
|
|
* {@inheritdoc} |
|
154
|
|
|
*/ |
|
155
|
|
|
public function mapProperties(\stdClass $values, $entityType) { |
|
156
|
|
|
$mapped = new \stdClass(); |
|
157
|
|
|
foreach ($this->getPropertyMapDefinition($entityType) as $propertyDefinition) { |
|
158
|
|
|
$mapped->{$propertyDefinition[1]} = NULL; |
|
159
|
|
View Code Duplication |
if (!isset($values->{$propertyDefinition[0]})) { |
|
|
|
|
|
|
160
|
|
|
$values->{$propertyDefinition[0]} = static::EMPTYPROPERTYPLACEHOLDER; |
|
161
|
|
|
} |
|
162
|
|
|
} |
|
163
|
|
|
return $this->sanitizeObject($this->propertyMapper->process($values, $mapped, $this->getPropertyMap($entityType))); |
|
|
|
|
|
|
164
|
|
|
} |
|
165
|
|
|
|
|
166
|
|
|
|
|
167
|
|
|
/** |
|
168
|
|
|
* {@inheritdoc} |
|
169
|
|
|
*/ |
|
170
|
|
|
public function reverseMapProperties(\stdClass $values, $entityType) { |
|
171
|
|
|
$reversed = new \stdClass(); |
|
172
|
|
|
foreach ($this->getPropertyMapDefinition($entityType) as $propertyDefinition) { |
|
173
|
|
|
if (!isset($reversed->{$propertyDefinition[0]})) { |
|
174
|
|
|
$reversed->{$propertyDefinition[0]} = static::EMPTYPROPERTYPLACEHOLDER; |
|
175
|
|
|
} |
|
176
|
|
View Code Duplication |
if (!isset($values->{$propertyDefinition[1]})) { |
|
|
|
|
|
|
177
|
|
|
$values->{$propertyDefinition[1]} = static::EMPTYPROPERTYPLACEHOLDER; |
|
178
|
|
|
} |
|
179
|
|
|
} |
|
180
|
|
|
return $this->sanitizeObject($this->propertyMapper->reverse($reversed, $values, $this->getPropertyMap($entityType))); |
|
|
|
|
|
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
/** |
|
184
|
|
|
* {@inheritdoc} |
|
185
|
|
|
*/ |
|
186
|
|
|
public function isFullObject(\stdClass $object, $entityType) { |
|
187
|
|
|
$reflection = new \ReflectionClass($this->getClass($entityType)); |
|
|
|
|
|
|
188
|
|
|
$defaultProperties = $reflection->getDefaultProperties(); |
|
189
|
|
|
$properties = array_flip(array_filter(array_keys($defaultProperties), function($prop) use ($reflection) { |
|
|
|
|
|
|
190
|
|
|
// Filter out static properties. |
|
191
|
|
|
$reflectionProp = $reflection->getProperty($prop); |
|
192
|
|
|
if ($reflectionProp->isStatic()) { |
|
|
|
|
|
|
193
|
|
|
return FALSE; |
|
194
|
|
|
} |
|
195
|
|
|
return TRUE; |
|
196
|
|
|
})); |
|
197
|
|
|
return count(array_intersect_key($properties, (array) $object)) === count($properties); |
|
198
|
|
|
} |
|
199
|
|
|
|
|
200
|
|
|
/** |
|
201
|
|
|
* Initializes the property map. |
|
202
|
|
|
* @param string $entityType |
|
203
|
|
|
*/ |
|
204
|
|
|
protected function initPropertyMap($entityType) { |
|
205
|
|
|
$this->propertyMaps[$entityType] = new Map(); |
|
206
|
|
|
$entityManager = $this; |
|
|
|
|
|
|
207
|
|
|
foreach ($this->getPropertyMapDefinition($entityType) as $args) { |
|
208
|
|
|
if (isset($args[2]) && is_array($args[2])) { |
|
209
|
|
|
$transform = $args[2][0]; |
|
210
|
|
|
$reverse = $args[2][1]; |
|
|
|
|
|
|
211
|
|
|
$args[2] = new Callback( |
|
|
|
|
|
|
212
|
|
|
|
|
213
|
|
|
/** |
|
214
|
|
|
* @param string $value |
|
215
|
|
|
*/ |
|
216
|
|
View Code Duplication |
function($value, $context) use ($entityManager, $transform) { |
|
|
|
|
|
|
217
|
|
|
if ($entityManager->isEmptyValue($value)) { |
|
218
|
|
|
return $value; |
|
219
|
|
|
} |
|
220
|
|
|
return call_user_func_array($transform, array($value, $context, $entityManager)); |
|
221
|
|
|
}, |
|
222
|
|
|
|
|
223
|
|
|
/** |
|
224
|
|
|
* @param string $value |
|
225
|
|
|
*/ |
|
226
|
|
View Code Duplication |
function($value, $context) use ($entityManager, $reverse) { |
|
|
|
|
|
|
227
|
|
|
if ($entityManager->isEmptyValue($value)) { |
|
228
|
|
|
return $value; |
|
229
|
|
|
} |
|
230
|
|
|
return call_user_func_array($reverse, array($value, $context, $entityManager)); |
|
231
|
|
|
} |
|
232
|
|
|
); |
|
233
|
|
|
} |
|
234
|
|
|
call_user_func_array(array($this->propertyMaps[$entityType], 'map'), $args); |
|
235
|
|
|
} |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
/** |
|
239
|
|
|
* Gets the property map. |
|
240
|
|
|
* |
|
241
|
|
|
* @param string $entityType |
|
242
|
|
|
* @return \FastNorth\PropertyMapper\MapInterface |
|
243
|
|
|
* The property map. |
|
244
|
|
|
*/ |
|
245
|
|
|
protected function getPropertyMap($entityType) { |
|
246
|
|
|
if (!isset($this->propertyMaps[$entityType])) { |
|
247
|
|
|
$this->initPropertyMap($entityType); |
|
248
|
|
|
} |
|
249
|
|
|
return $this->propertyMaps[$entityType]; |
|
250
|
|
|
} |
|
251
|
|
|
|
|
252
|
|
|
protected function sanitizeObject(\stdClass $object) { |
|
|
|
|
|
|
253
|
|
|
$arr = (array) $object; |
|
254
|
|
|
foreach ($arr as $prop => $val) { |
|
255
|
|
|
if ($this->isEmptyValue($val)) { |
|
256
|
|
|
unset($arr[$prop]); |
|
257
|
|
|
} |
|
258
|
|
|
} |
|
259
|
|
|
return (object) $arr; |
|
260
|
|
|
} |
|
261
|
|
|
|
|
262
|
|
|
|
|
263
|
|
|
public function isEmptyValue($value) { |
|
264
|
|
|
return $value === static::EMPTYPROPERTYPLACEHOLDER; |
|
265
|
|
|
} |
|
266
|
|
|
} |
|
267
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.