Completed
Push — 5.1 ( a89502...c13850 )
by Rémi
02:48
created
src/System/Manager.php 3 patches
Doc Comments   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -117,7 +117,7 @@  discard block
 block discarded – undo
117 117
      * Create a mapper for a given entity
118 118
      *
119 119
      * @param  \Analogue\ORM\Mappable|string|array|\Traversable $entity
120
-     * @param  mixed                                            $entityMap
120
+     * @param  null|EntityMap                                            $entityMap
121 121
      * @throws MappingException
122 122
      * @throws \InvalidArgumentException
123 123
      * @return Mapper
@@ -215,7 +215,7 @@  discard block
 block discarded – undo
215 215
     /**
216 216
      * Check if the entity is already registered
217 217
      *
218
-     * @param  string|object $entity
218
+     * @param  string $entity
219 219
      * @return boolean
220 220
      */
221 221
     public function isRegisteredEntity($entity)
@@ -230,7 +230,7 @@  discard block
 block discarded – undo
230 230
     /**
231 231
      * Register an entity
232 232
      *
233
-     * @param  string|\Analogue\ORM\Mappable $entity    entity's class name
233
+     * @param  string $entity    entity's class name
234 234
      * @param  string|EntityMap              $entityMap map's class name
235 235
      * @throws MappingException
236 236
      * @return void
Please login to merge, or discard this patch.
Indentation   +537 added lines, -537 removed lines patch added patch discarded remove patch
@@ -18,544 +18,544 @@
 block discarded – undo
18 18
  */
19 19
 class Manager
20 20
 {
21
-    /**
22
-     * Manager instance
23
-     *
24
-     * @var Manager
25
-     */
26
-    protected static $instance;
27
-
28
-    /**
29
-     * Driver Manager
30
-     *
31
-     * @var \Analogue\ORM\Drivers\Manager
32
-     */
33
-    protected $drivers;
34
-
35
-    /**
36
-     * Registered entity classes and corresponding map objects.
37
-     *
38
-     * @var array
39
-     */
40
-    protected $entityClasses = [];
41
-
42
-    /**
43
-     * Key value store of ValueObject Classes and corresponding map classes
44
-     *
45
-     * @var array
46
-     */
47
-    protected $valueClasses = [];
48
-
49
-    /**
50
-     * Morph map
51
-     */
52
-    protected $morphMap = [];
53
-
54
-    /**
55
-     * Loaded Mappers
56
-     *
57
-     * @var array
58
-     */
59
-    protected $mappers = [];
60
-
61
-    /**
62
-     * Loaded Repositories
63
-     *
64
-     * @var array
65
-     */
66
-    protected $repositories = [];
67
-
68
-    /**
69
-     * Event dispatcher instance
70
-     *
71
-     * @var \Illuminate\Contracts\Events\Dispatcher
72
-     */
73
-    protected $eventDispatcher;
74
-
75
-    /**
76
-     * Available Analogue Events
77
-     *
78
-     * @var array
79
-     */
80
-    protected $events = [
81
-        'initializing',
82
-        'initialized',
83
-        'store',
84
-        'stored',
85
-        'creating',
86
-        'created',
87
-        'updating',
88
-        'updated',
89
-        'deleting',
90
-        'deleted',
91
-    ];
92
-
93
-    /**
94
-     * If strictMode is set to true, Manager will throw
95
-     * an exception if no entityMap class are registered
96
-     * for a given entity class.
97
-     * 
98
-     * @var boolean
99
-     */
100
-    protected $strictMode = false;
101
-
102
-    /**
103
-     * @param \Analogue\ORM\Drivers\Manager $driverManager
104
-     * @param Dispatcher                    $event
105
-     */
106
-    public function __construct(DriverManager $driverManager, Dispatcher $event)
107
-    {
108
-        $this->drivers = $driverManager;
109
-
110
-        $this->eventDispatcher = $event;
111
-
112
-        static::$instance = $this;
113
-    }
114
-
115
-    /**
116
-     * Create a mapper for a given entity (static alias)
117
-     *
118
-     * @param  \Analogue\ORM\Mappable|string $entity
119
-     * @param  null|EntityMap                $entityMap
120
-     * @throws MappingException
121
-     * @return Mapper
122
-     */
123
-    public static function getMapper($entity, $entityMap = null)
124
-    {
125
-        return static::$instance->mapper($entity, $entityMap);
126
-    }
127
-
128
-    /**
129
-     * Create a mapper for a given entity
130
-     *
131
-     * @param  \Analogue\ORM\Mappable|string|array|\Traversable $entity
132
-     * @param  mixed                                            $entityMap
133
-     * @throws MappingException
134
-     * @throws \InvalidArgumentException
135
-     * @return Mapper
136
-     */
137
-    public function mapper($entity, $entityMap = null)
138
-    {
139
-        if ($entity instanceof Wrapper) {
140
-            throw new MappingException('Tried to instantiate mapper on wrapped Entity');
141
-        }
142
-
143
-        $entity = $this->resolveEntityClass($entity);
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
-     * This method resolve entity class from mappable instances or iterators
157
-     *
158
-     * @param \Analogue\ORM\Mappable|string|array|\Traversable $entity
159
-     * @return string
160
-     *
161
-     * @throws \InvalidArgumentException
162
-     */
163
-    protected function resolveEntityClass($entity)
164
-    {
165
-        // We first check if the entity is traversable and we'll resolve
166
-        // the entity based on the first item of the object.   
167
-        if ($this->isTraversable($entity)) {
168
-            if (! count($entity)) {
169
-                throw new \InvalidArgumentException('Length of Entity collection must be greater than 0');
170
-            }
171
-
172
-            $firstEntityItem = ($entity instanceof \Iterator || $entity instanceof \IteratorAggregate)
173
-                ? $entity->current()
174
-                : current($entity);
175
-
176
-            return $this->resolveEntityClass($firstEntityItem);
177
-        }
21
+	/**
22
+	 * Manager instance
23
+	 *
24
+	 * @var Manager
25
+	 */
26
+	protected static $instance;
27
+
28
+	/**
29
+	 * Driver Manager
30
+	 *
31
+	 * @var \Analogue\ORM\Drivers\Manager
32
+	 */
33
+	protected $drivers;
34
+
35
+	/**
36
+	 * Registered entity classes and corresponding map objects.
37
+	 *
38
+	 * @var array
39
+	 */
40
+	protected $entityClasses = [];
41
+
42
+	/**
43
+	 * Key value store of ValueObject Classes and corresponding map classes
44
+	 *
45
+	 * @var array
46
+	 */
47
+	protected $valueClasses = [];
48
+
49
+	/**
50
+	 * Morph map
51
+	 */
52
+	protected $morphMap = [];
53
+
54
+	/**
55
+	 * Loaded Mappers
56
+	 *
57
+	 * @var array
58
+	 */
59
+	protected $mappers = [];
60
+
61
+	/**
62
+	 * Loaded Repositories
63
+	 *
64
+	 * @var array
65
+	 */
66
+	protected $repositories = [];
67
+
68
+	/**
69
+	 * Event dispatcher instance
70
+	 *
71
+	 * @var \Illuminate\Contracts\Events\Dispatcher
72
+	 */
73
+	protected $eventDispatcher;
74
+
75
+	/**
76
+	 * Available Analogue Events
77
+	 *
78
+	 * @var array
79
+	 */
80
+	protected $events = [
81
+		'initializing',
82
+		'initialized',
83
+		'store',
84
+		'stored',
85
+		'creating',
86
+		'created',
87
+		'updating',
88
+		'updated',
89
+		'deleting',
90
+		'deleted',
91
+	];
92
+
93
+	/**
94
+	 * If strictMode is set to true, Manager will throw
95
+	 * an exception if no entityMap class are registered
96
+	 * for a given entity class.
97
+	 * 
98
+	 * @var boolean
99
+	 */
100
+	protected $strictMode = false;
101
+
102
+	/**
103
+	 * @param \Analogue\ORM\Drivers\Manager $driverManager
104
+	 * @param Dispatcher                    $event
105
+	 */
106
+	public function __construct(DriverManager $driverManager, Dispatcher $event)
107
+	{
108
+		$this->drivers = $driverManager;
109
+
110
+		$this->eventDispatcher = $event;
111
+
112
+		static::$instance = $this;
113
+	}
114
+
115
+	/**
116
+	 * Create a mapper for a given entity (static alias)
117
+	 *
118
+	 * @param  \Analogue\ORM\Mappable|string $entity
119
+	 * @param  null|EntityMap                $entityMap
120
+	 * @throws MappingException
121
+	 * @return Mapper
122
+	 */
123
+	public static function getMapper($entity, $entityMap = null)
124
+	{
125
+		return static::$instance->mapper($entity, $entityMap);
126
+	}
127
+
128
+	/**
129
+	 * Create a mapper for a given entity
130
+	 *
131
+	 * @param  \Analogue\ORM\Mappable|string|array|\Traversable $entity
132
+	 * @param  mixed                                            $entityMap
133
+	 * @throws MappingException
134
+	 * @throws \InvalidArgumentException
135
+	 * @return Mapper
136
+	 */
137
+	public function mapper($entity, $entityMap = null)
138
+	{
139
+		if ($entity instanceof Wrapper) {
140
+			throw new MappingException('Tried to instantiate mapper on wrapped Entity');
141
+		}
142
+
143
+		$entity = $this->resolveEntityClass($entity);
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
+	 * This method resolve entity class from mappable instances or iterators
157
+	 *
158
+	 * @param \Analogue\ORM\Mappable|string|array|\Traversable $entity
159
+	 * @return string
160
+	 *
161
+	 * @throws \InvalidArgumentException
162
+	 */
163
+	protected function resolveEntityClass($entity)
164
+	{
165
+		// We first check if the entity is traversable and we'll resolve
166
+		// the entity based on the first item of the object.   
167
+		if ($this->isTraversable($entity)) {
168
+			if (! count($entity)) {
169
+				throw new \InvalidArgumentException('Length of Entity collection must be greater than 0');
170
+			}
171
+
172
+			$firstEntityItem = ($entity instanceof \Iterator || $entity instanceof \IteratorAggregate)
173
+				? $entity->current()
174
+				: current($entity);
175
+
176
+			return $this->resolveEntityClass($firstEntityItem);
177
+		}
178 178
             
179
-        if (is_object($entity)) {
180
-            return get_class($entity);
181
-        }
179
+		if (is_object($entity)) {
180
+			return get_class($entity);
181
+		}
182 182
 
183
-        if (is_string($entity)) {
184
-            return $entity;
185
-        }
183
+		if (is_string($entity)) {
184
+			return $entity;
185
+		}
186 186
      
187
-        throw new \InvalidArgumentException('Invalid entity type');
188
-    }
189
-
190
-    /**
191
-     * @param string $key
192
-     * @return string
193
-     */
194
-    public function getInverseMorphMap($key)
195
-    {
196
-        return array_key_exists($key, $this->morphMap) ? $this->morphMap[$key] : $key;
197
-    }
198
-
199
-    /**
200
-     * Build a new Mapper instance for a given Entity
201
-     *
202
-     * @param  string $entity
203
-     * @param         $entityMap
204
-     * @throws MappingException
205
-     * @return Mapper
206
-     */
207
-    protected function buildMapper($entity, $entityMap)
208
-    {
209
-        // If an EntityMap hasn't been manually registered by the user
210
-        // register it at runtime.
211
-        if (!$this->isRegisteredEntity($entity)) {
212
-            $this->register($entity, $entityMap);
213
-        }
214
-
215
-        $entityMap = $this->entityClasses[$entity];
216
-
217
-        $factory = new MapperFactory($this->drivers, $this->eventDispatcher, $this);
218
-
219
-        $mapper = $factory->make($entity, $entityMap);
220
-
221
-        $this->mappers[$entity] = $mapper;
222
-
223
-        // At this point we can safely call the boot() method on the entityMap as
224
-        // the mapper is now instantiated & registered within the manager.
225
-
226
-        $mapper->getEntityMap()->boot();
227
-
228
-        return $mapper;
229
-    }
230
-
231
-    /**
232
-     * Check if the entity is already registered
233
-     *
234
-     * @param  string|object $entity
235
-     * @return boolean
236
-     */
237
-    public function isRegisteredEntity($entity)
238
-    {
239
-        if (!is_string($entity)) {
240
-            $entity = get_class($entity);
241
-        }
242
-
243
-        return array_key_exists($entity, $this->entityClasses);
244
-    }
245
-
246
-    /**
247
-     * Return true if an object is an array or iterator
248
-     *
249
-     * @param  mixed $argument
250
-     * @return boolean
251
-     */
252
-    public function isTraversable($argument)
253
-    {
254
-        return $argument instanceof \Traversable || is_array($argument);
255
-    }
256
-
257
-    /**
258
-     * Set strict mode for entityMap instantiation
259
-     * 
260
-     * @param boolean $mode
261
-     */
262
-    public function setStrictMode($mode)
263
-    {
264
-        $this->strictMode = $mode;
265
-    }
266
-
267
-    /**
268
-     * Register an entity
269
-     *
270
-     * @param  string|\Analogue\ORM\Mappable $entity    entity's class name
271
-     * @param  string|EntityMap              $entityMap map's class name
272
-     * @throws MappingException
273
-     * @return void
274
-     */
275
-    public function register($entity, $entityMap = null)
276
-    {
277
-        // If an object is provider, get the class name from it
278
-        if (!is_string($entity)) {
279
-            $entity = get_class($entity);
280
-        }
281
-
282
-        if ($this->isRegisteredEntity($entity)) {
283
-            throw new MappingException("Entity $entity is already registered.");
284
-        }
285
-
286
-        if (!class_exists($entity)) {
287
-            throw new MappingException("Class $entity does not exists");
288
-        }
289
-
290
-        if (is_null($entityMap)) {
291
-            $entityMap = $this->getEntityMapInstanceFor($entity);
292
-        }
293
-
294
-        if (is_string($entityMap)) {
295
-            $entityMap = new $entityMap;
296
-        }
297
-
298
-        if (!$entityMap instanceof EntityMap) {
299
-            throw new MappingException(get_class($entityMap) . ' must be an instance of EntityMap.');
300
-        }
301
-
302
-        $entityMap->setClass($entity);
303
-
304
-        $entityMap->setManager($this);
305
-
306
-        $this->entityClasses[$entity] = $entityMap;
307
-    }
308
-
309
-    /**
310
-     * Get the entity map instance for a custom entity
311
-     *
312
-     * @param  string $entity
313
-     * @return \Analogue\ORM\Mappable
314
-     */
315
-    protected function getEntityMapInstanceFor($entity)
316
-    {
317
-        if (class_exists($entity . 'Map')) {
318
-            $map = $entity . 'Map';
319
-            $map = new $map;
320
-        } else {
321
-            if ($this->strictMode) {
322
-                throw new EntityMapNotFoundException("No EntityMap registered for $entity");
323
-            }
324
-            $map = $this->getNewEntityMap();
325
-        }
326
-
327
-        return $map;
328
-    }
329
-
330
-    /**
331
-     * Dynamically create an entity map for a custom entity class
332
-     *
333
-     * @return EntityMap
334
-     */
335
-    protected function getNewEntityMap()
336
-    {
337
-        return new EntityMap;
338
-    }
339
-
340
-    /**
341
-     * Return the Singleton instance of the manager
342
-     *
343
-     * @return Manager
344
-     */
345
-    public static function getInstance()
346
-    {
347
-        return static::$instance;
348
-    }
349
-
350
-    /**
351
-     * Return the Driver Manager's instance
352
-     *
353
-     * @return \Analogue\ORM\Drivers\Manager
354
-     */
355
-    public function getDriverManager()
356
-    {
357
-        return $this->drivers;
358
-    }
359
-
360
-    /**
361
-     * Get the Repository instance for the given Entity
362
-     *
363
-     * @param  \Analogue\ORM\Mappable|string $entity
364
-     * @throws \InvalidArgumentException
365
-     * @throws MappingException
366
-     * @return \Analogue\ORM\Repository
367
-     */
368
-    public function repository($entity)
369
-    {
370
-        if (!is_string($entity)) {
371
-            $entity = get_class($entity);
372
-        }
373
-
374
-        // First we check if the repository is not already created.
375
-        if (array_key_exists($entity, $this->repositories)) {
376
-            return $this->repositories[$entity];
377
-        }
378
-
379
-        $this->repositories[$entity] = new Repository($this->mapper($entity));
380
-
381
-        return $this->repositories[$entity];
382
-    }
383
-
384
-    /**
385
-     * Return true is the object is registered as value object
386
-     *
387
-     * @param  mixed $object
388
-     * @return boolean
389
-     */
390
-    public function isValueObject($object)
391
-    {
392
-        if (!is_string($object)) {
393
-            $object = get_class($object);
394
-        }
395
-
396
-        return array_key_exists($object, $this->valueClasses);
397
-    }
398
-
399
-    /**
400
-     * Get the Value Map for a given Value Object Class
401
-     *
402
-     * @param  string $valueObject
403
-     * @throws MappingException
404
-     * @return \Analogue\ORM\ValueMap
405
-     */
406
-    public function getValueMap($valueObject)
407
-    {
408
-        if (!is_string($valueObject)) {
409
-            $valueObject = get_class($valueObject);
410
-        }
411
-
412
-        if (!array_key_exists($valueObject, $this->valueClasses)) {
413
-            $this->registerValueObject($valueObject);
414
-        }
415
-        $valueMap = new $this->valueClasses[$valueObject];
416
-
417
-        $valueMap->setClass($valueObject);
418
-
419
-        return $valueMap;
420
-    }
421
-
422
-    /**
423
-     * Register a Value Object
424
-     *
425
-     * @param  string $valueObject
426
-     * @param  string $valueMap
427
-     * @throws MappingException
428
-     * @return void
429
-     */
430
-    public function registerValueObject($valueObject, $valueMap = null)
431
-    {
432
-        if (!is_string($valueObject)) {
433
-            $valueObject = get_class($valueObject);
434
-        }
435
-
436
-        if (is_null($valueMap)) {
437
-            $valueMap = $valueObject . 'Map';
438
-        }
439
-
440
-        if (!class_exists($valueMap)) {
441
-            throw new MappingException("$valueMap doesn't exists");
442
-        }
443
-
444
-        $this->valueClasses[$valueObject] = $valueMap;
445
-    }
446
-
447
-    /**
448
-     * Instantiate a new Value Object instance
449
-     *
450
-     * @param  string $valueObject
451
-     * @return \Analogue\ORM\ValueObject
452
-     */
453
-    public function getValueObjectInstance($valueObject)
454
-    {
455
-        $prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($valueObject), $valueObject));
456
-
457
-        return $prototype;
458
-    }
459
-
460
-    /**
461
-     * Register Analogue Plugin
462
-     *
463
-     * @param  string $plugin class
464
-     * @return void
465
-     */
466
-    public function registerPlugin($plugin)
467
-    {
468
-        $plugin = new $plugin($this);
469
-
470
-        $this->events = array_merge($this->events, $plugin->getCustomEvents());
471
-
472
-        $plugin->register();
473
-    }
474
-
475
-    /**
476
-     * Register event listeners that will be fired regardless the type
477
-     * of the entity.
478
-     *
479
-     * @param  string   $event
480
-     * @param  \Closure $callback
481
-     * @throws \Exception
482
-     * @return void
483
-     */
484
-    public function registerGlobalEvent($event, $callback)
485
-    {
486
-        if (!in_array($event, $this->events)) {
487
-            throw new \Exception("Analogue : Event $event doesn't exist");
488
-        }
489
-        $this->eventDispatcher->listen("analogue.{$event}.*", $callback);
490
-    }
491
-
492
-    /**
493
-     * Shortcut to Mapper store
494
-     *
495
-     * @param  mixed $entity
496
-     * @throws MappingException
497
-     * @return mixed
498
-     */
499
-    public function store($entity)
500
-    {
501
-        return $this->mapper($entity)->store($entity);
502
-    }
503
-
504
-    /**
505
-     * Shortcut to Mapper delete
506
-     *
507
-     * @param  mixed $entity
508
-     * @throws MappingException
509
-     * @return \Illuminate\Support\Collection|null
510
-     */
511
-    public function delete($entity)
512
-    {
513
-        return $this->mapper($entity)->delete($entity);
514
-    }
515
-
516
-    /**
517
-     * Shortcut to Mapper query
518
-     *
519
-     * @param  mixed $entity
520
-     * @throws MappingException
521
-     * @return Query
522
-     */
523
-    public function query($entity)
524
-    {
525
-        return $this->mapper($entity)->query();
526
-    }
527
-
528
-    /**
529
-     * Shortcut to Mapper Global Query
530
-     *
531
-     * @param  mixed $entity
532
-     * @throws MappingException
533
-     * @return Query
534
-     */
535
-    public function globalQuery($entity)
536
-    {
537
-        return $this->mapper($entity)->globalQuery();
538
-    }
539
-
540
-    /**
541
-     * @param array $morphMap
542
-     * @return $this
543
-     */
544
-    public function morphMap(array $morphMap)
545
-    {
546
-        $this->morphMap = $morphMap;
547
-
548
-        return $this;
549
-    }
550
-
551
-    /**
552
-     * @param string $class
553
-     * @return mixed
554
-     */
555
-    public function getMorphMap($class)
556
-    {
557
-        $key = array_search($class, $this->morphMap);
558
-
559
-        return $key !== false ? $key : $class;
560
-    }
187
+		throw new \InvalidArgumentException('Invalid entity type');
188
+	}
189
+
190
+	/**
191
+	 * @param string $key
192
+	 * @return string
193
+	 */
194
+	public function getInverseMorphMap($key)
195
+	{
196
+		return array_key_exists($key, $this->morphMap) ? $this->morphMap[$key] : $key;
197
+	}
198
+
199
+	/**
200
+	 * Build a new Mapper instance for a given Entity
201
+	 *
202
+	 * @param  string $entity
203
+	 * @param         $entityMap
204
+	 * @throws MappingException
205
+	 * @return Mapper
206
+	 */
207
+	protected function buildMapper($entity, $entityMap)
208
+	{
209
+		// If an EntityMap hasn't been manually registered by the user
210
+		// register it at runtime.
211
+		if (!$this->isRegisteredEntity($entity)) {
212
+			$this->register($entity, $entityMap);
213
+		}
214
+
215
+		$entityMap = $this->entityClasses[$entity];
216
+
217
+		$factory = new MapperFactory($this->drivers, $this->eventDispatcher, $this);
218
+
219
+		$mapper = $factory->make($entity, $entityMap);
220
+
221
+		$this->mappers[$entity] = $mapper;
222
+
223
+		// At this point we can safely call the boot() method on the entityMap as
224
+		// the mapper is now instantiated & registered within the manager.
225
+
226
+		$mapper->getEntityMap()->boot();
227
+
228
+		return $mapper;
229
+	}
230
+
231
+	/**
232
+	 * Check if the entity is already registered
233
+	 *
234
+	 * @param  string|object $entity
235
+	 * @return boolean
236
+	 */
237
+	public function isRegisteredEntity($entity)
238
+	{
239
+		if (!is_string($entity)) {
240
+			$entity = get_class($entity);
241
+		}
242
+
243
+		return array_key_exists($entity, $this->entityClasses);
244
+	}
245
+
246
+	/**
247
+	 * Return true if an object is an array or iterator
248
+	 *
249
+	 * @param  mixed $argument
250
+	 * @return boolean
251
+	 */
252
+	public function isTraversable($argument)
253
+	{
254
+		return $argument instanceof \Traversable || is_array($argument);
255
+	}
256
+
257
+	/**
258
+	 * Set strict mode for entityMap instantiation
259
+	 * 
260
+	 * @param boolean $mode
261
+	 */
262
+	public function setStrictMode($mode)
263
+	{
264
+		$this->strictMode = $mode;
265
+	}
266
+
267
+	/**
268
+	 * Register an entity
269
+	 *
270
+	 * @param  string|\Analogue\ORM\Mappable $entity    entity's class name
271
+	 * @param  string|EntityMap              $entityMap map's class name
272
+	 * @throws MappingException
273
+	 * @return void
274
+	 */
275
+	public function register($entity, $entityMap = null)
276
+	{
277
+		// If an object is provider, get the class name from it
278
+		if (!is_string($entity)) {
279
+			$entity = get_class($entity);
280
+		}
281
+
282
+		if ($this->isRegisteredEntity($entity)) {
283
+			throw new MappingException("Entity $entity is already registered.");
284
+		}
285
+
286
+		if (!class_exists($entity)) {
287
+			throw new MappingException("Class $entity does not exists");
288
+		}
289
+
290
+		if (is_null($entityMap)) {
291
+			$entityMap = $this->getEntityMapInstanceFor($entity);
292
+		}
293
+
294
+		if (is_string($entityMap)) {
295
+			$entityMap = new $entityMap;
296
+		}
297
+
298
+		if (!$entityMap instanceof EntityMap) {
299
+			throw new MappingException(get_class($entityMap) . ' must be an instance of EntityMap.');
300
+		}
301
+
302
+		$entityMap->setClass($entity);
303
+
304
+		$entityMap->setManager($this);
305
+
306
+		$this->entityClasses[$entity] = $entityMap;
307
+	}
308
+
309
+	/**
310
+	 * Get the entity map instance for a custom entity
311
+	 *
312
+	 * @param  string $entity
313
+	 * @return \Analogue\ORM\Mappable
314
+	 */
315
+	protected function getEntityMapInstanceFor($entity)
316
+	{
317
+		if (class_exists($entity . 'Map')) {
318
+			$map = $entity . 'Map';
319
+			$map = new $map;
320
+		} else {
321
+			if ($this->strictMode) {
322
+				throw new EntityMapNotFoundException("No EntityMap registered for $entity");
323
+			}
324
+			$map = $this->getNewEntityMap();
325
+		}
326
+
327
+		return $map;
328
+	}
329
+
330
+	/**
331
+	 * Dynamically create an entity map for a custom entity class
332
+	 *
333
+	 * @return EntityMap
334
+	 */
335
+	protected function getNewEntityMap()
336
+	{
337
+		return new EntityMap;
338
+	}
339
+
340
+	/**
341
+	 * Return the Singleton instance of the manager
342
+	 *
343
+	 * @return Manager
344
+	 */
345
+	public static function getInstance()
346
+	{
347
+		return static::$instance;
348
+	}
349
+
350
+	/**
351
+	 * Return the Driver Manager's instance
352
+	 *
353
+	 * @return \Analogue\ORM\Drivers\Manager
354
+	 */
355
+	public function getDriverManager()
356
+	{
357
+		return $this->drivers;
358
+	}
359
+
360
+	/**
361
+	 * Get the Repository instance for the given Entity
362
+	 *
363
+	 * @param  \Analogue\ORM\Mappable|string $entity
364
+	 * @throws \InvalidArgumentException
365
+	 * @throws MappingException
366
+	 * @return \Analogue\ORM\Repository
367
+	 */
368
+	public function repository($entity)
369
+	{
370
+		if (!is_string($entity)) {
371
+			$entity = get_class($entity);
372
+		}
373
+
374
+		// First we check if the repository is not already created.
375
+		if (array_key_exists($entity, $this->repositories)) {
376
+			return $this->repositories[$entity];
377
+		}
378
+
379
+		$this->repositories[$entity] = new Repository($this->mapper($entity));
380
+
381
+		return $this->repositories[$entity];
382
+	}
383
+
384
+	/**
385
+	 * Return true is the object is registered as value object
386
+	 *
387
+	 * @param  mixed $object
388
+	 * @return boolean
389
+	 */
390
+	public function isValueObject($object)
391
+	{
392
+		if (!is_string($object)) {
393
+			$object = get_class($object);
394
+		}
395
+
396
+		return array_key_exists($object, $this->valueClasses);
397
+	}
398
+
399
+	/**
400
+	 * Get the Value Map for a given Value Object Class
401
+	 *
402
+	 * @param  string $valueObject
403
+	 * @throws MappingException
404
+	 * @return \Analogue\ORM\ValueMap
405
+	 */
406
+	public function getValueMap($valueObject)
407
+	{
408
+		if (!is_string($valueObject)) {
409
+			$valueObject = get_class($valueObject);
410
+		}
411
+
412
+		if (!array_key_exists($valueObject, $this->valueClasses)) {
413
+			$this->registerValueObject($valueObject);
414
+		}
415
+		$valueMap = new $this->valueClasses[$valueObject];
416
+
417
+		$valueMap->setClass($valueObject);
418
+
419
+		return $valueMap;
420
+	}
421
+
422
+	/**
423
+	 * Register a Value Object
424
+	 *
425
+	 * @param  string $valueObject
426
+	 * @param  string $valueMap
427
+	 * @throws MappingException
428
+	 * @return void
429
+	 */
430
+	public function registerValueObject($valueObject, $valueMap = null)
431
+	{
432
+		if (!is_string($valueObject)) {
433
+			$valueObject = get_class($valueObject);
434
+		}
435
+
436
+		if (is_null($valueMap)) {
437
+			$valueMap = $valueObject . 'Map';
438
+		}
439
+
440
+		if (!class_exists($valueMap)) {
441
+			throw new MappingException("$valueMap doesn't exists");
442
+		}
443
+
444
+		$this->valueClasses[$valueObject] = $valueMap;
445
+	}
446
+
447
+	/**
448
+	 * Instantiate a new Value Object instance
449
+	 *
450
+	 * @param  string $valueObject
451
+	 * @return \Analogue\ORM\ValueObject
452
+	 */
453
+	public function getValueObjectInstance($valueObject)
454
+	{
455
+		$prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($valueObject), $valueObject));
456
+
457
+		return $prototype;
458
+	}
459
+
460
+	/**
461
+	 * Register Analogue Plugin
462
+	 *
463
+	 * @param  string $plugin class
464
+	 * @return void
465
+	 */
466
+	public function registerPlugin($plugin)
467
+	{
468
+		$plugin = new $plugin($this);
469
+
470
+		$this->events = array_merge($this->events, $plugin->getCustomEvents());
471
+
472
+		$plugin->register();
473
+	}
474
+
475
+	/**
476
+	 * Register event listeners that will be fired regardless the type
477
+	 * of the entity.
478
+	 *
479
+	 * @param  string   $event
480
+	 * @param  \Closure $callback
481
+	 * @throws \Exception
482
+	 * @return void
483
+	 */
484
+	public function registerGlobalEvent($event, $callback)
485
+	{
486
+		if (!in_array($event, $this->events)) {
487
+			throw new \Exception("Analogue : Event $event doesn't exist");
488
+		}
489
+		$this->eventDispatcher->listen("analogue.{$event}.*", $callback);
490
+	}
491
+
492
+	/**
493
+	 * Shortcut to Mapper store
494
+	 *
495
+	 * @param  mixed $entity
496
+	 * @throws MappingException
497
+	 * @return mixed
498
+	 */
499
+	public function store($entity)
500
+	{
501
+		return $this->mapper($entity)->store($entity);
502
+	}
503
+
504
+	/**
505
+	 * Shortcut to Mapper delete
506
+	 *
507
+	 * @param  mixed $entity
508
+	 * @throws MappingException
509
+	 * @return \Illuminate\Support\Collection|null
510
+	 */
511
+	public function delete($entity)
512
+	{
513
+		return $this->mapper($entity)->delete($entity);
514
+	}
515
+
516
+	/**
517
+	 * Shortcut to Mapper query
518
+	 *
519
+	 * @param  mixed $entity
520
+	 * @throws MappingException
521
+	 * @return Query
522
+	 */
523
+	public function query($entity)
524
+	{
525
+		return $this->mapper($entity)->query();
526
+	}
527
+
528
+	/**
529
+	 * Shortcut to Mapper Global Query
530
+	 *
531
+	 * @param  mixed $entity
532
+	 * @throws MappingException
533
+	 * @return Query
534
+	 */
535
+	public function globalQuery($entity)
536
+	{
537
+		return $this->mapper($entity)->globalQuery();
538
+	}
539
+
540
+	/**
541
+	 * @param array $morphMap
542
+	 * @return $this
543
+	 */
544
+	public function morphMap(array $morphMap)
545
+	{
546
+		$this->morphMap = $morphMap;
547
+
548
+		return $this;
549
+	}
550
+
551
+	/**
552
+	 * @param string $class
553
+	 * @return mixed
554
+	 */
555
+	public function getMorphMap($class)
556
+	{
557
+		$key = array_search($class, $this->morphMap);
558
+
559
+		return $key !== false ? $key : $class;
560
+	}
561 561
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -165,7 +165,7 @@  discard block
 block discarded – undo
165 165
         // We first check if the entity is traversable and we'll resolve
166 166
         // the entity based on the first item of the object.   
167 167
         if ($this->isTraversable($entity)) {
168
-            if (! count($entity)) {
168
+            if (!count($entity)) {
169 169
                 throw new \InvalidArgumentException('Length of Entity collection must be greater than 0');
170 170
             }
171 171
 
@@ -296,7 +296,7 @@  discard block
 block discarded – undo
296 296
         }
297 297
 
298 298
         if (!$entityMap instanceof EntityMap) {
299
-            throw new MappingException(get_class($entityMap) . ' must be an instance of EntityMap.');
299
+            throw new MappingException(get_class($entityMap).' must be an instance of EntityMap.');
300 300
         }
301 301
 
302 302
         $entityMap->setClass($entity);
@@ -314,8 +314,8 @@  discard block
 block discarded – undo
314 314
      */
315 315
     protected function getEntityMapInstanceFor($entity)
316 316
     {
317
-        if (class_exists($entity . 'Map')) {
318
-            $map = $entity . 'Map';
317
+        if (class_exists($entity.'Map')) {
318
+            $map = $entity.'Map';
319 319
             $map = new $map;
320 320
         } else {
321 321
             if ($this->strictMode) {
@@ -434,7 +434,7 @@  discard block
 block discarded – undo
434 434
         }
435 435
 
436 436
         if (is_null($valueMap)) {
437
-            $valueMap = $valueObject . 'Map';
437
+            $valueMap = $valueObject.'Map';
438 438
         }
439 439
 
440 440
         if (!class_exists($valueMap)) {
Please login to merge, or discard this patch.
src/Exceptions/EntityMapNotFoundException.php 1 patch
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -6,5 +6,5 @@
 block discarded – undo
6 6
 
7 7
 class EntityMapNotFoundException extends RuntimeException
8 8
 {
9
-    //
9
+	//
10 10
 }
Please login to merge, or discard this patch.
src/System/Mapper.php 1 patch
Indentation   +550 added lines, -550 removed lines patch added patch discarded remove patch
@@ -22,554 +22,554 @@
 block discarded – undo
22 22
  */
23 23
 class Mapper
24 24
 {
25
-    /**
26
-     * The Manager instance
27
-     *
28
-     * @var \Analogue\ORM\System\Manager
29
-     */
30
-    protected $manager;
31
-
32
-    /**
33
-     * Instance of EntityMapper Object
34
-     *
35
-     * @var \Analogue\ORM\EntityMap
36
-     */
37
-    protected $entityMap;
38
-
39
-    /**
40
-     * The instance of db adapter
41
-     *
42
-     * @var \Analogue\ORM\Drivers\DBAdapter
43
-     */
44
-    protected $adapter;
45
-
46
-
47
-    /**
48
-     * Event dispatcher instance
49
-     *
50
-     * @var \Illuminate\Contracts\Events\Dispatcher
51
-     */
52
-    protected $dispatcher;
53
-
54
-    /**
55
-     * Entity Cache
56
-     *
57
-     * @var  \Analogue\ORM\System\EntityCache
58
-     */
59
-    protected $cache;
60
-
61
-    /**
62
-     * Global scopes
63
-     *
64
-     * @var array
65
-     */
66
-    protected $globalScopes = [];
67
-
68
-    /**
69
-     * Custom Commands
70
-     *
71
-     * @var array
72
-     */
73
-    protected $customCommands = [];
74
-
75
-    /**
76
-     * @param EntityMap  $entityMap
77
-     * @param DBAdapter  $adapter
78
-     * @param Dispatcher $dispatcher
79
-     * @param Manager    $manager
80
-     */
81
-    public function __construct(EntityMap $entityMap, DBAdapter $adapter, Dispatcher $dispatcher, Manager $manager)
82
-    {
83
-        $this->entityMap = $entityMap;
84
-
85
-        $this->adapter = $adapter;
86
-
87
-        $this->dispatcher = $dispatcher;
88
-
89
-        $this->manager = $manager;
90
-
91
-        $this->cache = new EntityCache($entityMap);
92
-    }
93
-
94
-    /**
95
-     * Persist an entity or an entity collection into the database
96
-     *
97
-     * @param  Mappable|\Traversable|array $entity
98
-     * @throws \InvalidArgumentException
99
-     * @throws MappingException
100
-     * @return Mappable|\Traversable|array
101
-     */
102
-    public function store($entity)
103
-    {
104
-        if ($this->manager->isTraversable($entity)) {
105
-            return $this->storeCollection($entity);
106
-        } else {
107
-            return $this->storeEntity($entity);
108
-        }
109
-    }
110
-
111
-    /**
112
-     * Store an entity collection inside a single DB Transaction
113
-     *
114
-     * @param  \Traversable|array $entities
115
-     * @throws \InvalidArgumentException
116
-     * @throws MappingException
117
-     * @return \Traversable|array
118
-     */
119
-    protected function storeCollection($entities)
120
-    {
121
-        $this->adapter->beginTransaction();
122
-
123
-        foreach ($entities as $entity) {
124
-            $this->storeEntity($entity);
125
-        }
126
-
127
-        $this->adapter->commit();
128
-
129
-        return $entities;
130
-    }
131
-
132
-    /**
133
-     * Store a single entity into the database
134
-     *
135
-     * @param  Mappable $entity
136
-     * @throws \InvalidArgumentException
137
-     * @throws MappingException
138
-     * @return \Analogue\ORM\Entity
139
-     */
140
-    protected function storeEntity($entity)
141
-    {
142
-        $this->checkEntityType($entity);
143
-
144
-        $store = new Store($this->aggregate($entity), $this->newQueryBuilder());
145
-
146
-        return $store->execute();
147
-    }
148
-
149
-    /**
150
-     * Check that the entity correspond to the current mapper.
151
-     *
152
-     * @param  mixed $entity
153
-     * @throws InvalidArgumentException
154
-     * @return void
155
-     */
156
-    protected function checkEntityType($entity)
157
-    {
158
-        if (get_class($entity) != $this->entityMap->getClass()) {
159
-            $expected = $this->entityMap->getClass();
160
-            $actual = get_class($entity);
161
-            throw new InvalidArgumentException("Expected : $expected, got $actual.");
162
-        }
163
-    }
164
-
165
-    /**
166
-     * Convert an entity into an aggregate root
167
-     *
168
-     * @param  mixed $entity
169
-     * @throws MappingException
170
-     * @return \Analogue\ORM\System\Aggregate
171
-     */
172
-    protected function aggregate($entity)
173
-    {
174
-        return new Aggregate($entity);
175
-    }
176
-
177
-    /**
178
-     * Get a the Underlying QueryAdapter.
179
-     *
180
-     * @return \Analogue\ORM\Drivers\QueryAdapter
181
-     */
182
-    public function newQueryBuilder()
183
-    {
184
-        return $this->adapter->getQuery();
185
-    }
186
-
187
-    /**
188
-     * Delete an entity or an entity collection from the database
189
-     *
190
-     * @param  Mappable|\Traversable|array
191
-     * @throws MappingException
192
-     * @throws \InvalidArgumentException
193
-     * @return \Traversable|array
194
-     */
195
-    public function delete($entity)
196
-    {
197
-        if ($this->manager->isTraversable($entity)) {
198
-            return $this->deleteCollection($entity);
199
-        } else {
200
-            $this->deleteEntity($entity);
201
-        }
202
-    }
203
-
204
-    /**
205
-     * Delete an Entity Collection inside a single db transaction
206
-     *
207
-     * @param  \Traversable|array $entities
208
-     * @throws \InvalidArgumentException
209
-     * @throws MappingException
210
-     * @return \Traversable|array
211
-     */
212
-    protected function deleteCollection($entities)
213
-    {
214
-        $this->adapter->beginTransaction();
215
-
216
-        foreach ($entities as $entity) {
217
-            $this->deleteEntity($entity);
218
-        }
219
-
220
-        $this->adapter->commit();
221
-
222
-        return $entities;
223
-    }
224
-
225
-    /**
226
-     * Delete a single entity from the database.
227
-     *
228
-     * @param  Mappable $entity
229
-     * @throws \InvalidArgumentException
230
-     * @throws MappingException
231
-     * @return void
232
-     */
233
-    protected function deleteEntity($entity)
234
-    {
235
-        $this->checkEntityType($entity);
236
-
237
-        $delete = new Delete($this->aggregate($entity), $this->newQueryBuilder());
238
-
239
-        $delete->execute();
240
-    }
241
-
242
-    /**
243
-     * Return the entity map for this mapper
244
-     *
245
-     * @return EntityMap
246
-     */
247
-    public function getEntityMap()
248
-    {
249
-        return $this->entityMap;
250
-    }
251
-
252
-    /**
253
-     * Get the entity cache for the current mapper
254
-     *
255
-     * @return EntityCache  $entityCache
256
-     */
257
-    public function getEntityCache()
258
-    {
259
-        return $this->cache;
260
-    }
261
-
262
-    /**
263
-     * Fire the given event for the entity
264
-     *
265
-     * @param  string               $event
266
-     * @param  \Analogue\ORM\Entity $entity
267
-     * @param  bool                 $halt
268
-     * @throws InvalidArgumentException
269
-     * @return mixed
270
-     */
271
-    public function fireEvent($event, $entity, $halt = true)
272
-    {
273
-        if ($entity instanceof Wrapper) {
274
-            throw new InvalidArgumentException('Fired Event with invalid Entity Object');
275
-        }
276
-
277
-        $event = "analogue.{$event}." . $this->entityMap->getClass();
278
-
279
-        $method = $halt ? 'until' : 'fire';
280
-
281
-        return $this->dispatcher->$method($event, $entity);
282
-    }
283
-
284
-    /**
285
-     * Register an entity event with the dispatcher.
286
-     *
287
-     * @param  string   $event
288
-     * @param  \Closure $callback
289
-     * @return void
290
-     */
291
-    public function registerEvent($event, $callback)
292
-    {
293
-        $name = $this->entityMap->getClass();
294
-
295
-        $this->dispatcher->listen("analogue.{$event}.{$name}", $callback);
296
-    }
297
-
298
-    /**
299
-     * Add a global scope to this mapper query builder
300
-     *
301
-     * @param  ScopeInterface $scope
302
-     * @return void
303
-     */
304
-    public function addGlobalScope(ScopeInterface $scope)
305
-    {
306
-        $this->globalScopes[get_class($scope)] = $scope;
307
-    }
308
-
309
-    /**
310
-     * Determine if the mapper has a global scope.
311
-     *
312
-     * @param  \Analogue\ORM\System\ScopeInterface $scope
313
-     * @return bool
314
-     */
315
-    public function hasGlobalScope($scope)
316
-    {
317
-        return !is_null($this->getGlobalScope($scope));
318
-    }
319
-
320
-    /**
321
-     * Get a global scope registered with the modal.
322
-     *
323
-     * @param  \Analogue\ORM\System\ScopeInterface $scope
324
-     * @return \Analogue\ORM\System\ScopeInterface|null
325
-     */
326
-    public function getGlobalScope($scope)
327
-    {
328
-        return array_first($this->globalScopes, function ($key, $value) use ($scope) {
329
-            return $scope instanceof $value;
330
-        });
331
-    }
332
-
333
-    /**
334
-     * Get a new query instance without a given scope.
335
-     *
336
-     * @param  \Analogue\ORM\System\ScopeInterface $scope
337
-     * @return \Analogue\ORM\System\Query
338
-     */
339
-    public function newQueryWithoutScope($scope)
340
-    {
341
-        $this->getGlobalScope($scope)->remove($query = $this->getQuery(), $this);
342
-
343
-        return $query;
344
-    }
345
-
346
-    /**
347
-     * Get the Analogue Query Builder for this instance
348
-     *
349
-     * @return \Analogue\ORM\System\Query
350
-     */
351
-    public function getQuery()
352
-    {
353
-        $query = new Query($this, $this->adapter);
354
-
355
-        return $this->applyGlobalScopes($query);
356
-    }
357
-
358
-    /**
359
-     * Apply all of the global scopes to an Analogue Query builder.
360
-     *
361
-     * @param Query $query
362
-     * @return \Analogue\ORM\System\Query
363
-     */
364
-    public function applyGlobalScopes($query)
365
-    {
366
-        foreach ($this->getGlobalScopes() as $scope) {
367
-            $scope->apply($query, $this);
368
-        }
369
-
370
-        return $query;
371
-    }
372
-
373
-    /**
374
-     * Get the global scopes for this class instance.
375
-     *
376
-     * @return \Analogue\ORM\System\ScopeInterface
377
-     */
378
-    public function getGlobalScopes()
379
-    {
380
-        return $this->globalScopes;
381
-    }
382
-
383
-    /**
384
-     * Add a dynamic method that extends the mapper/repository
385
-     *
386
-     * @param string $command
387
-     */
388
-    public function addCustomCommand($command)
389
-    {
390
-        $name = lcfirst(class_basename($command));
391
-
392
-        $this->customCommands[$name] = $command;
393
-    }
394
-
395
-    /**
396
-     * Create a new instance of the mapped entity class
397
-     *
398
-     * @param  array $attributes
399
-     * @return mixed
400
-     */
401
-    public function newInstance($attributes = [])
402
-    {
403
-        $class = $this->entityMap->getClass();
404
-
405
-        if ($this->entityMap->activator() != null) {
406
-            $entity = $this->entityMap->activator();
407
-        } else {
408
-            $entity = $this->customClassInstance($class);
409
-        }
410
-
411
-        // prevent hydrating with an empty array
412
-        if (count($attributes) > 0) {
413
-            $entity->setEntityAttributes($attributes);
414
-        }
415
-
416
-        return $entity;
417
-    }
418
-
419
-    /**
420
-     * Use a trick to generate a class prototype that we
421
-     * can instantiate without calling the constructor.
422
-     *
423
-     * @param string|null $className
424
-     * @throws MappingException
425
-     * @return mixed
426
-     */
427
-    protected function customClassInstance($className)
428
-    {
429
-        if (!class_exists($className)) {
430
-            throw new MappingException("Tried to instantiate a non-existing Entity class : $className");
431
-        }
432
-
433
-        $prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($className), $className));
434
-
435
-        return $prototype;
436
-    }
437
-
438
-    /**
439
-     * Get an unscoped Analogue Query Builder for this instance
440
-     *
441
-     * @return \Analogue\ORM\System\Query
442
-     */
443
-    public function globalQuery()
444
-    {
445
-        return $this->newQueryWithoutScopes();
446
-    }
447
-
448
-    /**
449
-     * Get a new query builder that doesn't have any global scopes.
450
-     *
451
-     * @return Query
452
-     */
453
-    public function newQueryWithoutScopes()
454
-    {
455
-        return $this->removeGlobalScopes($this->getQuery());
456
-    }
457
-
458
-    /**
459
-     * Remove all of the global scopes from an Analogue Query builder.
460
-     *
461
-     * @param Query $query
462
-     * @return \Analogue\ORM\System\Query
463
-     */
464
-    public function removeGlobalScopes($query)
465
-    {
466
-        foreach ($this->getGlobalScopes() as $scope) {
467
-            $scope->remove($query, $this);
468
-        }
469
-
470
-        return $query;
471
-    }
472
-
473
-    /**
474
-     * Return the manager instance
475
-     *
476
-     * @return \Analogue\ORM\System\Manager
477
-     */
478
-    public function getManager()
479
-    {
480
-        return $this->manager;
481
-    }
482
-
483
-    /**
484
-     * Dynamically handle calls to custom commands, or Redirects to query()
485
-     *
486
-     * @param  string $method
487
-     * @param  array  $parameters
488
-     * @throws \Exception
489
-     * @return mixed
490
-     */
491
-    public function __call($method, $parameters)
492
-    {
493
-        // Check if method is a custom command on the mapper
494
-        if ($this->hasCustomCommand($method)) {
495
-            if (count($parameters) == 0) {
496
-                throw new \Exception("$method must at least have 1 argument");
497
-            }
498
-
499
-            return $this->executeCustomCommand($method, $parameters[0]);
500
-        }
501
-
502
-        // Redirect call on a new query instance
503
-        return call_user_func_array([$this->query(), $method], $parameters);
504
-    }
505
-
506
-    /**
507
-     * Check if this mapper supports this command
508
-     * @param  string $command
509
-     * @return boolean
510
-     */
511
-    public function hasCustomCommand($command)
512
-    {
513
-        return in_array($command, $this->getCustomCommands());
514
-    }
515
-
516
-    /**
517
-     * Get all the custom commands registered on this mapper
518
-     *
519
-     * @return array
520
-     */
521
-    public function getCustomCommands()
522
-    {
523
-        return array_keys($this->customCommands);
524
-    }
525
-
526
-    /**
527
-     * Execute a custom command on an Entity
528
-     *
529
-     * @param  string                 $command
530
-     * @param  mixed|Collection|array $entity
531
-     * @throws \InvalidArgumentException
532
-     * @throws MappingException
533
-     * @return mixed
534
-     */
535
-    public function executeCustomCommand($command, $entity)
536
-    {
537
-        $commandClass = $this->customCommands[$command];
538
-
539
-        if ($this->manager->isTraversable($entity)) {
540
-            foreach ($entity as $instance) {
541
-                $this->executeSingleCustomCommand($commandClass, $instance);
542
-            }
543
-        } else {
544
-            return $this->executeSingleCustomCommand($commandClass, $entity);
545
-        }
546
-    }
547
-
548
-    /**
549
-     * Execute a single command instance
550
-     *
551
-     * @param  string $commandClass
552
-     * @param  mixed  $entity
553
-     * @throws \InvalidArgumentException
554
-     * @throws MappingException
555
-     * @return mixed
556
-     */
557
-    protected function executeSingleCustomCommand($commandClass, $entity)
558
-    {
559
-        $this->checkEntityType($entity);
560
-
561
-        $instance = new $commandClass($this->aggregate($entity), $this->newQueryBuilder());
562
-
563
-        return $instance->execute();
564
-    }
565
-
566
-    /**
567
-     * Get the Analogue Query Builder for this instance
568
-     *
569
-     * @return \Analogue\ORM\System\Query
570
-     */
571
-    public function query()
572
-    {
573
-        return $this->getQuery();
574
-    }
25
+	/**
26
+	 * The Manager instance
27
+	 *
28
+	 * @var \Analogue\ORM\System\Manager
29
+	 */
30
+	protected $manager;
31
+
32
+	/**
33
+	 * Instance of EntityMapper Object
34
+	 *
35
+	 * @var \Analogue\ORM\EntityMap
36
+	 */
37
+	protected $entityMap;
38
+
39
+	/**
40
+	 * The instance of db adapter
41
+	 *
42
+	 * @var \Analogue\ORM\Drivers\DBAdapter
43
+	 */
44
+	protected $adapter;
45
+
46
+
47
+	/**
48
+	 * Event dispatcher instance
49
+	 *
50
+	 * @var \Illuminate\Contracts\Events\Dispatcher
51
+	 */
52
+	protected $dispatcher;
53
+
54
+	/**
55
+	 * Entity Cache
56
+	 *
57
+	 * @var  \Analogue\ORM\System\EntityCache
58
+	 */
59
+	protected $cache;
60
+
61
+	/**
62
+	 * Global scopes
63
+	 *
64
+	 * @var array
65
+	 */
66
+	protected $globalScopes = [];
67
+
68
+	/**
69
+	 * Custom Commands
70
+	 *
71
+	 * @var array
72
+	 */
73
+	protected $customCommands = [];
74
+
75
+	/**
76
+	 * @param EntityMap  $entityMap
77
+	 * @param DBAdapter  $adapter
78
+	 * @param Dispatcher $dispatcher
79
+	 * @param Manager    $manager
80
+	 */
81
+	public function __construct(EntityMap $entityMap, DBAdapter $adapter, Dispatcher $dispatcher, Manager $manager)
82
+	{
83
+		$this->entityMap = $entityMap;
84
+
85
+		$this->adapter = $adapter;
86
+
87
+		$this->dispatcher = $dispatcher;
88
+
89
+		$this->manager = $manager;
90
+
91
+		$this->cache = new EntityCache($entityMap);
92
+	}
93
+
94
+	/**
95
+	 * Persist an entity or an entity collection into the database
96
+	 *
97
+	 * @param  Mappable|\Traversable|array $entity
98
+	 * @throws \InvalidArgumentException
99
+	 * @throws MappingException
100
+	 * @return Mappable|\Traversable|array
101
+	 */
102
+	public function store($entity)
103
+	{
104
+		if ($this->manager->isTraversable($entity)) {
105
+			return $this->storeCollection($entity);
106
+		} else {
107
+			return $this->storeEntity($entity);
108
+		}
109
+	}
110
+
111
+	/**
112
+	 * Store an entity collection inside a single DB Transaction
113
+	 *
114
+	 * @param  \Traversable|array $entities
115
+	 * @throws \InvalidArgumentException
116
+	 * @throws MappingException
117
+	 * @return \Traversable|array
118
+	 */
119
+	protected function storeCollection($entities)
120
+	{
121
+		$this->adapter->beginTransaction();
122
+
123
+		foreach ($entities as $entity) {
124
+			$this->storeEntity($entity);
125
+		}
126
+
127
+		$this->adapter->commit();
128
+
129
+		return $entities;
130
+	}
131
+
132
+	/**
133
+	 * Store a single entity into the database
134
+	 *
135
+	 * @param  Mappable $entity
136
+	 * @throws \InvalidArgumentException
137
+	 * @throws MappingException
138
+	 * @return \Analogue\ORM\Entity
139
+	 */
140
+	protected function storeEntity($entity)
141
+	{
142
+		$this->checkEntityType($entity);
143
+
144
+		$store = new Store($this->aggregate($entity), $this->newQueryBuilder());
145
+
146
+		return $store->execute();
147
+	}
148
+
149
+	/**
150
+	 * Check that the entity correspond to the current mapper.
151
+	 *
152
+	 * @param  mixed $entity
153
+	 * @throws InvalidArgumentException
154
+	 * @return void
155
+	 */
156
+	protected function checkEntityType($entity)
157
+	{
158
+		if (get_class($entity) != $this->entityMap->getClass()) {
159
+			$expected = $this->entityMap->getClass();
160
+			$actual = get_class($entity);
161
+			throw new InvalidArgumentException("Expected : $expected, got $actual.");
162
+		}
163
+	}
164
+
165
+	/**
166
+	 * Convert an entity into an aggregate root
167
+	 *
168
+	 * @param  mixed $entity
169
+	 * @throws MappingException
170
+	 * @return \Analogue\ORM\System\Aggregate
171
+	 */
172
+	protected function aggregate($entity)
173
+	{
174
+		return new Aggregate($entity);
175
+	}
176
+
177
+	/**
178
+	 * Get a the Underlying QueryAdapter.
179
+	 *
180
+	 * @return \Analogue\ORM\Drivers\QueryAdapter
181
+	 */
182
+	public function newQueryBuilder()
183
+	{
184
+		return $this->adapter->getQuery();
185
+	}
186
+
187
+	/**
188
+	 * Delete an entity or an entity collection from the database
189
+	 *
190
+	 * @param  Mappable|\Traversable|array
191
+	 * @throws MappingException
192
+	 * @throws \InvalidArgumentException
193
+	 * @return \Traversable|array
194
+	 */
195
+	public function delete($entity)
196
+	{
197
+		if ($this->manager->isTraversable($entity)) {
198
+			return $this->deleteCollection($entity);
199
+		} else {
200
+			$this->deleteEntity($entity);
201
+		}
202
+	}
203
+
204
+	/**
205
+	 * Delete an Entity Collection inside a single db transaction
206
+	 *
207
+	 * @param  \Traversable|array $entities
208
+	 * @throws \InvalidArgumentException
209
+	 * @throws MappingException
210
+	 * @return \Traversable|array
211
+	 */
212
+	protected function deleteCollection($entities)
213
+	{
214
+		$this->adapter->beginTransaction();
215
+
216
+		foreach ($entities as $entity) {
217
+			$this->deleteEntity($entity);
218
+		}
219
+
220
+		$this->adapter->commit();
221
+
222
+		return $entities;
223
+	}
224
+
225
+	/**
226
+	 * Delete a single entity from the database.
227
+	 *
228
+	 * @param  Mappable $entity
229
+	 * @throws \InvalidArgumentException
230
+	 * @throws MappingException
231
+	 * @return void
232
+	 */
233
+	protected function deleteEntity($entity)
234
+	{
235
+		$this->checkEntityType($entity);
236
+
237
+		$delete = new Delete($this->aggregate($entity), $this->newQueryBuilder());
238
+
239
+		$delete->execute();
240
+	}
241
+
242
+	/**
243
+	 * Return the entity map for this mapper
244
+	 *
245
+	 * @return EntityMap
246
+	 */
247
+	public function getEntityMap()
248
+	{
249
+		return $this->entityMap;
250
+	}
251
+
252
+	/**
253
+	 * Get the entity cache for the current mapper
254
+	 *
255
+	 * @return EntityCache  $entityCache
256
+	 */
257
+	public function getEntityCache()
258
+	{
259
+		return $this->cache;
260
+	}
261
+
262
+	/**
263
+	 * Fire the given event for the entity
264
+	 *
265
+	 * @param  string               $event
266
+	 * @param  \Analogue\ORM\Entity $entity
267
+	 * @param  bool                 $halt
268
+	 * @throws InvalidArgumentException
269
+	 * @return mixed
270
+	 */
271
+	public function fireEvent($event, $entity, $halt = true)
272
+	{
273
+		if ($entity instanceof Wrapper) {
274
+			throw new InvalidArgumentException('Fired Event with invalid Entity Object');
275
+		}
276
+
277
+		$event = "analogue.{$event}." . $this->entityMap->getClass();
278
+
279
+		$method = $halt ? 'until' : 'fire';
280
+
281
+		return $this->dispatcher->$method($event, $entity);
282
+	}
283
+
284
+	/**
285
+	 * Register an entity event with the dispatcher.
286
+	 *
287
+	 * @param  string   $event
288
+	 * @param  \Closure $callback
289
+	 * @return void
290
+	 */
291
+	public function registerEvent($event, $callback)
292
+	{
293
+		$name = $this->entityMap->getClass();
294
+
295
+		$this->dispatcher->listen("analogue.{$event}.{$name}", $callback);
296
+	}
297
+
298
+	/**
299
+	 * Add a global scope to this mapper query builder
300
+	 *
301
+	 * @param  ScopeInterface $scope
302
+	 * @return void
303
+	 */
304
+	public function addGlobalScope(ScopeInterface $scope)
305
+	{
306
+		$this->globalScopes[get_class($scope)] = $scope;
307
+	}
308
+
309
+	/**
310
+	 * Determine if the mapper has a global scope.
311
+	 *
312
+	 * @param  \Analogue\ORM\System\ScopeInterface $scope
313
+	 * @return bool
314
+	 */
315
+	public function hasGlobalScope($scope)
316
+	{
317
+		return !is_null($this->getGlobalScope($scope));
318
+	}
319
+
320
+	/**
321
+	 * Get a global scope registered with the modal.
322
+	 *
323
+	 * @param  \Analogue\ORM\System\ScopeInterface $scope
324
+	 * @return \Analogue\ORM\System\ScopeInterface|null
325
+	 */
326
+	public function getGlobalScope($scope)
327
+	{
328
+		return array_first($this->globalScopes, function ($key, $value) use ($scope) {
329
+			return $scope instanceof $value;
330
+		});
331
+	}
332
+
333
+	/**
334
+	 * Get a new query instance without a given scope.
335
+	 *
336
+	 * @param  \Analogue\ORM\System\ScopeInterface $scope
337
+	 * @return \Analogue\ORM\System\Query
338
+	 */
339
+	public function newQueryWithoutScope($scope)
340
+	{
341
+		$this->getGlobalScope($scope)->remove($query = $this->getQuery(), $this);
342
+
343
+		return $query;
344
+	}
345
+
346
+	/**
347
+	 * Get the Analogue Query Builder for this instance
348
+	 *
349
+	 * @return \Analogue\ORM\System\Query
350
+	 */
351
+	public function getQuery()
352
+	{
353
+		$query = new Query($this, $this->adapter);
354
+
355
+		return $this->applyGlobalScopes($query);
356
+	}
357
+
358
+	/**
359
+	 * Apply all of the global scopes to an Analogue Query builder.
360
+	 *
361
+	 * @param Query $query
362
+	 * @return \Analogue\ORM\System\Query
363
+	 */
364
+	public function applyGlobalScopes($query)
365
+	{
366
+		foreach ($this->getGlobalScopes() as $scope) {
367
+			$scope->apply($query, $this);
368
+		}
369
+
370
+		return $query;
371
+	}
372
+
373
+	/**
374
+	 * Get the global scopes for this class instance.
375
+	 *
376
+	 * @return \Analogue\ORM\System\ScopeInterface
377
+	 */
378
+	public function getGlobalScopes()
379
+	{
380
+		return $this->globalScopes;
381
+	}
382
+
383
+	/**
384
+	 * Add a dynamic method that extends the mapper/repository
385
+	 *
386
+	 * @param string $command
387
+	 */
388
+	public function addCustomCommand($command)
389
+	{
390
+		$name = lcfirst(class_basename($command));
391
+
392
+		$this->customCommands[$name] = $command;
393
+	}
394
+
395
+	/**
396
+	 * Create a new instance of the mapped entity class
397
+	 *
398
+	 * @param  array $attributes
399
+	 * @return mixed
400
+	 */
401
+	public function newInstance($attributes = [])
402
+	{
403
+		$class = $this->entityMap->getClass();
404
+
405
+		if ($this->entityMap->activator() != null) {
406
+			$entity = $this->entityMap->activator();
407
+		} else {
408
+			$entity = $this->customClassInstance($class);
409
+		}
410
+
411
+		// prevent hydrating with an empty array
412
+		if (count($attributes) > 0) {
413
+			$entity->setEntityAttributes($attributes);
414
+		}
415
+
416
+		return $entity;
417
+	}
418
+
419
+	/**
420
+	 * Use a trick to generate a class prototype that we
421
+	 * can instantiate without calling the constructor.
422
+	 *
423
+	 * @param string|null $className
424
+	 * @throws MappingException
425
+	 * @return mixed
426
+	 */
427
+	protected function customClassInstance($className)
428
+	{
429
+		if (!class_exists($className)) {
430
+			throw new MappingException("Tried to instantiate a non-existing Entity class : $className");
431
+		}
432
+
433
+		$prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($className), $className));
434
+
435
+		return $prototype;
436
+	}
437
+
438
+	/**
439
+	 * Get an unscoped Analogue Query Builder for this instance
440
+	 *
441
+	 * @return \Analogue\ORM\System\Query
442
+	 */
443
+	public function globalQuery()
444
+	{
445
+		return $this->newQueryWithoutScopes();
446
+	}
447
+
448
+	/**
449
+	 * Get a new query builder that doesn't have any global scopes.
450
+	 *
451
+	 * @return Query
452
+	 */
453
+	public function newQueryWithoutScopes()
454
+	{
455
+		return $this->removeGlobalScopes($this->getQuery());
456
+	}
457
+
458
+	/**
459
+	 * Remove all of the global scopes from an Analogue Query builder.
460
+	 *
461
+	 * @param Query $query
462
+	 * @return \Analogue\ORM\System\Query
463
+	 */
464
+	public function removeGlobalScopes($query)
465
+	{
466
+		foreach ($this->getGlobalScopes() as $scope) {
467
+			$scope->remove($query, $this);
468
+		}
469
+
470
+		return $query;
471
+	}
472
+
473
+	/**
474
+	 * Return the manager instance
475
+	 *
476
+	 * @return \Analogue\ORM\System\Manager
477
+	 */
478
+	public function getManager()
479
+	{
480
+		return $this->manager;
481
+	}
482
+
483
+	/**
484
+	 * Dynamically handle calls to custom commands, or Redirects to query()
485
+	 *
486
+	 * @param  string $method
487
+	 * @param  array  $parameters
488
+	 * @throws \Exception
489
+	 * @return mixed
490
+	 */
491
+	public function __call($method, $parameters)
492
+	{
493
+		// Check if method is a custom command on the mapper
494
+		if ($this->hasCustomCommand($method)) {
495
+			if (count($parameters) == 0) {
496
+				throw new \Exception("$method must at least have 1 argument");
497
+			}
498
+
499
+			return $this->executeCustomCommand($method, $parameters[0]);
500
+		}
501
+
502
+		// Redirect call on a new query instance
503
+		return call_user_func_array([$this->query(), $method], $parameters);
504
+	}
505
+
506
+	/**
507
+	 * Check if this mapper supports this command
508
+	 * @param  string $command
509
+	 * @return boolean
510
+	 */
511
+	public function hasCustomCommand($command)
512
+	{
513
+		return in_array($command, $this->getCustomCommands());
514
+	}
515
+
516
+	/**
517
+	 * Get all the custom commands registered on this mapper
518
+	 *
519
+	 * @return array
520
+	 */
521
+	public function getCustomCommands()
522
+	{
523
+		return array_keys($this->customCommands);
524
+	}
525
+
526
+	/**
527
+	 * Execute a custom command on an Entity
528
+	 *
529
+	 * @param  string                 $command
530
+	 * @param  mixed|Collection|array $entity
531
+	 * @throws \InvalidArgumentException
532
+	 * @throws MappingException
533
+	 * @return mixed
534
+	 */
535
+	public function executeCustomCommand($command, $entity)
536
+	{
537
+		$commandClass = $this->customCommands[$command];
538
+
539
+		if ($this->manager->isTraversable($entity)) {
540
+			foreach ($entity as $instance) {
541
+				$this->executeSingleCustomCommand($commandClass, $instance);
542
+			}
543
+		} else {
544
+			return $this->executeSingleCustomCommand($commandClass, $entity);
545
+		}
546
+	}
547
+
548
+	/**
549
+	 * Execute a single command instance
550
+	 *
551
+	 * @param  string $commandClass
552
+	 * @param  mixed  $entity
553
+	 * @throws \InvalidArgumentException
554
+	 * @throws MappingException
555
+	 * @return mixed
556
+	 */
557
+	protected function executeSingleCustomCommand($commandClass, $entity)
558
+	{
559
+		$this->checkEntityType($entity);
560
+
561
+		$instance = new $commandClass($this->aggregate($entity), $this->newQueryBuilder());
562
+
563
+		return $instance->execute();
564
+	}
565
+
566
+	/**
567
+	 * Get the Analogue Query Builder for this instance
568
+	 *
569
+	 * @return \Analogue\ORM\System\Query
570
+	 */
571
+	public function query()
572
+	{
573
+		return $this->getQuery();
574
+	}
575 575
 }
Please login to merge, or discard this patch.