AbstractManagerBuilder::getManager()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
cc 3
nc 4
nop 1
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);
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\Common\Annotati...egistry::registerFile() has been deprecated with message: this method is deprecated and will be removed in doctrine/annotations 2.0 autoloading should be deferred to the globally registered autoloader by then. For now, use @example AnnotationRegistry::registerLoader('class_exists')

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.

Loading history...
168
            }
169
        );
170
171
        AnnotationRegistry::registerAutoloadNamespaces($this->getAnnotationNamespaces());
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\Common\Annotati...terAutoloadNamespaces() has been deprecated with message: this method is deprecated and will be removed in doctrine/annotations 2.0 autoloading should be deferred to the globally registered autoloader by then. For now, use @example AnnotationRegistry::registerLoader('class_exists')

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.

Loading history...
172
173
        $annotationLoaders = (array) $this->getOption('annotation_autoloaders');
174
        array_walk(
175
            $annotationLoaders,
176
            function ($autoLoader) {
177
                AnnotationRegistry::registerLoader($autoLoader);
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\Common\Annotati...istry::registerLoader() has been deprecated with message: this method is deprecated and will be removed in doctrine/annotations 2.0 autoloading should be deferred to the globally registered autoloader by then. For now, use @example AnnotationRegistry::registerLoader('class_exists')

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.

Loading history...
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