Completed
Branch master (cbd196)
by Rémi
08:54
created
src/Plugins/SoftDeletes/SoftDeletingScope.php 3 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -73,7 +73,7 @@  discard block
 block discarded – undo
73 73
      */
74 74
     protected function addWithTrashed(Query $query)
75 75
     {
76
-        $query->macro('withTrashed', function (Query $query) {
76
+        $query->macro('withTrashed', function(Query $query) {
77 77
             $this->remove($query);
78 78
 
79 79
             return $query;
@@ -88,7 +88,7 @@  discard block
 block discarded – undo
88 88
      */
89 89
     protected function addOnlyTrashed(Query $query)
90 90
     {
91
-        $query->macro('onlyTrashed', function (Query $query) {
91
+        $query->macro('onlyTrashed', function(Query $query) {
92 92
             $this->remove($query);
93 93
 
94 94
             $query->getQuery()->whereNotNull($query->getMapper()->getEntityMap()->getQualifiedDeletedAtColumn());
Please login to merge, or discard this patch.
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -33,7 +33,7 @@
 block discarded – undo
33 33
     /**
34 34
      * Remove the scope from the given Analogue query builder.
35 35
      *
36
-     * @param mixed $query
36
+     * @param Query $query
37 37
      *
38 38
      * @return void
39 39
      */
Please login to merge, or discard this patch.
Indentation   +108 added lines, -108 removed lines patch added patch discarded remove patch
@@ -7,112 +7,112 @@
 block discarded – undo
7 7
 
8 8
 class SoftDeletingScope implements ScopeInterface
9 9
 {
10
-    /**
11
-     * All of the extensions to be added to the builder.
12
-     *
13
-     * @var array
14
-     */
15
-    protected $extensions = ['WithTrashed', 'OnlyTrashed'];
16
-
17
-    /**
18
-     * Apply the scope to a given Analogue query builder.
19
-     *
20
-     * @param \Analogue\ORM\System\Query $query
21
-     *
22
-     * @return void
23
-     */
24
-    public function apply(Query $query)
25
-    {
26
-        $entityMap = $query->getMapper()->getEntityMap();
27
-
28
-        $query->whereNull($entityMap->getQualifiedDeletedAtColumn());
29
-
30
-        $this->extend($query);
31
-    }
32
-
33
-    /**
34
-     * Remove the scope from the given Analogue query builder.
35
-     *
36
-     * @param mixed $query
37
-     *
38
-     * @return void
39
-     */
40
-    public function remove(Query $query)
41
-    {
42
-        $column = $query->getMapper()->getEntityMap()->getQualifiedDeletedAtColumn();
43
-
44
-        $query = $query->getQuery();
45
-
46
-        foreach ((array) $query->wheres as $key => $where) {
47
-            // If the where clause is a soft delete date constraint, we will remove it from
48
-            // the query and reset the keys on the wheres. This allows this developer to
49
-            // include deleted model in a relationship result set that is lazy loaded.
50
-            if ($this->isSoftDeleteConstraint($where, $column)) {
51
-                unset($query->wheres[$key]);
52
-
53
-                $query->wheres = array_values($query->wheres);
54
-            }
55
-        }
56
-    }
57
-
58
-    /**
59
-     * Extend the query builder with the needed functions.
60
-     *
61
-     * @param \Analogue\ORM\System\Query $query
62
-     *
63
-     * @return void
64
-     */
65
-    public function extend(Query $query)
66
-    {
67
-        foreach ($this->extensions as $extension) {
68
-            $this->{"add{$extension}"}($query);
69
-        }
70
-    }
71
-
72
-    /**
73
-     * Add the with-trashed extension to the builder.
74
-     *
75
-     * @param \Analogue\ORM\System\Query $query
76
-     *
77
-     * @return void
78
-     */
79
-    protected function addWithTrashed(Query $query)
80
-    {
81
-        $query->macro('withTrashed', function (Query $query) {
82
-            $this->remove($query);
83
-
84
-            return $query;
85
-        });
86
-    }
87
-
88
-    /**
89
-     * Add the only-trashed extension to the builder.
90
-     *
91
-     * @param \Analogue\ORM\System\Query $query
92
-     *
93
-     * @return void
94
-     */
95
-    protected function addOnlyTrashed(Query $query)
96
-    {
97
-        $query->macro('onlyTrashed', function (Query $query) {
98
-            $this->remove($query);
99
-
100
-            $query->getQuery()->whereNotNull($query->getMapper()->getEntityMap()->getQualifiedDeletedAtColumn());
101
-
102
-            return $query;
103
-        });
104
-    }
105
-
106
-    /**
107
-     * Determine if the given where clause is a soft delete constraint.
108
-     *
109
-     * @param array  $where
110
-     * @param string $column
111
-     *
112
-     * @return bool
113
-     */
114
-    protected function isSoftDeleteConstraint(array $where, $column)
115
-    {
116
-        return $where['type'] == 'Null' && $where['column'] == $column;
117
-    }
10
+	/**
11
+	 * All of the extensions to be added to the builder.
12
+	 *
13
+	 * @var array
14
+	 */
15
+	protected $extensions = ['WithTrashed', 'OnlyTrashed'];
16
+
17
+	/**
18
+	 * Apply the scope to a given Analogue query builder.
19
+	 *
20
+	 * @param \Analogue\ORM\System\Query $query
21
+	 *
22
+	 * @return void
23
+	 */
24
+	public function apply(Query $query)
25
+	{
26
+		$entityMap = $query->getMapper()->getEntityMap();
27
+
28
+		$query->whereNull($entityMap->getQualifiedDeletedAtColumn());
29
+
30
+		$this->extend($query);
31
+	}
32
+
33
+	/**
34
+	 * Remove the scope from the given Analogue query builder.
35
+	 *
36
+	 * @param mixed $query
37
+	 *
38
+	 * @return void
39
+	 */
40
+	public function remove(Query $query)
41
+	{
42
+		$column = $query->getMapper()->getEntityMap()->getQualifiedDeletedAtColumn();
43
+
44
+		$query = $query->getQuery();
45
+
46
+		foreach ((array) $query->wheres as $key => $where) {
47
+			// If the where clause is a soft delete date constraint, we will remove it from
48
+			// the query and reset the keys on the wheres. This allows this developer to
49
+			// include deleted model in a relationship result set that is lazy loaded.
50
+			if ($this->isSoftDeleteConstraint($where, $column)) {
51
+				unset($query->wheres[$key]);
52
+
53
+				$query->wheres = array_values($query->wheres);
54
+			}
55
+		}
56
+	}
57
+
58
+	/**
59
+	 * Extend the query builder with the needed functions.
60
+	 *
61
+	 * @param \Analogue\ORM\System\Query $query
62
+	 *
63
+	 * @return void
64
+	 */
65
+	public function extend(Query $query)
66
+	{
67
+		foreach ($this->extensions as $extension) {
68
+			$this->{"add{$extension}"}($query);
69
+		}
70
+	}
71
+
72
+	/**
73
+	 * Add the with-trashed extension to the builder.
74
+	 *
75
+	 * @param \Analogue\ORM\System\Query $query
76
+	 *
77
+	 * @return void
78
+	 */
79
+	protected function addWithTrashed(Query $query)
80
+	{
81
+		$query->macro('withTrashed', function (Query $query) {
82
+			$this->remove($query);
83
+
84
+			return $query;
85
+		});
86
+	}
87
+
88
+	/**
89
+	 * Add the only-trashed extension to the builder.
90
+	 *
91
+	 * @param \Analogue\ORM\System\Query $query
92
+	 *
93
+	 * @return void
94
+	 */
95
+	protected function addOnlyTrashed(Query $query)
96
+	{
97
+		$query->macro('onlyTrashed', function (Query $query) {
98
+			$this->remove($query);
99
+
100
+			$query->getQuery()->whereNotNull($query->getMapper()->getEntityMap()->getQualifiedDeletedAtColumn());
101
+
102
+			return $query;
103
+		});
104
+	}
105
+
106
+	/**
107
+	 * Determine if the given where clause is a soft delete constraint.
108
+	 *
109
+	 * @param array  $where
110
+	 * @param string $column
111
+	 *
112
+	 * @return bool
113
+	 */
114
+	protected function isSoftDeleteConstraint(array $where, $column)
115
+	{
116
+		return $where['type'] == 'Null' && $where['column'] == $column;
117
+	}
118 118
 }
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 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -177,7 +177,7 @@
 block discarded – undo
177 177
     /**
178 178
      * Get a the Underlying QueryAdapter.
179 179
      *
180
-     * @return \Analogue\ORM\Drivers\QueryAdapter
180
+     * @return \Illuminate\Database\Query\Builder
181 181
      */
182 182
     public function newQueryBuilder()
183 183
     {
Please login to merge, or discard this patch.
Indentation   +630 added lines, -630 removed lines patch added patch discarded remove patch
@@ -25,634 +25,634 @@
 block discarded – undo
25 25
  */
26 26
 class Mapper
27 27
 {
28
-    /**
29
-     * The Manager instance.
30
-     *
31
-     * @var \Analogue\ORM\System\Manager
32
-     */
33
-    protected $manager;
34
-
35
-    /**
36
-     * Instance of EntityMapper Object.
37
-     *
38
-     * @var \Analogue\ORM\EntityMap
39
-     */
40
-    protected $entityMap;
41
-
42
-    /**
43
-     * The instance of db adapter.
44
-     *
45
-     * @var \Analogue\ORM\Drivers\DBAdapter
46
-     */
47
-    protected $adapter;
48
-
49
-    /**
50
-     * Event dispatcher instance.
51
-     *
52
-     * @var \Illuminate\Contracts\Events\Dispatcher
53
-     */
54
-    protected $dispatcher;
55
-
56
-    /**
57
-     * Entity Cache.
58
-     *
59
-     * @var \Analogue\ORM\System\EntityCache
60
-     */
61
-    protected $cache;
62
-
63
-    /**
64
-     * Global scopes.
65
-     *
66
-     * @var array
67
-     */
68
-    protected $globalScopes = [];
69
-
70
-    /**
71
-     * Custom Commands.
72
-     *
73
-     * @var array
74
-     */
75
-    protected $customCommands = [];
76
-
77
-    /**
78
-     * @param EntityMap  $entityMap
79
-     * @param DBAdapter  $adapter
80
-     * @param Dispatcher $dispatcher
81
-     * @param Manager    $manager
82
-     */
83
-    public function __construct(EntityMap $entityMap, DBAdapter $adapter, Dispatcher $dispatcher, Manager $manager)
84
-    {
85
-        $this->entityMap = $entityMap;
86
-
87
-        $this->adapter = $adapter;
88
-
89
-        $this->dispatcher = $dispatcher;
90
-
91
-        $this->manager = $manager;
92
-
93
-        $this->cache = new EntityCache($entityMap);
94
-    }
95
-
96
-    /**
97
-     * Map results to a Collection.
98
-     *
99
-     * @param array|Collection $results
100
-     *
101
-     * @return Collection
102
-     */
103
-    public function map($results, array $eagerLoads = []) : Collection
104
-    {
105
-        $builder = new ResultBuilder($this);
106
-
107
-        if ($results instanceof collection) {
108
-            // Get underlying collection array
109
-            $results = $results->all();
110
-        }
111
-
112
-        if (!is_array($results)) {
113
-            throw new InvalidArgumentException("'results' should be an array or collection.");
114
-        }
115
-
116
-        // First, we'll cast every single result to array
117
-        $results = array_map(function ($item) {
118
-            return (array) $item;
119
-        }, $results);
120
-
121
-        // Then, we'll cache every single results as raw attributes, before
122
-        // adding relationships, which will be cached when the relationship's
123
-        // query takes place.
124
-        $this->getEntityCache()->add($results);
125
-
126
-        $entities = $builder->build($results, $eagerLoads);
127
-
128
-        return $this->entityMap->newCollection($entities);
129
-    }
130
-
131
-    /**
132
-     * Return all records for a mapped object.
133
-     *
134
-     * @return EntityCollection
135
-     */
136
-    public function all()
137
-    {
138
-        return $this->query()->get();
139
-    }
140
-
141
-    /**
142
-     * Persist an entity or an entity collection into the database.
143
-     *
144
-     * @param Mappable|\Traversable|array $entity
145
-     *
146
-     * @throws \InvalidArgumentException
147
-     * @throws MappingException
148
-     *
149
-     * @return Mappable|\Traversable|array
150
-     */
151
-    public function store($entity)
152
-    {
153
-        if ($this->manager->isTraversable($entity)) {
154
-            return $this->storeCollection($entity);
155
-        } else {
156
-            return $this->storeEntity($entity);
157
-        }
158
-    }
159
-
160
-    /**
161
-     * Store an entity collection inside a single DB Transaction.
162
-     *
163
-     * @param \Traversable|array $entities
164
-     *
165
-     * @throws \InvalidArgumentException
166
-     * @throws MappingException
167
-     *
168
-     * @return \Traversable|array
169
-     */
170
-    protected function storeCollection($entities)
171
-    {
172
-        $this->adapter->beginTransaction();
173
-
174
-        foreach ($entities as $entity) {
175
-            $this->storeEntity($entity);
176
-        }
177
-
178
-        $this->adapter->commit();
179
-
180
-        return $entities;
181
-    }
182
-
183
-    /**
184
-     * Store a single entity into the database.
185
-     *
186
-     * @param Mappable $entity
187
-     *
188
-     * @throws \InvalidArgumentException
189
-     * @throws MappingException
190
-     *
191
-     * @return \Analogue\ORM\Entity
192
-     */
193
-    protected function storeEntity($entity)
194
-    {   
195
-        $this->checkEntityType($entity);
196
-
197
-        $store = new Store($this->aggregate($entity), $this->newQueryBuilder());
198
-
199
-        return $store->execute();
200
-    }
201
-
202
-    /**
203
-     * Check that the entity correspond to the current mapper.
204
-     *
205
-     * @param mixed $entity
206
-     *
207
-     * @throws InvalidArgumentException
208
-     *
209
-     * @return void
210
-     */
211
-    protected function checkEntityType($entity)
212
-    {
213
-        if (get_class($entity) != $this->entityMap->getClass() && !is_subclass_of($entity, $this->entityMap->getClass())) {
214
-            $expected = $this->entityMap->getClass();
215
-            $actual = get_class($entity);
216
-            throw new InvalidArgumentException("Expected : $expected, got $actual.");
217
-        }
218
-    }
219
-
220
-    /**
221
-     * Convert an entity into an aggregate root.
222
-     *
223
-     * @param mixed $entity
224
-     *
225
-     * @throws MappingException
226
-     *
227
-     * @return \Analogue\ORM\System\Aggregate
228
-     */
229
-    protected function aggregate($entity)
230
-    {
231
-        return new Aggregate($entity);
232
-    }
233
-
234
-    /**
235
-     * Get a the Underlying QueryAdapter.
236
-     *
237
-     * @return \Analogue\ORM\Drivers\QueryAdapter
238
-     */
239
-    public function newQueryBuilder()
240
-    {
241
-        return $this->adapter->getQuery();
242
-    }
243
-
244
-    /**
245
-     * Delete an entity or an entity collection from the database.
246
-     *
247
-     * @param  Mappable|\Traversable|array
248
-     *
249
-     * @throws MappingException
250
-     * @throws \InvalidArgumentException
251
-     *
252
-     * @return \Traversable|array
253
-     */
254
-    public function delete($entity)
255
-    {
256
-        if ($this->manager->isTraversable($entity)) {
257
-            return $this->deleteCollection($entity);
258
-        } else {
259
-            $this->deleteEntity($entity);
260
-        }
261
-    }
262
-
263
-    /**
264
-     * Delete an Entity Collection inside a single db transaction.
265
-     *
266
-     * @param \Traversable|array $entities
267
-     *
268
-     * @throws \InvalidArgumentException
269
-     * @throws MappingException
270
-     *
271
-     * @return \Traversable|array
272
-     */
273
-    protected function deleteCollection($entities)
274
-    {
275
-        $this->adapter->beginTransaction();
276
-
277
-        foreach ($entities as $entity) {
278
-            $this->deleteEntity($entity);
279
-        }
280
-
281
-        $this->adapter->commit();
282
-
283
-        return $entities;
284
-    }
285
-
286
-    /**
287
-     * Delete a single entity from the database.
288
-     *
289
-     * @param Mappable $entity
290
-     *
291
-     * @throws \InvalidArgumentException
292
-     * @throws MappingException
293
-     *
294
-     * @return void
295
-     */
296
-    protected function deleteEntity($entity)
297
-    {
298
-        $this->checkEntityType($entity);
299
-
300
-        $delete = new Delete($this->aggregate($entity), $this->newQueryBuilder());
301
-
302
-        $delete->execute();
303
-    }
304
-
305
-    /**
306
-     * Return the entity map for this mapper.
307
-     *
308
-     * @return EntityMap
309
-     */
310
-    public function getEntityMap()
311
-    {
312
-        return $this->entityMap;
313
-    }
314
-
315
-    /**
316
-     * Get the entity cache for the current mapper.
317
-     *
318
-     * @return EntityCache $entityCache
319
-     */
320
-    public function getEntityCache()
321
-    {
322
-        return $this->cache;
323
-    }
324
-
325
-    /**
326
-     * Fire the given event for the entity.
327
-     *
328
-     * @param string               $event
329
-     * @param \Analogue\ORM\Entity $entity
330
-     * @param bool                 $halt
331
-     *
332
-     * @throws InvalidArgumentException
333
-     *
334
-     * @return mixed
335
-     */
336
-    public function fireEvent($event, $entity, $halt = true)
337
-    {
338
-        if ($entity instanceof Wrapper) {
339
-            throw new InvalidArgumentException('Fired Event with invalid Entity Object');
340
-        }
341
-
342
-        $event = "analogue.{$event}.".$this->entityMap->getClass();
343
-
344
-        $method = $halt ? 'until' : 'fire';
345
-
346
-        return $this->dispatcher->$method($event, $entity);
347
-    }
348
-
349
-    /**
350
-     * Register an entity event with the dispatcher.
351
-     *
352
-     * @param string   $event
353
-     * @param \Closure $callback
354
-     *
355
-     * @return void
356
-     */
357
-    public function registerEvent($event, $callback)
358
-    {
359
-        $name = $this->entityMap->getClass();
360
-
361
-        $this->dispatcher->listen("analogue.{$event}.{$name}", $callback);
362
-    }
363
-
364
-    /**
365
-     * Add a global scope to this mapper query builder.
366
-     *
367
-     * @param ScopeInterface $scope
368
-     *
369
-     * @return void
370
-     */
371
-    public function addGlobalScope(ScopeInterface $scope)
372
-    {
373
-        $this->globalScopes[get_class($scope)] = $scope;
374
-    }
375
-
376
-    /**
377
-     * Determine if the mapper has a global scope.
378
-     *
379
-     * @param \Analogue\ORM\System\ScopeInterface $scope
380
-     *
381
-     * @return bool
382
-     */
383
-    public function hasGlobalScope($scope)
384
-    {
385
-        return !is_null($this->getGlobalScope($scope));
386
-    }
387
-
388
-    /**
389
-     * Get a global scope registered with the modal.
390
-     *
391
-     * @param \Analogue\ORM\System\ScopeInterface $scope
392
-     *
393
-     * @return \Analogue\ORM\System\ScopeInterface|null
394
-     */
395
-    public function getGlobalScope($scope)
396
-    {
397
-        return array_first($this->globalScopes, function ($key, $value) use ($scope) {
398
-            return $scope instanceof $value;
399
-        });
400
-    }
401
-
402
-    /**
403
-     * Get a new query instance without a given scope.
404
-     *
405
-     * @param \Analogue\ORM\System\ScopeInterface $scope
406
-     *
407
-     * @return \Analogue\ORM\System\Query
408
-     */
409
-    public function newQueryWithoutScope($scope)
410
-    {
411
-        $this->getGlobalScope($scope)->remove($query = $this->getQuery(), $this);
412
-
413
-        return $query;
414
-    }
415
-
416
-    /**
417
-     * Get the Analogue Query Builder for this instance.
418
-     *
419
-     * @return \Analogue\ORM\System\Query
420
-     */
421
-    public function getQuery()
422
-    {
423
-        $query = new Query($this, $this->adapter);
424
-
425
-        return $this->applyGlobalScopes($query);
426
-    }
427
-
428
-    /**
429
-     * Apply all of the global scopes to an Analogue Query builder.
430
-     *
431
-     * @param Query $query
432
-     *
433
-     * @return \Analogue\ORM\System\Query
434
-     */
435
-    public function applyGlobalScopes($query)
436
-    {
437
-        foreach ($this->getGlobalScopes() as $scope) {
438
-            $scope->apply($query, $this);
439
-        }
440
-
441
-        return $query;
442
-    }
443
-
444
-    /**
445
-     * Get the global scopes for this class instance.
446
-     *
447
-     * @return \Analogue\ORM\System\ScopeInterface
448
-     */
449
-    public function getGlobalScopes()
450
-    {
451
-        return $this->globalScopes;
452
-    }
453
-
454
-    /**
455
-     * Add a dynamic method that extends the mapper/repository.
456
-     *
457
-     * @param string $command
458
-     */
459
-    public function addCustomCommand($command)
460
-    {
461
-        $name = lcfirst(class_basename($command));
462
-
463
-        $this->customCommands[$name] = $command;
464
-    }
465
-
466
-    /**
467
-     * Create a new instance of the mapped entity class.
468
-     *
469
-     * @return mixed
470
-     */
471
-    public function newInstance()
472
-    {
473
-        $class = $this->entityMap->getClass();
474
-
475
-        if ($this->entityMap->useDependencyInjection()) {
476
-            return $this->newInstanceUsingDependencyInjection($class);
477
-        }
478
-
479
-        return $this->newInstanceUsingInstantiator($class);
480
-    }
481
-
482
-    /**
483
-     * Return a new object instance using dependency injection.
484
-     *
485
-     * @param string $class
486
-     *
487
-     * @return mixed
488
-     */
489
-    protected function newInstanceUsingDependencyInjection($class)
490
-    {
491
-        if (!class_exists(Container::class)) {
492
-            throw new ErrorException("Illuminate\Container\Container is required to use Dependency Injection");
493
-        }
494
-
495
-        return Container::getInstance()->make($class);
496
-    }
497
-
498
-    /**
499
-     * Return a new object instance using doctrine's instantiator.
500
-     *
501
-     * @param string $class
502
-     *
503
-     * @return mixed
504
-     */
505
-    protected function newInstanceUsingInstantiator($class)
506
-    {
507
-        $instantiator = new \Doctrine\Instantiator\Instantiator();
508
-
509
-        return $instantiator->instantiate($class);
510
-    }
511
-
512
-    /**
513
-     * Get an unscoped Analogue Query Builder for this instance.
514
-     *
515
-     * @return \Analogue\ORM\System\Query
516
-     */
517
-    public function globalQuery()
518
-    {
519
-        return $this->newQueryWithoutScopes();
520
-    }
521
-
522
-    /**
523
-     * Get a new query builder that doesn't have any global scopes.
524
-     *
525
-     * @return Query
526
-     */
527
-    public function newQueryWithoutScopes()
528
-    {
529
-        return $this->removeGlobalScopes($this->getQuery());
530
-    }
531
-
532
-    /**
533
-     * Remove all of the global scopes from an Analogue Query builder.
534
-     *
535
-     * @param Query $query
536
-     *
537
-     * @return \Analogue\ORM\System\Query
538
-     */
539
-    public function removeGlobalScopes($query)
540
-    {
541
-        foreach ($this->getGlobalScopes() as $scope) {
542
-            $scope->remove($query, $this);
543
-        }
544
-
545
-        return $query;
546
-    }
547
-
548
-    /**
549
-     * Return the manager instance.
550
-     *
551
-     * @return \Analogue\ORM\System\Manager
552
-     */
553
-    public function getManager()
554
-    {
555
-        return $this->manager;
556
-    }
557
-
558
-    /**
559
-     * Dynamically handle calls to custom commands, or Redirects to query().
560
-     *
561
-     * @param string $method
562
-     * @param array  $parameters
563
-     *
564
-     * @throws \Exception
565
-     *
566
-     * @return mixed
567
-     */
568
-    public function __call($method, $parameters)
569
-    {
570
-        // Check if method is a custom command on the mapper
571
-        if ($this->hasCustomCommand($method)) {
572
-            if (count($parameters) == 0) {
573
-                throw new \Exception("$method must at least have 1 argument");
574
-            }
575
-
576
-            return $this->executeCustomCommand($method, $parameters[0]);
577
-        }
578
-
579
-        // Redirect call on a new query instance
580
-        return call_user_func_array([$this->query(), $method], $parameters);
581
-    }
582
-
583
-    /**
584
-     * Check if this mapper supports this command.
585
-     *
586
-     * @param string $command
587
-     *
588
-     * @return bool
589
-     */
590
-    public function hasCustomCommand($command)
591
-    {
592
-        return in_array($command, $this->getCustomCommands());
593
-    }
594
-
595
-    /**
596
-     * Get all the custom commands registered on this mapper.
597
-     *
598
-     * @return array
599
-     */
600
-    public function getCustomCommands()
601
-    {
602
-        return array_keys($this->customCommands);
603
-    }
604
-
605
-    /**
606
-     * Execute a custom command on an Entity.
607
-     *
608
-     * @param string                 $command
609
-     * @param mixed|Collection|array $entity
610
-     *
611
-     * @throws \InvalidArgumentException
612
-     * @throws MappingException
613
-     *
614
-     * @return mixed
615
-     */
616
-    public function executeCustomCommand($command, $entity)
617
-    {
618
-        $commandClass = $this->customCommands[$command];
619
-
620
-        if ($this->manager->isTraversable($entity)) {
621
-            foreach ($entity as $instance) {
622
-                $this->executeSingleCustomCommand($commandClass, $instance);
623
-            }
624
-        } else {
625
-            return $this->executeSingleCustomCommand($commandClass, $entity);
626
-        }
627
-    }
628
-
629
-    /**
630
-     * Execute a single command instance.
631
-     *
632
-     * @param string $commandClass
633
-     * @param mixed  $entity
634
-     *
635
-     * @throws \InvalidArgumentException
636
-     * @throws MappingException
637
-     *
638
-     * @return mixed
639
-     */
640
-    protected function executeSingleCustomCommand($commandClass, $entity)
641
-    {
642
-        $this->checkEntityType($entity);
643
-
644
-        $instance = new $commandClass($this->aggregate($entity), $this->newQueryBuilder());
645
-
646
-        return $instance->execute();
647
-    }
648
-
649
-    /**
650
-     * Get the Analogue Query Builder for this instance.
651
-     *
652
-     * @return \Analogue\ORM\System\Query
653
-     */
654
-    public function query()
655
-    {
656
-        return $this->getQuery();
657
-    }
28
+	/**
29
+	 * The Manager instance.
30
+	 *
31
+	 * @var \Analogue\ORM\System\Manager
32
+	 */
33
+	protected $manager;
34
+
35
+	/**
36
+	 * Instance of EntityMapper Object.
37
+	 *
38
+	 * @var \Analogue\ORM\EntityMap
39
+	 */
40
+	protected $entityMap;
41
+
42
+	/**
43
+	 * The instance of db adapter.
44
+	 *
45
+	 * @var \Analogue\ORM\Drivers\DBAdapter
46
+	 */
47
+	protected $adapter;
48
+
49
+	/**
50
+	 * Event dispatcher instance.
51
+	 *
52
+	 * @var \Illuminate\Contracts\Events\Dispatcher
53
+	 */
54
+	protected $dispatcher;
55
+
56
+	/**
57
+	 * Entity Cache.
58
+	 *
59
+	 * @var \Analogue\ORM\System\EntityCache
60
+	 */
61
+	protected $cache;
62
+
63
+	/**
64
+	 * Global scopes.
65
+	 *
66
+	 * @var array
67
+	 */
68
+	protected $globalScopes = [];
69
+
70
+	/**
71
+	 * Custom Commands.
72
+	 *
73
+	 * @var array
74
+	 */
75
+	protected $customCommands = [];
76
+
77
+	/**
78
+	 * @param EntityMap  $entityMap
79
+	 * @param DBAdapter  $adapter
80
+	 * @param Dispatcher $dispatcher
81
+	 * @param Manager    $manager
82
+	 */
83
+	public function __construct(EntityMap $entityMap, DBAdapter $adapter, Dispatcher $dispatcher, Manager $manager)
84
+	{
85
+		$this->entityMap = $entityMap;
86
+
87
+		$this->adapter = $adapter;
88
+
89
+		$this->dispatcher = $dispatcher;
90
+
91
+		$this->manager = $manager;
92
+
93
+		$this->cache = new EntityCache($entityMap);
94
+	}
95
+
96
+	/**
97
+	 * Map results to a Collection.
98
+	 *
99
+	 * @param array|Collection $results
100
+	 *
101
+	 * @return Collection
102
+	 */
103
+	public function map($results, array $eagerLoads = []) : Collection
104
+	{
105
+		$builder = new ResultBuilder($this);
106
+
107
+		if ($results instanceof collection) {
108
+			// Get underlying collection array
109
+			$results = $results->all();
110
+		}
111
+
112
+		if (!is_array($results)) {
113
+			throw new InvalidArgumentException("'results' should be an array or collection.");
114
+		}
115
+
116
+		// First, we'll cast every single result to array
117
+		$results = array_map(function ($item) {
118
+			return (array) $item;
119
+		}, $results);
120
+
121
+		// Then, we'll cache every single results as raw attributes, before
122
+		// adding relationships, which will be cached when the relationship's
123
+		// query takes place.
124
+		$this->getEntityCache()->add($results);
125
+
126
+		$entities = $builder->build($results, $eagerLoads);
127
+
128
+		return $this->entityMap->newCollection($entities);
129
+	}
130
+
131
+	/**
132
+	 * Return all records for a mapped object.
133
+	 *
134
+	 * @return EntityCollection
135
+	 */
136
+	public function all()
137
+	{
138
+		return $this->query()->get();
139
+	}
140
+
141
+	/**
142
+	 * Persist an entity or an entity collection into the database.
143
+	 *
144
+	 * @param Mappable|\Traversable|array $entity
145
+	 *
146
+	 * @throws \InvalidArgumentException
147
+	 * @throws MappingException
148
+	 *
149
+	 * @return Mappable|\Traversable|array
150
+	 */
151
+	public function store($entity)
152
+	{
153
+		if ($this->manager->isTraversable($entity)) {
154
+			return $this->storeCollection($entity);
155
+		} else {
156
+			return $this->storeEntity($entity);
157
+		}
158
+	}
159
+
160
+	/**
161
+	 * Store an entity collection inside a single DB Transaction.
162
+	 *
163
+	 * @param \Traversable|array $entities
164
+	 *
165
+	 * @throws \InvalidArgumentException
166
+	 * @throws MappingException
167
+	 *
168
+	 * @return \Traversable|array
169
+	 */
170
+	protected function storeCollection($entities)
171
+	{
172
+		$this->adapter->beginTransaction();
173
+
174
+		foreach ($entities as $entity) {
175
+			$this->storeEntity($entity);
176
+		}
177
+
178
+		$this->adapter->commit();
179
+
180
+		return $entities;
181
+	}
182
+
183
+	/**
184
+	 * Store a single entity into the database.
185
+	 *
186
+	 * @param Mappable $entity
187
+	 *
188
+	 * @throws \InvalidArgumentException
189
+	 * @throws MappingException
190
+	 *
191
+	 * @return \Analogue\ORM\Entity
192
+	 */
193
+	protected function storeEntity($entity)
194
+	{   
195
+		$this->checkEntityType($entity);
196
+
197
+		$store = new Store($this->aggregate($entity), $this->newQueryBuilder());
198
+
199
+		return $store->execute();
200
+	}
201
+
202
+	/**
203
+	 * Check that the entity correspond to the current mapper.
204
+	 *
205
+	 * @param mixed $entity
206
+	 *
207
+	 * @throws InvalidArgumentException
208
+	 *
209
+	 * @return void
210
+	 */
211
+	protected function checkEntityType($entity)
212
+	{
213
+		if (get_class($entity) != $this->entityMap->getClass() && !is_subclass_of($entity, $this->entityMap->getClass())) {
214
+			$expected = $this->entityMap->getClass();
215
+			$actual = get_class($entity);
216
+			throw new InvalidArgumentException("Expected : $expected, got $actual.");
217
+		}
218
+	}
219
+
220
+	/**
221
+	 * Convert an entity into an aggregate root.
222
+	 *
223
+	 * @param mixed $entity
224
+	 *
225
+	 * @throws MappingException
226
+	 *
227
+	 * @return \Analogue\ORM\System\Aggregate
228
+	 */
229
+	protected function aggregate($entity)
230
+	{
231
+		return new Aggregate($entity);
232
+	}
233
+
234
+	/**
235
+	 * Get a the Underlying QueryAdapter.
236
+	 *
237
+	 * @return \Analogue\ORM\Drivers\QueryAdapter
238
+	 */
239
+	public function newQueryBuilder()
240
+	{
241
+		return $this->adapter->getQuery();
242
+	}
243
+
244
+	/**
245
+	 * Delete an entity or an entity collection from the database.
246
+	 *
247
+	 * @param  Mappable|\Traversable|array
248
+	 *
249
+	 * @throws MappingException
250
+	 * @throws \InvalidArgumentException
251
+	 *
252
+	 * @return \Traversable|array
253
+	 */
254
+	public function delete($entity)
255
+	{
256
+		if ($this->manager->isTraversable($entity)) {
257
+			return $this->deleteCollection($entity);
258
+		} else {
259
+			$this->deleteEntity($entity);
260
+		}
261
+	}
262
+
263
+	/**
264
+	 * Delete an Entity Collection inside a single db transaction.
265
+	 *
266
+	 * @param \Traversable|array $entities
267
+	 *
268
+	 * @throws \InvalidArgumentException
269
+	 * @throws MappingException
270
+	 *
271
+	 * @return \Traversable|array
272
+	 */
273
+	protected function deleteCollection($entities)
274
+	{
275
+		$this->adapter->beginTransaction();
276
+
277
+		foreach ($entities as $entity) {
278
+			$this->deleteEntity($entity);
279
+		}
280
+
281
+		$this->adapter->commit();
282
+
283
+		return $entities;
284
+	}
285
+
286
+	/**
287
+	 * Delete a single entity from the database.
288
+	 *
289
+	 * @param Mappable $entity
290
+	 *
291
+	 * @throws \InvalidArgumentException
292
+	 * @throws MappingException
293
+	 *
294
+	 * @return void
295
+	 */
296
+	protected function deleteEntity($entity)
297
+	{
298
+		$this->checkEntityType($entity);
299
+
300
+		$delete = new Delete($this->aggregate($entity), $this->newQueryBuilder());
301
+
302
+		$delete->execute();
303
+	}
304
+
305
+	/**
306
+	 * Return the entity map for this mapper.
307
+	 *
308
+	 * @return EntityMap
309
+	 */
310
+	public function getEntityMap()
311
+	{
312
+		return $this->entityMap;
313
+	}
314
+
315
+	/**
316
+	 * Get the entity cache for the current mapper.
317
+	 *
318
+	 * @return EntityCache $entityCache
319
+	 */
320
+	public function getEntityCache()
321
+	{
322
+		return $this->cache;
323
+	}
324
+
325
+	/**
326
+	 * Fire the given event for the entity.
327
+	 *
328
+	 * @param string               $event
329
+	 * @param \Analogue\ORM\Entity $entity
330
+	 * @param bool                 $halt
331
+	 *
332
+	 * @throws InvalidArgumentException
333
+	 *
334
+	 * @return mixed
335
+	 */
336
+	public function fireEvent($event, $entity, $halt = true)
337
+	{
338
+		if ($entity instanceof Wrapper) {
339
+			throw new InvalidArgumentException('Fired Event with invalid Entity Object');
340
+		}
341
+
342
+		$event = "analogue.{$event}.".$this->entityMap->getClass();
343
+
344
+		$method = $halt ? 'until' : 'fire';
345
+
346
+		return $this->dispatcher->$method($event, $entity);
347
+	}
348
+
349
+	/**
350
+	 * Register an entity event with the dispatcher.
351
+	 *
352
+	 * @param string   $event
353
+	 * @param \Closure $callback
354
+	 *
355
+	 * @return void
356
+	 */
357
+	public function registerEvent($event, $callback)
358
+	{
359
+		$name = $this->entityMap->getClass();
360
+
361
+		$this->dispatcher->listen("analogue.{$event}.{$name}", $callback);
362
+	}
363
+
364
+	/**
365
+	 * Add a global scope to this mapper query builder.
366
+	 *
367
+	 * @param ScopeInterface $scope
368
+	 *
369
+	 * @return void
370
+	 */
371
+	public function addGlobalScope(ScopeInterface $scope)
372
+	{
373
+		$this->globalScopes[get_class($scope)] = $scope;
374
+	}
375
+
376
+	/**
377
+	 * Determine if the mapper has a global scope.
378
+	 *
379
+	 * @param \Analogue\ORM\System\ScopeInterface $scope
380
+	 *
381
+	 * @return bool
382
+	 */
383
+	public function hasGlobalScope($scope)
384
+	{
385
+		return !is_null($this->getGlobalScope($scope));
386
+	}
387
+
388
+	/**
389
+	 * Get a global scope registered with the modal.
390
+	 *
391
+	 * @param \Analogue\ORM\System\ScopeInterface $scope
392
+	 *
393
+	 * @return \Analogue\ORM\System\ScopeInterface|null
394
+	 */
395
+	public function getGlobalScope($scope)
396
+	{
397
+		return array_first($this->globalScopes, function ($key, $value) use ($scope) {
398
+			return $scope instanceof $value;
399
+		});
400
+	}
401
+
402
+	/**
403
+	 * Get a new query instance without a given scope.
404
+	 *
405
+	 * @param \Analogue\ORM\System\ScopeInterface $scope
406
+	 *
407
+	 * @return \Analogue\ORM\System\Query
408
+	 */
409
+	public function newQueryWithoutScope($scope)
410
+	{
411
+		$this->getGlobalScope($scope)->remove($query = $this->getQuery(), $this);
412
+
413
+		return $query;
414
+	}
415
+
416
+	/**
417
+	 * Get the Analogue Query Builder for this instance.
418
+	 *
419
+	 * @return \Analogue\ORM\System\Query
420
+	 */
421
+	public function getQuery()
422
+	{
423
+		$query = new Query($this, $this->adapter);
424
+
425
+		return $this->applyGlobalScopes($query);
426
+	}
427
+
428
+	/**
429
+	 * Apply all of the global scopes to an Analogue Query builder.
430
+	 *
431
+	 * @param Query $query
432
+	 *
433
+	 * @return \Analogue\ORM\System\Query
434
+	 */
435
+	public function applyGlobalScopes($query)
436
+	{
437
+		foreach ($this->getGlobalScopes() as $scope) {
438
+			$scope->apply($query, $this);
439
+		}
440
+
441
+		return $query;
442
+	}
443
+
444
+	/**
445
+	 * Get the global scopes for this class instance.
446
+	 *
447
+	 * @return \Analogue\ORM\System\ScopeInterface
448
+	 */
449
+	public function getGlobalScopes()
450
+	{
451
+		return $this->globalScopes;
452
+	}
453
+
454
+	/**
455
+	 * Add a dynamic method that extends the mapper/repository.
456
+	 *
457
+	 * @param string $command
458
+	 */
459
+	public function addCustomCommand($command)
460
+	{
461
+		$name = lcfirst(class_basename($command));
462
+
463
+		$this->customCommands[$name] = $command;
464
+	}
465
+
466
+	/**
467
+	 * Create a new instance of the mapped entity class.
468
+	 *
469
+	 * @return mixed
470
+	 */
471
+	public function newInstance()
472
+	{
473
+		$class = $this->entityMap->getClass();
474
+
475
+		if ($this->entityMap->useDependencyInjection()) {
476
+			return $this->newInstanceUsingDependencyInjection($class);
477
+		}
478
+
479
+		return $this->newInstanceUsingInstantiator($class);
480
+	}
481
+
482
+	/**
483
+	 * Return a new object instance using dependency injection.
484
+	 *
485
+	 * @param string $class
486
+	 *
487
+	 * @return mixed
488
+	 */
489
+	protected function newInstanceUsingDependencyInjection($class)
490
+	{
491
+		if (!class_exists(Container::class)) {
492
+			throw new ErrorException("Illuminate\Container\Container is required to use Dependency Injection");
493
+		}
494
+
495
+		return Container::getInstance()->make($class);
496
+	}
497
+
498
+	/**
499
+	 * Return a new object instance using doctrine's instantiator.
500
+	 *
501
+	 * @param string $class
502
+	 *
503
+	 * @return mixed
504
+	 */
505
+	protected function newInstanceUsingInstantiator($class)
506
+	{
507
+		$instantiator = new \Doctrine\Instantiator\Instantiator();
508
+
509
+		return $instantiator->instantiate($class);
510
+	}
511
+
512
+	/**
513
+	 * Get an unscoped Analogue Query Builder for this instance.
514
+	 *
515
+	 * @return \Analogue\ORM\System\Query
516
+	 */
517
+	public function globalQuery()
518
+	{
519
+		return $this->newQueryWithoutScopes();
520
+	}
521
+
522
+	/**
523
+	 * Get a new query builder that doesn't have any global scopes.
524
+	 *
525
+	 * @return Query
526
+	 */
527
+	public function newQueryWithoutScopes()
528
+	{
529
+		return $this->removeGlobalScopes($this->getQuery());
530
+	}
531
+
532
+	/**
533
+	 * Remove all of the global scopes from an Analogue Query builder.
534
+	 *
535
+	 * @param Query $query
536
+	 *
537
+	 * @return \Analogue\ORM\System\Query
538
+	 */
539
+	public function removeGlobalScopes($query)
540
+	{
541
+		foreach ($this->getGlobalScopes() as $scope) {
542
+			$scope->remove($query, $this);
543
+		}
544
+
545
+		return $query;
546
+	}
547
+
548
+	/**
549
+	 * Return the manager instance.
550
+	 *
551
+	 * @return \Analogue\ORM\System\Manager
552
+	 */
553
+	public function getManager()
554
+	{
555
+		return $this->manager;
556
+	}
557
+
558
+	/**
559
+	 * Dynamically handle calls to custom commands, or Redirects to query().
560
+	 *
561
+	 * @param string $method
562
+	 * @param array  $parameters
563
+	 *
564
+	 * @throws \Exception
565
+	 *
566
+	 * @return mixed
567
+	 */
568
+	public function __call($method, $parameters)
569
+	{
570
+		// Check if method is a custom command on the mapper
571
+		if ($this->hasCustomCommand($method)) {
572
+			if (count($parameters) == 0) {
573
+				throw new \Exception("$method must at least have 1 argument");
574
+			}
575
+
576
+			return $this->executeCustomCommand($method, $parameters[0]);
577
+		}
578
+
579
+		// Redirect call on a new query instance
580
+		return call_user_func_array([$this->query(), $method], $parameters);
581
+	}
582
+
583
+	/**
584
+	 * Check if this mapper supports this command.
585
+	 *
586
+	 * @param string $command
587
+	 *
588
+	 * @return bool
589
+	 */
590
+	public function hasCustomCommand($command)
591
+	{
592
+		return in_array($command, $this->getCustomCommands());
593
+	}
594
+
595
+	/**
596
+	 * Get all the custom commands registered on this mapper.
597
+	 *
598
+	 * @return array
599
+	 */
600
+	public function getCustomCommands()
601
+	{
602
+		return array_keys($this->customCommands);
603
+	}
604
+
605
+	/**
606
+	 * Execute a custom command on an Entity.
607
+	 *
608
+	 * @param string                 $command
609
+	 * @param mixed|Collection|array $entity
610
+	 *
611
+	 * @throws \InvalidArgumentException
612
+	 * @throws MappingException
613
+	 *
614
+	 * @return mixed
615
+	 */
616
+	public function executeCustomCommand($command, $entity)
617
+	{
618
+		$commandClass = $this->customCommands[$command];
619
+
620
+		if ($this->manager->isTraversable($entity)) {
621
+			foreach ($entity as $instance) {
622
+				$this->executeSingleCustomCommand($commandClass, $instance);
623
+			}
624
+		} else {
625
+			return $this->executeSingleCustomCommand($commandClass, $entity);
626
+		}
627
+	}
628
+
629
+	/**
630
+	 * Execute a single command instance.
631
+	 *
632
+	 * @param string $commandClass
633
+	 * @param mixed  $entity
634
+	 *
635
+	 * @throws \InvalidArgumentException
636
+	 * @throws MappingException
637
+	 *
638
+	 * @return mixed
639
+	 */
640
+	protected function executeSingleCustomCommand($commandClass, $entity)
641
+	{
642
+		$this->checkEntityType($entity);
643
+
644
+		$instance = new $commandClass($this->aggregate($entity), $this->newQueryBuilder());
645
+
646
+		return $instance->execute();
647
+	}
648
+
649
+	/**
650
+	 * Get the Analogue Query Builder for this instance.
651
+	 *
652
+	 * @return \Analogue\ORM\System\Query
653
+	 */
654
+	public function query()
655
+	{
656
+		return $this->getQuery();
657
+	}
658 658
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -114,7 +114,7 @@  discard block
 block discarded – undo
114 114
         }
115 115
 
116 116
         // First, we'll cast every single result to array
117
-        $results = array_map(function ($item) {
117
+        $results = array_map(function($item) {
118 118
             return (array) $item;
119 119
         }, $results);
120 120
 
@@ -394,7 +394,7 @@  discard block
 block discarded – undo
394 394
      */
395 395
     public function getGlobalScope($scope)
396 396
     {
397
-        return array_first($this->globalScopes, function ($key, $value) use ($scope) {
397
+        return array_first($this->globalScopes, function($key, $value) use ($scope) {
398 398
             return $scope instanceof $value;
399 399
         });
400 400
     }
Please login to merge, or discard this patch.
src/ValueObject.php 1 patch
Indentation   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -9,9 +9,9 @@
 block discarded – undo
9 9
 
10 10
 class ValueObject implements Mappable, ArrayAccess, Jsonable, JsonSerializable, Arrayable
11 11
 {
12
-    use MappableTrait;
13
-    use MagicGetters;
14
-    use MagicSetters;
15
-    use MagicCasting;
12
+	use MappableTrait;
13
+	use MagicGetters;
14
+	use MagicSetters;
15
+	use MagicCasting;
16 16
 }
17 17
 
Please login to merge, or discard this patch.
src/ValueMap.php 2 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -71,7 +71,7 @@  discard block
 block discarded – undo
71 71
     }
72 72
 
73 73
     /**
74
-     * @param $class
74
+     * @param string $class
75 75
      */
76 76
     public function setClass($class)
77 77
     {
@@ -79,7 +79,7 @@  discard block
 block discarded – undo
79 79
     }
80 80
 
81 81
     /**
82
-     * @return mixed
82
+     * @return string
83 83
      */
84 84
     public function getClass()
85 85
     {
Please login to merge, or discard this patch.
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -4,97 +4,97 @@
 block discarded – undo
4 4
 
5 5
 class ValueMap
6 6
 {
7
-    /**
8
-     * @var string
9
-     */
10
-    protected $name;
7
+	/**
8
+	 * @var string
9
+	 */
10
+	protected $name;
11 11
 
12
-    /**
13
-     * @var string
14
-     */
15
-    protected $class;
12
+	/**
13
+	 * @var string
14
+	 */
15
+	protected $class;
16 16
 
17
-    /**
18
-     * @var array
19
-     */
20
-    protected $embeddables = [];
17
+	/**
18
+	 * @var array
19
+	 */
20
+	protected $embeddables = [];
21 21
 
22
-    /**
23
-     * @var array
24
-     */
25
-    protected $attributes = [];
22
+	/**
23
+	 * @var array
24
+	 */
25
+	protected $attributes = [];
26 26
 
27
-    /**
28
-     * @var array
29
-     */
30
-    protected $properties = [];
27
+	/**
28
+	 * @var array
29
+	 */
30
+	protected $properties = [];
31 31
 
32
-    protected $arrayName = null;
32
+	protected $arrayName = null;
33 33
 
34
-    /**
35
-     * @return array
36
-     */
37
-    public function getAttributes()
38
-    {
39
-        return $this->attributes;
40
-    }
34
+	/**
35
+	 * @return array
36
+	 */
37
+	public function getAttributes()
38
+	{
39
+		return $this->attributes;
40
+	}
41 41
 
42
-    /**
43
-     * [getAttributesArrayName description].
44
-     *
45
-     * @return [type] [description]
46
-     */
47
-    public function getAttributesArrayName()
48
-    {
49
-        return $this->arrayName;
50
-    }
42
+	/**
43
+	 * [getAttributesArrayName description].
44
+	 *
45
+	 * @return [type] [description]
46
+	 */
47
+	public function getAttributesArrayName()
48
+	{
49
+		return $this->arrayName;
50
+	}
51 51
 
52
-    public function usesAttributesArray()
53
-    {
54
-        return $this->arrayName != null;
55
-    }
52
+	public function usesAttributesArray()
53
+	{
54
+		return $this->arrayName != null;
55
+	}
56 56
 
57
-    /**
58
-     * @return array
59
-     */
60
-    public function getProperties()
61
-    {
62
-        return $this->properties;
63
-    }
57
+	/**
58
+	 * @return array
59
+	 */
60
+	public function getProperties()
61
+	{
62
+		return $this->properties;
63
+	}
64 64
 
65
-    /**
66
-     * @return array
67
-     */
68
-    public function getEmbeddables()
69
-    {
70
-        return $this->embeddables;
71
-    }
65
+	/**
66
+	 * @return array
67
+	 */
68
+	public function getEmbeddables()
69
+	{
70
+		return $this->embeddables;
71
+	}
72 72
 
73
-    /**
74
-     * @param $class
75
-     */
76
-    public function setClass($class)
77
-    {
78
-        $this->class = $class;
79
-    }
73
+	/**
74
+	 * @param $class
75
+	 */
76
+	public function setClass($class)
77
+	{
78
+		$this->class = $class;
79
+	}
80 80
 
81
-    /**
82
-     * @return mixed
83
-     */
84
-    public function getClass()
85
-    {
86
-        return $this->class;
87
-    }
81
+	/**
82
+	 * @return mixed
83
+	 */
84
+	public function getClass()
85
+	{
86
+		return $this->class;
87
+	}
88 88
 
89
-    /**
90
-     * @return string
91
-     */
92
-    public function getName()
93
-    {
94
-        if (isset($this->name)) {
95
-            return $this->name;
96
-        } else {
97
-            return class_basename($this);
98
-        }
99
-    }
89
+	/**
90
+	 * @return string
91
+	 */
92
+	public function getName()
93
+	{
94
+		if (isset($this->name)) {
95
+			return $this->name;
96
+		} else {
97
+			return class_basename($this);
98
+		}
99
+	}
100 100
 }
Please login to merge, or discard this patch.
src/Relationships/HasMany.php 2 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -9,7 +9,7 @@  discard block
 block discarded – undo
9 9
      *
10 10
      * @param  $relation
11 11
      *
12
-     * @return mixed
12
+     * @return \Analogue\ORM\EntityCollection
13 13
      */
14 14
     public function getResults($relation)
15 15
     {
@@ -23,7 +23,7 @@  discard block
 block discarded – undo
23 23
     /**
24 24
      * Match the eagerly loaded results to their parents.
25 25
      *
26
-     * @param array  $$results
26
+     * @param array  $results
27 27
      * @param string $relation
28 28
      *
29 29
      * @return array
Please login to merge, or discard this patch.
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -4,32 +4,32 @@
 block discarded – undo
4 4
 
5 5
 class HasMany extends HasOneOrMany
6 6
 {
7
-    /**
8
-     * Lazy-Load the results of the relationship.
9
-     *
10
-     * @param  $relation
11
-     *
12
-     * @return mixed
13
-     */
14
-    public function getResults($relation)
15
-    {
16
-        $results = $this->query->get();
7
+	/**
8
+	 * Lazy-Load the results of the relationship.
9
+	 *
10
+	 * @param  $relation
11
+	 *
12
+	 * @return mixed
13
+	 */
14
+	public function getResults($relation)
15
+	{
16
+		$results = $this->query->get();
17 17
 
18
-        $this->cacheRelation($results, $relation);
18
+		$this->cacheRelation($results, $relation);
19 19
 
20
-        return $results;
21
-    }
20
+		return $results;
21
+	}
22 22
 
23
-    /**
24
-     * Match the eagerly loaded results to their parents.
25
-     *
26
-     * @param array  $$results
27
-     * @param string $relation
28
-     *
29
-     * @return array
30
-     */
31
-    public function match(array $results, $relation)
32
-    {
33
-        return $this->matchMany($results, $relation);
34
-    }
23
+	/**
24
+	 * Match the eagerly loaded results to their parents.
25
+	 *
26
+	 * @param array  $$results
27
+	 * @param string $relation
28
+	 *
29
+	 * @return array
30
+	 */
31
+	public function match(array $results, $relation)
32
+	{
33
+		return $this->matchMany($results, $relation);
34
+	}
35 35
 }
Please login to merge, or discard this patch.
src/Relationships/HasManyThrough.php 3 patches
Doc Comments   -1 removed lines patch added patch discarded remove patch
@@ -291,7 +291,6 @@
 block discarded – undo
291 291
      * Run synchronization content if needed by the
292 292
      * relation type.
293 293
      *
294
-     * @param array $actualContent
295 294
      *
296 295
      * @return void
297 296
      */
Please login to merge, or discard this patch.
Indentation   +290 added lines, -290 removed lines patch added patch discarded remove patch
@@ -9,294 +9,294 @@
 block discarded – undo
9 9
 
10 10
 class HasManyThrough extends Relationship
11 11
 {
12
-    /**
13
-     * The distance parent Entity instance.
14
-     *
15
-     * @var \Analogue\ORM\Entity
16
-     */
17
-    protected $farParent;
18
-
19
-    /**
20
-     * The far parent map instance.
21
-     *
22
-     * @var \Analogue\ORM\EntityMap
23
-     */
24
-    protected $farParentMap;
25
-
26
-    /**
27
-     * The near key on the relationship.
28
-     *
29
-     * @var string
30
-     */
31
-    protected $firstKey;
32
-
33
-    /**
34
-     * The far key on the relationship.
35
-     *
36
-     * @var string
37
-     */
38
-    protected $secondKey;
39
-
40
-    /**
41
-     * Create a new has many relationship instance.
42
-     *
43
-     * @param Mapper                  $mapper
44
-     * @param \Analogue\ORM\Mappable  $farParent
45
-     * @param \Analogue\ORM\EntityMap $parentMap
46
-     * @param string                  $firstKey
47
-     * @param string                  $secondKey
48
-     *
49
-     * @throws \Analogue\ORM\Exceptions\MappingException
50
-     */
51
-    public function __construct(Mapper $mapper, $farParent, $parentMap, $firstKey, $secondKey)
52
-    {
53
-        $this->firstKey = $firstKey;
54
-        $this->secondKey = $secondKey;
55
-        $this->farParent = $farParent;
56
-
57
-        $this->farParentMap = $mapper->getManager()->mapper($farParent)->getEntityMap();
58
-        $parentInstance = $mapper->getManager()->mapper($parentMap->getClass())->newInstance();
59
-
60
-        parent::__construct($mapper, $parentInstance);
61
-    }
62
-
63
-    /**
64
-     * Set the base constraints on the relation query.
65
-     *
66
-     * @return void
67
-     */
68
-    public function addConstraints()
69
-    {
70
-        $parentTable = $this->parentMap->getTable();
71
-
72
-        $this->setJoin();
73
-
74
-        if (static::$constraints) {
75
-            $farParentKeyName = $this->farParentMap->getKeyName();
76
-
77
-            $this->query->where(
78
-                $parentTable.'.'.$this->firstKey,
79
-                '=',
80
-                $this->farParent->getEntityAttribute($farParentKeyName)
81
-            );
82
-        }
83
-    }
84
-
85
-    /**
86
-     * Add the constraints for a relationship count query.
87
-     *
88
-     * @param Query $query
89
-     * @param Query $parent
90
-     *
91
-     * @return Query
92
-     */
93
-    public function getRelationCountQuery(Query $query, Query $parent)
94
-    {
95
-        $parentTable = $this->parentMap->getTable();
96
-
97
-        $this->setJoin($query);
98
-
99
-        $query->select(new Expression('count(*)'));
100
-
101
-        $key = $this->wrap($parentTable.'.'.$this->firstKey);
102
-
103
-        return $query->where($this->getHasCompareKey(), '=', new Expression($key));
104
-    }
105
-
106
-    /**
107
-     * Set the join clause on the query.
108
-     *
109
-     * @param null|Query $query
110
-     *
111
-     * @return void
112
-     */
113
-    protected function setJoin(Query $query = null)
114
-    {
115
-        $query = $query ?: $this->query;
116
-
117
-        $foreignKey = $this->relatedMap->getTable().'.'.$this->secondKey;
118
-
119
-        $query->join($this->parentMap->getTable(), $this->getQualifiedParentKeyName(), '=', $foreignKey);
120
-    }
121
-
122
-    /**
123
-     * Set the constraints for an eager load of the relation.
124
-     *
125
-     * @param array $results
126
-     *
127
-     * @return void
128
-     */
129
-    public function addEagerConstraints(array $results)
130
-    {
131
-        $table = $this->parentMap->getTable();
132
-
133
-        $this->query->whereIn($table.'.'.$this->firstKey, $this->getKeysFromResults($results));
134
-    }
135
-
136
-    /**
137
-     * Match eagerly loaded relationship to a result set.
138
-     *
139
-     * @param array  $results
140
-     * @param string $relation
141
-     *
142
-     * @return array
143
-     */
144
-    public function match(array $results, $relation)
145
-    {
146
-        $entities = $this->getEager();
147
-
148
-        $dictionary = $this->buildDictionary($entities);
149
-
150
-        $relatedKey = $this->relatedMap->getKeyName();
151
-
152
-        $cache = $this->parentMapper->getEntityCache();
153
-
154
-        $host = $this;
155
-
156
-        // Once we have the dictionary we can simply spin through the parent entities to
157
-        // link them up with their children using the keyed dictionary to make the
158
-        // matching very convenient and easy work. Then we'll just return them.
159
-        return array_map(function ($result) use ($relation, $relatedKey, $dictionary, $cache, $host) {
160
-            $key = $result[$relatedKey];
161
-
162
-            if (isset($dictionary[$key])) {
163
-                $value = $host->relatedMap->newCollection($dictionary[$key]);
164
-
165
-                $result[$relation] = $value;
166
-
167
-                $cache->cacheLoadedRelationResult($key, $relation, $value, $this);
168
-            }
169
-
170
-            return $result;
171
-        }, $results);
172
-    }
173
-
174
-    /**
175
-     * Build model dictionary keyed by the relation's foreign key.
176
-     *
177
-     * @param EntityCollection $results
178
-     *
179
-     * @return array
180
-     */
181
-    protected function buildDictionary(EntityCollection $results)
182
-    {
183
-        $dictionary = [];
184
-
185
-        $foreign = $this->firstKey;
186
-
187
-        // First we will create a dictionary of entities keyed by the foreign key of the
188
-        // relationship as this will allow us to quickly access all of the related
189
-        // entities without having to do nested looping which will be quite slow.
190
-        foreach ($results as $result) {
191
-            $dictionary[$result->{$foreign}][] = $result;
192
-        }
193
-
194
-        return $dictionary;
195
-    }
196
-
197
-    /**
198
-     * Get the results of the relationship.
199
-     *
200
-     * @param  $relation
201
-     *
202
-     * @return EntityCollection
203
-     */
204
-    public function getResults($relation)
205
-    {
206
-        $results = $this->query->get();
207
-
208
-        $this->cacheRelation($results, $relation);
209
-
210
-        return $results;
211
-    }
212
-
213
-    /**
214
-     * Execute the query as a "select" statement.
215
-     *
216
-     * @param array $columns
217
-     *
218
-     * @return EntityCollection
219
-     */
220
-    public function get($columns = ['*'])
221
-    {
222
-        // First we'll add the proper select columns onto the query so it is run with
223
-        // the proper columns. Then, we will get the results and hydrate out pivot
224
-        // entities with the result of those columns as a separate model relation.
225
-        $select = $this->getSelectColumns($columns);
226
-
227
-        $entities = $this->query->addSelect($select)->getEntities();
228
-
229
-        // If we actually found entities we will also eager load any relationships that
230
-        // have been specified as needing to be eager loaded. This will solve the
231
-        // n + 1 query problem for the developer and also increase performance.
232
-        if (count($entities) > 0) {
233
-            $entities = $this->query->eagerLoadRelations($entities);
234
-        }
235
-
236
-        return $this->relatedMap->newCollection($entities);
237
-    }
238
-
239
-    /**
240
-     * Set the select clause for the relation query.
241
-     *
242
-     * @param array $columns
243
-     *
244
-     * @return BelongsToMany
245
-     */
246
-    protected function getSelectColumns(array $columns = ['*'])
247
-    {
248
-        if ($columns == ['*']) {
249
-            $columns = [$this->relatedMap->getTable().'.*'];
250
-        }
251
-
252
-        return array_merge($columns, [$this->parentMap->getTable().'.'.$this->firstKey]);
253
-    }
254
-
255
-    /**
256
-     * Get a paginator for the "select" statement.
257
-     *
258
-     * @param int   $perPage
259
-     * @param array $columns
260
-     *
261
-     * @return \Illuminate\Pagination\LengthAwarePaginator
262
-     */
263
-    public function paginate($perPage = null, $columns = ['*'])
264
-    {
265
-        $this->query->addSelect($this->getSelectColumns($columns));
266
-
267
-        return $this->query->paginate($perPage, $columns);
268
-    }
269
-
270
-    /**
271
-     * Get the key name of the parent model.
272
-     *
273
-     * @return string
274
-     */
275
-    protected function getQualifiedParentKeyName()
276
-    {
277
-        return $this->parentMap->getQualifiedKeyName();
278
-    }
279
-
280
-    /**
281
-     * Get the key for comparing against the parent key in "has" query.
282
-     *
283
-     * @return string
284
-     */
285
-    public function getHasCompareKey()
286
-    {
287
-        return $this->farParentMap->getQualifiedKeyName();
288
-    }
289
-
290
-    /**
291
-     * Run synchronization content if needed by the
292
-     * relation type.
293
-     *
294
-     * @param array $actualContent
295
-     *
296
-     * @return void
297
-     */
298
-    public function sync(array $entities)
299
-    {
300
-        // N/A
301
-    }
12
+	/**
13
+	 * The distance parent Entity instance.
14
+	 *
15
+	 * @var \Analogue\ORM\Entity
16
+	 */
17
+	protected $farParent;
18
+
19
+	/**
20
+	 * The far parent map instance.
21
+	 *
22
+	 * @var \Analogue\ORM\EntityMap
23
+	 */
24
+	protected $farParentMap;
25
+
26
+	/**
27
+	 * The near key on the relationship.
28
+	 *
29
+	 * @var string
30
+	 */
31
+	protected $firstKey;
32
+
33
+	/**
34
+	 * The far key on the relationship.
35
+	 *
36
+	 * @var string
37
+	 */
38
+	protected $secondKey;
39
+
40
+	/**
41
+	 * Create a new has many relationship instance.
42
+	 *
43
+	 * @param Mapper                  $mapper
44
+	 * @param \Analogue\ORM\Mappable  $farParent
45
+	 * @param \Analogue\ORM\EntityMap $parentMap
46
+	 * @param string                  $firstKey
47
+	 * @param string                  $secondKey
48
+	 *
49
+	 * @throws \Analogue\ORM\Exceptions\MappingException
50
+	 */
51
+	public function __construct(Mapper $mapper, $farParent, $parentMap, $firstKey, $secondKey)
52
+	{
53
+		$this->firstKey = $firstKey;
54
+		$this->secondKey = $secondKey;
55
+		$this->farParent = $farParent;
56
+
57
+		$this->farParentMap = $mapper->getManager()->mapper($farParent)->getEntityMap();
58
+		$parentInstance = $mapper->getManager()->mapper($parentMap->getClass())->newInstance();
59
+
60
+		parent::__construct($mapper, $parentInstance);
61
+	}
62
+
63
+	/**
64
+	 * Set the base constraints on the relation query.
65
+	 *
66
+	 * @return void
67
+	 */
68
+	public function addConstraints()
69
+	{
70
+		$parentTable = $this->parentMap->getTable();
71
+
72
+		$this->setJoin();
73
+
74
+		if (static::$constraints) {
75
+			$farParentKeyName = $this->farParentMap->getKeyName();
76
+
77
+			$this->query->where(
78
+				$parentTable.'.'.$this->firstKey,
79
+				'=',
80
+				$this->farParent->getEntityAttribute($farParentKeyName)
81
+			);
82
+		}
83
+	}
84
+
85
+	/**
86
+	 * Add the constraints for a relationship count query.
87
+	 *
88
+	 * @param Query $query
89
+	 * @param Query $parent
90
+	 *
91
+	 * @return Query
92
+	 */
93
+	public function getRelationCountQuery(Query $query, Query $parent)
94
+	{
95
+		$parentTable = $this->parentMap->getTable();
96
+
97
+		$this->setJoin($query);
98
+
99
+		$query->select(new Expression('count(*)'));
100
+
101
+		$key = $this->wrap($parentTable.'.'.$this->firstKey);
102
+
103
+		return $query->where($this->getHasCompareKey(), '=', new Expression($key));
104
+	}
105
+
106
+	/**
107
+	 * Set the join clause on the query.
108
+	 *
109
+	 * @param null|Query $query
110
+	 *
111
+	 * @return void
112
+	 */
113
+	protected function setJoin(Query $query = null)
114
+	{
115
+		$query = $query ?: $this->query;
116
+
117
+		$foreignKey = $this->relatedMap->getTable().'.'.$this->secondKey;
118
+
119
+		$query->join($this->parentMap->getTable(), $this->getQualifiedParentKeyName(), '=', $foreignKey);
120
+	}
121
+
122
+	/**
123
+	 * Set the constraints for an eager load of the relation.
124
+	 *
125
+	 * @param array $results
126
+	 *
127
+	 * @return void
128
+	 */
129
+	public function addEagerConstraints(array $results)
130
+	{
131
+		$table = $this->parentMap->getTable();
132
+
133
+		$this->query->whereIn($table.'.'.$this->firstKey, $this->getKeysFromResults($results));
134
+	}
135
+
136
+	/**
137
+	 * Match eagerly loaded relationship to a result set.
138
+	 *
139
+	 * @param array  $results
140
+	 * @param string $relation
141
+	 *
142
+	 * @return array
143
+	 */
144
+	public function match(array $results, $relation)
145
+	{
146
+		$entities = $this->getEager();
147
+
148
+		$dictionary = $this->buildDictionary($entities);
149
+
150
+		$relatedKey = $this->relatedMap->getKeyName();
151
+
152
+		$cache = $this->parentMapper->getEntityCache();
153
+
154
+		$host = $this;
155
+
156
+		// Once we have the dictionary we can simply spin through the parent entities to
157
+		// link them up with their children using the keyed dictionary to make the
158
+		// matching very convenient and easy work. Then we'll just return them.
159
+		return array_map(function ($result) use ($relation, $relatedKey, $dictionary, $cache, $host) {
160
+			$key = $result[$relatedKey];
161
+
162
+			if (isset($dictionary[$key])) {
163
+				$value = $host->relatedMap->newCollection($dictionary[$key]);
164
+
165
+				$result[$relation] = $value;
166
+
167
+				$cache->cacheLoadedRelationResult($key, $relation, $value, $this);
168
+			}
169
+
170
+			return $result;
171
+		}, $results);
172
+	}
173
+
174
+	/**
175
+	 * Build model dictionary keyed by the relation's foreign key.
176
+	 *
177
+	 * @param EntityCollection $results
178
+	 *
179
+	 * @return array
180
+	 */
181
+	protected function buildDictionary(EntityCollection $results)
182
+	{
183
+		$dictionary = [];
184
+
185
+		$foreign = $this->firstKey;
186
+
187
+		// First we will create a dictionary of entities keyed by the foreign key of the
188
+		// relationship as this will allow us to quickly access all of the related
189
+		// entities without having to do nested looping which will be quite slow.
190
+		foreach ($results as $result) {
191
+			$dictionary[$result->{$foreign}][] = $result;
192
+		}
193
+
194
+		return $dictionary;
195
+	}
196
+
197
+	/**
198
+	 * Get the results of the relationship.
199
+	 *
200
+	 * @param  $relation
201
+	 *
202
+	 * @return EntityCollection
203
+	 */
204
+	public function getResults($relation)
205
+	{
206
+		$results = $this->query->get();
207
+
208
+		$this->cacheRelation($results, $relation);
209
+
210
+		return $results;
211
+	}
212
+
213
+	/**
214
+	 * Execute the query as a "select" statement.
215
+	 *
216
+	 * @param array $columns
217
+	 *
218
+	 * @return EntityCollection
219
+	 */
220
+	public function get($columns = ['*'])
221
+	{
222
+		// First we'll add the proper select columns onto the query so it is run with
223
+		// the proper columns. Then, we will get the results and hydrate out pivot
224
+		// entities with the result of those columns as a separate model relation.
225
+		$select = $this->getSelectColumns($columns);
226
+
227
+		$entities = $this->query->addSelect($select)->getEntities();
228
+
229
+		// If we actually found entities we will also eager load any relationships that
230
+		// have been specified as needing to be eager loaded. This will solve the
231
+		// n + 1 query problem for the developer and also increase performance.
232
+		if (count($entities) > 0) {
233
+			$entities = $this->query->eagerLoadRelations($entities);
234
+		}
235
+
236
+		return $this->relatedMap->newCollection($entities);
237
+	}
238
+
239
+	/**
240
+	 * Set the select clause for the relation query.
241
+	 *
242
+	 * @param array $columns
243
+	 *
244
+	 * @return BelongsToMany
245
+	 */
246
+	protected function getSelectColumns(array $columns = ['*'])
247
+	{
248
+		if ($columns == ['*']) {
249
+			$columns = [$this->relatedMap->getTable().'.*'];
250
+		}
251
+
252
+		return array_merge($columns, [$this->parentMap->getTable().'.'.$this->firstKey]);
253
+	}
254
+
255
+	/**
256
+	 * Get a paginator for the "select" statement.
257
+	 *
258
+	 * @param int   $perPage
259
+	 * @param array $columns
260
+	 *
261
+	 * @return \Illuminate\Pagination\LengthAwarePaginator
262
+	 */
263
+	public function paginate($perPage = null, $columns = ['*'])
264
+	{
265
+		$this->query->addSelect($this->getSelectColumns($columns));
266
+
267
+		return $this->query->paginate($perPage, $columns);
268
+	}
269
+
270
+	/**
271
+	 * Get the key name of the parent model.
272
+	 *
273
+	 * @return string
274
+	 */
275
+	protected function getQualifiedParentKeyName()
276
+	{
277
+		return $this->parentMap->getQualifiedKeyName();
278
+	}
279
+
280
+	/**
281
+	 * Get the key for comparing against the parent key in "has" query.
282
+	 *
283
+	 * @return string
284
+	 */
285
+	public function getHasCompareKey()
286
+	{
287
+		return $this->farParentMap->getQualifiedKeyName();
288
+	}
289
+
290
+	/**
291
+	 * Run synchronization content if needed by the
292
+	 * relation type.
293
+	 *
294
+	 * @param array $actualContent
295
+	 *
296
+	 * @return void
297
+	 */
298
+	public function sync(array $entities)
299
+	{
300
+		// N/A
301
+	}
302 302
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -156,7 +156,7 @@
 block discarded – undo
156 156
         // Once we have the dictionary we can simply spin through the parent entities to
157 157
         // link them up with their children using the keyed dictionary to make the
158 158
         // matching very convenient and easy work. Then we'll just return them.
159
-        return array_map(function ($result) use ($relation, $relatedKey, $dictionary, $cache, $host) {
159
+        return array_map(function($result) use ($relation, $relatedKey, $dictionary, $cache, $host) {
160 160
             $key = $result[$relatedKey];
161 161
 
162 162
             if (isset($dictionary[$key])) {
Please login to merge, or discard this patch.
src/System/Manager.php 3 patches
Doc Comments   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -143,7 +143,7 @@  discard block
 block discarded – undo
143 143
      * Create a mapper for a given entity.
144 144
      *
145 145
      * @param \Analogue\ORM\Mappable|string|array|\Traversable $entity
146
-     * @param mixed                                            $entityMap
146
+     * @param null|EntityMap                                            $entityMap
147 147
      *
148 148
      * @throws MappingException
149 149
      * @throws \InvalidArgumentException
@@ -251,7 +251,7 @@  discard block
 block discarded – undo
251 251
     /**
252 252
      * Check if the entity is already registered.
253 253
      *
254
-     * @param string|Entity $entity
254
+     * @param string $entity
255 255
      *
256 256
      * @return bool
257 257
      */
@@ -333,7 +333,7 @@  discard block
 block discarded – undo
333 333
     /**
334 334
      * Register an entity.
335 335
      *
336
-     * @param string|\Analogue\ORM\Mappable $entity    entity's class name
336
+     * @param string $entity    entity's class name
337 337
      * @param string|EntityMap              $entityMap map's class name
338 338
      *
339 339
      * @throws MappingException
Please login to merge, or discard this patch.
Indentation   +689 added lines, -689 removed lines patch added patch discarded remove patch
@@ -21,693 +21,693 @@
 block discarded – undo
21 21
  */
22 22
 class Manager
23 23
 {
24
-    /**
25
-     * Manager instance.
26
-     *
27
-     * @var Manager
28
-     */
29
-    protected static $instance;
30
-
31
-    /**
32
-     * Driver Manager.
33
-     *
34
-     * @var \Analogue\ORM\Drivers\Manager
35
-     */
36
-    protected $drivers;
37
-
38
-    /**
39
-     * Registered entity classes and corresponding map objects.
40
-     *
41
-     * @var array
42
-     */
43
-    protected $entityClasses = [];
44
-
45
-    /**
46
-     * Key value store of ValueObject Classes and corresponding map classes.
47
-     *
48
-     * @var array|ValueMap[]
49
-     */
50
-    protected $valueClasses = [];
51
-
52
-    /**
53
-     * Morph map.
54
-     */
55
-    protected $morphMap = [];
56
-
57
-    /**
58
-     * Loaded Mappers.
59
-     *
60
-     * @var array
61
-     */
62
-    protected $mappers = [];
63
-
64
-    /**
65
-     * Loaded Repositories.
66
-     *
67
-     * @var array
68
-     */
69
-    protected $repositories = [];
70
-
71
-    /**
72
-     * Event dispatcher instance.
73
-     *
74
-     * @var \Illuminate\Contracts\Events\Dispatcher
75
-     */
76
-    protected $eventDispatcher;
77
-
78
-    /**
79
-     * Available Analogue Events.
80
-     *
81
-     * @var array
82
-     */
83
-    protected $events = [
84
-        'initializing',
85
-        'initialized',
86
-        'store',
87
-        'stored',
88
-        'creating',
89
-        'created',
90
-        'updating',
91
-        'updated',
92
-        'deleting',
93
-        'deleted',
94
-    ];
95
-
96
-    /**
97
-     * If strictMode is set to true, Manager will throw
98
-     * an exception if no entityMap class are registered
99
-     * for a given entity class.
100
-     *
101
-     * @var bool
102
-     */
103
-    protected $strictMode = true;
104
-
105
-    /**
106
-     * We can add namespaces in this array where the manager
107
-     * will look for when auto registering entityMaps.
108
-     *
109
-     * @var array
110
-     */
111
-    protected $customMapNamespaces = [];
112
-
113
-    /**
114
-     * @param \Analogue\ORM\Drivers\Manager $driverManager
115
-     * @param Dispatcher                    $event
116
-     */
117
-    public function __construct(DriverManager $driverManager, Dispatcher $event)
118
-    {
119
-        $this->drivers = $driverManager;
120
-
121
-        $this->eventDispatcher = $event;
122
-
123
-        static::$instance = $this;
124
-    }
125
-
126
-    /**
127
-     * Create a mapper for a given entity (static alias).
128
-     *
129
-     * @param \Analogue\ORM\Mappable|string $entity
130
-     * @param null|EntityMap                $entityMap
131
-     *
132
-     * @throws MappingException
133
-     * @throws \InvalidArgumentException
134
-     *
135
-     * @return Mapper
136
-     */
137
-    public static function getMapper($entity, $entityMap = null)
138
-    {
139
-        return static::$instance->mapper($entity, $entityMap);
140
-    }
141
-
142
-    /**
143
-     * Create a mapper for a given entity.
144
-     *
145
-     * @param \Analogue\ORM\Mappable|string|array|\Traversable $entity
146
-     * @param mixed                                            $entityMap
147
-     *
148
-     * @throws MappingException
149
-     * @throws \InvalidArgumentException
150
-     *
151
-     * @return Mapper
152
-     */
153
-    public function mapper($entity, $entityMap = null)
154
-    {
155
-        if ($entity instanceof Wrapper) {
156
-            throw new MappingException('Tried to instantiate mapper on wrapped Entity');
157
-        }
158
-
159
-        $entity = $this->resolveEntityClass($entity);
160
-
161
-        $entity = $this->getInverseMorphMap($entity);
162
-
163
-        // Return existing mapper instance if exists.
164
-        if (array_key_exists($entity, $this->mappers)) {
165
-            return $this->mappers[$entity];
166
-        } else {
167
-            return $this->buildMapper($entity, $entityMap);
168
-        }
169
-    }
170
-
171
-    /**
172
-     * This method resolve entity class from mappable instances or iterators.
173
-     *
174
-     * @param \Analogue\ORM\Mappable|string|array|\Traversable $entity
175
-     *
176
-     * @throws \InvalidArgumentException
177
-     *
178
-     * @return string
179
-     */
180
-    protected function resolveEntityClass($entity)
181
-    {
182
-        // We first check if the entity is traversable and we'll resolve
183
-        // the entity based on the first item of the object.
184
-        if ($this->isTraversable($entity)) {
185
-            if (!count($entity)) {
186
-                throw new \InvalidArgumentException('Length of Entity collection must be greater than 0');
187
-            }
188
-
189
-            $firstEntityItem = ($entity instanceof \Iterator)
190
-                ? $entity->current()
191
-                : current($entity);
192
-
193
-            return $this->resolveEntityClass($firstEntityItem);
194
-        }
195
-
196
-        if (is_object($entity)) {
197
-            return get_class($entity);
198
-        }
199
-
200
-        if (is_string($entity)) {
201
-            return $entity;
202
-        }
203
-
204
-        throw new \InvalidArgumentException('Invalid entity type');
205
-    }
206
-
207
-    /**
208
-     * @param string $key
209
-     *
210
-     * @return string
211
-     */
212
-    public function getInverseMorphMap($key)
213
-    {
214
-        return array_key_exists($key, $this->morphMap) ? $this->morphMap[$key] : $key;
215
-    }
216
-
217
-    /**
218
-     * Build a new Mapper instance for a given Entity.
219
-     *
220
-     * @param string $entity
221
-     * @param        $entityMap
222
-     *
223
-     * @throws MappingException
224
-     *
225
-     * @return Mapper
226
-     */
227
-    protected function buildMapper($entity, $entityMap)
228
-    {
229
-        // If an EntityMap hasn't been manually registered by the user
230
-        // register it at runtime.
231
-        if (!$this->isRegisteredEntity($entity)) {
232
-            $this->register($entity, $entityMap);
233
-        }
234
-
235
-        $entityMap = $this->entityClasses[$entity];
236
-
237
-        $factory = new MapperFactory($this->drivers, $this->eventDispatcher, $this);
238
-
239
-        $mapper = $factory->make($entity, $entityMap);
240
-
241
-        $this->mappers[$entity] = $mapper;
242
-
243
-        // At this point we can safely call the boot() method on the entityMap as
244
-        // the mapper is now instantiated & registered within the manager.
245
-
246
-        $mapper->getEntityMap()->boot();
247
-
248
-        return $mapper;
249
-    }
250
-
251
-    /**
252
-     * Check if the entity is already registered.
253
-     *
254
-     * @param string|Entity $entity
255
-     *
256
-     * @return bool
257
-     */
258
-    public function isRegisteredEntity($entity)
259
-    {
260
-        if (!is_string($entity)) {
261
-            $entity = get_class($entity);
262
-        }
263
-
264
-        return array_key_exists($entity, $this->entityClasses);
265
-    }
266
-
267
-    /**
268
-     * Return an array containing registered entities & entityMap instances.
269
-     *
270
-     * @return array
271
-     */
272
-    public function getRegisteredEntities()
273
-    {
274
-        return $this->entityClasses;
275
-    }
276
-
277
-    /**
278
-     * Check if a value class is already registered.
279
-     *
280
-     * @param string|sdtClass $object
281
-     *
282
-     * @return bool
283
-     */
284
-    public function isRegisteredValueObject($object)
285
-    {
286
-        if (!is_string($object)) {
287
-            $object = get_class($object);
288
-        }
289
-
290
-        return array_key_exists($object, $this->valueClasses);
291
-    }
292
-
293
-    /**
294
-     * Return true if an object is an array or iterator.
295
-     *
296
-     * @param mixed $argument
297
-     *
298
-     * @return bool
299
-     */
300
-    public function isTraversable($argument)
301
-    {
302
-        return $argument instanceof \Traversable || is_array($argument);
303
-    }
304
-
305
-    /**
306
-     * Set strict mode for entityMap instantiation.
307
-     *
308
-     * @param bool $mode
309
-     */
310
-    public function setStrictMode($mode)
311
-    {
312
-        $this->strictMode = $mode;
313
-    }
314
-
315
-    /**
316
-     * Register a namespace in where Analogue
317
-     * will scan for EntityMaps & ValueMaps.
318
-     *
319
-     * @param string $namespace
320
-     *
321
-     * @return void
322
-     */
323
-    public function registerMapNamespace($namespace)
324
-    {
325
-        // Add a trailing antislash to namespace if not present
326
-        if (substr('testers', -1) != '\\') {
327
-            $namespace = $namespace.'\\';
328
-        }
329
-
330
-        $this->customMapNamespaces[] = $namespace;
331
-    }
332
-
333
-    /**
334
-     * Register an entity.
335
-     *
336
-     * @param string|\Analogue\ORM\Mappable $entity    entity's class name
337
-     * @param string|EntityMap              $entityMap map's class name
338
-     *
339
-     * @throws MappingException
340
-     *
341
-     * @return void
342
-     */
343
-    public function register($entity, $entityMap = null)
344
-    {
345
-        // If an object is provider, get the class name from it
346
-        if (!is_string($entity)) {
347
-            $entity = get_class($entity);
348
-        }
349
-
350
-        if ($this->isRegisteredEntity($entity)) {
351
-            throw new MappingException("Entity $entity is already registered.");
352
-        }
353
-
354
-        if (!class_exists($entity)) {
355
-            throw new MappingException("Class $entity does not exists");
356
-        }
357
-
358
-        if ($entityMap === null) {
359
-            $entityMap = $this->getEntityMapInstanceFor($entity);
360
-        }
361
-
362
-        if (is_string($entityMap)) {
363
-            $entityMap = new $entityMap();
364
-        }
365
-
366
-        if (!$entityMap instanceof EntityMap) {
367
-            throw new MappingException(get_class($entityMap).' must be an instance of EntityMap.');
368
-        }
369
-
370
-        $entityMap->setClass($entity);
371
-
372
-        $this->entityClasses[$entity] = $entityMap;
373
-    }
374
-
375
-    /**
376
-     * Get the entity map instance for a custom entity.
377
-     *
378
-     * @param string $entity
379
-     *
380
-     * @return \Analogue\ORM\EntityMap
381
-     */
382
-    protected function getEntityMapInstanceFor($entity)
383
-    {
384
-        if (class_exists($entity.'Map')) {
385
-            $map = $entity.'Map';
386
-            $map = new $map();
387
-
388
-            return $map;
389
-        }
390
-
391
-        if ($map = $this->getMapFromNamespaces($entity)) {
392
-            return $map;
393
-        }
394
-
395
-        if ($this->strictMode) {
396
-            throw new EntityMapNotFoundException("No Map registered for $entity");
397
-        }
398
-
399
-        $map = $this->getNewEntityMap();
400
-
401
-        return $map;
402
-    }
403
-
404
-    /**
405
-     * Scan through registered custom namespace
406
-     * for an Entity/ValueMap.
407
-     *
408
-     * @param string $class
409
-     *
410
-     * @return ValueMap|EntityMap|bool
411
-     */
412
-    protected function getMapFromNamespaces($class)
413
-    {
414
-        foreach ($this->customMapNamespaces as $namespace) {
415
-            if ($map = $this->findMapInNamespace($class, $namespace)) {
416
-                return $map;
417
-            }
418
-        }
419
-
420
-        return false;
421
-    }
422
-
423
-    /**
424
-     * Look in a custom namespace for an Entity/ValueMap.
425
-     *
426
-     * @param string $class
427
-     * @param string $namespace
428
-     *
429
-     * @return ValueMap|EntityMap|bool
430
-     */
431
-    protected function findMapInNamespace($class, $namespace)
432
-    {
433
-        $parts = explode('\\', $class);
434
-
435
-        $baseClass = $parts[count($parts) - 1];
436
-
437
-        $expectedClass = $namespace.$baseClass.'Map';
438
-
439
-        if (class_exists($expectedClass)) {
440
-            return new $expectedClass();
441
-        }
442
-
443
-        return false;
444
-    }
445
-
446
-    /**
447
-     * Dynamically create an entity map for a custom entity class.
448
-     *
449
-     * @return EntityMap
450
-     */
451
-    protected function getNewEntityMap()
452
-    {
453
-        return new EntityMap();
454
-    }
455
-
456
-    /**
457
-     * Return the Singleton instance of the manager.
458
-     *
459
-     * @return Manager
460
-     */
461
-    public static function getInstance()
462
-    {
463
-        return static::$instance;
464
-    }
465
-
466
-    /**
467
-     * Return the Driver Manager's instance.
468
-     *
469
-     * @return \Analogue\ORM\Drivers\Manager
470
-     */
471
-    public function getDriverManager()
472
-    {
473
-        return $this->drivers;
474
-    }
475
-
476
-    /**
477
-     * Get the Repository instance for the given Entity.
478
-     *
479
-     * @param \Analogue\ORM\Mappable|string $entity
480
-     *
481
-     * @throws \InvalidArgumentException
482
-     * @throws MappingException
483
-     *
484
-     * @return \Analogue\ORM\Repository
485
-     */
486
-    public function repository($entity)
487
-    {
488
-        if (!is_string($entity)) {
489
-            $entity = get_class($entity);
490
-        }
491
-
492
-        // First we check if the repository is not already created.
493
-        if (array_key_exists($entity, $this->repositories)) {
494
-            return $this->repositories[$entity];
495
-        }
496
-
497
-        $this->repositories[$entity] = new Repository($this->mapper($entity));
498
-
499
-        return $this->repositories[$entity];
500
-    }
501
-
502
-    /**
503
-     * Return true is the object is registered as value object.
504
-     *
505
-     * @param mixed $object
506
-     *
507
-     * @return bool
508
-     */
509
-    public function isValueObject($object)
510
-    {
511
-        if (!is_string($object)) {
512
-            $object = get_class($object);
513
-        }
514
-
515
-        return array_key_exists($object, $this->valueClasses);
516
-    }
517
-
518
-    /**
519
-     * Get the Value Map for a given Value Object Class.
520
-     *
521
-     * @param string $valueObject
522
-     *
523
-     * @throws MappingException
524
-     *
525
-     * @return \Analogue\ORM\ValueMap
526
-     */
527
-    public function getValueMap($valueObject)
528
-    {
529
-        if (!is_string($valueObject)) {
530
-            $valueObject = get_class($valueObject);
531
-        }
532
-
533
-        if (!array_key_exists($valueObject, $this->valueClasses)) {
534
-            $this->registerValueObject($valueObject);
535
-        }
536
-
537
-        /** @var ValueMap $valueMap */
538
-        $valueMap = new $this->valueClasses[$valueObject]();
539
-
540
-        $valueMap->setClass($valueObject);
541
-
542
-        return $valueMap;
543
-    }
544
-
545
-    /**
546
-     * Register a Value Object.
547
-     *
548
-     * @param string $valueObject
549
-     * @param string $valueMap
550
-     *
551
-     * @throws MappingException
552
-     *
553
-     * @return void
554
-     */
555
-    public function registerValueObject($valueObject, $valueMap = null)
556
-    {
557
-        if (!is_string($valueObject)) {
558
-            $valueObject = get_class($valueObject);
559
-        }
560
-
561
-        if ($valueMap === null) {
562
-
563
-            // First, we'll look into registered namespaces for Entity Maps,
564
-            // if any. Then we'll fallback to the same namespace of the object
565
-            if (!$valueMap = $this->getMapFromNamespaces($valueObject)) {
566
-                $valueMap = $valueObject.'Map';
567
-            } else {
568
-                $valueMap = get_class($valueMap);
569
-            }
570
-        }
571
-
572
-        if (!class_exists($valueMap)) {
573
-            throw new MappingException("$valueMap doesn't exists");
574
-        }
575
-
576
-        $this->valueClasses[$valueObject] = $valueMap;
577
-    }
578
-
579
-    /**
580
-     * Instantiate a new Value Object instance.
581
-     *
582
-     * @param string $valueObject
583
-     *
584
-     * @return \Analogue\ORM\ValueObject
585
-     */
586
-    public function getValueObjectInstance($valueObject)
587
-    {
588
-        $prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($valueObject), $valueObject));
589
-
590
-        return $prototype;
591
-    }
592
-
593
-    /**
594
-     * Register Analogue Plugin.
595
-     *
596
-     * @param string $plugin class
597
-     *
598
-     * @return void
599
-     */
600
-    public function registerPlugin($plugin)
601
-    {
602
-        /** @var AnaloguePluginInterface $plugin */
603
-        $plugin = new $plugin($this);
604
-
605
-        $this->events = array_merge($this->events, $plugin->getCustomEvents());
606
-
607
-        $plugin->register();
608
-    }
609
-
610
-    /**
611
-     * Register event listeners that will be fired regardless the type
612
-     * of the entity.
613
-     *
614
-     * @param string   $event
615
-     * @param \Closure $callback
616
-     *
617
-     * @throws \LogicException
618
-     *
619
-     * @return void
620
-     */
621
-    public function registerGlobalEvent($event, $callback)
622
-    {
623
-        if (!in_array($event, $this->events, false)) {
624
-            throw new \LogicException("Analogue : Event $event doesn't exist");
625
-        }
626
-
627
-        $this->eventDispatcher->listen("analogue.{$event}.*", $callback);
628
-    }
629
-
630
-    /**
631
-     * Shortcut to Mapper store.
632
-     *
633
-     * @param mixed $entity
634
-     *
635
-     * @throws MappingException
636
-     * @throws \InvalidArgumentException
637
-     *
638
-     * @return mixed
639
-     */
640
-    public function store($entity)
641
-    {
642
-        return $this->mapper($entity)->store($entity);
643
-    }
644
-
645
-    /**
646
-     * Shortcut to Mapper delete.
647
-     *
648
-     * @param mixed $entity
649
-     *
650
-     * @throws MappingException
651
-     * @throws \InvalidArgumentException
652
-     *
653
-     * @return \Illuminate\Support\Collection|null
654
-     */
655
-    public function delete($entity)
656
-    {
657
-        return $this->mapper($entity)->delete($entity);
658
-    }
659
-
660
-    /**
661
-     * Shortcut to Mapper query.
662
-     *
663
-     * @param mixed $entity
664
-     *
665
-     * @throws MappingException
666
-     * @throws \InvalidArgumentException
667
-     *
668
-     * @return Query
669
-     */
670
-    public function query($entity)
671
-    {
672
-        return $this->mapper($entity)->query();
673
-    }
674
-
675
-    /**
676
-     * Shortcut to Mapper Global Query.
677
-     *
678
-     * @param mixed $entity
679
-     *
680
-     * @throws MappingException
681
-     * @throws \InvalidArgumentException
682
-     *
683
-     * @return Query
684
-     */
685
-    public function globalQuery($entity)
686
-    {
687
-        return $this->mapper($entity)->globalQuery();
688
-    }
689
-
690
-    /**
691
-     * @param array $morphMap
692
-     *
693
-     * @return $this
694
-     */
695
-    public function morphMap(array $morphMap)
696
-    {
697
-        $this->morphMap = $morphMap;
698
-
699
-        return $this;
700
-    }
701
-
702
-    /**
703
-     * @param string $class
704
-     *
705
-     * @return mixed
706
-     */
707
-    public function getMorphMap($class)
708
-    {
709
-        $key = array_search($class, $this->morphMap, false);
710
-
711
-        return $key !== false ? $key : $class;
712
-    }
24
+	/**
25
+	 * Manager instance.
26
+	 *
27
+	 * @var Manager
28
+	 */
29
+	protected static $instance;
30
+
31
+	/**
32
+	 * Driver Manager.
33
+	 *
34
+	 * @var \Analogue\ORM\Drivers\Manager
35
+	 */
36
+	protected $drivers;
37
+
38
+	/**
39
+	 * Registered entity classes and corresponding map objects.
40
+	 *
41
+	 * @var array
42
+	 */
43
+	protected $entityClasses = [];
44
+
45
+	/**
46
+	 * Key value store of ValueObject Classes and corresponding map classes.
47
+	 *
48
+	 * @var array|ValueMap[]
49
+	 */
50
+	protected $valueClasses = [];
51
+
52
+	/**
53
+	 * Morph map.
54
+	 */
55
+	protected $morphMap = [];
56
+
57
+	/**
58
+	 * Loaded Mappers.
59
+	 *
60
+	 * @var array
61
+	 */
62
+	protected $mappers = [];
63
+
64
+	/**
65
+	 * Loaded Repositories.
66
+	 *
67
+	 * @var array
68
+	 */
69
+	protected $repositories = [];
70
+
71
+	/**
72
+	 * Event dispatcher instance.
73
+	 *
74
+	 * @var \Illuminate\Contracts\Events\Dispatcher
75
+	 */
76
+	protected $eventDispatcher;
77
+
78
+	/**
79
+	 * Available Analogue Events.
80
+	 *
81
+	 * @var array
82
+	 */
83
+	protected $events = [
84
+		'initializing',
85
+		'initialized',
86
+		'store',
87
+		'stored',
88
+		'creating',
89
+		'created',
90
+		'updating',
91
+		'updated',
92
+		'deleting',
93
+		'deleted',
94
+	];
95
+
96
+	/**
97
+	 * If strictMode is set to true, Manager will throw
98
+	 * an exception if no entityMap class are registered
99
+	 * for a given entity class.
100
+	 *
101
+	 * @var bool
102
+	 */
103
+	protected $strictMode = true;
104
+
105
+	/**
106
+	 * We can add namespaces in this array where the manager
107
+	 * will look for when auto registering entityMaps.
108
+	 *
109
+	 * @var array
110
+	 */
111
+	protected $customMapNamespaces = [];
112
+
113
+	/**
114
+	 * @param \Analogue\ORM\Drivers\Manager $driverManager
115
+	 * @param Dispatcher                    $event
116
+	 */
117
+	public function __construct(DriverManager $driverManager, Dispatcher $event)
118
+	{
119
+		$this->drivers = $driverManager;
120
+
121
+		$this->eventDispatcher = $event;
122
+
123
+		static::$instance = $this;
124
+	}
125
+
126
+	/**
127
+	 * Create a mapper for a given entity (static alias).
128
+	 *
129
+	 * @param \Analogue\ORM\Mappable|string $entity
130
+	 * @param null|EntityMap                $entityMap
131
+	 *
132
+	 * @throws MappingException
133
+	 * @throws \InvalidArgumentException
134
+	 *
135
+	 * @return Mapper
136
+	 */
137
+	public static function getMapper($entity, $entityMap = null)
138
+	{
139
+		return static::$instance->mapper($entity, $entityMap);
140
+	}
141
+
142
+	/**
143
+	 * Create a mapper for a given entity.
144
+	 *
145
+	 * @param \Analogue\ORM\Mappable|string|array|\Traversable $entity
146
+	 * @param mixed                                            $entityMap
147
+	 *
148
+	 * @throws MappingException
149
+	 * @throws \InvalidArgumentException
150
+	 *
151
+	 * @return Mapper
152
+	 */
153
+	public function mapper($entity, $entityMap = null)
154
+	{
155
+		if ($entity instanceof Wrapper) {
156
+			throw new MappingException('Tried to instantiate mapper on wrapped Entity');
157
+		}
158
+
159
+		$entity = $this->resolveEntityClass($entity);
160
+
161
+		$entity = $this->getInverseMorphMap($entity);
162
+
163
+		// Return existing mapper instance if exists.
164
+		if (array_key_exists($entity, $this->mappers)) {
165
+			return $this->mappers[$entity];
166
+		} else {
167
+			return $this->buildMapper($entity, $entityMap);
168
+		}
169
+	}
170
+
171
+	/**
172
+	 * This method resolve entity class from mappable instances or iterators.
173
+	 *
174
+	 * @param \Analogue\ORM\Mappable|string|array|\Traversable $entity
175
+	 *
176
+	 * @throws \InvalidArgumentException
177
+	 *
178
+	 * @return string
179
+	 */
180
+	protected function resolveEntityClass($entity)
181
+	{
182
+		// We first check if the entity is traversable and we'll resolve
183
+		// the entity based on the first item of the object.
184
+		if ($this->isTraversable($entity)) {
185
+			if (!count($entity)) {
186
+				throw new \InvalidArgumentException('Length of Entity collection must be greater than 0');
187
+			}
188
+
189
+			$firstEntityItem = ($entity instanceof \Iterator)
190
+				? $entity->current()
191
+				: current($entity);
192
+
193
+			return $this->resolveEntityClass($firstEntityItem);
194
+		}
195
+
196
+		if (is_object($entity)) {
197
+			return get_class($entity);
198
+		}
199
+
200
+		if (is_string($entity)) {
201
+			return $entity;
202
+		}
203
+
204
+		throw new \InvalidArgumentException('Invalid entity type');
205
+	}
206
+
207
+	/**
208
+	 * @param string $key
209
+	 *
210
+	 * @return string
211
+	 */
212
+	public function getInverseMorphMap($key)
213
+	{
214
+		return array_key_exists($key, $this->morphMap) ? $this->morphMap[$key] : $key;
215
+	}
216
+
217
+	/**
218
+	 * Build a new Mapper instance for a given Entity.
219
+	 *
220
+	 * @param string $entity
221
+	 * @param        $entityMap
222
+	 *
223
+	 * @throws MappingException
224
+	 *
225
+	 * @return Mapper
226
+	 */
227
+	protected function buildMapper($entity, $entityMap)
228
+	{
229
+		// If an EntityMap hasn't been manually registered by the user
230
+		// register it at runtime.
231
+		if (!$this->isRegisteredEntity($entity)) {
232
+			$this->register($entity, $entityMap);
233
+		}
234
+
235
+		$entityMap = $this->entityClasses[$entity];
236
+
237
+		$factory = new MapperFactory($this->drivers, $this->eventDispatcher, $this);
238
+
239
+		$mapper = $factory->make($entity, $entityMap);
240
+
241
+		$this->mappers[$entity] = $mapper;
242
+
243
+		// At this point we can safely call the boot() method on the entityMap as
244
+		// the mapper is now instantiated & registered within the manager.
245
+
246
+		$mapper->getEntityMap()->boot();
247
+
248
+		return $mapper;
249
+	}
250
+
251
+	/**
252
+	 * Check if the entity is already registered.
253
+	 *
254
+	 * @param string|Entity $entity
255
+	 *
256
+	 * @return bool
257
+	 */
258
+	public function isRegisteredEntity($entity)
259
+	{
260
+		if (!is_string($entity)) {
261
+			$entity = get_class($entity);
262
+		}
263
+
264
+		return array_key_exists($entity, $this->entityClasses);
265
+	}
266
+
267
+	/**
268
+	 * Return an array containing registered entities & entityMap instances.
269
+	 *
270
+	 * @return array
271
+	 */
272
+	public function getRegisteredEntities()
273
+	{
274
+		return $this->entityClasses;
275
+	}
276
+
277
+	/**
278
+	 * Check if a value class is already registered.
279
+	 *
280
+	 * @param string|sdtClass $object
281
+	 *
282
+	 * @return bool
283
+	 */
284
+	public function isRegisteredValueObject($object)
285
+	{
286
+		if (!is_string($object)) {
287
+			$object = get_class($object);
288
+		}
289
+
290
+		return array_key_exists($object, $this->valueClasses);
291
+	}
292
+
293
+	/**
294
+	 * Return true if an object is an array or iterator.
295
+	 *
296
+	 * @param mixed $argument
297
+	 *
298
+	 * @return bool
299
+	 */
300
+	public function isTraversable($argument)
301
+	{
302
+		return $argument instanceof \Traversable || is_array($argument);
303
+	}
304
+
305
+	/**
306
+	 * Set strict mode for entityMap instantiation.
307
+	 *
308
+	 * @param bool $mode
309
+	 */
310
+	public function setStrictMode($mode)
311
+	{
312
+		$this->strictMode = $mode;
313
+	}
314
+
315
+	/**
316
+	 * Register a namespace in where Analogue
317
+	 * will scan for EntityMaps & ValueMaps.
318
+	 *
319
+	 * @param string $namespace
320
+	 *
321
+	 * @return void
322
+	 */
323
+	public function registerMapNamespace($namespace)
324
+	{
325
+		// Add a trailing antislash to namespace if not present
326
+		if (substr('testers', -1) != '\\') {
327
+			$namespace = $namespace.'\\';
328
+		}
329
+
330
+		$this->customMapNamespaces[] = $namespace;
331
+	}
332
+
333
+	/**
334
+	 * Register an entity.
335
+	 *
336
+	 * @param string|\Analogue\ORM\Mappable $entity    entity's class name
337
+	 * @param string|EntityMap              $entityMap map's class name
338
+	 *
339
+	 * @throws MappingException
340
+	 *
341
+	 * @return void
342
+	 */
343
+	public function register($entity, $entityMap = null)
344
+	{
345
+		// If an object is provider, get the class name from it
346
+		if (!is_string($entity)) {
347
+			$entity = get_class($entity);
348
+		}
349
+
350
+		if ($this->isRegisteredEntity($entity)) {
351
+			throw new MappingException("Entity $entity is already registered.");
352
+		}
353
+
354
+		if (!class_exists($entity)) {
355
+			throw new MappingException("Class $entity does not exists");
356
+		}
357
+
358
+		if ($entityMap === null) {
359
+			$entityMap = $this->getEntityMapInstanceFor($entity);
360
+		}
361
+
362
+		if (is_string($entityMap)) {
363
+			$entityMap = new $entityMap();
364
+		}
365
+
366
+		if (!$entityMap instanceof EntityMap) {
367
+			throw new MappingException(get_class($entityMap).' must be an instance of EntityMap.');
368
+		}
369
+
370
+		$entityMap->setClass($entity);
371
+
372
+		$this->entityClasses[$entity] = $entityMap;
373
+	}
374
+
375
+	/**
376
+	 * Get the entity map instance for a custom entity.
377
+	 *
378
+	 * @param string $entity
379
+	 *
380
+	 * @return \Analogue\ORM\EntityMap
381
+	 */
382
+	protected function getEntityMapInstanceFor($entity)
383
+	{
384
+		if (class_exists($entity.'Map')) {
385
+			$map = $entity.'Map';
386
+			$map = new $map();
387
+
388
+			return $map;
389
+		}
390
+
391
+		if ($map = $this->getMapFromNamespaces($entity)) {
392
+			return $map;
393
+		}
394
+
395
+		if ($this->strictMode) {
396
+			throw new EntityMapNotFoundException("No Map registered for $entity");
397
+		}
398
+
399
+		$map = $this->getNewEntityMap();
400
+
401
+		return $map;
402
+	}
403
+
404
+	/**
405
+	 * Scan through registered custom namespace
406
+	 * for an Entity/ValueMap.
407
+	 *
408
+	 * @param string $class
409
+	 *
410
+	 * @return ValueMap|EntityMap|bool
411
+	 */
412
+	protected function getMapFromNamespaces($class)
413
+	{
414
+		foreach ($this->customMapNamespaces as $namespace) {
415
+			if ($map = $this->findMapInNamespace($class, $namespace)) {
416
+				return $map;
417
+			}
418
+		}
419
+
420
+		return false;
421
+	}
422
+
423
+	/**
424
+	 * Look in a custom namespace for an Entity/ValueMap.
425
+	 *
426
+	 * @param string $class
427
+	 * @param string $namespace
428
+	 *
429
+	 * @return ValueMap|EntityMap|bool
430
+	 */
431
+	protected function findMapInNamespace($class, $namespace)
432
+	{
433
+		$parts = explode('\\', $class);
434
+
435
+		$baseClass = $parts[count($parts) - 1];
436
+
437
+		$expectedClass = $namespace.$baseClass.'Map';
438
+
439
+		if (class_exists($expectedClass)) {
440
+			return new $expectedClass();
441
+		}
442
+
443
+		return false;
444
+	}
445
+
446
+	/**
447
+	 * Dynamically create an entity map for a custom entity class.
448
+	 *
449
+	 * @return EntityMap
450
+	 */
451
+	protected function getNewEntityMap()
452
+	{
453
+		return new EntityMap();
454
+	}
455
+
456
+	/**
457
+	 * Return the Singleton instance of the manager.
458
+	 *
459
+	 * @return Manager
460
+	 */
461
+	public static function getInstance()
462
+	{
463
+		return static::$instance;
464
+	}
465
+
466
+	/**
467
+	 * Return the Driver Manager's instance.
468
+	 *
469
+	 * @return \Analogue\ORM\Drivers\Manager
470
+	 */
471
+	public function getDriverManager()
472
+	{
473
+		return $this->drivers;
474
+	}
475
+
476
+	/**
477
+	 * Get the Repository instance for the given Entity.
478
+	 *
479
+	 * @param \Analogue\ORM\Mappable|string $entity
480
+	 *
481
+	 * @throws \InvalidArgumentException
482
+	 * @throws MappingException
483
+	 *
484
+	 * @return \Analogue\ORM\Repository
485
+	 */
486
+	public function repository($entity)
487
+	{
488
+		if (!is_string($entity)) {
489
+			$entity = get_class($entity);
490
+		}
491
+
492
+		// First we check if the repository is not already created.
493
+		if (array_key_exists($entity, $this->repositories)) {
494
+			return $this->repositories[$entity];
495
+		}
496
+
497
+		$this->repositories[$entity] = new Repository($this->mapper($entity));
498
+
499
+		return $this->repositories[$entity];
500
+	}
501
+
502
+	/**
503
+	 * Return true is the object is registered as value object.
504
+	 *
505
+	 * @param mixed $object
506
+	 *
507
+	 * @return bool
508
+	 */
509
+	public function isValueObject($object)
510
+	{
511
+		if (!is_string($object)) {
512
+			$object = get_class($object);
513
+		}
514
+
515
+		return array_key_exists($object, $this->valueClasses);
516
+	}
517
+
518
+	/**
519
+	 * Get the Value Map for a given Value Object Class.
520
+	 *
521
+	 * @param string $valueObject
522
+	 *
523
+	 * @throws MappingException
524
+	 *
525
+	 * @return \Analogue\ORM\ValueMap
526
+	 */
527
+	public function getValueMap($valueObject)
528
+	{
529
+		if (!is_string($valueObject)) {
530
+			$valueObject = get_class($valueObject);
531
+		}
532
+
533
+		if (!array_key_exists($valueObject, $this->valueClasses)) {
534
+			$this->registerValueObject($valueObject);
535
+		}
536
+
537
+		/** @var ValueMap $valueMap */
538
+		$valueMap = new $this->valueClasses[$valueObject]();
539
+
540
+		$valueMap->setClass($valueObject);
541
+
542
+		return $valueMap;
543
+	}
544
+
545
+	/**
546
+	 * Register a Value Object.
547
+	 *
548
+	 * @param string $valueObject
549
+	 * @param string $valueMap
550
+	 *
551
+	 * @throws MappingException
552
+	 *
553
+	 * @return void
554
+	 */
555
+	public function registerValueObject($valueObject, $valueMap = null)
556
+	{
557
+		if (!is_string($valueObject)) {
558
+			$valueObject = get_class($valueObject);
559
+		}
560
+
561
+		if ($valueMap === null) {
562
+
563
+			// First, we'll look into registered namespaces for Entity Maps,
564
+			// if any. Then we'll fallback to the same namespace of the object
565
+			if (!$valueMap = $this->getMapFromNamespaces($valueObject)) {
566
+				$valueMap = $valueObject.'Map';
567
+			} else {
568
+				$valueMap = get_class($valueMap);
569
+			}
570
+		}
571
+
572
+		if (!class_exists($valueMap)) {
573
+			throw new MappingException("$valueMap doesn't exists");
574
+		}
575
+
576
+		$this->valueClasses[$valueObject] = $valueMap;
577
+	}
578
+
579
+	/**
580
+	 * Instantiate a new Value Object instance.
581
+	 *
582
+	 * @param string $valueObject
583
+	 *
584
+	 * @return \Analogue\ORM\ValueObject
585
+	 */
586
+	public function getValueObjectInstance($valueObject)
587
+	{
588
+		$prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($valueObject), $valueObject));
589
+
590
+		return $prototype;
591
+	}
592
+
593
+	/**
594
+	 * Register Analogue Plugin.
595
+	 *
596
+	 * @param string $plugin class
597
+	 *
598
+	 * @return void
599
+	 */
600
+	public function registerPlugin($plugin)
601
+	{
602
+		/** @var AnaloguePluginInterface $plugin */
603
+		$plugin = new $plugin($this);
604
+
605
+		$this->events = array_merge($this->events, $plugin->getCustomEvents());
606
+
607
+		$plugin->register();
608
+	}
609
+
610
+	/**
611
+	 * Register event listeners that will be fired regardless the type
612
+	 * of the entity.
613
+	 *
614
+	 * @param string   $event
615
+	 * @param \Closure $callback
616
+	 *
617
+	 * @throws \LogicException
618
+	 *
619
+	 * @return void
620
+	 */
621
+	public function registerGlobalEvent($event, $callback)
622
+	{
623
+		if (!in_array($event, $this->events, false)) {
624
+			throw new \LogicException("Analogue : Event $event doesn't exist");
625
+		}
626
+
627
+		$this->eventDispatcher->listen("analogue.{$event}.*", $callback);
628
+	}
629
+
630
+	/**
631
+	 * Shortcut to Mapper store.
632
+	 *
633
+	 * @param mixed $entity
634
+	 *
635
+	 * @throws MappingException
636
+	 * @throws \InvalidArgumentException
637
+	 *
638
+	 * @return mixed
639
+	 */
640
+	public function store($entity)
641
+	{
642
+		return $this->mapper($entity)->store($entity);
643
+	}
644
+
645
+	/**
646
+	 * Shortcut to Mapper delete.
647
+	 *
648
+	 * @param mixed $entity
649
+	 *
650
+	 * @throws MappingException
651
+	 * @throws \InvalidArgumentException
652
+	 *
653
+	 * @return \Illuminate\Support\Collection|null
654
+	 */
655
+	public function delete($entity)
656
+	{
657
+		return $this->mapper($entity)->delete($entity);
658
+	}
659
+
660
+	/**
661
+	 * Shortcut to Mapper query.
662
+	 *
663
+	 * @param mixed $entity
664
+	 *
665
+	 * @throws MappingException
666
+	 * @throws \InvalidArgumentException
667
+	 *
668
+	 * @return Query
669
+	 */
670
+	public function query($entity)
671
+	{
672
+		return $this->mapper($entity)->query();
673
+	}
674
+
675
+	/**
676
+	 * Shortcut to Mapper Global Query.
677
+	 *
678
+	 * @param mixed $entity
679
+	 *
680
+	 * @throws MappingException
681
+	 * @throws \InvalidArgumentException
682
+	 *
683
+	 * @return Query
684
+	 */
685
+	public function globalQuery($entity)
686
+	{
687
+		return $this->mapper($entity)->globalQuery();
688
+	}
689
+
690
+	/**
691
+	 * @param array $morphMap
692
+	 *
693
+	 * @return $this
694
+	 */
695
+	public function morphMap(array $morphMap)
696
+	{
697
+		$this->morphMap = $morphMap;
698
+
699
+		return $this;
700
+	}
701
+
702
+	/**
703
+	 * @param string $class
704
+	 *
705
+	 * @return mixed
706
+	 */
707
+	public function getMorphMap($class)
708
+	{
709
+		$key = array_search($class, $this->morphMap, false);
710
+
711
+		return $key !== false ? $key : $class;
712
+	}
713 713
 }
Please login to merge, or discard this patch.
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -11,7 +11,6 @@
 block discarded – undo
11 11
 use Analogue\ORM\Repository;
12 12
 use Analogue\ORM\System\Wrappers\Wrapper;
13 13
 use Analogue\ORM\ValueMap;
14
-use Exception;
15 14
 use Illuminate\Contracts\Events\Dispatcher;
16 15
 use Illuminate\Support\Collection;
17 16
 
Please login to merge, or discard this patch.
src/System/ResultBuilder.php 3 patches
Doc Comments   -1 removed lines patch added patch discarded remove patch
@@ -38,7 +38,6 @@
 block discarded – undo
38 38
 
39 39
     /**
40 40
      * @param Mapper $defaultMapper
41
-     * @param array  $eagerLoads
42 41
      */
43 42
     public function __construct(Mapper $defaultMapper)
44 43
     {
Please login to merge, or discard this patch.
Indentation   +340 added lines, -340 removed lines patch added patch discarded remove patch
@@ -7,344 +7,344 @@
 block discarded – undo
7 7
 
8 8
 class ResultBuilder
9 9
 {
10
-    /**
11
-     * The default mapper used to build entities with.
12
-     *
13
-     * @var \Analogue\ORM\System\Mapper
14
-     */
15
-    protected $defaultMapper;
16
-
17
-    /**
18
-     * Relations that will be eager loaded on this query.
19
-     *
20
-     * @var array
21
-     */
22
-    protected $eagerLoads;
23
-
24
-    /**
25
-     * The Entity Map for the entity to build.
26
-     *
27
-     * @var \Analogue\ORM\EntityMap
28
-     */
29
-    protected $entityMap;
30
-
31
-    /**
32
-     * An array of builders used by this class to build necessary
33
-     * entities for each result type.
34
-     *
35
-     * @var array
36
-     */
37
-    protected $builders = [];
38
-
39
-    /**
40
-     * @param Mapper $defaultMapper
41
-     * @param array  $eagerLoads
42
-     */
43
-    public function __construct(Mapper $defaultMapper)
44
-    {
45
-        $this->defaultMapper = $defaultMapper;
46
-        $this->entityMap = $defaultMapper->getEntityMap();
47
-    }
48
-
49
-    /**
50
-     * Convert a result set into an array of entities.
51
-     *
52
-     * @param array $results
53
-     * @param array $eagerLoads name of the relation to be eager loaded on the Entities
54
-     *
55
-     * @return \Illuminate\Support\Collection
56
-     */
57
-    public function build(array $results, array $eagerLoads)
58
-    {
59
-        // Parse embedded relations and build corresponding entities using the default
60
-        // mapper.
61
-        $results = $this->buildEmbeddedRelationships($results);
62
-
63
-        // Launch the queries related to eager loads, and match the
64
-        // current result set to these loaded relationships.
65
-        $results = $this->queryEagerLoadedRelationships($results, $eagerLoads);
66
-
67
-        // Note : Maybe we could use a PolymorphicResultBuilder, which would
68
-        // be shared by both STI and polymorphic relations, as they share the
69
-        // same process.
70
-
71
-        switch ($this->entityMap->getInheritanceType()) {
72
-            case 'single_table':
73
-                return $this->buildUsingSingleTableInheritance($results);
74
-                break;
75
-
76
-            default:
77
-                return $this->buildWithDefaultMapper($results);
78
-                break;
79
-        }
80
-    }
81
-
82
-    /**
83
-     * Build embedded objects and match them to the result set.
84
-     *
85
-     * @param array $results
86
-     *
87
-     * @return array
88
-     */
89
-    protected function buildEmbeddedRelationships(array $results) : array
90
-    {
91
-        $entityMap = $this->entityMap;
92
-        $instance = $this->defaultMapper->newInstance();
93
-        $embeddeds = $entityMap->getEmbeddedRelationships();
94
-
95
-        foreach ($embeddeds as $embedded) {
96
-            $results = $entityMap->$embedded($instance)->match($results, $embedded);
97
-        }
98
-
99
-        return $results;
100
-    }
101
-
102
-    /**
103
-     * Launch queries on eager loaded relationships.
104
-     *
105
-     * @return array
106
-     */
107
-    protected function queryEagerLoadedRelationships(array $results, array $eagerLoads) : array
108
-    {
109
-        $this->eagerLoads = $this->parseRelations($eagerLoads);
110
-
111
-        return $this->eagerLoadRelations($results);
112
-    }
113
-
114
-    /**
115
-     * Parse a list of relations into individuals.
116
-     *
117
-     * @param array $relations
118
-     *
119
-     * @return array
120
-     */
121
-    protected function parseRelations(array $relations)
122
-    {
123
-        $results = [];
124
-
125
-        foreach ($relations as $name => $constraints) {
126
-            // If the "relation" value is actually a numeric key, we can assume that no
127
-            // constraints have been specified for the eager load and we'll just put
128
-            // an empty Closure with the loader so that we can treat all the same.
129
-            if (is_numeric($name)) {
130
-                $f = function () {
131
-                };
132
-
133
-                list($name, $constraints) = [$constraints, $f];
134
-            }
135
-
136
-            // We need to separate out any nested includes. Which allows the developers
137
-            // to load deep relationships using "dots" without stating each level of
138
-            // the relationship with its own key in the array of eager load names.
139
-            $results = $this->parseNested($name, $results);
140
-
141
-            $results[$name] = $constraints;
142
-        }
143
-
144
-        return $results;
145
-    }
146
-
147
-    /**
148
-     * Parse the nested relationships in a relation.
149
-     *
150
-     * @param string $name
151
-     * @param array  $results
152
-     *
153
-     * @return array
154
-     */
155
-    protected function parseNested($name, $results)
156
-    {
157
-        $progress = [];
158
-
159
-        // If the relation has already been set on the result array, we will not set it
160
-        // again, since that would override any constraints that were already placed
161
-        // on the relationships. We will only set the ones that are not specified.
162
-        foreach (explode('.', $name) as $segment) {
163
-            $progress[] = $segment;
164
-
165
-            if (!isset($results[$last = implode('.', $progress)])) {
166
-                $results[$last] = function () {
167
-                };
168
-            }
169
-        }
170
-
171
-        return $results;
172
-    }
173
-
174
-    /**
175
-     * Eager load the relationships on a result set.
176
-     *
177
-     * @param array $results
178
-     *
179
-     * @return array
180
-     */
181
-    public function eagerLoadRelations(array $results)
182
-    {
183
-        foreach ($this->eagerLoads as $name => $constraints) {
184
-
185
-            // For nested eager loads we'll skip loading them here and they will be set as an
186
-            // eager load on the query to retrieve the relation so that they will be eager
187
-            // loaded on that query, because that is where they get hydrated as models.
188
-            if (strpos($name, '.') === false) {
189
-                $results = $this->loadRelation($results, $name, $constraints);
190
-            }
191
-        }
192
-
193
-        return $results;
194
-    }
195
-
196
-    /**
197
-     * Eagerly load the relationship on a set of entities.
198
-     *
199
-     * @param array    $results
200
-     * @param string   $name
201
-     * @param \Closure $constraints
202
-     *
203
-     * @return array
204
-     */
205
-    protected function loadRelation(array $results, $name, Closure $constraints) : array
206
-    {
207
-        // First we will "back up" the existing where conditions on the query so we can
208
-        // add our eager constraints. Then we will merge the wheres that were on the
209
-        // query back to it in order that any where conditions might be specified.
210
-        $relation = $this->getRelation($name);
211
-
212
-        $relation->addEagerConstraints($results);
213
-
214
-        call_user_func($constraints, $relation);
215
-
216
-        // Once we have the results, we just match those back up to their parent models
217
-        // using the relationship instance. Then we just return the finished arrays
218
-        // of models which have been eagerly hydrated and are readied for return.
219
-
220
-        return $relation->match($results, $name);
221
-    }
222
-
223
-    /**
224
-     * Get the relation instance for the given relation name.
225
-     *
226
-     * @param string $relation
227
-     *
228
-     * @return \Analogue\ORM\Relationships\Relationship
229
-     */
230
-    public function getRelation($relation)
231
-    {
232
-        // We want to run a relationship query without any constrains so that we will
233
-        // not have to remove these where clauses manually which gets really hacky
234
-        // and is error prone while we remove the developer's own where clauses.
235
-        $query = Relationship::noConstraints(function () use ($relation) {
236
-            return $this->entityMap->$relation($this->defaultMapper->newInstance());
237
-        });
238
-
239
-        $nested = $this->nestedRelations($relation);
240
-
241
-        // If there are nested relationships set on the query, we will put those onto
242
-        // the query instances so that they can be handled after this relationship
243
-        // is loaded. In this way they will all trickle down as they are loaded.
244
-        if (count($nested) > 0) {
245
-            $query->getQuery()->with($nested);
246
-        }
247
-
248
-        return $query;
249
-    }
250
-
251
-    /**
252
-     * Get the deeply nested relations for a given top-level relation.
253
-     *
254
-     * @param string $relation
255
-     *
256
-     * @return array
257
-     */
258
-    protected function nestedRelations($relation)
259
-    {
260
-        $nested = [];
261
-
262
-        // We are basically looking for any relationships that are nested deeper than
263
-        // the given top-level relationship. We will just check for any relations
264
-        // that start with the given top relations and adds them to our arrays.
265
-        foreach ($this->eagerLoads as $name => $constraints) {
266
-            if ($this->isNested($name, $relation)) {
267
-                $nested[substr($name, strlen($relation.'.'))] = $constraints;
268
-            }
269
-        }
270
-
271
-        return $nested;
272
-    }
273
-
274
-    /**
275
-     * Determine if the relationship is nested.
276
-     *
277
-     * @param string $name
278
-     * @param string $relation
279
-     *
280
-     * @return bool
281
-     */
282
-    protected function isNested($name, $relation)
283
-    {
284
-        $dots = str_contains($name, '.');
285
-
286
-        return $dots && starts_with($name, $relation.'.');
287
-    }
288
-
289
-    /**
290
-     * Build an entity from results, using the default mapper on this builder.
291
-     * This is the default build plan when no table inheritance is being used.
292
-     *
293
-     * @param array $results
294
-     *
295
-     * @return Collection
296
-     */
297
-    protected function buildWithDefaultMapper(array $results)
298
-    {
299
-        $builder = new EntityBuilder($this->defaultMapper, array_keys($this->eagerLoads));
300
-
301
-        return collect($results)->map(function ($item, $key) use ($builder) {
302
-            return $builder->build($item);
303
-        })->all();
304
-    }
305
-
306
-    /**
307
-     * Build an entity from results, using single table inheritance.
308
-     *
309
-     * @param array $results
310
-     *
311
-     * @return Collection
312
-     */
313
-    protected function buildUsingSingleTableInheritance(array $results)
314
-    {
315
-        return collect($results)->map(function ($item, $key) {
316
-            $builder = $this->builderForResult($item);
317
-
318
-            return $builder->build($item);
319
-        })->all();
320
-    }
321
-
322
-    /**
323
-     * Given a result array, return the entity builder needed to correctly
324
-     * build the result into an entity. If no getDiscriminatorColumnMap property
325
-     * has been defined on the EntityMap, we'll assume that the value stored in
326
-     * the $type column is the fully qualified class name of the entity and
327
-     * we'll use it instead.
328
-     *
329
-     * @param array $result
330
-     *
331
-     * @return EntityBuilder
332
-     */
333
-    protected function builderForResult(array $result)
334
-    {
335
-        $type = $result[$this->entityMap->getDiscriminatorColumn()];
336
-
337
-        $columnMap = $this->entityMap->getDiscriminatorColumnMap();
338
-
339
-        $class = isset($columnMap[$type]) ? $columnMap[$type] : $type;
340
-
341
-        if (!isset($this->builders[$type])) {
342
-            $this->builders[$type] = new EntityBuilder(
343
-                Manager::getInstance()->mapper($class),
344
-                array_keys($this->eagerLoads)
345
-            );
346
-        }
347
-
348
-        return $this->builders[$type];
349
-    }
10
+	/**
11
+	 * The default mapper used to build entities with.
12
+	 *
13
+	 * @var \Analogue\ORM\System\Mapper
14
+	 */
15
+	protected $defaultMapper;
16
+
17
+	/**
18
+	 * Relations that will be eager loaded on this query.
19
+	 *
20
+	 * @var array
21
+	 */
22
+	protected $eagerLoads;
23
+
24
+	/**
25
+	 * The Entity Map for the entity to build.
26
+	 *
27
+	 * @var \Analogue\ORM\EntityMap
28
+	 */
29
+	protected $entityMap;
30
+
31
+	/**
32
+	 * An array of builders used by this class to build necessary
33
+	 * entities for each result type.
34
+	 *
35
+	 * @var array
36
+	 */
37
+	protected $builders = [];
38
+
39
+	/**
40
+	 * @param Mapper $defaultMapper
41
+	 * @param array  $eagerLoads
42
+	 */
43
+	public function __construct(Mapper $defaultMapper)
44
+	{
45
+		$this->defaultMapper = $defaultMapper;
46
+		$this->entityMap = $defaultMapper->getEntityMap();
47
+	}
48
+
49
+	/**
50
+	 * Convert a result set into an array of entities.
51
+	 *
52
+	 * @param array $results
53
+	 * @param array $eagerLoads name of the relation to be eager loaded on the Entities
54
+	 *
55
+	 * @return \Illuminate\Support\Collection
56
+	 */
57
+	public function build(array $results, array $eagerLoads)
58
+	{
59
+		// Parse embedded relations and build corresponding entities using the default
60
+		// mapper.
61
+		$results = $this->buildEmbeddedRelationships($results);
62
+
63
+		// Launch the queries related to eager loads, and match the
64
+		// current result set to these loaded relationships.
65
+		$results = $this->queryEagerLoadedRelationships($results, $eagerLoads);
66
+
67
+		// Note : Maybe we could use a PolymorphicResultBuilder, which would
68
+		// be shared by both STI and polymorphic relations, as they share the
69
+		// same process.
70
+
71
+		switch ($this->entityMap->getInheritanceType()) {
72
+			case 'single_table':
73
+				return $this->buildUsingSingleTableInheritance($results);
74
+				break;
75
+
76
+			default:
77
+				return $this->buildWithDefaultMapper($results);
78
+				break;
79
+		}
80
+	}
81
+
82
+	/**
83
+	 * Build embedded objects and match them to the result set.
84
+	 *
85
+	 * @param array $results
86
+	 *
87
+	 * @return array
88
+	 */
89
+	protected function buildEmbeddedRelationships(array $results) : array
90
+	{
91
+		$entityMap = $this->entityMap;
92
+		$instance = $this->defaultMapper->newInstance();
93
+		$embeddeds = $entityMap->getEmbeddedRelationships();
94
+
95
+		foreach ($embeddeds as $embedded) {
96
+			$results = $entityMap->$embedded($instance)->match($results, $embedded);
97
+		}
98
+
99
+		return $results;
100
+	}
101
+
102
+	/**
103
+	 * Launch queries on eager loaded relationships.
104
+	 *
105
+	 * @return array
106
+	 */
107
+	protected function queryEagerLoadedRelationships(array $results, array $eagerLoads) : array
108
+	{
109
+		$this->eagerLoads = $this->parseRelations($eagerLoads);
110
+
111
+		return $this->eagerLoadRelations($results);
112
+	}
113
+
114
+	/**
115
+	 * Parse a list of relations into individuals.
116
+	 *
117
+	 * @param array $relations
118
+	 *
119
+	 * @return array
120
+	 */
121
+	protected function parseRelations(array $relations)
122
+	{
123
+		$results = [];
124
+
125
+		foreach ($relations as $name => $constraints) {
126
+			// If the "relation" value is actually a numeric key, we can assume that no
127
+			// constraints have been specified for the eager load and we'll just put
128
+			// an empty Closure with the loader so that we can treat all the same.
129
+			if (is_numeric($name)) {
130
+				$f = function () {
131
+				};
132
+
133
+				list($name, $constraints) = [$constraints, $f];
134
+			}
135
+
136
+			// We need to separate out any nested includes. Which allows the developers
137
+			// to load deep relationships using "dots" without stating each level of
138
+			// the relationship with its own key in the array of eager load names.
139
+			$results = $this->parseNested($name, $results);
140
+
141
+			$results[$name] = $constraints;
142
+		}
143
+
144
+		return $results;
145
+	}
146
+
147
+	/**
148
+	 * Parse the nested relationships in a relation.
149
+	 *
150
+	 * @param string $name
151
+	 * @param array  $results
152
+	 *
153
+	 * @return array
154
+	 */
155
+	protected function parseNested($name, $results)
156
+	{
157
+		$progress = [];
158
+
159
+		// If the relation has already been set on the result array, we will not set it
160
+		// again, since that would override any constraints that were already placed
161
+		// on the relationships. We will only set the ones that are not specified.
162
+		foreach (explode('.', $name) as $segment) {
163
+			$progress[] = $segment;
164
+
165
+			if (!isset($results[$last = implode('.', $progress)])) {
166
+				$results[$last] = function () {
167
+				};
168
+			}
169
+		}
170
+
171
+		return $results;
172
+	}
173
+
174
+	/**
175
+	 * Eager load the relationships on a result set.
176
+	 *
177
+	 * @param array $results
178
+	 *
179
+	 * @return array
180
+	 */
181
+	public function eagerLoadRelations(array $results)
182
+	{
183
+		foreach ($this->eagerLoads as $name => $constraints) {
184
+
185
+			// For nested eager loads we'll skip loading them here and they will be set as an
186
+			// eager load on the query to retrieve the relation so that they will be eager
187
+			// loaded on that query, because that is where they get hydrated as models.
188
+			if (strpos($name, '.') === false) {
189
+				$results = $this->loadRelation($results, $name, $constraints);
190
+			}
191
+		}
192
+
193
+		return $results;
194
+	}
195
+
196
+	/**
197
+	 * Eagerly load the relationship on a set of entities.
198
+	 *
199
+	 * @param array    $results
200
+	 * @param string   $name
201
+	 * @param \Closure $constraints
202
+	 *
203
+	 * @return array
204
+	 */
205
+	protected function loadRelation(array $results, $name, Closure $constraints) : array
206
+	{
207
+		// First we will "back up" the existing where conditions on the query so we can
208
+		// add our eager constraints. Then we will merge the wheres that were on the
209
+		// query back to it in order that any where conditions might be specified.
210
+		$relation = $this->getRelation($name);
211
+
212
+		$relation->addEagerConstraints($results);
213
+
214
+		call_user_func($constraints, $relation);
215
+
216
+		// Once we have the results, we just match those back up to their parent models
217
+		// using the relationship instance. Then we just return the finished arrays
218
+		// of models which have been eagerly hydrated and are readied for return.
219
+
220
+		return $relation->match($results, $name);
221
+	}
222
+
223
+	/**
224
+	 * Get the relation instance for the given relation name.
225
+	 *
226
+	 * @param string $relation
227
+	 *
228
+	 * @return \Analogue\ORM\Relationships\Relationship
229
+	 */
230
+	public function getRelation($relation)
231
+	{
232
+		// We want to run a relationship query without any constrains so that we will
233
+		// not have to remove these where clauses manually which gets really hacky
234
+		// and is error prone while we remove the developer's own where clauses.
235
+		$query = Relationship::noConstraints(function () use ($relation) {
236
+			return $this->entityMap->$relation($this->defaultMapper->newInstance());
237
+		});
238
+
239
+		$nested = $this->nestedRelations($relation);
240
+
241
+		// If there are nested relationships set on the query, we will put those onto
242
+		// the query instances so that they can be handled after this relationship
243
+		// is loaded. In this way they will all trickle down as they are loaded.
244
+		if (count($nested) > 0) {
245
+			$query->getQuery()->with($nested);
246
+		}
247
+
248
+		return $query;
249
+	}
250
+
251
+	/**
252
+	 * Get the deeply nested relations for a given top-level relation.
253
+	 *
254
+	 * @param string $relation
255
+	 *
256
+	 * @return array
257
+	 */
258
+	protected function nestedRelations($relation)
259
+	{
260
+		$nested = [];
261
+
262
+		// We are basically looking for any relationships that are nested deeper than
263
+		// the given top-level relationship. We will just check for any relations
264
+		// that start with the given top relations and adds them to our arrays.
265
+		foreach ($this->eagerLoads as $name => $constraints) {
266
+			if ($this->isNested($name, $relation)) {
267
+				$nested[substr($name, strlen($relation.'.'))] = $constraints;
268
+			}
269
+		}
270
+
271
+		return $nested;
272
+	}
273
+
274
+	/**
275
+	 * Determine if the relationship is nested.
276
+	 *
277
+	 * @param string $name
278
+	 * @param string $relation
279
+	 *
280
+	 * @return bool
281
+	 */
282
+	protected function isNested($name, $relation)
283
+	{
284
+		$dots = str_contains($name, '.');
285
+
286
+		return $dots && starts_with($name, $relation.'.');
287
+	}
288
+
289
+	/**
290
+	 * Build an entity from results, using the default mapper on this builder.
291
+	 * This is the default build plan when no table inheritance is being used.
292
+	 *
293
+	 * @param array $results
294
+	 *
295
+	 * @return Collection
296
+	 */
297
+	protected function buildWithDefaultMapper(array $results)
298
+	{
299
+		$builder = new EntityBuilder($this->defaultMapper, array_keys($this->eagerLoads));
300
+
301
+		return collect($results)->map(function ($item, $key) use ($builder) {
302
+			return $builder->build($item);
303
+		})->all();
304
+	}
305
+
306
+	/**
307
+	 * Build an entity from results, using single table inheritance.
308
+	 *
309
+	 * @param array $results
310
+	 *
311
+	 * @return Collection
312
+	 */
313
+	protected function buildUsingSingleTableInheritance(array $results)
314
+	{
315
+		return collect($results)->map(function ($item, $key) {
316
+			$builder = $this->builderForResult($item);
317
+
318
+			return $builder->build($item);
319
+		})->all();
320
+	}
321
+
322
+	/**
323
+	 * Given a result array, return the entity builder needed to correctly
324
+	 * build the result into an entity. If no getDiscriminatorColumnMap property
325
+	 * has been defined on the EntityMap, we'll assume that the value stored in
326
+	 * the $type column is the fully qualified class name of the entity and
327
+	 * we'll use it instead.
328
+	 *
329
+	 * @param array $result
330
+	 *
331
+	 * @return EntityBuilder
332
+	 */
333
+	protected function builderForResult(array $result)
334
+	{
335
+		$type = $result[$this->entityMap->getDiscriminatorColumn()];
336
+
337
+		$columnMap = $this->entityMap->getDiscriminatorColumnMap();
338
+
339
+		$class = isset($columnMap[$type]) ? $columnMap[$type] : $type;
340
+
341
+		if (!isset($this->builders[$type])) {
342
+			$this->builders[$type] = new EntityBuilder(
343
+				Manager::getInstance()->mapper($class),
344
+				array_keys($this->eagerLoads)
345
+			);
346
+		}
347
+
348
+		return $this->builders[$type];
349
+	}
350 350
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -127,7 +127,7 @@  discard block
 block discarded – undo
127 127
             // constraints have been specified for the eager load and we'll just put
128 128
             // an empty Closure with the loader so that we can treat all the same.
129 129
             if (is_numeric($name)) {
130
-                $f = function () {
130
+                $f = function() {
131 131
                 };
132 132
 
133 133
                 list($name, $constraints) = [$constraints, $f];
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
             $progress[] = $segment;
164 164
 
165 165
             if (!isset($results[$last = implode('.', $progress)])) {
166
-                $results[$last] = function () {
166
+                $results[$last] = function() {
167 167
                 };
168 168
             }
169 169
         }
@@ -232,7 +232,7 @@  discard block
 block discarded – undo
232 232
         // We want to run a relationship query without any constrains so that we will
233 233
         // not have to remove these where clauses manually which gets really hacky
234 234
         // and is error prone while we remove the developer's own where clauses.
235
-        $query = Relationship::noConstraints(function () use ($relation) {
235
+        $query = Relationship::noConstraints(function() use ($relation) {
236 236
             return $this->entityMap->$relation($this->defaultMapper->newInstance());
237 237
         });
238 238
 
@@ -298,7 +298,7 @@  discard block
 block discarded – undo
298 298
     {
299 299
         $builder = new EntityBuilder($this->defaultMapper, array_keys($this->eagerLoads));
300 300
 
301
-        return collect($results)->map(function ($item, $key) use ($builder) {
301
+        return collect($results)->map(function($item, $key) use ($builder) {
302 302
             return $builder->build($item);
303 303
         })->all();
304 304
     }
@@ -312,7 +312,7 @@  discard block
 block discarded – undo
312 312
      */
313 313
     protected function buildUsingSingleTableInheritance(array $results)
314 314
     {
315
-        return collect($results)->map(function ($item, $key) {
315
+        return collect($results)->map(function($item, $key) {
316 316
             $builder = $this->builderForResult($item);
317 317
 
318 318
             return $builder->build($item);
Please login to merge, or discard this patch.