Completed
Push — 5.1 ( 690605...99a6b9 )
by Rémi
03:00
created

Manager::morphMap()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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