Completed
Push — master ( d34e64...7e6b75 )
by Julián
06:06
created

getAnnotationMetadataDriver()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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