Completed
Push — 5.1 ( a7d90f...f422a4 )
by Rémi
8s
created

Manager::mapper()   C

Complexity

Conditions 8
Paths 9

Size

Total Lines 32
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 9
Bugs 1 Features 2
Metric Value
c 9
b 1
f 2
dl 0
loc 32
rs 5.3846
cc 8
eloc 16
nc 9
nop 2
1
<?php
2
3
namespace Analogue\ORM\System;
4
5
use Exception;
6
use Analogue\ORM\EntityMap;
7
use Analogue\ORM\Repository;
8
use Analogue\ORM\System\Wrappers\Wrapper;
9
use Illuminate\Contracts\Events\Dispatcher;
10
use Analogue\ORM\Exceptions\MappingException;
11
use Analogue\ORM\Drivers\Manager as DriverManager;
12
13
/**
14
 * This class keeps track of instantiated mappers, and entity <-> entityMap associations
15
 */
16
class Manager
17
{
18
    /**
19
     * Driver Manager
20
     *
21
     * @var \Analogue\ORM\Drivers\Manager
22
     */
23
    protected $drivers;
24
25
    /**
26
     * Registered entity classes and corresponding map objects.
27
     *
28
     * @var array
29
     */
30
    protected $entityClasses = [];
31
32
    /**
33
     * Key value store of ValueObject Classes and corresponding map classes
34
     *
35
     * @var array
36
     */
37
    protected $valueClasses = [];
38
39
    /**
40
     * Morph map
41
     */
42
    protected $morphMap = [];
43
44
    /**
45
     * Loaded Mappers
46
     *
47
     * @var array
48
     */
49
    protected $mappers = [];
50
51
    /**
52
     * Loaded Repositories
53
     *
54
     * @var array
55
     */
56
    protected $repositories = [];
57
58
    /**
59
     * Event dispatcher instance
60
     *
61
     * @var \Illuminate\Contracts\Events\Dispatcher
62
     */
63
    protected $eventDispatcher;
64
65
    /**
66
     * Manager instance
67
     *
68
     * @var Manager
69
     */
70
    protected static $instance;
71
72
    /**
73
     * Available Analogue Events
74
     *
75
     * @var array
76
     */
77
    protected $events = [
78
        'initializing',
79
        'initialized',
80
        'store',
81
        'stored',
82
        'creating',
83
        'created',
84
        'updating',
85
        'updated',
86
        'deleting',
87
        'deleted',
88
    ];
89
90
    /**
91
     * @param \Analogue\ORM\Drivers\Manager $driverManager
92
     * @param Dispatcher $event
93
     */
94
    public function __construct(DriverManager $driverManager, Dispatcher $event)
95
    {
96
        $this->drivers = $driverManager;
97
98
        $this->eventDispatcher = $event;
99
100
        static::$instance = $this;
101
    }
102
103
    /**
104
     * Return the Driver Manager's instance
105
     *
106
     * @return \Analogue\ORM\Drivers\Manager
107
     */
108
    public function getDriverManager()
109
    {
110
        return $this->drivers;
111
    }
112
113
    /**
114
     * Create a mapper for a given entity
115
     *
116
     * @param  \Analogue\ORM\Mappable|string|array|Collection $entity
117
     * @param  mixed $entityMap
118
     * @throws MappingException
119
     * @throws \InvalidArgumentException
120
     * @return Mapper
121
     */
122
    public function mapper($entity, $entityMap = null)
123
    {
124
        if ($entity instanceof Wrapper) {
125
            throw new MappingException('Tried to instantiate mapper on wrapped Entity');
126
        }
127
128
        // Implementation Mapper isArrayOrCollection method
129
        if (is_array($entity) || $entity instanceof Collection) {
0 ignored issues
show
Bug introduced by
The class Analogue\ORM\System\Collection does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
130
            if (!count($entity)) {
131
                throw new \InvalidArgumentException('Length of Entity collection must be greater than 0');
132
            }
133
            $entity = $entity[0];
134
135
136
        } elseif (is_object($entity)) {
137
            $entity = get_class($entity);
138
139
140
        } elseif (!is_string($entity)) {
141
            throw new \InvalidArgumentException('Invalid mapper Entity type');
142
        }
143
144
145
        $entity = $this->getInverseMorphMap($entity);
146
147
        // Return existing mapper instance if exists.
148
        if (array_key_exists($entity, $this->mappers)) {
149
            return $this->mappers[$entity];
150
        } else {
151
            return $this->buildMapper($entity, $entityMap);
152
        }
153
    }
154
155
    /**
156
     * Build a new Mapper instance for a given Entity
157
     *
158
     * @param  string $entity
159
     * @param         $entityMap
160
     * @throws MappingException
161
     * @return Mapper
162
     */
163
    protected function buildMapper($entity, $entityMap)
164
    {
165
        // If an EntityMap hasn't been manually registered by the user
166
        // register it at runtime.
167
        if (!$this->isRegisteredEntity($entity)) {
168
            $this->register($entity, $entityMap);
169
        }
170
171
        $entityMap = $this->entityClasses[$entity];
172
173
        $factory = new MapperFactory($this->drivers, $this->eventDispatcher, $this);
174
175
        $mapper = $factory->make($entity, $entityMap);
176
177
        $this->mappers[$entity] = $mapper;
178
179
        // At this point we can safely call the boot() method on the entityMap as
180
        // the mapper is now instantiated & registered within the manager.
181
182
        $mapper->getEntityMap()->boot();
183
        
184
        return $mapper;
185
    }
186
187
    /**
188
     * Create a mapper for a given entity (static alias)
189
     *
190
     * @param  \Analogue\ORM\Mappable|string $entity
191
     * @param  null|EntityMap                $entityMap
192
     * @throws MappingException
193
     * @return Mapper
194
     */
195
    public static function getMapper($entity, $entityMap = null)
196
    {
197
        return static::$instance->mapper($entity, $entityMap);
198
    }
199
200
    /**
201
     * Get the Repository instance for the given Entity
202
     *
203
     * @param  \Analogue\ORM\Mappable|string $entity
204
     * @throws \InvalidArgumentException
205
     * @throws MappingException
206
     * @return \Analogue\ORM\Repository
207
     */
208
    public function repository($entity)
209
    {
210
        if (!is_string($entity)) {
211
            $entity = get_class($entity);
212
        }
213
214
        // First we check if the repository is not already created.
215
        if (array_key_exists($entity, $this->repositories)) {
216
            return $this->repositories[$entity];
217
        }
218
219
        $this->repositories[$entity] = new Repository($this->mapper($entity));
220
        
221
        return $this->repositories[$entity];
222
    }
223
224
    /**
225
     * Register an entity
226
     *
227
     * @param  string|\Analogue\ORM\Mappable $entity    entity's class name
228
     * @param  string|EntityMap              $entityMap map's class name
229
     * @throws MappingException
230
     * @return void
231
     */
232
    public function register($entity, $entityMap = null)
233
    {
234
        // If an object is provider, get the class name from it
235
        if (!is_string($entity)) {
236
            $entity = get_class($entity);
237
        }
238
239
        if ($this->isRegisteredEntity($entity)) {
240
            throw new MappingException("Entity $entity is already registered.");
241
        }
242
243
        if (!class_exists($entity)) {
244
            throw new MappingException("Class $entity does not exists");
245
        }
246
247
        if (is_null($entityMap)) {
248
            $entityMap = $this->getEntityMapInstanceFor($entity);
249
        }
250
251
        if (is_string($entityMap)) {
252
            $entityMap = new $entityMap;
253
        }
254
255
        if (!$entityMap instanceof EntityMap) {
256
            throw new MappingException(get_class($entityMap) . ' must be an instance of EntityMap.');
257
        }
258
259
        $entityMap->setClass($entity);
260
261
        $entityMap->setManager($this);
262
263
        $this->entityClasses[$entity] = $entityMap;
264
    }
265
266
    /**
267
     * Get the entity map instance for a custom entity
268
     *
269
     * @param  string   $entity
270
     * @return \Analogue\ORM\Mappable
271
     */
272
    protected function getEntityMapInstanceFor($entity)
273
    {
274
        if (class_exists($entity . 'Map')) {
275
            $map = $entity . 'Map';
276
            $map = new $map;
277
        } else {
278
            // Generate an EntityMap object
279
            $map = $this->getNewEntityMap();
280
        }
281
        
282
        return $map;
283
    }
284
285
    /**
286
     * Dynamically create an entity map for a custom entity class
287
     *
288
     * @return EntityMap
289
     */
290
    protected function getNewEntityMap()
291
    {
292
        return new EntityMap;
293
    }
294
295
    /**
296
     * Register a Value Object
297
     *
298
     * @param  string $valueObject
299
     * @param  string $valueMap
300
     * @throws MappingException
301
     * @return void
302
     */
303
    public function registerValueObject($valueObject, $valueMap = null)
304
    {
305
        if (!is_string($valueObject)) {
306
            $valueObject = get_class($valueObject);
307
        }
308
309
        if (is_null($valueMap)) {
310
            $valueMap = $valueObject . 'Map';
311
        }
312
313
        if (!class_exists($valueMap)) {
314
            throw new MappingException("$valueMap doesn't exists");
315
        }
316
317
        $this->valueClasses[$valueObject] = $valueMap;
318
    }
319
320
    /**
321
     * Return true is the object is registered as value object
322
     *
323
     * @param  mixed $object
324
     * @return boolean
325
     */
326
    public function isValueObject($object)
327
    {
328
        if (!is_string($object)) {
329
            $object = get_class($object);
330
        }
331
332
        return array_key_exists($object, $this->valueClasses);
333
    }
334
335
    /**
336
     * Get the Value Map for a given Value Object Class
337
     *
338
     * @param  string $valueObject
339
     * @throws MappingException
340
     * @return \Analogue\ORM\ValueMap
341
     */
342
    public function getValueMap($valueObject)
343
    {
344
        if (!is_string($valueObject)) {
345
            $valueObject = get_class($valueObject);
346
        }
347
348
        if (!array_key_exists($valueObject, $this->valueClasses)) {
349
            $this->registerValueObject($valueObject);
350
        }
351
        $valueMap = new $this->valueClasses[$valueObject];
352
353
        $valueMap->setClass($valueObject);
354
355
        return $valueMap;
356
    }
357
358
    /**
359
     * Instantiate a new Value Object instance
360
     *
361
     * @param  string $valueObject
362
     * @return \Analogue\ORM\ValueObject
363
     */
364
    public function getValueObjectInstance($valueObject)
365
    {
366
        $prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($valueObject), $valueObject));
367
        return $prototype;
368
    }
369
370
    /**
371
     * Register Analogue Plugin
372
     *
373
     * @param  string $plugin class
374
     * @return void
375
     */
376
    public function registerPlugin($plugin)
377
    {
378
        $plugin = new $plugin($this);
379
380
        $this->events = array_merge($this->events, $plugin->getCustomEvents());
381
382
        $plugin->register();
383
    }
384
385
    /**
386
     * Check if the entity is already registered
387
     *
388
     * @param  string|object $entity
389
     * @return boolean
390
     */
391
    public function isRegisteredEntity($entity)
392
    {
393
        if (!is_string($entity)) {
394
            $entity = get_class($entity);
395
        }
396
397
        return array_key_exists($entity, $this->entityClasses);
398
    }
399
400
    /**
401
     * Register event listeners that will be fired regardless the type
402
     * of the entity.
403
     *
404
     * @param  string $event
405
     * @param  \Closure $callback
406
     * @throws \Exception
407
     * @return void
408
     */
409
    public function registerGlobalEvent($event, $callback)
410
    {
411
        if (!in_array($event, $this->events)) {
412
            throw new \Exception("Analogue : Event $event doesn't exist");
413
        }
414
        $this->eventDispatcher->listen("analogue.{$event}.*", $callback);
415
    }
416
417
    /**
418
     * Shortcut to Mapper store
419
     *
420
     * @param  mixed $entity
421
     * @throws MappingException
422
     * @return mixed
423
     */
424
    public function store($entity)
425
    {
426
        return $this->mapper($entity)->store($entity);
427
    }
428
429
    /**
430
     * Shortcut to Mapper delete
431
     *
432
     * @param  mixed $entity
433
     * @throws MappingException
434
     * @return \Illuminate\Support\Collection|null
435
     */
436
    public function delete($entity)
437
    {
438
        return $this->mapper($entity)->delete($entity);
439
    }
440
441
    /**
442
     * Shortcut to Mapper query
443
     *
444
     * @param  mixed $entity
445
     * @throws MappingException
446
     * @return Query
447
     */
448
    public function query($entity)
449
    {
450
        return $this->mapper($entity)->query();
451
    }
452
453
    /**
454
     * Shortcut to Mapper Global Query
455
     *
456
     * @param  mixed $entity
457
     * @throws MappingException
458
     * @return Query
459
     */
460
    public function globalQuery($entity)
461
    {
462
        return $this->mapper($entity)->globalQuery();
463
    }
464
465
    public function morphMap(array $morphMap)
466
    {
467
        $this->morphMap = $morphMap;
468
        return $this;
469
    }
470
471
    public function getMorphMap($class)
472
    {
473
        $key = array_search($class, $this->morphMap);
474
        return $key !== false ? $key : $class;
475
    }
476
477
    public function getInverseMorphMap($key)
478
    {
479
        return array_key_exists($key, $this->morphMap) ? $this->morphMap[$key] : $key;
480
    }
481
    
482
    /**
483
     * Return the Singleton instance of the manager
484
     *
485
     * @return Manager
486
     */
487
    public static function getInstance()
488
    {
489
        return static::$instance;
490
    }
491
}
492