1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* doctrine-manager-builder (https://github.com/juliangut/doctrine-manager-builder). |
5
|
|
|
* Doctrine2 managers builder. |
6
|
|
|
* |
7
|
|
|
* @license BSD-3-Clause |
8
|
|
|
* @link https://github.com/juliangut/doctrine-manager-builder |
9
|
|
|
* @author Julián Gutiérrez <[email protected]> |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Jgut\Doctrine\ManagerBuilder; |
13
|
|
|
|
14
|
|
|
use Doctrine\Common\Annotations\AnnotationRegistry; |
15
|
|
|
use Doctrine\Common\Cache\CacheProvider; |
16
|
|
|
use Doctrine\Common\EventManager; |
17
|
|
|
use Doctrine\Common\EventSubscriber; |
18
|
|
|
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver; |
19
|
|
|
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain; |
20
|
|
|
use Doctrine\Common\Persistence\Mapping\Driver\PHPDriver; |
21
|
|
|
use Doctrine\Common\Persistence\ObjectManager; |
22
|
|
|
use Doctrine\Common\Proxy\AbstractProxyFactory; |
23
|
|
|
use Jgut\Doctrine\ManagerBuilder\Util\CacheBuilder; |
24
|
|
|
use Jgut\Doctrine\ManagerBuilder\Util\OptionsTrait; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Abstract Doctrine Manager builder. |
28
|
|
|
* |
29
|
|
|
* @SuppressWarnings(PHPMD.CouplingBetweenObjects) |
30
|
|
|
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity) |
31
|
|
|
*/ |
32
|
|
|
abstract class AbstractManagerBuilder implements ManagerBuilder |
33
|
|
|
{ |
34
|
|
|
use OptionsTrait; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Manager builder's common default options. |
38
|
|
|
* |
39
|
|
|
* @var array |
40
|
|
|
*/ |
41
|
|
|
private $defaultOptions = [ |
42
|
|
|
'proxies_auto_generation' => AbstractProxyFactory::AUTOGENERATE_NEVER, |
43
|
|
|
]; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* Builder name. |
47
|
|
|
* |
48
|
|
|
* @var |
49
|
|
|
*/ |
50
|
|
|
protected $name; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Object Manager. |
54
|
|
|
* |
55
|
|
|
* @var ObjectManager |
56
|
|
|
*/ |
57
|
|
|
protected $manager; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Metadata mapping driver. |
61
|
|
|
* |
62
|
|
|
* @var MappingDriverChain |
63
|
|
|
*/ |
64
|
|
|
protected $mappingDriver; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Metadata cache driver. |
68
|
|
|
* |
69
|
|
|
* @var CacheProvider |
70
|
|
|
*/ |
71
|
|
|
protected $metadataCacheDriver; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Event manager. |
75
|
|
|
* |
76
|
|
|
* @var EventManager |
77
|
|
|
*/ |
78
|
|
|
protected $eventManager; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* ManagerBuilder constructor. |
82
|
|
|
* |
83
|
|
|
* @param array $options |
84
|
|
|
* @param string|null $name |
85
|
|
|
*/ |
86
|
|
|
public function __construct(array $options = [], $name = null) |
87
|
|
|
{ |
88
|
|
|
$this->setOptions(array_merge($this->defaultOptions, $this->getDefaultOptions(), $options)); |
89
|
|
|
$this->setName($name); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Get manager builder's default options. |
94
|
|
|
* |
95
|
|
|
* @return array |
96
|
|
|
*/ |
97
|
|
|
abstract protected function getDefaultOptions(); |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* {@inheritdoc} |
101
|
|
|
* |
102
|
|
|
* @return ObjectManager |
103
|
|
|
*/ |
104
|
|
|
public function getManager($force = false) |
105
|
|
|
{ |
106
|
|
|
if ($force === true) { |
107
|
|
|
$this->wipe(); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
if (!$this->manager instanceof ObjectManager) { |
111
|
|
|
$this->manager = $this->buildManager(); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
return $this->manager; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Unset created objects for rebuild. |
119
|
|
|
*/ |
120
|
|
|
abstract protected function wipe(); |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Build new Doctrine object manager. |
124
|
|
|
* |
125
|
|
|
* @return ObjectManager |
126
|
|
|
*/ |
127
|
|
|
abstract protected function buildManager(); |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* {@inheritdoc} |
131
|
|
|
* |
132
|
|
|
* @return string|null |
133
|
|
|
*/ |
134
|
|
|
public function getName() |
135
|
|
|
{ |
136
|
|
|
return $this->name; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* {@inheritdoc} |
141
|
|
|
* |
142
|
|
|
* @return $this |
143
|
|
|
*/ |
144
|
|
|
public function setName($name = null) |
145
|
|
|
{ |
146
|
|
|
$this->name = $name; |
147
|
|
|
|
148
|
|
|
return $this; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* Set up annotation metadata. |
153
|
|
|
* |
154
|
|
|
* @throws \InvalidArgumentException |
155
|
|
|
* @throws \RuntimeException |
156
|
|
|
*/ |
157
|
|
|
protected function setupAnnotationMetadata() |
158
|
|
|
{ |
159
|
|
|
$annotationFiles = (array) $this->getOption('annotation_files'); |
160
|
|
|
array_walk( |
161
|
|
|
$annotationFiles, |
162
|
|
|
function ($file) { |
163
|
|
|
if (!file_exists($file)) { |
164
|
|
|
throw new \RuntimeException(sprintf('"%s" file does not exist', $file)); |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
AnnotationRegistry::registerFile($file); |
|
|
|
|
168
|
|
|
} |
169
|
|
|
); |
170
|
|
|
|
171
|
|
|
AnnotationRegistry::registerAutoloadNamespaces($this->getAnnotationNamespaces()); |
|
|
|
|
172
|
|
|
|
173
|
|
|
$annotationLoaders = (array) $this->getOption('annotation_autoloaders'); |
174
|
|
|
array_walk( |
175
|
|
|
$annotationLoaders, |
176
|
|
|
function ($autoLoader) { |
177
|
|
|
AnnotationRegistry::registerLoader($autoLoader); |
|
|
|
|
178
|
|
|
} |
179
|
|
|
); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Retrieve annotation namespaces. |
184
|
|
|
* |
185
|
|
|
* @return array |
186
|
|
|
*/ |
187
|
|
|
protected function getAnnotationNamespaces() |
188
|
|
|
{ |
189
|
|
|
$namespaces = (array) $this->getOption('annotation_namespaces'); |
190
|
|
|
|
191
|
|
|
return array_filter( |
192
|
|
|
$namespaces, |
193
|
|
|
function ($namespace) { |
194
|
|
|
return is_string($namespace); |
195
|
|
|
}, |
196
|
|
|
ARRAY_FILTER_USE_KEY |
197
|
|
|
); |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* {@inheritdoc} |
202
|
|
|
* |
203
|
|
|
* @throws \RuntimeException |
204
|
|
|
* @throws \UnexpectedValueException |
205
|
|
|
*/ |
206
|
|
|
public function getMetadataMappingDriver() |
207
|
|
|
{ |
208
|
|
|
if (!$this->mappingDriver instanceof MappingDriverChain) { |
209
|
|
|
$metadataDriverChain = new MappingDriverChain; |
210
|
|
|
|
211
|
|
|
$this->parseMetadataMapping($metadataDriverChain); |
212
|
|
|
|
213
|
|
|
if ($metadataDriverChain->getDefaultDriver() === null && count($metadataDriverChain->getDrivers()) === 0) { |
214
|
|
|
throw new \RuntimeException('No metadata mapping defined'); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
$this->mappingDriver = $metadataDriverChain; |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
return $this->mappingDriver; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* Parse metadata mapping configuration. |
225
|
|
|
* |
226
|
|
|
* @param MappingDriverChain $metadataDriverChain |
227
|
|
|
* |
228
|
|
|
* @throws \RuntimeException |
229
|
|
|
*/ |
230
|
|
|
protected function parseMetadataMapping(MappingDriverChain $metadataDriverChain) |
231
|
|
|
{ |
232
|
|
|
foreach ((array) $this->getOption('metadata_mapping') as $metadataMapping) { |
233
|
|
|
if (!is_array($metadataMapping)) { |
234
|
|
|
$metadataMapping = ['driver' => $metadataMapping]; |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
if (!array_key_exists('namespace', $metadataMapping) && $metadataDriverChain->getDefaultDriver() !== null) { |
238
|
|
|
throw new \RuntimeException( |
239
|
|
|
'Only one default metadata mapping driver allowed, a namespace must be defined' |
240
|
|
|
); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
$mappingDriver = $this->getMappingDriver($metadataMapping); |
244
|
|
|
|
245
|
|
|
if (array_key_exists('namespace', $metadataMapping)) { |
246
|
|
|
$metadataDriverChain->addDriver($mappingDriver, $metadataMapping['namespace']); |
247
|
|
|
} else { |
248
|
|
|
$metadataDriverChain->setDefaultDriver($mappingDriver); |
249
|
|
|
} |
250
|
|
|
} |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* Retrieve mapping driver. |
255
|
|
|
* |
256
|
|
|
* @param array $metadataMapping |
257
|
|
|
* |
258
|
|
|
* @throws \UnexpectedValueException |
259
|
|
|
* |
260
|
|
|
* @return MappingDriver |
261
|
|
|
*/ |
262
|
|
|
protected function getMappingDriver(array $metadataMapping) |
263
|
|
|
{ |
264
|
|
|
if (array_key_exists('driver', $metadataMapping)) { |
265
|
|
|
$mappingDriver = $metadataMapping['driver']; |
266
|
|
|
|
267
|
|
|
if (!$mappingDriver instanceof MappingDriver) { |
268
|
|
|
throw new \UnexpectedValueException( |
269
|
|
|
sprintf('Provided driver should be of the type MappingDriver, "%s" given', gettype($mappingDriver)) |
270
|
|
|
); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
return $mappingDriver; |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
if (count(array_intersect(['type', 'path'], array_keys($metadataMapping))) === 2) { |
277
|
|
|
$metadataMapping = array_merge(['extension' => null], $metadataMapping); |
278
|
|
|
|
279
|
|
|
return $this->getMappingDriverImplementation( |
280
|
|
|
$metadataMapping['type'], |
281
|
|
|
(array) $metadataMapping['path'], |
282
|
|
|
$metadataMapping['extension'] |
283
|
|
|
); |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
throw new \UnexpectedValueException( |
287
|
|
|
'metadata_mapping must be array with "driver" key or "type" and "path" keys' |
288
|
|
|
); |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
/** |
292
|
|
|
* Get metadata mapping driver implementation. |
293
|
|
|
* |
294
|
|
|
* @param string $type |
295
|
|
|
* @param array $paths |
296
|
|
|
* @param string $extension |
297
|
|
|
* |
298
|
|
|
* @throws \UnexpectedValueException |
299
|
|
|
* |
300
|
|
|
* @return MappingDriver|PHPDriver |
301
|
|
|
*/ |
302
|
|
|
protected function getMappingDriverImplementation($type, $paths, $extension) |
303
|
|
|
{ |
304
|
|
|
switch ($type) { |
305
|
|
|
case ManagerBuilder::METADATA_MAPPING_ANNOTATION: |
306
|
|
|
return $this->getAnnotationMappingDriver($paths); |
307
|
|
|
|
308
|
|
|
case ManagerBuilder::METADATA_MAPPING_XML: |
309
|
|
|
return $this->getXmlMappingDriver($paths, $extension); |
310
|
|
|
|
311
|
|
|
case ManagerBuilder::METADATA_MAPPING_YAML: |
312
|
|
|
return $this->getYamlMappingDriver($paths, $extension); |
313
|
|
|
|
314
|
|
|
case ManagerBuilder::METADATA_MAPPING_PHP: |
315
|
|
|
return $this->getPhpMappingDriver($paths); |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
throw new \UnexpectedValueException( |
319
|
|
|
sprintf('"%s" is not a valid metadata mapping type', $type) |
320
|
|
|
); |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
/** |
324
|
|
|
* Get annotation metadata driver. |
325
|
|
|
* |
326
|
|
|
* @param array $paths |
327
|
|
|
* |
328
|
|
|
* @return MappingDriver |
329
|
|
|
*/ |
330
|
|
|
abstract protected function getAnnotationMappingDriver(array $paths); |
331
|
|
|
|
332
|
|
|
/** |
333
|
|
|
* Get XML metadata driver. |
334
|
|
|
* |
335
|
|
|
* @param array $paths |
336
|
|
|
* @param string|null $extension |
337
|
|
|
* |
338
|
|
|
* @return MappingDriver |
339
|
|
|
*/ |
340
|
|
|
abstract protected function getXmlMappingDriver(array $paths, $extension = null); |
341
|
|
|
|
342
|
|
|
/** |
343
|
|
|
* Get YAML metadata driver. |
344
|
|
|
* |
345
|
|
|
* @param array $paths |
346
|
|
|
* @param string|null $extension |
347
|
|
|
* |
348
|
|
|
* @return MappingDriver |
349
|
|
|
*/ |
350
|
|
|
abstract protected function getYamlMappingDriver(array $paths, $extension = null); |
351
|
|
|
|
352
|
|
|
/** |
353
|
|
|
* Get PHP metadata driver. |
354
|
|
|
* |
355
|
|
|
* @param array $paths |
356
|
|
|
* |
357
|
|
|
* @return PHPDriver |
358
|
|
|
*/ |
359
|
|
|
protected function getPhpMappingDriver(array $paths) |
360
|
|
|
{ |
361
|
|
|
return new PHPDriver($paths); |
362
|
|
|
} |
363
|
|
|
|
364
|
|
|
/** |
365
|
|
|
* {@inheritdoc} |
366
|
|
|
* |
367
|
|
|
* @return $this |
368
|
|
|
*/ |
369
|
|
|
public function setMetadataMappingDriver(MappingDriverChain $mappingDriver) |
370
|
|
|
{ |
371
|
|
|
$this->mappingDriver = $mappingDriver; |
372
|
|
|
|
373
|
|
|
return $this; |
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
/** |
377
|
|
|
* Get custom repository factory. |
378
|
|
|
*/ |
379
|
|
|
abstract protected function getRepositoryFactory(); |
380
|
|
|
|
381
|
|
|
/** |
382
|
|
|
* Get default repository class name. |
383
|
|
|
* |
384
|
|
|
* @return string|null |
385
|
|
|
*/ |
386
|
|
|
protected function getDefaultRepositoryClass() |
387
|
|
|
{ |
388
|
|
|
$repositoryClass = $this->getOption('default_repository_class'); |
389
|
|
|
|
390
|
|
|
return is_string($repositoryClass) ? $repositoryClass : null; |
391
|
|
|
} |
392
|
|
|
|
393
|
|
|
/** |
394
|
|
|
* Retrieve proxies path. |
395
|
|
|
* |
396
|
|
|
* @return string |
397
|
|
|
*/ |
398
|
|
|
protected function getProxiesPath() |
399
|
|
|
{ |
400
|
|
|
return (string) $this->getOption('proxies_path', sys_get_temp_dir()); |
401
|
|
|
} |
402
|
|
|
|
403
|
|
|
/** |
404
|
|
|
* Retrieve proxies namespace. |
405
|
|
|
* |
406
|
|
|
* @return null|string |
407
|
|
|
*/ |
408
|
|
|
protected function getProxiesNamespace() |
409
|
|
|
{ |
410
|
|
|
$proxyNamespace = $this->getOption('proxies_namespace'); |
411
|
|
|
|
412
|
|
|
return is_string($proxyNamespace) ? $proxyNamespace : null; |
413
|
|
|
} |
414
|
|
|
|
415
|
|
|
/** |
416
|
|
|
* Retrieve proxy generation strategy. |
417
|
|
|
* |
418
|
|
|
* @return int |
419
|
|
|
*/ |
420
|
|
|
protected function getProxiesAutoGeneration() |
421
|
|
|
{ |
422
|
|
|
return (int) $this->getOption('proxies_auto_generation'); |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
/** |
426
|
|
|
* {@inheritdoc} |
427
|
|
|
* |
428
|
|
|
* @throws \InvalidArgumentException |
429
|
|
|
*/ |
430
|
|
|
public function getMetadataCacheDriver() |
431
|
|
|
{ |
432
|
|
|
if (!$this->metadataCacheDriver instanceof CacheProvider) { |
433
|
|
|
$metadataCacheDriver = $this->getOption('metadata_cache_driver'); |
434
|
|
|
|
435
|
|
|
if (!$metadataCacheDriver instanceof CacheProvider) { |
436
|
|
|
$metadataCacheDriver = CacheBuilder::build(); |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
if ($metadataCacheDriver->getNamespace() === '') { |
440
|
|
|
$metadataCacheDriver->setNamespace((string) $this->getOption('metadata_cache_namespace')); |
441
|
|
|
} |
442
|
|
|
|
443
|
|
|
$this->metadataCacheDriver = $metadataCacheDriver; |
444
|
|
|
} |
445
|
|
|
|
446
|
|
|
return $this->metadataCacheDriver; |
447
|
|
|
} |
448
|
|
|
|
449
|
|
|
/** |
450
|
|
|
* {@inheritdoc} |
451
|
|
|
* |
452
|
|
|
* @return $this |
453
|
|
|
*/ |
454
|
|
|
public function setMetadataCacheDriver(CacheProvider $metadataCacheDriver) |
455
|
|
|
{ |
456
|
|
|
$this->metadataCacheDriver = $metadataCacheDriver; |
457
|
|
|
|
458
|
|
|
return $this; |
459
|
|
|
} |
460
|
|
|
|
461
|
|
|
/** |
462
|
|
|
* {@inheritdoc} |
463
|
|
|
*/ |
464
|
|
|
public function getEventManager() |
465
|
|
|
{ |
466
|
|
|
if (!$this->eventManager instanceof EventManager) { |
467
|
|
|
$eventManager = $this->getOption('event_manager'); |
468
|
|
|
|
469
|
|
|
if (!$eventManager instanceof EventManager) { |
470
|
|
|
$eventManager = new EventManager; |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
$this->eventManager = $eventManager; |
474
|
|
|
} |
475
|
|
|
|
476
|
|
|
return $this->eventManager; |
477
|
|
|
} |
478
|
|
|
|
479
|
|
|
/** |
480
|
|
|
* {@inheritdoc} |
481
|
|
|
* |
482
|
|
|
* @return $this |
483
|
|
|
*/ |
484
|
|
|
public function setEventManager(EventManager $eventManager) |
485
|
|
|
{ |
486
|
|
|
$this->eventManager = $eventManager; |
487
|
|
|
|
488
|
|
|
return $this; |
489
|
|
|
} |
490
|
|
|
|
491
|
|
|
/** |
492
|
|
|
* Get event subscribers. |
493
|
|
|
* |
494
|
|
|
* @return array|null |
495
|
|
|
*/ |
496
|
|
|
protected function getEventSubscribers() |
497
|
|
|
{ |
498
|
|
|
$eventSubscribers = $this->getOption('event_subscribers'); |
499
|
|
|
|
500
|
|
|
if (is_null($eventSubscribers) || !is_array($eventSubscribers)) { |
501
|
|
|
return; |
502
|
|
|
} |
503
|
|
|
|
504
|
|
|
return array_filter( |
505
|
|
|
$eventSubscribers, |
506
|
|
|
function ($subscriber) { |
507
|
|
|
return $subscriber instanceof EventSubscriber; |
508
|
|
|
} |
509
|
|
|
); |
510
|
|
|
} |
511
|
|
|
} |
512
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.