1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of slick/orm package |
5
|
|
|
* |
6
|
|
|
* For the full copyright and license information, please view the LICENSE |
7
|
|
|
* file that was distributed with this source code. |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
namespace Slick\Orm; |
11
|
|
|
|
12
|
|
|
use League\Event\Emitter; |
13
|
|
|
use League\Event\EmitterInterface; |
14
|
|
|
use League\Event\ListenerInterface; |
15
|
|
|
use Slick\Database\Adapter\AdapterInterface; |
16
|
|
|
use Slick\Orm\Descriptor\EntityDescriptor; |
17
|
|
|
use Slick\Orm\Descriptor\EntityDescriptorRegistry; |
18
|
|
|
use Slick\Orm\Event\EmittersMap; |
19
|
|
|
use Slick\Orm\Exception\InvalidArgumentException; |
20
|
|
|
use Slick\Orm\Mapper\EntityMapper; |
21
|
|
|
use Slick\Orm\Mapper\MappersMap; |
22
|
|
|
use Slick\Orm\Repository\EntityRepository; |
23
|
|
|
use Slick\Orm\Repository\RepositoryMap; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Orm registry |
27
|
|
|
* |
28
|
|
|
* @package Slick\Orm |
29
|
|
|
* @author Filipe Silva <[email protected]> |
30
|
|
|
*/ |
31
|
|
|
final class Orm |
32
|
|
|
{ |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var MappersMap|EntityMapperInterface[] |
36
|
|
|
*/ |
37
|
|
|
private $mappers; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var Orm |
41
|
|
|
*/ |
42
|
|
|
private static $instance; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @var AdaptersMap |
46
|
|
|
*/ |
47
|
|
|
private $adapters; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @var RepositoryMap |
51
|
|
|
*/ |
52
|
|
|
private $repositories; |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* @var EmittersMap |
56
|
|
|
*/ |
57
|
|
|
private $emitters; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Initialize Orm registry with empty lists |
61
|
|
|
*/ |
62
|
2 |
|
private function __construct() |
63
|
|
|
{ |
64
|
2 |
|
$this->mappers = new MappersMap(); |
65
|
2 |
|
$this->adapters = new AdaptersMap(); |
66
|
2 |
|
$this->repositories = new RepositoryMap(); |
67
|
2 |
|
$this->emitters = new EmittersMap(); |
68
|
2 |
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* Avoid clone on a singleton |
72
|
|
|
* @codeCoverageIgnore |
73
|
|
|
*/ |
74
|
|
|
private function __clone() |
75
|
|
|
{ |
76
|
|
|
|
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Gets a ORM registry instance |
81
|
|
|
* |
82
|
|
|
* @return Orm |
83
|
|
|
*/ |
84
|
16 |
|
public static function getInstance() |
85
|
|
|
{ |
86
|
16 |
|
if (null === self::$instance) { |
87
|
2 |
|
self::$instance = new static; |
88
|
1 |
|
} |
89
|
16 |
|
return self::$instance; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Retrieves the mapper for provided entity |
94
|
|
|
* |
95
|
|
|
* If mapper does not exists it will be created and stored in the |
96
|
|
|
* mapper map. |
97
|
|
|
* |
98
|
|
|
* @param String $entity |
99
|
|
|
* @return EntityMapper |
100
|
|
|
*/ |
101
|
6 |
|
public static function getMapper($entity) |
102
|
|
|
{ |
103
|
6 |
|
return self::getInstance()->getMapperFor($entity); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Gets repository for provided entity class name |
108
|
|
|
* |
109
|
|
|
* @param string $entityClass FQ entity class name |
110
|
|
|
* |
111
|
|
|
* @return EntityRepository |
112
|
|
|
* |
113
|
|
|
* @throws InvalidArgumentException If provide class name is not |
114
|
|
|
* from a class that implements the EntityInterface interface. |
115
|
|
|
*/ |
116
|
8 |
|
public static function getRepository($entityClass) |
117
|
|
|
{ |
118
|
8 |
|
return self::getInstance()->getRepositoryFor($entityClass); |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Gets event emitter for provided entity class |
123
|
|
|
* |
124
|
|
|
* @param string $entityClass FQ entity class name |
125
|
|
|
* |
126
|
|
|
* @return Emitter |
127
|
|
|
*/ |
128
|
4 |
|
public static function getEmitter($entityClass) |
129
|
|
|
{ |
130
|
4 |
|
return self::getInstance()->getEmitterFor($entityClass); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Add a listener for an entity event. |
135
|
|
|
* |
136
|
|
|
* The $event parameter should be the event name, and the second should be |
137
|
|
|
* the event listener. It may implement the League\Event\ListenerInterface |
138
|
|
|
* or simply be "callable". In this case, the priority emitter also accepts |
139
|
|
|
* an optional third parameter specifying the priority as an integer. You |
140
|
|
|
* may use one of EmitterInterface predefined constants here if you want. |
141
|
|
|
* |
142
|
|
|
* @param string|EntityInterface $entityClass |
143
|
|
|
* @param string $event |
144
|
|
|
* @param ListenerInterface|callable $listener |
145
|
|
|
* @param int $priority |
146
|
|
|
* |
147
|
|
|
* @return EmitterInterface |
148
|
|
|
*/ |
149
|
|
|
public static function addListener( |
150
|
|
|
$entityClass, $event, $listener, $priority = EmitterInterface::P_NORMAL |
151
|
|
|
) { |
152
|
|
|
return self::getInstance()->addListenerFor($entityClass,$event, $listener, $priority); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Add a listener for an entity event. |
157
|
|
|
* |
158
|
|
|
* The $event parameter should be the event name, and the second should be |
159
|
|
|
* the event listener. It may implement the League\Event\ListenerInterface |
160
|
|
|
* or simply be "callable". In this case, the priority emitter also accepts |
161
|
|
|
* an optional third parameter specifying the priority as an integer. You |
162
|
|
|
* may use one of EmitterInterface predefined constants here if you want. |
163
|
|
|
* |
164
|
|
|
* @param string|EntityInterface $entityClass |
165
|
|
|
* @param string $event |
166
|
|
|
* @param ListenerInterface|callable $listener |
167
|
|
|
* @param int $priority |
168
|
|
|
* |
169
|
|
|
* @return EmitterInterface |
170
|
|
|
*/ |
171
|
|
|
public function addListenerFor( |
172
|
|
|
$entityClass, $event, $listener, $priority = EmitterInterface::P_NORMAL |
173
|
|
|
) { |
174
|
|
|
$className = is_object($entityClass) |
175
|
|
|
? get_class($entityClass) |
176
|
|
|
: $entityClass; |
177
|
|
|
return $this->getEmitterFor($className) |
178
|
|
|
->addListener($event, $listener, $priority); |
|
|
|
|
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Gets repository for provided entity class name |
183
|
|
|
* |
184
|
|
|
* @param string $entityClass FQ entity class name |
185
|
|
|
* |
186
|
|
|
* @return EntityRepository |
187
|
|
|
* |
188
|
|
|
* @throws InvalidArgumentException If provide class name is not |
189
|
|
|
* from a class that implements the EntityInterface interface. |
190
|
|
|
*/ |
191
|
8 |
|
public function getRepositoryFor($entityClass) |
192
|
|
|
{ |
193
|
8 |
|
if (!is_subclass_of($entityClass, EntityInterface::class)) { |
194
|
2 |
|
throw new InvalidArgumentException( |
195
|
|
|
'Cannot create ORM repository for a class that does not '. |
196
|
1 |
|
'implement EntityInterface.' |
197
|
1 |
|
); |
198
|
|
|
} |
199
|
|
|
|
200
|
6 |
|
return $this->repositories->containsKey($entityClass) |
201
|
5 |
|
? $this->repositories->get($entityClass) |
202
|
6 |
|
: $this->createRepository($entityClass); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Creates a repository for provided entity class name |
207
|
|
|
* |
208
|
|
|
* @param string $entityClass |
209
|
|
|
* @return EntityRepository |
210
|
|
|
*/ |
211
|
2 |
|
private function createRepository($entityClass) |
212
|
|
|
{ |
213
|
2 |
|
$repository = new EntityRepository(); |
214
|
2 |
|
$repository->setAdapter( |
215
|
2 |
|
$this->adapters->get($this->getAdapterAlias($entityClass)) |
216
|
1 |
|
) |
217
|
2 |
|
->setEntityMapper($this->getMapperFor($entityClass)) |
218
|
2 |
|
->setEntityDescriptor(EntityDescriptorRegistry::getInstance() |
219
|
2 |
|
->getDescriptorFor($entityClass)); |
220
|
2 |
|
$this->repositories->set($entityClass, $repository); |
221
|
2 |
|
return $repository; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* Retrieves the mapper for provided entity |
226
|
|
|
* |
227
|
|
|
* If mapper does not exists it will be created and stored in the |
228
|
|
|
* mapper map. |
229
|
|
|
* |
230
|
|
|
* @param string $entity |
231
|
|
|
* @return EntityMapper |
232
|
|
|
*/ |
233
|
8 |
|
public function getMapperFor($entity) |
234
|
|
|
{ |
235
|
8 |
|
return $this->mappers->containsKey($entity) |
236
|
6 |
|
? $this->mappers->get($entity) |
237
|
8 |
|
: $this->createMapper($entity); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* Gets the event emitter for provided entity |
242
|
|
|
* |
243
|
|
|
* @param string $entity |
244
|
|
|
* |
245
|
|
|
* @return Emitter |
246
|
|
|
*/ |
247
|
4 |
|
public function getEmitterFor($entity) |
248
|
|
|
{ |
249
|
4 |
|
return $this->emitters->containsKey($entity) |
250
|
4 |
|
? $this->emitters->get($entity) |
251
|
4 |
|
: $this->createEmitter($entity); |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Sets default adapter |
256
|
|
|
* |
257
|
|
|
* @param AdapterInterface $adapter |
258
|
|
|
* @return $this|Orm|self |
259
|
|
|
*/ |
260
|
10 |
|
public function setDefaultAdapter(AdapterInterface $adapter) |
261
|
|
|
{ |
262
|
10 |
|
return $this->setAdapter('default', $adapter); |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Sets an adapter mapped with alias name |
267
|
|
|
* |
268
|
|
|
* @param string $alias |
269
|
|
|
* @param AdapterInterface $adapter |
270
|
|
|
* |
271
|
|
|
* @return $this|Orm|self |
272
|
|
|
*/ |
273
|
10 |
|
public function setAdapter($alias, AdapterInterface $adapter) |
274
|
|
|
{ |
275
|
10 |
|
$this->adapters->set($alias, $adapter); |
276
|
10 |
|
return $this; |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
/** |
280
|
|
|
* Creates entity map for provided entity |
281
|
|
|
* |
282
|
|
|
* @param string $entity |
283
|
|
|
* @return EntityMapper |
284
|
|
|
*/ |
285
|
4 |
|
private function createMapper($entity) |
286
|
|
|
{ |
287
|
4 |
|
$mapper = new EntityMapper(); |
288
|
4 |
|
$mapper->setAdapter( |
289
|
4 |
|
$this->adapters->get( |
290
|
4 |
|
$this->getAdapterAlias($entity) |
291
|
2 |
|
) |
292
|
2 |
|
) |
293
|
4 |
|
->setEntityClassName($entity); |
294
|
4 |
|
$this->mappers->set($entity, $mapper); |
295
|
4 |
|
return $mapper; |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* Creates an emitter for provided entity class name |
300
|
|
|
* |
301
|
|
|
* @param string $entity |
302
|
|
|
* @return Emitter |
303
|
|
|
*/ |
304
|
2 |
|
private function createEmitter($entity) |
305
|
|
|
{ |
306
|
2 |
|
$emitter = new Emitter(); |
307
|
2 |
|
$this->emitters->set($entity, $emitter); |
308
|
2 |
|
return $emitter; |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* Gets the adapter alias for current working entity |
313
|
|
|
* |
314
|
|
|
* @param string $entity |
315
|
|
|
* |
316
|
|
|
* @return EntityDescriptor|string |
317
|
|
|
*/ |
318
|
6 |
|
private function getAdapterAlias($entity) |
319
|
|
|
{ |
320
|
6 |
|
$descriptor = EntityDescriptorRegistry::getInstance() |
321
|
6 |
|
->getDescriptorFor($entity); |
322
|
6 |
|
return $descriptor->getAdapterAlias() |
323
|
6 |
|
? $descriptor->getAdapterAlias() |
324
|
6 |
|
: 'default'; |
325
|
|
|
} |
326
|
|
|
} |
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.