Completed
Branch 5.6 (cd95fb)
by Rémi
10:17
created
src/MagicCasting.php 1 patch
Indentation   +102 added lines, -102 removed lines patch added patch discarded remove patch
@@ -8,117 +8,117 @@
 block discarded – undo
8 8
 
9 9
 trait MagicCasting
10 10
 {
11
-    /**
12
-     * Determine if the given attribute exists.
13
-     *
14
-     * @param mixed $offset
15
-     *
16
-     * @return bool
17
-     */
18
-    public function offsetExists($offset)
19
-    {
20
-        return isset($this->$offset);
21
-    }
11
+	/**
12
+	 * Determine if the given attribute exists.
13
+	 *
14
+	 * @param mixed $offset
15
+	 *
16
+	 * @return bool
17
+	 */
18
+	public function offsetExists($offset)
19
+	{
20
+		return isset($this->$offset);
21
+	}
22 22
 
23
-    /**
24
-     * Get the value for a given offset.
25
-     *
26
-     * @param mixed $offset
27
-     *
28
-     * @return mixed
29
-     */
30
-    public function offsetGet($offset)
31
-    {
32
-        return $this->$offset;
33
-    }
23
+	/**
24
+	 * Get the value for a given offset.
25
+	 *
26
+	 * @param mixed $offset
27
+	 *
28
+	 * @return mixed
29
+	 */
30
+	public function offsetGet($offset)
31
+	{
32
+		return $this->$offset;
33
+	}
34 34
 
35
-    /**
36
-     * Set the value for a given offset.
37
-     *
38
-     * @param mixed $offset
39
-     * @param mixed $value
40
-     *
41
-     * @return void
42
-     */
43
-    public function offsetSet($offset, $value)
44
-    {
45
-        $this->$offset = $value;
46
-    }
35
+	/**
36
+	 * Set the value for a given offset.
37
+	 *
38
+	 * @param mixed $offset
39
+	 * @param mixed $value
40
+	 *
41
+	 * @return void
42
+	 */
43
+	public function offsetSet($offset, $value)
44
+	{
45
+		$this->$offset = $value;
46
+	}
47 47
 
48
-    /**
49
-     * Unset the value for a given offset.
50
-     *
51
-     * @param mixed $offset
52
-     *
53
-     * @return void
54
-     */
55
-    public function offsetUnset($offset)
56
-    {
57
-        unset($this->$offset);
58
-    }
48
+	/**
49
+	 * Unset the value for a given offset.
50
+	 *
51
+	 * @param mixed $offset
52
+	 *
53
+	 * @return void
54
+	 */
55
+	public function offsetUnset($offset)
56
+	{
57
+		unset($this->$offset);
58
+	}
59 59
 
60
-    /**
61
-     * Convert the object into something JSON serializable.
62
-     *
63
-     * @return array
64
-     */
65
-    public function jsonSerialize()
66
-    {
67
-        return $this->toArray();
68
-    }
60
+	/**
61
+	 * Convert the object into something JSON serializable.
62
+	 *
63
+	 * @return array
64
+	 */
65
+	public function jsonSerialize()
66
+	{
67
+		return $this->toArray();
68
+	}
69 69
 
70
-    /**
71
-     * Convert the entity instance to JSON.
72
-     *
73
-     * @param int $options
74
-     *
75
-     * @return string
76
-     */
77
-    public function toJson($options = 0)
78
-    {
79
-        return json_encode($this->toArray(), $options);
80
-    }
70
+	/**
71
+	 * Convert the entity instance to JSON.
72
+	 *
73
+	 * @param int $options
74
+	 *
75
+	 * @return string
76
+	 */
77
+	public function toJson($options = 0)
78
+	{
79
+		return json_encode($this->toArray(), $options);
80
+	}
81 81
 
82
-    /**
83
-     * Convert Mappable object to array;.
84
-     *
85
-     * @return array
86
-     */
87
-    public function toArray()
88
-    {
89
-        return $this->attributesToArray($this->attributes);
90
-    }
82
+	/**
83
+	 * Convert Mappable object to array;.
84
+	 *
85
+	 * @return array
86
+	 */
87
+	public function toArray()
88
+	{
89
+		return $this->attributesToArray($this->attributes);
90
+	}
91 91
 
92
-    /**
93
-     * Transform the Object to array/json,.
94
-     *
95
-     * @param array $sourceAttributes
96
-     *
97
-     * @return array
98
-     */
99
-    protected function attributesToArray(array $sourceAttributes)
100
-    {
101
-        $attributes = [];
92
+	/**
93
+	 * Transform the Object to array/json,.
94
+	 *
95
+	 * @param array $sourceAttributes
96
+	 *
97
+	 * @return array
98
+	 */
99
+	protected function attributesToArray(array $sourceAttributes)
100
+	{
101
+		$attributes = [];
102 102
 
103
-        foreach ($sourceAttributes as $key => $attribute) {
104
-            // If the attribute is a proxy, and hasn't be loaded, we discard
105
-            // it from the returned set.
106
-            if ($attribute instanceof ProxyInterface && !$attribute->isProxyInitialized()) {
107
-                continue;
108
-            }
103
+		foreach ($sourceAttributes as $key => $attribute) {
104
+			// If the attribute is a proxy, and hasn't be loaded, we discard
105
+			// it from the returned set.
106
+			if ($attribute instanceof ProxyInterface && !$attribute->isProxyInitialized()) {
107
+				continue;
108
+			}
109 109
 
110
-            if ($attribute instanceof Carbon) {
111
-                $attributes[$key] = $attribute->__toString();
112
-                continue;
113
-            }
110
+			if ($attribute instanceof Carbon) {
111
+				$attributes[$key] = $attribute->__toString();
112
+				continue;
113
+			}
114 114
 
115
-            if ($attribute instanceof Arrayable) {
116
-                $attributes[$key] = $attribute->toArray();
117
-            } else {
118
-                $attributes[$key] = $attribute;
119
-            }
120
-        }
115
+			if ($attribute instanceof Arrayable) {
116
+				$attributes[$key] = $attribute->toArray();
117
+			} else {
118
+				$attributes[$key] = $attribute;
119
+			}
120
+		}
121 121
 
122
-        return $attributes;
123
-    }
122
+		return $attributes;
123
+	}
124 124
 }
Please login to merge, or discard this patch.
src/System/Query.php 3 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -514,7 +514,7 @@
 block discarded – undo
514 514
      */
515 515
     protected function getHasRelationQuery($relation, $entity)
516 516
     {
517
-        return Relationship::noConstraints(function () use ($relation, $entity) {
517
+        return Relationship::noConstraints(function() use ($relation, $entity) {
518 518
             return $this->entityMap->$relation($entity);
519 519
         });
520 520
     }
Please login to merge, or discard this patch.
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -176,7 +176,7 @@  discard block
 block discarded – undo
176 176
      *
177 177
      * @throws \Analogue\ORM\Exceptions\EntityNotFoundException
178 178
      *
179
-     * @return mixed|self
179
+     * @return \Analogue\ORM\Mappable
180 180
      */
181 181
     public function findOrFail($id, $columns = ['*'])
182 182
     {
@@ -247,7 +247,7 @@  discard block
 block discarded – undo
247 247
      * @param string $column
248 248
      * @param string $key
249 249
      *
250
-     * @return array
250
+     * @return Collection
251 251
      */
252 252
     public function lists($column, $key = null)
253 253
     {
Please login to merge, or discard this patch.
Indentation   +653 added lines, -653 removed lines patch added patch discarded remove patch
@@ -20,657 +20,657 @@
 block discarded – undo
20 20
  */
21 21
 class Query
22 22
 {
23
-    /**
24
-     * Mapper Instance.
25
-     *
26
-     * @var \Analogue\ORM\System\Mapper
27
-     */
28
-    protected $mapper;
29
-
30
-    /**
31
-     * DB Adatper.
32
-     *
33
-     * @var \Analogue\ORM\Drivers\DBAdapter
34
-     */
35
-    protected $adapter;
36
-
37
-    /**
38
-     * Query Builder Instance.
39
-     *
40
-     * @var \Illuminate\Database\Query\Builder
41
-     */
42
-    protected $query;
43
-
44
-    /**
45
-     * Entity Map Instance.
46
-     *
47
-     * @var \Analogue\ORM\EntityMap
48
-     */
49
-    protected $entityMap;
50
-
51
-    /**
52
-     * The relationships that should be eager loaded.
53
-     *
54
-     * @var array
55
-     */
56
-    protected $eagerLoad = [];
57
-
58
-    /**
59
-     * All of the registered builder macros.
60
-     *
61
-     * @var array
62
-     */
63
-    protected $macros = [];
64
-
65
-    /**
66
-     * The methods that should be returned from query builder.
67
-     *
68
-     * @var array
69
-     */
70
-    protected $passthru = [
71
-        'cursor',
72
-        'toSql',
73
-        'lists',
74
-        'pluck',
75
-        'count',
76
-        'min',
77
-        'max',
78
-        'avg',
79
-        'sum',
80
-        'exists',
81
-        'getBindings',
82
-    ];
83
-
84
-    /**
85
-     * Query Builder Blacklist.
86
-     */
87
-    protected $blacklist = [
88
-        'insert',
89
-        'insertGetId',
90
-        'lock',
91
-        'lockForUpdate',
92
-        'sharedLock',
93
-        'update',
94
-        'increment',
95
-        'decrement',
96
-        'delete',
97
-        'truncate',
98
-        'raw',
99
-    ];
100
-
101
-    /**
102
-     * Create a new Analogue Query Builder instance.
103
-     *
104
-     * @param Mapper    $mapper
105
-     * @param DBAdapter $adapter
106
-     */
107
-    public function __construct(Mapper $mapper, DBAdapter $adapter)
108
-    {
109
-        $this->mapper = $mapper;
110
-
111
-        $this->adapter = $adapter;
112
-
113
-        $this->entityMap = $mapper->getEntityMap();
114
-
115
-        // Specify the table to work on
116
-        $this->query = $adapter->getQuery()->from($this->entityMap->getTable());
117
-
118
-        $this->with($this->entityMap->getEagerloadedRelationships());
119
-    }
120
-
121
-    /**
122
-     * Run the query and return the result.
123
-     *
124
-     * @param array $columns
125
-     *
126
-     * @return \Illuminate\Support\Collection
127
-     */
128
-    public function get($columns = ['*']) : Collection
129
-    {
130
-        return $this->getEntities($columns);
131
-    }
132
-
133
-    /**
134
-     * Find an entity by its primary key.
135
-     *
136
-     * @param string|int $id
137
-     * @param array      $columns
138
-     *
139
-     * @return \Analogue\ORM\Mappable
140
-     */
141
-    public function find($id, $columns = ['*'])
142
-    {
143
-        if (is_array($id)) {
144
-            return $this->findMany($id, $columns);
145
-        }
146
-
147
-        $this->query->where($this->entityMap->getKeyName(), '=', $id);
148
-
149
-        return $this->first($columns);
150
-    }
151
-
152
-    /**
153
-     * Find many entities by their primary keys.
154
-     *
155
-     * @param array $id
156
-     * @param array $columns
157
-     *
158
-     * @return \Illuminate\Support\Collection
159
-     */
160
-    public function findMany($id, $columns = ['*'])
161
-    {
162
-        if (empty($id)) {
163
-            return new EntityCollection();
164
-        }
165
-
166
-        $this->query->whereIn($this->entityMap->getKeyName(), $id);
167
-
168
-        return $this->get($columns);
169
-    }
170
-
171
-    /**
172
-     * Find a model by its primary key or throw an exception.
173
-     *
174
-     * @param mixed $id
175
-     * @param array $columns
176
-     *
177
-     * @throws \Analogue\ORM\Exceptions\EntityNotFoundException
178
-     *
179
-     * @return mixed|self
180
-     */
181
-    public function findOrFail($id, $columns = ['*'])
182
-    {
183
-        if (!is_null($entity = $this->find($id, $columns))) {
184
-            return $entity;
185
-        }
186
-
187
-        throw (new EntityNotFoundException())->setEntity(get_class($this->entityMap));
188
-    }
189
-
190
-    /**
191
-     * Execute the query and get the first result.
192
-     *
193
-     * @param array $columns
194
-     *
195
-     * @return \Analogue\ORM\Entity
196
-     */
197
-    public function first($columns = ['*'])
198
-    {
199
-        return $this->take(1)->get($columns)->first();
200
-    }
201
-
202
-    /**
203
-     * Execute the query and get the first result or throw an exception.
204
-     *
205
-     * @param array $columns
206
-     *
207
-     * @throws EntityNotFoundException
208
-     *
209
-     * @return \Analogue\ORM\Entity
210
-     */
211
-    public function firstOrFail($columns = ['*'])
212
-    {
213
-        if (!is_null($entity = $this->first($columns))) {
214
-            return $entity;
215
-        }
216
-
217
-        throw (new EntityNotFoundException())->setEntity(get_class($this->entityMap));
218
-    }
219
-
220
-    /**
221
-     * Chunk the results of the query.
222
-     *
223
-     * @param int      $count
224
-     * @param callable $callback
225
-     *
226
-     * @return void
227
-     */
228
-    public function chunk($count, callable $callback)
229
-    {
230
-        $results = $this->forPage($page = 1, $count)->get();
231
-
232
-        while (count($results) > 0) {
233
-            // On each chunk result set, we will pass them to the callback and then let the
234
-            // developer take care of everything within the callback, which allows us to
235
-            // keep the memory low for spinning through large result sets for working.
236
-            call_user_func($callback, $results);
237
-
238
-            $page++;
239
-
240
-            $results = $this->forPage($page, $count)->get();
241
-        }
242
-    }
243
-
244
-    /**
245
-     * Get an array with the values of a given column.
246
-     *
247
-     * @param string $column
248
-     * @param string $key
249
-     *
250
-     * @return array
251
-     */
252
-    public function lists($column, $key = null)
253
-    {
254
-        return $this->query->pluck($column, $key);
255
-    }
256
-
257
-    /**
258
-     * Get a paginator for the "select" statement.
259
-     *
260
-     * @param int   $perPage
261
-     * @param array $columns
262
-     *
263
-     * @return LengthAwarePaginator
264
-     */
265
-    public function paginate($perPage = null, $columns = ['*'])
266
-    {
267
-        $total = $this->query->getCountForPagination();
268
-
269
-        $this->query->forPage(
270
-            $page = Paginator::resolveCurrentPage(),
271
-            $perPage = $perPage ?: $this->entityMap->getPerPage()
272
-        );
273
-
274
-        return new LengthAwarePaginator($this->get($columns)->all(), $total, $perPage, $page, [
275
-            'path' => Paginator::resolveCurrentPath(),
276
-        ]);
277
-    }
278
-
279
-    /**
280
-     * Get a paginator for a grouped statement.
281
-     *
282
-     * @param \Illuminate\Pagination\Factory $paginator
283
-     * @param int                            $perPage
284
-     * @param array                          $columns
285
-     *
286
-     * @return \Illuminate\Pagination\Paginator
287
-     */
288
-    protected function groupedPaginate($paginator, $perPage, $columns)
289
-    {
290
-        $results = $this->get($columns)->all();
291
-
292
-        return $this->query->buildRawPaginator($paginator, $results, $perPage);
293
-    }
294
-
295
-    /**
296
-     * Get a paginator for an ungrouped statement.
297
-     *
298
-     * @param \Illuminate\Pagination\Factory $paginator
299
-     * @param int                            $perPage
300
-     * @param array                          $columns
301
-     *
302
-     * @return \Illuminate\Pagination\Paginator
303
-     */
304
-    protected function ungroupedPaginate($paginator, $perPage, $columns)
305
-    {
306
-        $total = $this->query->getPaginationCount();
307
-
308
-        // Once we have the paginator we need to set the limit and offset values for
309
-        // the query so we can get the properly paginated items. Once we have an
310
-        // array of items we can create the paginator instances for the items.
311
-        $page = $paginator->getCurrentPage($total);
312
-
313
-        $this->query->forPage($page, $perPage);
314
-
315
-        return $paginator->make($this->get($columns)->all(), $total, $perPage);
316
-    }
317
-
318
-    /**
319
-     * Paginate the given query into a simple paginator.
320
-     *
321
-     * @param int   $perPage
322
-     * @param array $columns
323
-     *
324
-     * @return \Illuminate\Contracts\Pagination\Paginator
325
-     */
326
-    public function simplePaginate($perPage = null, $columns = ['*'])
327
-    {
328
-        $page = Paginator::resolveCurrentPage();
329
-
330
-        $perPage = $perPage ?: $this->entityMap->getPerPage();
331
-
332
-        $this->skip(($page - 1) * $perPage)->take($perPage + 1);
333
-
334
-        return new Paginator($this->get($columns)->all(), $perPage, $page, ['path' => Paginator::resolveCurrentPath()]);
335
-    }
336
-
337
-    /**
338
-     * Add a basic where clause to the query.
339
-     *
340
-     * @param string $column
341
-     * @param string $operator
342
-     * @param mixed  $value
343
-     * @param string $boolean
344
-     *
345
-     * @return $this
346
-     */
347
-    public function where($column, $operator = null, $value = null, $boolean = 'and')
348
-    {
349
-        if ($column instanceof Closure) {
350
-            $query = $this->newQueryWithoutScopes();
351
-
352
-            call_user_func($column, $query);
353
-
354
-            $this->query->addNestedWhereQuery($query->getQuery(), $boolean);
355
-        } else {
356
-            call_user_func_array([$this->query, 'where'], func_get_args());
357
-        }
358
-
359
-        return $this;
360
-    }
361
-
362
-    /**
363
-     * Add an "or where" clause to the query.
364
-     *
365
-     * @param string $column
366
-     * @param string $operator
367
-     * @param mixed  $value
368
-     *
369
-     * @return \Analogue\ORM\System\Query
370
-     */
371
-    public function orWhere($column, $operator = null, $value = null)
372
-    {
373
-        return $this->where($column, $operator, $value, 'or');
374
-    }
375
-
376
-    /**
377
-     * Add a relationship count condition to the query.
378
-     *
379
-     * @param string   $relation
380
-     * @param string   $operator
381
-     * @param int      $count
382
-     * @param string   $boolean
383
-     * @param \Closure $callback
384
-     *
385
-     * @return \Analogue\ORM\System\Query
386
-     */
387
-    public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
388
-    {
389
-        $entity = $this->mapper->newInstance();
390
-
391
-        $relation = $this->getHasRelationQuery($relation, $entity);
392
-
393
-        $query = $relation->getRelationCountQuery($relation->getRelatedMapper()->getQuery(), $this);
394
-
395
-        if ($callback) {
396
-            call_user_func($callback, $query);
397
-        }
398
-
399
-        return $this->addHasWhere($query, $relation, $operator, $count, $boolean);
400
-    }
401
-
402
-    /**
403
-     * Add a relationship count condition to the query with where clauses.
404
-     *
405
-     * @param string   $relation
406
-     * @param \Closure $callback
407
-     * @param string   $operator
408
-     * @param int      $count
409
-     *
410
-     * @return \Analogue\ORM\System\Query
411
-     */
412
-    public function whereHas($relation, Closure $callback, $operator = '>=', $count = 1)
413
-    {
414
-        return $this->has($relation, $operator, $count, 'and', $callback);
415
-    }
416
-
417
-    /**
418
-     * Add a relationship count condition to the query with an "or".
419
-     *
420
-     * @param string $relation
421
-     * @param string $operator
422
-     * @param int    $count
423
-     *
424
-     * @return \Analogue\ORM\System\Query
425
-     */
426
-    public function orHas($relation, $operator = '>=', $count = 1)
427
-    {
428
-        return $this->has($relation, $operator, $count, 'or');
429
-    }
430
-
431
-    /**
432
-     * Add a relationship count condition to the query with where clauses and an "or".
433
-     *
434
-     * @param string   $relation
435
-     * @param \Closure $callback
436
-     * @param string   $operator
437
-     * @param int      $count
438
-     *
439
-     * @return \Analogue\ORM\System\Query
440
-     */
441
-    public function orWhereHas($relation, Closure $callback, $operator = '>=', $count = 1)
442
-    {
443
-        return $this->has($relation, $operator, $count, 'or', $callback);
444
-    }
445
-
446
-    /**
447
-     * Add the "has" condition where clause to the query.
448
-     *
449
-     * @param \Analogue\ORM\System\Query               $hasQuery
450
-     * @param \Analogue\ORM\Relationships\Relationship $relation
451
-     * @param string                                   $operator
452
-     * @param int                                      $count
453
-     * @param string                                   $boolean
454
-     *
455
-     * @return \Analogue\ORM\System\Query
456
-     */
457
-    protected function addHasWhere(self $hasQuery, Relationship $relation, $operator, $count, $boolean)
458
-    {
459
-        $this->mergeWheresToHas($hasQuery, $relation);
460
-
461
-        if (is_numeric($count)) {
462
-            $count = new Expression($count);
463
-        }
464
-
465
-        return $this->where(new Expression('('.$hasQuery->toSql().')'), $operator, $count, $boolean);
466
-    }
467
-
468
-    /**
469
-     * Merge the "wheres" from a relation query to a has query.
470
-     *
471
-     * @param \Analogue\ORM\System\Query               $hasQuery
472
-     * @param \Analogue\ORM\Relationships\Relationship $relation
473
-     *
474
-     * @return void
475
-     */
476
-    protected function mergeWheresToHas(self $hasQuery, Relationship $relation)
477
-    {
478
-        // Here we have the "has" query and the original relation. We need to copy over any
479
-        // where clauses the developer may have put in the relationship function over to
480
-        // the has query, and then copy the bindings from the "has" query to the main.
481
-        $relationQuery = $relation->getBaseQuery();
482
-
483
-        $hasQuery->mergeWheres(
484
-            $relationQuery->wheres, $relationQuery->getBindings()
485
-        );
486
-
487
-        $this->query->mergeBindings($hasQuery->getQuery());
488
-    }
489
-
490
-    /**
491
-     * Get the "has relation" base query instance.
492
-     *
493
-     * @param string $relation
494
-     * @param        $entity
495
-     *
496
-     * @return \Analogue\ORM\System\Query
497
-     */
498
-    protected function getHasRelationQuery($relation, $entity)
499
-    {
500
-        return Relationship::noConstraints(function () use ($relation, $entity) {
501
-            return $this->entityMap->$relation($entity);
502
-        });
503
-    }
504
-
505
-    /**
506
-     * Get the table for the current query object.
507
-     *
508
-     * @return string
509
-     */
510
-    public function getTable()
511
-    {
512
-        return $this->entityMap->getTable();
513
-    }
514
-
515
-    /**
516
-     * Set the relationships that should be eager loaded.
517
-     *
518
-     * @param mixed $relations
519
-     *
520
-     * @return $this
521
-     */
522
-    public function with($relations)
523
-    {
524
-        if (is_string($relations)) {
525
-            $relations = func_get_args();
526
-        }
527
-
528
-        $this->eagerLoad = array_merge($this->eagerLoad, $relations);
529
-
530
-        return $this;
531
-    }
532
-
533
-    /**
534
-     * Get the relationships being eagerly loaded.
535
-     *
536
-     * @return array
537
-     */
538
-    public function getEagerLoads()
539
-    {
540
-        return $this->eagerLoad;
541
-    }
542
-
543
-    /**
544
-     * Add the Entity primary key if not in requested columns.
545
-     *
546
-     * @param array $columns
547
-     *
548
-     * @return array
549
-     */
550
-    protected function enforceIdColumn($columns)
551
-    {
552
-        if (!in_array($this->entityMap->getKeyName(), $columns)) {
553
-            $columns[] = $this->entityMap->getKeyName();
554
-        }
555
-
556
-        return $columns;
557
-    }
558
-
559
-    /**
560
-     * Get the hydrated models without eager loading.
561
-     *
562
-     * @param array $columns
563
-     *
564
-     * @return \Illuminate\Support\Collection
565
-     */
566
-    public function getEntities($columns = ['*'])
567
-    {
568
-        // As we need the primary key to feed the
569
-        // entity cache, we need it loaded on each
570
-        // request
571
-        $columns = $this->enforceIdColumn($columns);
572
-
573
-        // Run the query
574
-        $results = $this->query->get($columns);
575
-
576
-        // Pass result set to the mapper and return the EntityCollection
577
-        return $this->mapper->map($results, $this->getEagerLoads());
578
-    }
579
-
580
-    /**
581
-     * Extend the builder with a given callback.
582
-     *
583
-     * @param string   $name
584
-     * @param \Closure $callback
585
-     *
586
-     * @return void
587
-     */
588
-    public function macro($name, Closure $callback)
589
-    {
590
-        $this->macros[$name] = $callback;
591
-    }
592
-
593
-    /**
594
-     * Get the given macro by name.
595
-     *
596
-     * @param string $name
597
-     *
598
-     * @return \Closure
599
-     */
600
-    public function getMacro($name)
601
-    {
602
-        return array_get($this->macros, $name);
603
-    }
604
-
605
-    /**
606
-     * Get a new query builder for the model's table.
607
-     *
608
-     * @return \Analogue\ORM\System\Query
609
-     */
610
-    public function newQuery()
611
-    {
612
-        $builder = new self($this->mapper, $this->adapter);
613
-
614
-        return $this->applyGlobalScopes($builder);
615
-    }
616
-
617
-    /**
618
-     * Get a new query builder without any scope applied.
619
-     *
620
-     * @return \Analogue\ORM\System\Query
621
-     */
622
-    public function newQueryWithoutScopes()
623
-    {
624
-        return new self($this->mapper, $this->adapter);
625
-    }
626
-
627
-    /**
628
-     * Get the Mapper instance for this Query Builder.
629
-     *
630
-     * @return \Analogue\ORM\System\Mapper
631
-     */
632
-    public function getMapper()
633
-    {
634
-        return $this->mapper;
635
-    }
636
-
637
-    /**
638
-     * Get the underlying query adapter.
639
-     *
640
-     * (REFACTOR: this method should move out, we need to provide the client classes
641
-     * with the adapter instead.)
642
-     *
643
-     * @return \Illuminate\Database\Query\Builder
644
-     */
645
-    public function getQuery()
646
-    {
647
-        return $this->query;
648
-    }
649
-
650
-    /**
651
-     * Dynamically handle calls into the query instance.
652
-     *
653
-     * @param string $method
654
-     * @param array  $parameters
655
-     *
656
-     * @throws Exception
657
-     *
658
-     * @return mixed
659
-     */
660
-    public function __call($method, $parameters)
661
-    {
662
-        if (isset($this->macros[$method])) {
663
-            array_unshift($parameters, $this);
664
-
665
-            return call_user_func_array($this->macros[$method], $parameters);
666
-        }
667
-
668
-        if (in_array($method, $this->blacklist)) {
669
-            throw new Exception("Method $method doesn't exist");
670
-        }
671
-
672
-        $result = call_user_func_array([$this->query, $method], $parameters);
673
-
674
-        return in_array($method, $this->passthru) ? $result : $this;
675
-    }
23
+	/**
24
+	 * Mapper Instance.
25
+	 *
26
+	 * @var \Analogue\ORM\System\Mapper
27
+	 */
28
+	protected $mapper;
29
+
30
+	/**
31
+	 * DB Adatper.
32
+	 *
33
+	 * @var \Analogue\ORM\Drivers\DBAdapter
34
+	 */
35
+	protected $adapter;
36
+
37
+	/**
38
+	 * Query Builder Instance.
39
+	 *
40
+	 * @var \Illuminate\Database\Query\Builder
41
+	 */
42
+	protected $query;
43
+
44
+	/**
45
+	 * Entity Map Instance.
46
+	 *
47
+	 * @var \Analogue\ORM\EntityMap
48
+	 */
49
+	protected $entityMap;
50
+
51
+	/**
52
+	 * The relationships that should be eager loaded.
53
+	 *
54
+	 * @var array
55
+	 */
56
+	protected $eagerLoad = [];
57
+
58
+	/**
59
+	 * All of the registered builder macros.
60
+	 *
61
+	 * @var array
62
+	 */
63
+	protected $macros = [];
64
+
65
+	/**
66
+	 * The methods that should be returned from query builder.
67
+	 *
68
+	 * @var array
69
+	 */
70
+	protected $passthru = [
71
+		'cursor',
72
+		'toSql',
73
+		'lists',
74
+		'pluck',
75
+		'count',
76
+		'min',
77
+		'max',
78
+		'avg',
79
+		'sum',
80
+		'exists',
81
+		'getBindings',
82
+	];
83
+
84
+	/**
85
+	 * Query Builder Blacklist.
86
+	 */
87
+	protected $blacklist = [
88
+		'insert',
89
+		'insertGetId',
90
+		'lock',
91
+		'lockForUpdate',
92
+		'sharedLock',
93
+		'update',
94
+		'increment',
95
+		'decrement',
96
+		'delete',
97
+		'truncate',
98
+		'raw',
99
+	];
100
+
101
+	/**
102
+	 * Create a new Analogue Query Builder instance.
103
+	 *
104
+	 * @param Mapper    $mapper
105
+	 * @param DBAdapter $adapter
106
+	 */
107
+	public function __construct(Mapper $mapper, DBAdapter $adapter)
108
+	{
109
+		$this->mapper = $mapper;
110
+
111
+		$this->adapter = $adapter;
112
+
113
+		$this->entityMap = $mapper->getEntityMap();
114
+
115
+		// Specify the table to work on
116
+		$this->query = $adapter->getQuery()->from($this->entityMap->getTable());
117
+
118
+		$this->with($this->entityMap->getEagerloadedRelationships());
119
+	}
120
+
121
+	/**
122
+	 * Run the query and return the result.
123
+	 *
124
+	 * @param array $columns
125
+	 *
126
+	 * @return \Illuminate\Support\Collection
127
+	 */
128
+	public function get($columns = ['*']) : Collection
129
+	{
130
+		return $this->getEntities($columns);
131
+	}
132
+
133
+	/**
134
+	 * Find an entity by its primary key.
135
+	 *
136
+	 * @param string|int $id
137
+	 * @param array      $columns
138
+	 *
139
+	 * @return \Analogue\ORM\Mappable
140
+	 */
141
+	public function find($id, $columns = ['*'])
142
+	{
143
+		if (is_array($id)) {
144
+			return $this->findMany($id, $columns);
145
+		}
146
+
147
+		$this->query->where($this->entityMap->getKeyName(), '=', $id);
148
+
149
+		return $this->first($columns);
150
+	}
151
+
152
+	/**
153
+	 * Find many entities by their primary keys.
154
+	 *
155
+	 * @param array $id
156
+	 * @param array $columns
157
+	 *
158
+	 * @return \Illuminate\Support\Collection
159
+	 */
160
+	public function findMany($id, $columns = ['*'])
161
+	{
162
+		if (empty($id)) {
163
+			return new EntityCollection();
164
+		}
165
+
166
+		$this->query->whereIn($this->entityMap->getKeyName(), $id);
167
+
168
+		return $this->get($columns);
169
+	}
170
+
171
+	/**
172
+	 * Find a model by its primary key or throw an exception.
173
+	 *
174
+	 * @param mixed $id
175
+	 * @param array $columns
176
+	 *
177
+	 * @throws \Analogue\ORM\Exceptions\EntityNotFoundException
178
+	 *
179
+	 * @return mixed|self
180
+	 */
181
+	public function findOrFail($id, $columns = ['*'])
182
+	{
183
+		if (!is_null($entity = $this->find($id, $columns))) {
184
+			return $entity;
185
+		}
186
+
187
+		throw (new EntityNotFoundException())->setEntity(get_class($this->entityMap));
188
+	}
189
+
190
+	/**
191
+	 * Execute the query and get the first result.
192
+	 *
193
+	 * @param array $columns
194
+	 *
195
+	 * @return \Analogue\ORM\Entity
196
+	 */
197
+	public function first($columns = ['*'])
198
+	{
199
+		return $this->take(1)->get($columns)->first();
200
+	}
201
+
202
+	/**
203
+	 * Execute the query and get the first result or throw an exception.
204
+	 *
205
+	 * @param array $columns
206
+	 *
207
+	 * @throws EntityNotFoundException
208
+	 *
209
+	 * @return \Analogue\ORM\Entity
210
+	 */
211
+	public function firstOrFail($columns = ['*'])
212
+	{
213
+		if (!is_null($entity = $this->first($columns))) {
214
+			return $entity;
215
+		}
216
+
217
+		throw (new EntityNotFoundException())->setEntity(get_class($this->entityMap));
218
+	}
219
+
220
+	/**
221
+	 * Chunk the results of the query.
222
+	 *
223
+	 * @param int      $count
224
+	 * @param callable $callback
225
+	 *
226
+	 * @return void
227
+	 */
228
+	public function chunk($count, callable $callback)
229
+	{
230
+		$results = $this->forPage($page = 1, $count)->get();
231
+
232
+		while (count($results) > 0) {
233
+			// On each chunk result set, we will pass them to the callback and then let the
234
+			// developer take care of everything within the callback, which allows us to
235
+			// keep the memory low for spinning through large result sets for working.
236
+			call_user_func($callback, $results);
237
+
238
+			$page++;
239
+
240
+			$results = $this->forPage($page, $count)->get();
241
+		}
242
+	}
243
+
244
+	/**
245
+	 * Get an array with the values of a given column.
246
+	 *
247
+	 * @param string $column
248
+	 * @param string $key
249
+	 *
250
+	 * @return array
251
+	 */
252
+	public function lists($column, $key = null)
253
+	{
254
+		return $this->query->pluck($column, $key);
255
+	}
256
+
257
+	/**
258
+	 * Get a paginator for the "select" statement.
259
+	 *
260
+	 * @param int   $perPage
261
+	 * @param array $columns
262
+	 *
263
+	 * @return LengthAwarePaginator
264
+	 */
265
+	public function paginate($perPage = null, $columns = ['*'])
266
+	{
267
+		$total = $this->query->getCountForPagination();
268
+
269
+		$this->query->forPage(
270
+			$page = Paginator::resolveCurrentPage(),
271
+			$perPage = $perPage ?: $this->entityMap->getPerPage()
272
+		);
273
+
274
+		return new LengthAwarePaginator($this->get($columns)->all(), $total, $perPage, $page, [
275
+			'path' => Paginator::resolveCurrentPath(),
276
+		]);
277
+	}
278
+
279
+	/**
280
+	 * Get a paginator for a grouped statement.
281
+	 *
282
+	 * @param \Illuminate\Pagination\Factory $paginator
283
+	 * @param int                            $perPage
284
+	 * @param array                          $columns
285
+	 *
286
+	 * @return \Illuminate\Pagination\Paginator
287
+	 */
288
+	protected function groupedPaginate($paginator, $perPage, $columns)
289
+	{
290
+		$results = $this->get($columns)->all();
291
+
292
+		return $this->query->buildRawPaginator($paginator, $results, $perPage);
293
+	}
294
+
295
+	/**
296
+	 * Get a paginator for an ungrouped statement.
297
+	 *
298
+	 * @param \Illuminate\Pagination\Factory $paginator
299
+	 * @param int                            $perPage
300
+	 * @param array                          $columns
301
+	 *
302
+	 * @return \Illuminate\Pagination\Paginator
303
+	 */
304
+	protected function ungroupedPaginate($paginator, $perPage, $columns)
305
+	{
306
+		$total = $this->query->getPaginationCount();
307
+
308
+		// Once we have the paginator we need to set the limit and offset values for
309
+		// the query so we can get the properly paginated items. Once we have an
310
+		// array of items we can create the paginator instances for the items.
311
+		$page = $paginator->getCurrentPage($total);
312
+
313
+		$this->query->forPage($page, $perPage);
314
+
315
+		return $paginator->make($this->get($columns)->all(), $total, $perPage);
316
+	}
317
+
318
+	/**
319
+	 * Paginate the given query into a simple paginator.
320
+	 *
321
+	 * @param int   $perPage
322
+	 * @param array $columns
323
+	 *
324
+	 * @return \Illuminate\Contracts\Pagination\Paginator
325
+	 */
326
+	public function simplePaginate($perPage = null, $columns = ['*'])
327
+	{
328
+		$page = Paginator::resolveCurrentPage();
329
+
330
+		$perPage = $perPage ?: $this->entityMap->getPerPage();
331
+
332
+		$this->skip(($page - 1) * $perPage)->take($perPage + 1);
333
+
334
+		return new Paginator($this->get($columns)->all(), $perPage, $page, ['path' => Paginator::resolveCurrentPath()]);
335
+	}
336
+
337
+	/**
338
+	 * Add a basic where clause to the query.
339
+	 *
340
+	 * @param string $column
341
+	 * @param string $operator
342
+	 * @param mixed  $value
343
+	 * @param string $boolean
344
+	 *
345
+	 * @return $this
346
+	 */
347
+	public function where($column, $operator = null, $value = null, $boolean = 'and')
348
+	{
349
+		if ($column instanceof Closure) {
350
+			$query = $this->newQueryWithoutScopes();
351
+
352
+			call_user_func($column, $query);
353
+
354
+			$this->query->addNestedWhereQuery($query->getQuery(), $boolean);
355
+		} else {
356
+			call_user_func_array([$this->query, 'where'], func_get_args());
357
+		}
358
+
359
+		return $this;
360
+	}
361
+
362
+	/**
363
+	 * Add an "or where" clause to the query.
364
+	 *
365
+	 * @param string $column
366
+	 * @param string $operator
367
+	 * @param mixed  $value
368
+	 *
369
+	 * @return \Analogue\ORM\System\Query
370
+	 */
371
+	public function orWhere($column, $operator = null, $value = null)
372
+	{
373
+		return $this->where($column, $operator, $value, 'or');
374
+	}
375
+
376
+	/**
377
+	 * Add a relationship count condition to the query.
378
+	 *
379
+	 * @param string   $relation
380
+	 * @param string   $operator
381
+	 * @param int      $count
382
+	 * @param string   $boolean
383
+	 * @param \Closure $callback
384
+	 *
385
+	 * @return \Analogue\ORM\System\Query
386
+	 */
387
+	public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
388
+	{
389
+		$entity = $this->mapper->newInstance();
390
+
391
+		$relation = $this->getHasRelationQuery($relation, $entity);
392
+
393
+		$query = $relation->getRelationCountQuery($relation->getRelatedMapper()->getQuery(), $this);
394
+
395
+		if ($callback) {
396
+			call_user_func($callback, $query);
397
+		}
398
+
399
+		return $this->addHasWhere($query, $relation, $operator, $count, $boolean);
400
+	}
401
+
402
+	/**
403
+	 * Add a relationship count condition to the query with where clauses.
404
+	 *
405
+	 * @param string   $relation
406
+	 * @param \Closure $callback
407
+	 * @param string   $operator
408
+	 * @param int      $count
409
+	 *
410
+	 * @return \Analogue\ORM\System\Query
411
+	 */
412
+	public function whereHas($relation, Closure $callback, $operator = '>=', $count = 1)
413
+	{
414
+		return $this->has($relation, $operator, $count, 'and', $callback);
415
+	}
416
+
417
+	/**
418
+	 * Add a relationship count condition to the query with an "or".
419
+	 *
420
+	 * @param string $relation
421
+	 * @param string $operator
422
+	 * @param int    $count
423
+	 *
424
+	 * @return \Analogue\ORM\System\Query
425
+	 */
426
+	public function orHas($relation, $operator = '>=', $count = 1)
427
+	{
428
+		return $this->has($relation, $operator, $count, 'or');
429
+	}
430
+
431
+	/**
432
+	 * Add a relationship count condition to the query with where clauses and an "or".
433
+	 *
434
+	 * @param string   $relation
435
+	 * @param \Closure $callback
436
+	 * @param string   $operator
437
+	 * @param int      $count
438
+	 *
439
+	 * @return \Analogue\ORM\System\Query
440
+	 */
441
+	public function orWhereHas($relation, Closure $callback, $operator = '>=', $count = 1)
442
+	{
443
+		return $this->has($relation, $operator, $count, 'or', $callback);
444
+	}
445
+
446
+	/**
447
+	 * Add the "has" condition where clause to the query.
448
+	 *
449
+	 * @param \Analogue\ORM\System\Query               $hasQuery
450
+	 * @param \Analogue\ORM\Relationships\Relationship $relation
451
+	 * @param string                                   $operator
452
+	 * @param int                                      $count
453
+	 * @param string                                   $boolean
454
+	 *
455
+	 * @return \Analogue\ORM\System\Query
456
+	 */
457
+	protected function addHasWhere(self $hasQuery, Relationship $relation, $operator, $count, $boolean)
458
+	{
459
+		$this->mergeWheresToHas($hasQuery, $relation);
460
+
461
+		if (is_numeric($count)) {
462
+			$count = new Expression($count);
463
+		}
464
+
465
+		return $this->where(new Expression('('.$hasQuery->toSql().')'), $operator, $count, $boolean);
466
+	}
467
+
468
+	/**
469
+	 * Merge the "wheres" from a relation query to a has query.
470
+	 *
471
+	 * @param \Analogue\ORM\System\Query               $hasQuery
472
+	 * @param \Analogue\ORM\Relationships\Relationship $relation
473
+	 *
474
+	 * @return void
475
+	 */
476
+	protected function mergeWheresToHas(self $hasQuery, Relationship $relation)
477
+	{
478
+		// Here we have the "has" query and the original relation. We need to copy over any
479
+		// where clauses the developer may have put in the relationship function over to
480
+		// the has query, and then copy the bindings from the "has" query to the main.
481
+		$relationQuery = $relation->getBaseQuery();
482
+
483
+		$hasQuery->mergeWheres(
484
+			$relationQuery->wheres, $relationQuery->getBindings()
485
+		);
486
+
487
+		$this->query->mergeBindings($hasQuery->getQuery());
488
+	}
489
+
490
+	/**
491
+	 * Get the "has relation" base query instance.
492
+	 *
493
+	 * @param string $relation
494
+	 * @param        $entity
495
+	 *
496
+	 * @return \Analogue\ORM\System\Query
497
+	 */
498
+	protected function getHasRelationQuery($relation, $entity)
499
+	{
500
+		return Relationship::noConstraints(function () use ($relation, $entity) {
501
+			return $this->entityMap->$relation($entity);
502
+		});
503
+	}
504
+
505
+	/**
506
+	 * Get the table for the current query object.
507
+	 *
508
+	 * @return string
509
+	 */
510
+	public function getTable()
511
+	{
512
+		return $this->entityMap->getTable();
513
+	}
514
+
515
+	/**
516
+	 * Set the relationships that should be eager loaded.
517
+	 *
518
+	 * @param mixed $relations
519
+	 *
520
+	 * @return $this
521
+	 */
522
+	public function with($relations)
523
+	{
524
+		if (is_string($relations)) {
525
+			$relations = func_get_args();
526
+		}
527
+
528
+		$this->eagerLoad = array_merge($this->eagerLoad, $relations);
529
+
530
+		return $this;
531
+	}
532
+
533
+	/**
534
+	 * Get the relationships being eagerly loaded.
535
+	 *
536
+	 * @return array
537
+	 */
538
+	public function getEagerLoads()
539
+	{
540
+		return $this->eagerLoad;
541
+	}
542
+
543
+	/**
544
+	 * Add the Entity primary key if not in requested columns.
545
+	 *
546
+	 * @param array $columns
547
+	 *
548
+	 * @return array
549
+	 */
550
+	protected function enforceIdColumn($columns)
551
+	{
552
+		if (!in_array($this->entityMap->getKeyName(), $columns)) {
553
+			$columns[] = $this->entityMap->getKeyName();
554
+		}
555
+
556
+		return $columns;
557
+	}
558
+
559
+	/**
560
+	 * Get the hydrated models without eager loading.
561
+	 *
562
+	 * @param array $columns
563
+	 *
564
+	 * @return \Illuminate\Support\Collection
565
+	 */
566
+	public function getEntities($columns = ['*'])
567
+	{
568
+		// As we need the primary key to feed the
569
+		// entity cache, we need it loaded on each
570
+		// request
571
+		$columns = $this->enforceIdColumn($columns);
572
+
573
+		// Run the query
574
+		$results = $this->query->get($columns);
575
+
576
+		// Pass result set to the mapper and return the EntityCollection
577
+		return $this->mapper->map($results, $this->getEagerLoads());
578
+	}
579
+
580
+	/**
581
+	 * Extend the builder with a given callback.
582
+	 *
583
+	 * @param string   $name
584
+	 * @param \Closure $callback
585
+	 *
586
+	 * @return void
587
+	 */
588
+	public function macro($name, Closure $callback)
589
+	{
590
+		$this->macros[$name] = $callback;
591
+	}
592
+
593
+	/**
594
+	 * Get the given macro by name.
595
+	 *
596
+	 * @param string $name
597
+	 *
598
+	 * @return \Closure
599
+	 */
600
+	public function getMacro($name)
601
+	{
602
+		return array_get($this->macros, $name);
603
+	}
604
+
605
+	/**
606
+	 * Get a new query builder for the model's table.
607
+	 *
608
+	 * @return \Analogue\ORM\System\Query
609
+	 */
610
+	public function newQuery()
611
+	{
612
+		$builder = new self($this->mapper, $this->adapter);
613
+
614
+		return $this->applyGlobalScopes($builder);
615
+	}
616
+
617
+	/**
618
+	 * Get a new query builder without any scope applied.
619
+	 *
620
+	 * @return \Analogue\ORM\System\Query
621
+	 */
622
+	public function newQueryWithoutScopes()
623
+	{
624
+		return new self($this->mapper, $this->adapter);
625
+	}
626
+
627
+	/**
628
+	 * Get the Mapper instance for this Query Builder.
629
+	 *
630
+	 * @return \Analogue\ORM\System\Mapper
631
+	 */
632
+	public function getMapper()
633
+	{
634
+		return $this->mapper;
635
+	}
636
+
637
+	/**
638
+	 * Get the underlying query adapter.
639
+	 *
640
+	 * (REFACTOR: this method should move out, we need to provide the client classes
641
+	 * with the adapter instead.)
642
+	 *
643
+	 * @return \Illuminate\Database\Query\Builder
644
+	 */
645
+	public function getQuery()
646
+	{
647
+		return $this->query;
648
+	}
649
+
650
+	/**
651
+	 * Dynamically handle calls into the query instance.
652
+	 *
653
+	 * @param string $method
654
+	 * @param array  $parameters
655
+	 *
656
+	 * @throws Exception
657
+	 *
658
+	 * @return mixed
659
+	 */
660
+	public function __call($method, $parameters)
661
+	{
662
+		if (isset($this->macros[$method])) {
663
+			array_unshift($parameters, $this);
664
+
665
+			return call_user_func_array($this->macros[$method], $parameters);
666
+		}
667
+
668
+		if (in_array($method, $this->blacklist)) {
669
+			throw new Exception("Method $method doesn't exist");
670
+		}
671
+
672
+		$result = call_user_func_array([$this->query, $method], $parameters);
673
+
674
+		return in_array($method, $this->passthru) ? $result : $this;
675
+	}
676 676
 }
Please login to merge, or discard this patch.
src/System/ScopeInterface.php 1 patch
Indentation   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -4,21 +4,21 @@
 block discarded – undo
4 4
 
5 5
 interface ScopeInterface
6 6
 {
7
-    /**
8
-     * Apply the scope to a given Query builder.
9
-     *
10
-     * @param \Analogue\ORM\System\Query $builder
11
-     *
12
-     * @return void
13
-     */
14
-    public function apply(Query $builder);
7
+	/**
8
+	 * Apply the scope to a given Query builder.
9
+	 *
10
+	 * @param \Analogue\ORM\System\Query $builder
11
+	 *
12
+	 * @return void
13
+	 */
14
+	public function apply(Query $builder);
15 15
 
16
-    /**
17
-     * Remove the scope from the Query builder.
18
-     *
19
-     * @param \Analogue\ORM\System\Query $builder
20
-     *
21
-     * @return void
22
-     */
23
-    public function remove(Query $builder);
16
+	/**
17
+	 * Remove the scope from the Query builder.
18
+	 *
19
+	 * @param \Analogue\ORM\System\Query $builder
20
+	 *
21
+	 * @return void
22
+	 */
23
+	public function remove(Query $builder);
24 24
 }
Please login to merge, or discard this patch.
src/System/SingleTableInheritanceScope.php 2 patches
Indentation   +106 added lines, -106 removed lines patch added patch discarded remove patch
@@ -6,110 +6,110 @@
 block discarded – undo
6 6
 
7 7
 class SingleTableInheritanceScope implements ScopeInterface
8 8
 {
9
-    /**
10
-     * Discriminator column name.
11
-     *
12
-     * @var string
13
-     */
14
-    protected $column;
15
-
16
-    /**
17
-     * Discriminator column allowed types.
18
-     *
19
-     * @var array
20
-     */
21
-    protected $types = [];
22
-
23
-    public function __construct(EntityMap $entityMap)
24
-    {
25
-        // Putting the heavy logic in here, so we won't have
26
-        // to go through it each time we reach for a query
27
-        // builder.
28
-
29
-        $this->column = $entityMap->getDiscriminatorColumn();
30
-
31
-        // First we need to retrieve the base class & it's normalized
32
-        // type string
33
-        $class = $entityMap->getClass();
34
-        $this->types[] = $this->getTypeStringForEntity($class, $entityMap);
35
-
36
-        // Then, we parse all registered entities for any potential
37
-        // child class.
38
-        $classes = Manager::getInstance()->getRegisteredEntities();
39
-
40
-        foreach ($classes as $otherClass => $entityMap) {
41
-            if (is_subclass_of($otherClass, $class)) {
42
-                $this->types[] = $this->getTypeStringForEntity($otherClass, $entityMap);
43
-            }
44
-        }
45
-    }
46
-
47
-    /**
48
-     * Get the normalized value to use for query on discriminator column.
49
-     *
50
-     * @param string    $class
51
-     * @param EntityMap $entityMap
52
-     *
53
-     * @return string
54
-     */
55
-    protected function getTypeStringForEntity($class, EntityMap $entityMap)
56
-    {
57
-        $class = $entityMap->getClass();
58
-
59
-        $type = array_keys(
60
-            $entityMap->getDiscriminatorColumnMap(),
61
-            $class
62
-        );
63
-
64
-        if (count($type) == 0) {
65
-            return $class;
66
-        }
67
-
68
-        return $type[0];
69
-    }
70
-
71
-    /**
72
-     * Apply the scope to a given Analogue query builder.
73
-     *
74
-     * @param \Analogue\ORM\System\Query $query
75
-     *
76
-     * @return void
77
-     */
78
-    public function apply(Query $query)
79
-    {
80
-        $query->whereIn($this->column, $this->types);
81
-    }
82
-
83
-    /**
84
-     * Remove the scope from the given Analogue query builder.
85
-     *
86
-     * @param mixed $query
87
-     *
88
-     * @return void
89
-     */
90
-    public function remove(Query $query)
91
-    {
92
-        $query = $query->getQuery();
93
-
94
-        foreach ((array) $query->wheres as $key => $where) {
95
-            if ($this->isSingleTableConstraint($where, $this->column)) {
96
-                unset($query->wheres[$key]);
97
-
98
-                $query->wheres = array_values($query->wheres);
99
-            }
100
-        }
101
-    }
102
-
103
-    /**
104
-     * Determine if the given where clause is a single table inheritance constraint.
105
-     *
106
-     * @param array  $where
107
-     * @param string $column
108
-     *
109
-     * @return bool
110
-     */
111
-    protected function isSingleTableConstraint(array $where, $column)
112
-    {
113
-        return $where['column'] == $column;
114
-    }
9
+	/**
10
+	 * Discriminator column name.
11
+	 *
12
+	 * @var string
13
+	 */
14
+	protected $column;
15
+
16
+	/**
17
+	 * Discriminator column allowed types.
18
+	 *
19
+	 * @var array
20
+	 */
21
+	protected $types = [];
22
+
23
+	public function __construct(EntityMap $entityMap)
24
+	{
25
+		// Putting the heavy logic in here, so we won't have
26
+		// to go through it each time we reach for a query
27
+		// builder.
28
+
29
+		$this->column = $entityMap->getDiscriminatorColumn();
30
+
31
+		// First we need to retrieve the base class & it's normalized
32
+		// type string
33
+		$class = $entityMap->getClass();
34
+		$this->types[] = $this->getTypeStringForEntity($class, $entityMap);
35
+
36
+		// Then, we parse all registered entities for any potential
37
+		// child class.
38
+		$classes = Manager::getInstance()->getRegisteredEntities();
39
+
40
+		foreach ($classes as $otherClass => $entityMap) {
41
+			if (is_subclass_of($otherClass, $class)) {
42
+				$this->types[] = $this->getTypeStringForEntity($otherClass, $entityMap);
43
+			}
44
+		}
45
+	}
46
+
47
+	/**
48
+	 * Get the normalized value to use for query on discriminator column.
49
+	 *
50
+	 * @param string    $class
51
+	 * @param EntityMap $entityMap
52
+	 *
53
+	 * @return string
54
+	 */
55
+	protected function getTypeStringForEntity($class, EntityMap $entityMap)
56
+	{
57
+		$class = $entityMap->getClass();
58
+
59
+		$type = array_keys(
60
+			$entityMap->getDiscriminatorColumnMap(),
61
+			$class
62
+		);
63
+
64
+		if (count($type) == 0) {
65
+			return $class;
66
+		}
67
+
68
+		return $type[0];
69
+	}
70
+
71
+	/**
72
+	 * Apply the scope to a given Analogue query builder.
73
+	 *
74
+	 * @param \Analogue\ORM\System\Query $query
75
+	 *
76
+	 * @return void
77
+	 */
78
+	public function apply(Query $query)
79
+	{
80
+		$query->whereIn($this->column, $this->types);
81
+	}
82
+
83
+	/**
84
+	 * Remove the scope from the given Analogue query builder.
85
+	 *
86
+	 * @param mixed $query
87
+	 *
88
+	 * @return void
89
+	 */
90
+	public function remove(Query $query)
91
+	{
92
+		$query = $query->getQuery();
93
+
94
+		foreach ((array) $query->wheres as $key => $where) {
95
+			if ($this->isSingleTableConstraint($where, $this->column)) {
96
+				unset($query->wheres[$key]);
97
+
98
+				$query->wheres = array_values($query->wheres);
99
+			}
100
+		}
101
+	}
102
+
103
+	/**
104
+	 * Determine if the given where clause is a single table inheritance constraint.
105
+	 *
106
+	 * @param array  $where
107
+	 * @param string $column
108
+	 *
109
+	 * @return bool
110
+	 */
111
+	protected function isSingleTableConstraint(array $where, $column)
112
+	{
113
+		return $where['column'] == $column;
114
+	}
115 115
 }
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.
src/MappableTrait.php 1 patch
Indentation   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -8,65 +8,65 @@
 block discarded – undo
8 8
  */
9 9
 trait MappableTrait
10 10
 {
11
-    /**
12
-     * The Entity's Attributes.
13
-     *
14
-     * @var array
15
-     */
16
-    //protected $attributes = [];
11
+	/**
12
+	 * The Entity's Attributes.
13
+	 *
14
+	 * @var array
15
+	 */
16
+	//protected $attributes = [];
17 17
 
18
-    /**
19
-     * Method used by the mapper to set the object
20
-     * attribute raw values (hydration).
21
-     *
22
-     * @param array $attributes
23
-     *
24
-     * @return void
25
-     */
26
-    public function setEntityAttributes(array $attributes)
27
-    {
28
-        $this->attributes = $attributes;
29
-    }
18
+	/**
19
+	 * Method used by the mapper to set the object
20
+	 * attribute raw values (hydration).
21
+	 *
22
+	 * @param array $attributes
23
+	 *
24
+	 * @return void
25
+	 */
26
+	public function setEntityAttributes(array $attributes)
27
+	{
28
+		$this->attributes = $attributes;
29
+	}
30 30
 
31
-    /**
32
-     * Method used by the mapper to get the
33
-     * raw object's values.
34
-     *
35
-     * @return array
36
-     */
37
-    public function getEntityAttributes()
38
-    {
39
-        return $this->attributes;
40
-    }
31
+	/**
32
+	 * Method used by the mapper to get the
33
+	 * raw object's values.
34
+	 *
35
+	 * @return array
36
+	 */
37
+	public function getEntityAttributes()
38
+	{
39
+		return $this->attributes;
40
+	}
41 41
 
42
-    /**
43
-     * Method used by the mapper to set raw
44
-     * key-value pair.
45
-     *
46
-     * @param string $key
47
-     * @param string $value
48
-     *
49
-     * @return void
50
-     */
51
-    public function setEntityAttribute($key, $value)
52
-    {
53
-        $this->attributes[$key] = $value;
54
-    }
42
+	/**
43
+	 * Method used by the mapper to set raw
44
+	 * key-value pair.
45
+	 *
46
+	 * @param string $key
47
+	 * @param string $value
48
+	 *
49
+	 * @return void
50
+	 */
51
+	public function setEntityAttribute($key, $value)
52
+	{
53
+		$this->attributes[$key] = $value;
54
+	}
55 55
 
56
-    /**
57
-     * Method used by the mapper to get single
58
-     * key-value pair.
59
-     *
60
-     * @param string $key
61
-     *
62
-     * @return mixed|null
63
-     */
64
-    public function getEntityAttribute($key)
65
-    {
66
-        if (array_key_exists($key, $this->attributes)) {
67
-            return $this->attributes[$key];
68
-        } else {
69
-            return;
70
-        }
71
-    }
56
+	/**
57
+	 * Method used by the mapper to get single
58
+	 * key-value pair.
59
+	 *
60
+	 * @param string $key
61
+	 *
62
+	 * @return mixed|null
63
+	 */
64
+	public function getEntityAttribute($key)
65
+	{
66
+		if (array_key_exists($key, $this->attributes)) {
67
+			return $this->attributes[$key];
68
+		} else {
69
+			return;
70
+		}
71
+	}
72 72
 }
Please login to merge, or discard this patch.
src/Relationships/MorphPivot.php 1 patch
Indentation   +52 added lines, -52 removed lines patch added patch discarded remove patch
@@ -6,63 +6,63 @@
 block discarded – undo
6 6
 
7 7
 class MorphPivot extends Pivot
8 8
 {
9
-    /**
10
-     * The type of the polymorphic relation.
11
-     *
12
-     * Explicitly define this so it's not included in saved attributes.
13
-     *
14
-     * @var string
15
-     */
16
-    protected $morphType;
9
+	/**
10
+	 * The type of the polymorphic relation.
11
+	 *
12
+	 * Explicitly define this so it's not included in saved attributes.
13
+	 *
14
+	 * @var string
15
+	 */
16
+	protected $morphType;
17 17
 
18
-    /**
19
-     * The value of the polymorphic relation.
20
-     *
21
-     * Explicitly define this so it's not included in saved attributes.
22
-     *
23
-     * @var string
24
-     */
25
-    protected $morphClass;
18
+	/**
19
+	 * The value of the polymorphic relation.
20
+	 *
21
+	 * Explicitly define this so it's not included in saved attributes.
22
+	 *
23
+	 * @var string
24
+	 */
25
+	protected $morphClass;
26 26
 
27
-    /**
28
-     * Set the keys for a save update query.
29
-     *
30
-     * @param Query $query
31
-     *
32
-     * @return Query
33
-     */
34
-    protected function setKeysForSaveQuery(Query $query)
35
-    {
36
-        $query->where($this->morphType, $this->morphClass);
27
+	/**
28
+	 * Set the keys for a save update query.
29
+	 *
30
+	 * @param Query $query
31
+	 *
32
+	 * @return Query
33
+	 */
34
+	protected function setKeysForSaveQuery(Query $query)
35
+	{
36
+		$query->where($this->morphType, $this->morphClass);
37 37
 
38
-        return parent::setKeysForSaveQuery($query);
39
-    }
38
+		return parent::setKeysForSaveQuery($query);
39
+	}
40 40
 
41
-    /**
42
-     * Set the morph type for the pivot.
43
-     *
44
-     * @param string $morphType
45
-     *
46
-     * @return self
47
-     */
48
-    public function setMorphType($morphType)
49
-    {
50
-        $this->morphType = $morphType;
41
+	/**
42
+	 * Set the morph type for the pivot.
43
+	 *
44
+	 * @param string $morphType
45
+	 *
46
+	 * @return self
47
+	 */
48
+	public function setMorphType($morphType)
49
+	{
50
+		$this->morphType = $morphType;
51 51
 
52
-        return $this;
53
-    }
52
+		return $this;
53
+	}
54 54
 
55
-    /**
56
-     * Set the morph class for the pivot.
57
-     *
58
-     * @param string $morphClass
59
-     *
60
-     * @return self
61
-     */
62
-    public function setMorphClass($morphClass)
63
-    {
64
-        $this->morphClass = $morphClass;
55
+	/**
56
+	 * Set the morph class for the pivot.
57
+	 *
58
+	 * @param string $morphClass
59
+	 *
60
+	 * @return self
61
+	 */
62
+	public function setMorphClass($morphClass)
63
+	{
64
+		$this->morphClass = $morphClass;
65 65
 
66
-        return $this;
67
-    }
66
+		return $this;
67
+	}
68 68
 }
Please login to merge, or discard this patch.
src/Relationships/MorphOne.php 1 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 MorphOne extends MorphOneOrMany
6 6
 {
7
-    /**
8
-     * Get the results of the relationship.
9
-     *
10
-     * @param  $relation
11
-     *
12
-     * @return mixed
13
-     */
14
-    public function getResults($relation)
15
-    {
16
-        $result = $this->query->first();
7
+	/**
8
+	 * Get the results of the relationship.
9
+	 *
10
+	 * @param  $relation
11
+	 *
12
+	 * @return mixed
13
+	 */
14
+	public function getResults($relation)
15
+	{
16
+		$result = $this->query->first();
17 17
 
18
-        $this->cacheRelation($result, $relation);
18
+		$this->cacheRelation($result, $relation);
19 19
 
20
-        return $result;
21
-    }
20
+		return $result;
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->matchOne($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->matchOne($results, $relation);
34
+	}
35 35
 }
Please login to merge, or discard this patch.
src/Relationships/BelongsToMany.php 3 patches
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -224,7 +224,7 @@  discard block
 block discarded – undo
224 224
         // release, as this is not quite relevant in a datamapper context.
225 225
         $host = $this;
226 226
 
227
-        return array_map(function ($entity) use ($host) {
227
+        return array_map(function($entity) use ($host) {
228 228
             $entityWrapper = $this->factory->make($entity);
229 229
 
230 230
             $pivot = $this->newExistingPivot($this->cleanPivotAttributes($entityWrapper));
@@ -440,7 +440,7 @@  discard block
 block discarded – undo
440 440
         // Once we have an array dictionary of child objects we can easily match the
441 441
         // children back to their parent using the dictionary and the keys on the
442 442
         // the parent models. Then we will return the hydrated models back out.
443
-        return array_map(function ($result) use ($dictionary, $keyName, $cache, $relation, $host) {
443
+        return array_map(function($result) use ($dictionary, $keyName, $cache, $relation, $host) {
444 444
             if (isset($dictionary[$key = $result[$keyName]])) {
445 445
                 $collection = $host->relatedMap->newCollection($dictionary[$key]);
446 446
 
@@ -739,7 +739,7 @@  discard block
 block discarded – undo
739 739
     {
740 740
         $keyName = $this->relatedMap->getKeyName();
741 741
 
742
-        return array_map(function ($m) use ($keyName) {
742
+        return array_map(function($m) use ($keyName) {
743 743
             return $m->$keyName;
744 744
         }, $entities);
745 745
     }
Please login to merge, or discard this patch.
Doc Comments   +1 added lines patch added patch discarded remove patch
@@ -369,6 +369,7 @@
 block discarded – undo
369 369
      * Set the join clause for the relation query.
370 370
      *
371 371
      * @param  \Analogue\ORM\Query|null
372
+     * @param Query $query
372 373
      *
373 374
      * @return $this
374 375
      */
Please login to merge, or discard this patch.
Indentation   +925 added lines, -925 removed lines patch added patch discarded remove patch
@@ -13,929 +13,929 @@
 block discarded – undo
13 13
 
14 14
 class BelongsToMany extends Relationship
15 15
 {
16
-    /**
17
-     * The intermediate table for the relation.
18
-     *
19
-     * @var string
20
-     */
21
-    protected $table;
22
-
23
-    /**
24
-     * The foreign key of the parent model.
25
-     *
26
-     * @var string
27
-     */
28
-    protected $foreignKey;
29
-
30
-    /**
31
-     * The associated key of the relation.
32
-     *
33
-     * @var string
34
-     */
35
-    protected $otherKey;
36
-
37
-    /**
38
-     * The "name" of the relationship.
39
-     *
40
-     * @var string
41
-     */
42
-    protected $relation;
43
-
44
-    /**
45
-     * The pivot table columns to retrieve.
46
-     *
47
-     * @var array
48
-     */
49
-    protected $pivotColumns = [];
50
-
51
-    /**
52
-     * This relationship has pivot attributes.
53
-     *
54
-     * @var bool
55
-     */
56
-    protected static $hasPivot = true;
57
-
58
-    /**
59
-     * Create a new has many relationship instance.
60
-     *
61
-     * @param Mapper   $mapper
62
-     * @param Mappable $parent
63
-     * @param string   $table
64
-     * @param string   $foreignKey
65
-     * @param string   $otherKey
66
-     * @param string   $relation
67
-     */
68
-    public function __construct(Mapper $mapper, $parent, $table, $foreignKey, $otherKey, $relation)
69
-    {
70
-        $this->table = $table;
71
-        $this->otherKey = $otherKey;
72
-        $this->foreignKey = $foreignKey;
73
-        $this->relation = $relation;
74
-
75
-        parent::__construct($mapper, $parent);
76
-    }
77
-
78
-    /**
79
-     * @param $related
80
-     */
81
-    public function detachMany($related)
82
-    {
83
-        $ids = $this->getIdsFromHashes($related);
84
-
85
-        $this->detach($ids);
86
-    }
87
-
88
-    /**
89
-     * @param array $hashes
90
-     *
91
-     * @return array
92
-     */
93
-    protected function getIdsFromHashes(array $hashes)
94
-    {
95
-        $ids = [];
96
-
97
-        foreach ($hashes as $hash) {
98
-            $split = explode('.', $hash);
99
-            $ids[] = $split[1];
100
-        }
101
-
102
-        return $ids;
103
-    }
104
-
105
-    /**
106
-     * Get the results of the relationship.
107
-     *
108
-     * @param $relation
109
-     *
110
-     * @return EntityCollection
111
-     */
112
-    public function getResults($relation)
113
-    {
114
-        $results = $this->get();
115
-
116
-        $this->cacheRelation($results, $relation);
117
-
118
-        return $results;
119
-    }
120
-
121
-    /**
122
-     * Set a where clause for a pivot table column.
123
-     *
124
-     * @param string $column
125
-     * @param string $operator
126
-     * @param mixed  $value
127
-     * @param string $boolean
128
-     *
129
-     * @return self
130
-     */
131
-    public function wherePivot($column, $operator = null, $value = null, $boolean = 'and')
132
-    {
133
-        return $this->where($this->table.'.'.$column, $operator, $value, $boolean);
134
-    }
135
-
136
-    /**
137
-     * Set an or where clause for a pivot table column.
138
-     *
139
-     * @param string $column
140
-     * @param string $operator
141
-     * @param mixed  $value
142
-     *
143
-     * @return self
144
-     */
145
-    public function orWherePivot($column, $operator = null, $value = null)
146
-    {
147
-        return $this->wherePivot($column, $operator, $value, 'or');
148
-    }
149
-
150
-    /**
151
-     * Return Pivot attributes when available on a relationship.
152
-     *
153
-     * @return array
154
-     */
155
-    public function getPivotAttributes()
156
-    {
157
-        return $this->pivotColumns;
158
-    }
159
-
160
-    /**
161
-     * Execute the query and get the first result.
162
-     *
163
-     * @param array $columns
164
-     *
165
-     * @return mixed
166
-     */
167
-    public function first($columns = ['*'])
168
-    {
169
-        $results = $this->take(1)->get($columns);
170
-
171
-        return count($results) > 0 ? $results->first() : null;
172
-    }
173
-
174
-    /**
175
-     * Execute the query and get the first result or throw an exception.
176
-     *
177
-     * @param array $columns
178
-     *
179
-     * @throws EntityNotFoundException
180
-     *
181
-     * @return Mappable|self
182
-     */
183
-    public function firstOrFail($columns = ['*'])
184
-    {
185
-        if (!is_null($entity = $this->first($columns))) {
186
-            return $entity;
187
-        }
188
-
189
-        throw new EntityNotFoundException();
190
-    }
191
-
192
-    /**
193
-     * Execute the query as a "select" statement.
194
-     *
195
-     * @param array $columns
196
-     *
197
-     * @return \Illuminate\Support\Collection
198
-     */
199
-    public function get($columns = ['*']) : Collection
200
-    {
201
-        // First we'll add the proper select columns onto the query so it is run with
202
-        // the proper columns. Then, we will get the results and hydrate out pivot
203
-        // models with the result of those columns as a separate model relation.
204
-        $columns = $this->query->getQuery()->columns ? [] : $columns;
205
-
206
-        $select = $this->getSelectColumns($columns);
207
-
208
-        $entities = $this->query->addSelect($select)->get()->all();
209
-
210
-        $entities = $this->hydratePivotRelation($entities);
211
-
212
-        return $this->relatedMap->newCollection($entities);
213
-    }
214
-
215
-    /**
216
-     * Hydrate the pivot table relationship on the models.
217
-     *
218
-     * @param array $entities
219
-     *
220
-     * @return void
221
-     */
222
-    protected function hydratePivotRelation(array $entities)
223
-    {
224
-        // TODO (note) We should definitely get rid of the pivot in a next
225
-        // release, as this is not quite relevant in a datamapper context.
226
-        $host = $this;
227
-
228
-        return array_map(function ($entity) use ($host) {
229
-            $entityWrapper = $this->factory->make($entity);
230
-
231
-            $pivot = $this->newExistingPivot($this->cleanPivotAttributes($entityWrapper));
232
-            $entityWrapper->setEntityAttribute('pivot', $pivot);
233
-
234
-            return $entityWrapper->getObject();
235
-        }, $entities);
236
-    }
237
-
238
-    /**
239
-     * Get the pivot attributes from a model.
240
-     *
241
-     * @param  $entity
242
-     *
243
-     * @return array
244
-     */
245
-    protected function cleanPivotAttributes(InternallyMappable $entity)
246
-    {
247
-        $values = [];
248
-
249
-        $attributes = $entity->getEntityAttributes();
250
-
251
-        foreach ($attributes as $key => $value) {
252
-            // To get the pivots attributes we will just take any of the attributes which
253
-            // begin with "pivot_" and add those to this arrays, as well as unsetting
254
-            // them from the parent's models since they exist in a different table.
255
-            if (strpos($key, 'pivot_') === 0) {
256
-                $values[substr($key, 6)] = $value;
257
-
258
-                unset($attributes[$key]);
259
-            }
260
-        }
261
-
262
-        // Rehydrate Entity with cleaned array.
263
-        $entity->setEntityAttributes($attributes);
264
-
265
-        return $values;
266
-    }
267
-
268
-    /**
269
-     * Set the base constraints on the relation query.
270
-     *
271
-     * @return void
272
-     */
273
-    public function addConstraints()
274
-    {
275
-        $this->setJoin();
276
-
277
-        if (static::$constraints) {
278
-            $this->setWhere();
279
-        }
280
-    }
281
-
282
-    /**
283
-     * Add the constraints for a relationship count query.
284
-     *
285
-     * @param Query $query
286
-     * @param Query $parent
287
-     *
288
-     * @return Query
289
-     */
290
-    public function getRelationCountQuery(Query $query, Query $parent)
291
-    {
292
-        if ($parent->getQuery()->from == $query->getQuery()->from) {
293
-            return $this->getRelationCountQueryForSelfJoin($query, $parent);
294
-        }
295
-
296
-        $this->setJoin($query);
297
-
298
-        return parent::getRelationCountQuery($query, $parent);
299
-    }
300
-
301
-    /**
302
-     * Add the constraints for a relationship count query on the same table.
303
-     *
304
-     * @param Query $query
305
-     * @param Query $parent
306
-     *
307
-     * @return Query
308
-     */
309
-    public function getRelationCountQueryForSelfJoin(Query $query, Query $parent)
310
-    {
311
-        $query->select(new Expression('count(*)'));
312
-
313
-        $tablePrefix = $this->query->getQuery()->getConnection()->getTablePrefix();
314
-
315
-        $query->from($this->table.' as '.$tablePrefix.$hash = $this->getRelationCountHash());
316
-
317
-        $key = $this->wrap($this->getQualifiedParentKeyName());
318
-
319
-        return $query->where($hash.'.'.$this->foreignKey, '=', new Expression($key));
320
-    }
321
-
322
-    /**
323
-     * Get a relationship join table hash.
324
-     *
325
-     * @return string
326
-     */
327
-    public function getRelationCountHash()
328
-    {
329
-        return 'self_'.md5(microtime(true));
330
-    }
331
-
332
-    /**
333
-     * Set the select clause for the relation query.
334
-     *
335
-     * @param array $columns
336
-     *
337
-     * @return \Analogue\ORM\Relationships\BelongsToMany
338
-     */
339
-    protected function getSelectColumns(array $columns = ['*'])
340
-    {
341
-        if ($columns == ['*']) {
342
-            $columns = [$this->relatedMap->getTable().'.*'];
343
-        }
344
-
345
-        return array_merge($columns, $this->getAliasedPivotColumns());
346
-    }
347
-
348
-    /**
349
-     * Get the pivot columns for the relation.
350
-     *
351
-     * @return array
352
-     */
353
-    protected function getAliasedPivotColumns()
354
-    {
355
-        $defaults = [$this->foreignKey, $this->otherKey];
356
-
357
-        // We need to alias all of the pivot columns with the "pivot_" prefix so we
358
-        // can easily extract them out of the models and put them into the pivot
359
-        // relationships when they are retrieved and hydrated into the models.
360
-        $columns = [];
361
-
362
-        foreach (array_merge($defaults, $this->pivotColumns) as $column) {
363
-            $columns[] = $this->table.'.'.$column.' as pivot_'.$column;
364
-        }
365
-
366
-        return array_unique($columns);
367
-    }
368
-
369
-    /**
370
-     * Set the join clause for the relation query.
371
-     *
372
-     * @param  \Analogue\ORM\Query|null
373
-     *
374
-     * @return $this
375
-     */
376
-    protected function setJoin($query = null)
377
-    {
378
-        $query = $query ?: $this->query;
379
-
380
-        // We need to join to the intermediate table on the related model's primary
381
-        // key column with the intermediate table's foreign key for the related
382
-        // model instance. Then we can set the "where" for the parent models.
383
-        $baseTable = $this->relatedMap->getTable();
384
-
385
-        $key = $baseTable.'.'.$this->relatedMap->getKeyName();
386
-
387
-        $query->join($this->table, $key, '=', $this->getOtherKey());
388
-
389
-        return $this;
390
-    }
391
-
392
-    /**
393
-     * Set the where clause for the relation query.
394
-     *
395
-     * @return $this
396
-     */
397
-    protected function setWhere()
398
-    {
399
-        $foreign = $this->getForeignKey();
400
-
401
-        $parentKey = $this->parentMap->getKeyName();
402
-
403
-        $this->query->where($foreign, '=', $this->parent->getEntityAttribute($parentKey));
404
-
405
-        return $this;
406
-    }
407
-
408
-    /**
409
-     * Set the constraints for an eager load of the relation.
410
-     *
411
-     * @param array $results
412
-     *
413
-     * @return void
414
-     */
415
-    public function addEagerConstraints(array $results)
416
-    {
417
-        $this->query->whereIn($this->getForeignKey(), $this->getKeysFromResults($results));
418
-    }
419
-
420
-    /**
421
-     * Match Eagerly loaded relation to result.
422
-     *
423
-     * @param array  $results
424
-     * @param string $relation
425
-     *
426
-     * @return array
427
-     */
428
-    public function match(array $results, $relation)
429
-    {
430
-        $entities = $this->getEager();
431
-
432
-        // TODO; optimize this operation
433
-        $dictionary = $this->buildDictionary($entities);
434
-
435
-        $keyName = $this->parentMap->getKeyName();
436
-
437
-        $cache = $this->parentMapper->getEntityCache();
438
-
439
-        $host = $this;
440
-
441
-        // Once we have an array dictionary of child objects we can easily match the
442
-        // children back to their parent using the dictionary and the keys on the
443
-        // the parent models. Then we will return the hydrated models back out.
444
-        return array_map(function ($result) use ($dictionary, $keyName, $cache, $relation, $host) {
445
-            if (isset($dictionary[$key = $result[$keyName]])) {
446
-                $collection = $host->relatedMap->newCollection($dictionary[$key]);
447
-
448
-                $result[$relation] = $collection;
449
-
450
-                // TODO Refactor this
451
-                $cache->cacheLoadedRelationResult($key, $relation, $collection, $this);
452
-            } else {
453
-                $result[$relation] = $host->relatedMap->newCollection();
454
-            }
455
-
456
-            return $result;
457
-        }, $results);
458
-    }
459
-
460
-    /**
461
-     * Build model dictionary keyed by the relation's foreign key.
462
-     *
463
-     * @param EntityCollection $results
464
-     *
465
-     * @return array
466
-     */
467
-    protected function buildDictionary(EntityCollection $results)
468
-    {
469
-        $foreign = $this->foreignKey;
470
-
471
-        // First we will build a dictionary of child models keyed by the foreign key
472
-        // of the relation so that we will easily and quickly match them to their
473
-        // parents without having a possibly slow inner loops for every models.
474
-        $dictionary = [];
475
-
476
-        foreach ($results as $entity) {
477
-            $wrapper = $this->factory->make($entity);
478
-            $dictionary[$wrapper->getEntityAttribute('pivot')->$foreign][] = $entity;
479
-        }
480
-
481
-        return $dictionary;
482
-    }
483
-
484
-    /**
485
-     * Get all of the IDs for the related models.
486
-     *
487
-     * @return array
488
-     */
489
-    public function getRelatedIds()
490
-    {
491
-        $fullKey = $this->relatedMap->getQualifiedKeyName();
492
-
493
-        return $this->getQuery()->select($fullKey)->lists($this->relatedMap->getKeyName());
494
-    }
495
-
496
-    /**
497
-     * Update Pivot.
498
-     *
499
-     * @param \Analogue\ORM\Entity $entity
500
-     *
501
-     * @return void
502
-     */
503
-    public function updatePivot($entity)
504
-    {
505
-        $keyName = $this->relatedMap->getKeyName();
506
-
507
-        $this->updateExistingPivot(
508
-            $entity->getEntityAttribute($keyName),
509
-            $entity->getEntityAttribute('pivot')->getEntityAttributes()
510
-        );
511
-    }
512
-
513
-    /**
514
-     * Update Multiple pivot.
515
-     *
516
-     * @param  $relatedEntities
517
-     *
518
-     * @return void
519
-     */
520
-    public function updatePivots($relatedEntities)
521
-    {
522
-        foreach ($relatedEntities as $entity) {
523
-            $this->updatePivot($entity);
524
-        }
525
-    }
526
-
527
-    /**
528
-     * Create Pivot Records.
529
-     *
530
-     * @param \Analogue\ORM\Entity[] $relatedEntities
531
-     *
532
-     * @return void
533
-     */
534
-    public function createPivots($relatedEntities)
535
-    {
536
-        $keys = [];
537
-        $attributes = [];
538
-
539
-        $keyName = $this->relatedMap->getKeyName();
540
-
541
-        foreach ($relatedEntities as $entity) {
542
-            $keys[] = $entity->getEntityAttribute($keyName);
543
-        }
544
-
545
-        $records = $this->createAttachRecords($keys, $attributes);
546
-
547
-        $this->query->getQuery()->from($this->table)->insert($records);
548
-    }
549
-
550
-    /**
551
-     * Update an existing pivot record on the table.
552
-     *
553
-     * @param mixed $id
554
-     * @param array $attributes
555
-     *
556
-     * @throws \InvalidArgumentException
557
-     *
558
-     * @return int
559
-     */
560
-    public function updateExistingPivot($id, array $attributes)
561
-    {
562
-        if (in_array($this->updatedAt(), $this->pivotColumns)) {
563
-            $attributes = $this->setTimestampsOnAttach($attributes, true);
564
-        }
565
-
566
-        return $this->newPivotStatementForId($id)->update($attributes);
567
-    }
568
-
569
-    /**
570
-     * Attach a model to the parent.
571
-     *
572
-     * @param mixed $id
573
-     * @param array $attributes
574
-     *
575
-     * @return void
576
-     */
577
-    public function attach($id, array $attributes = [])
578
-    {
579
-        $query = $this->newPivotStatement();
580
-
581
-        $query->insert($this->createAttachRecords((array) $id, $attributes));
582
-    }
583
-
584
-    /**
585
-     * @param array $entities
586
-     *
587
-     * @throws \InvalidArgumentException
588
-     */
589
-    public function sync(array $entities)
590
-    {
591
-        $this->detachExcept($entities);
592
-    }
593
-
594
-    /**
595
-     * Detach related entities that are not in $id.
596
-     *
597
-     * @param array $entities
598
-     *
599
-     * @throws \InvalidArgumentException
600
-     *
601
-     * @return void
602
-     */
603
-    protected function detachExcept(array $entities = [])
604
-    {
605
-        $query = $this->newPivotQuery();
606
-
607
-        if (count($entities) > 0) {
608
-            $keys = $this->getKeys($entities);
609
-
610
-            $query->whereNotIn($this->otherKey, $keys);
611
-        }
612
-        $parentKey = $this->parentMap->getKeyName();
613
-
614
-        $query->where($this->foreignKey, '=', $this->parent->getEntityAttribute($parentKey));
615
-
616
-        $query->delete();
617
-
618
-        $query = $this->newPivotQuery();
619
-    }
620
-
621
-    /**
622
-     * Create an array of records to insert into the pivot table.
623
-     *
624
-     * @param array $ids
625
-     * @param array $attributes
626
-     *
627
-     * @return array
628
-     */
629
-    protected function createAttachRecords($ids, array $attributes)
630
-    {
631
-        $records = [];
632
-
633
-        $timed = in_array($this->createdAt(), $this->pivotColumns);
634
-
635
-        // To create the attachment records, we will simply spin through the IDs given
636
-        // and create a new record to insert for each ID. Each ID may actually be a
637
-        // key in the array, with extra attributes to be placed in other columns.
638
-        foreach ($ids as $key => $value) {
639
-            $records[] = $this->attacher($key, $value, $attributes, $timed);
640
-        }
641
-
642
-        return $records;
643
-    }
644
-
645
-    /**
646
-     * Create a full attachment record payload.
647
-     *
648
-     * @param int   $key
649
-     * @param mixed $value
650
-     * @param array $attributes
651
-     * @param bool  $timed
652
-     *
653
-     * @return array
654
-     */
655
-    protected function attacher($key, $value, $attributes, $timed)
656
-    {
657
-        list($id, $extra) = $this->getAttachId($key, $value, $attributes);
658
-
659
-        // To create the attachment records, we will simply spin through the IDs given
660
-        // and create a new record to insert for each ID. Each ID may actually be a
661
-        // key in the array, with extra attributes to be placed in other columns.
662
-        $record = $this->createAttachRecord($id, $timed);
663
-
664
-        return array_merge($record, $extra);
665
-    }
666
-
667
-    /**
668
-     * Get the attach record ID and extra attributes.
669
-     *
670
-     * @param int   $key
671
-     * @param mixed $value
672
-     * @param array $attributes
673
-     *
674
-     * @return array
675
-     */
676
-    protected function getAttachId($key, $value, array $attributes)
677
-    {
678
-        if (is_array($value)) {
679
-            return [$key, array_merge($value, $attributes)];
680
-        }
681
-
682
-        return [$value, $attributes];
683
-    }
684
-
685
-    /**
686
-     * Create a new pivot attachment record.
687
-     *
688
-     * @param int  $id
689
-     * @param bool $timed
690
-     *
691
-     * @return array
692
-     */
693
-    protected function createAttachRecord($id, $timed)
694
-    {
695
-        $parentKey = $this->parentMap->getKeyName();
696
-
697
-        $record = [];
698
-
699
-        $record[$this->foreignKey] = $this->parent->getEntityAttribute($parentKey);
700
-
701
-        $record[$this->otherKey] = $id;
702
-
703
-        // If the record needs to have creation and update timestamps, we will make
704
-        // them by calling the parent model's "freshTimestamp" method which will
705
-        // provide us with a fresh timestamp in this model's preferred format.
706
-        if ($timed) {
707
-            $record = $this->setTimestampsOnAttach($record);
708
-        }
709
-
710
-        return $record;
711
-    }
712
-
713
-    /**
714
-     * Set the creation and update timestamps on an attach record.
715
-     *
716
-     * @param array $record
717
-     * @param bool  $exists
718
-     *
719
-     * @return array
720
-     */
721
-    protected function setTimestampsOnAttach(array $record, $exists = false)
722
-    {
723
-        $fresh = $this->freshTimestamp();
724
-
725
-        if (!$exists) {
726
-            $record[$this->createdAt()] = $fresh;
727
-        }
728
-
729
-        $record[$this->updatedAt()] = $fresh;
730
-
731
-        return $record;
732
-    }
733
-
734
-    /**
735
-     * @param EntityCollection $entities
736
-     *
737
-     * @return array
738
-     */
739
-    protected function getModelKeysFromCollection(EntityCollection $entities)
740
-    {
741
-        $keyName = $this->relatedMap->getKeyName();
742
-
743
-        return array_map(function ($m) use ($keyName) {
744
-            return $m->$keyName;
745
-        }, $entities);
746
-    }
747
-
748
-    /**
749
-     * Detach models from the relationship.
750
-     *
751
-     * @param int|array $ids
752
-     *
753
-     * @throws \InvalidArgumentException
754
-     *
755
-     * @return int
756
-     */
757
-    public function detach($ids = [])
758
-    {
759
-        if ($ids instanceof EntityCollection) {
760
-            $ids = (array) $ids->modelKeys();
761
-        }
762
-
763
-        $query = $this->newPivotQuery();
764
-
765
-        // If associated IDs were passed to the method we will only delete those
766
-        // associations, otherwise all of the association ties will be broken.
767
-        // We'll return the numbers of affected rows when we do the deletes.
768
-        $ids = (array) $ids;
769
-
770
-        if (count($ids) > 0) {
771
-            $query->whereIn($this->otherKey, (array) $ids);
772
-        }
773
-
774
-        // Once we have all of the conditions set on the statement, we are ready
775
-        // to run the delete on the pivot table. Then, if the touch parameter
776
-        // is true, we will go ahead and touch all related models to sync.
777
-        return $query->delete();
778
-    }
779
-
780
-    /**
781
-     * Create a new query builder for the pivot table.
782
-     *
783
-     * @throws \InvalidArgumentException
784
-     *
785
-     * @return \Illuminate\Database\Query\Builder
786
-     */
787
-    protected function newPivotQuery()
788
-    {
789
-        $query = $this->newPivotStatement();
790
-
791
-        $parentKey = $this->parentMap->getKeyName();
792
-
793
-        return $query->where($this->foreignKey, $this->parent->getEntityAttribute($parentKey));
794
-    }
795
-
796
-    /**
797
-     * Get a new plain query builder for the pivot table.
798
-     *
799
-     * @return \Illuminate\Database\Query\Builder
800
-     */
801
-    public function newPivotStatement()
802
-    {
803
-        return $this->query->getQuery()->newQuery()->from($this->table);
804
-    }
805
-
806
-    /**
807
-     * Get a new pivot statement for a given "other" ID.
808
-     *
809
-     * @param mixed $id
810
-     *
811
-     * @throws \InvalidArgumentException
812
-     *
813
-     * @return \Illuminate\Database\Query\Builder
814
-     */
815
-    public function newPivotStatementForId($id)
816
-    {
817
-        $pivot = $this->newPivotStatement();
818
-
819
-        $parentKeyName = $this->parentMap->getKeyName();
820
-
821
-        $key = $this->parent->getEntityAttribute($parentKeyName);
822
-
823
-        return $pivot->where($this->foreignKey, $key)->where($this->otherKey, $id);
824
-    }
825
-
826
-    /**
827
-     * Create a new pivot model instance.
828
-     *
829
-     * @param array $attributes
830
-     * @param bool  $exists
831
-     *
832
-     * @return \Analogue\ORM\Relationships\Pivot
833
-     */
834
-    public function newPivot(array $attributes = [], $exists = false)
835
-    {
836
-        $pivot = new Pivot($this->parent, $this->parentMap, $attributes, $this->table, $exists);
837
-
838
-        return $pivot->setPivotKeys($this->foreignKey, $this->otherKey);
839
-    }
840
-
841
-    /**
842
-     * Create a new existing pivot model instance.
843
-     *
844
-     * @param array $attributes
845
-     *
846
-     * @return \Analogue\ORM\Relationships\Pivot
847
-     */
848
-    public function newExistingPivot(array $attributes = [])
849
-    {
850
-        return $this->newPivot($attributes, true);
851
-    }
852
-
853
-    /**
854
-     * Set the columns on the pivot table to retrieve.
855
-     *
856
-     * @param array $columns
857
-     *
858
-     * @return $this
859
-     */
860
-    public function withPivot($columns)
861
-    {
862
-        $columns = is_array($columns) ? $columns : func_get_args();
863
-
864
-        $this->pivotColumns = array_merge($this->pivotColumns, $columns);
865
-
866
-        return $this;
867
-    }
868
-
869
-    /**
870
-     * Specify that the pivot table has creation and update timestamps.
871
-     *
872
-     * @param mixed $createdAt
873
-     * @param mixed $updatedAt
874
-     *
875
-     * @return \Analogue\ORM\Relationships\BelongsToMany
876
-     */
877
-    public function withTimestamps($createdAt = null, $updatedAt = null)
878
-    {
879
-        return $this->withPivot($createdAt ?: $this->createdAt(), $updatedAt ?: $this->updatedAt());
880
-    }
881
-
882
-    /**
883
-     * Get the key for comparing against the parent key in "has" query.
884
-     *
885
-     * @return string
886
-     */
887
-    public function getHasCompareKey()
888
-    {
889
-        return $this->getForeignKey();
890
-    }
891
-
892
-    /**
893
-     * Get the fully qualified foreign key for the relation.
894
-     *
895
-     * @return string
896
-     */
897
-    public function getForeignKey()
898
-    {
899
-        return $this->table.'.'.$this->foreignKey;
900
-    }
901
-
902
-    /**
903
-     * Get the fully qualified "other key" for the relation.
904
-     *
905
-     * @return string
906
-     */
907
-    public function getOtherKey()
908
-    {
909
-        return $this->table.'.'.$this->otherKey;
910
-    }
911
-
912
-    /**
913
-     * Get the fully qualified parent key name.
914
-     *
915
-     * @return string
916
-     */
917
-    protected function getQualifiedParentKeyName()
918
-    {
919
-        return $this->parentMap->getQualifiedKeyName();
920
-    }
921
-
922
-    /**
923
-     * Get the intermediate table for the relationship.
924
-     *
925
-     * @return string
926
-     */
927
-    public function getTable()
928
-    {
929
-        return $this->table;
930
-    }
931
-
932
-    /**
933
-     * Get the relationship name for the relationship.
934
-     *
935
-     * @return string
936
-     */
937
-    public function getRelationName()
938
-    {
939
-        return $this->relation;
940
-    }
16
+	/**
17
+	 * The intermediate table for the relation.
18
+	 *
19
+	 * @var string
20
+	 */
21
+	protected $table;
22
+
23
+	/**
24
+	 * The foreign key of the parent model.
25
+	 *
26
+	 * @var string
27
+	 */
28
+	protected $foreignKey;
29
+
30
+	/**
31
+	 * The associated key of the relation.
32
+	 *
33
+	 * @var string
34
+	 */
35
+	protected $otherKey;
36
+
37
+	/**
38
+	 * The "name" of the relationship.
39
+	 *
40
+	 * @var string
41
+	 */
42
+	protected $relation;
43
+
44
+	/**
45
+	 * The pivot table columns to retrieve.
46
+	 *
47
+	 * @var array
48
+	 */
49
+	protected $pivotColumns = [];
50
+
51
+	/**
52
+	 * This relationship has pivot attributes.
53
+	 *
54
+	 * @var bool
55
+	 */
56
+	protected static $hasPivot = true;
57
+
58
+	/**
59
+	 * Create a new has many relationship instance.
60
+	 *
61
+	 * @param Mapper   $mapper
62
+	 * @param Mappable $parent
63
+	 * @param string   $table
64
+	 * @param string   $foreignKey
65
+	 * @param string   $otherKey
66
+	 * @param string   $relation
67
+	 */
68
+	public function __construct(Mapper $mapper, $parent, $table, $foreignKey, $otherKey, $relation)
69
+	{
70
+		$this->table = $table;
71
+		$this->otherKey = $otherKey;
72
+		$this->foreignKey = $foreignKey;
73
+		$this->relation = $relation;
74
+
75
+		parent::__construct($mapper, $parent);
76
+	}
77
+
78
+	/**
79
+	 * @param $related
80
+	 */
81
+	public function detachMany($related)
82
+	{
83
+		$ids = $this->getIdsFromHashes($related);
84
+
85
+		$this->detach($ids);
86
+	}
87
+
88
+	/**
89
+	 * @param array $hashes
90
+	 *
91
+	 * @return array
92
+	 */
93
+	protected function getIdsFromHashes(array $hashes)
94
+	{
95
+		$ids = [];
96
+
97
+		foreach ($hashes as $hash) {
98
+			$split = explode('.', $hash);
99
+			$ids[] = $split[1];
100
+		}
101
+
102
+		return $ids;
103
+	}
104
+
105
+	/**
106
+	 * Get the results of the relationship.
107
+	 *
108
+	 * @param $relation
109
+	 *
110
+	 * @return EntityCollection
111
+	 */
112
+	public function getResults($relation)
113
+	{
114
+		$results = $this->get();
115
+
116
+		$this->cacheRelation($results, $relation);
117
+
118
+		return $results;
119
+	}
120
+
121
+	/**
122
+	 * Set a where clause for a pivot table column.
123
+	 *
124
+	 * @param string $column
125
+	 * @param string $operator
126
+	 * @param mixed  $value
127
+	 * @param string $boolean
128
+	 *
129
+	 * @return self
130
+	 */
131
+	public function wherePivot($column, $operator = null, $value = null, $boolean = 'and')
132
+	{
133
+		return $this->where($this->table.'.'.$column, $operator, $value, $boolean);
134
+	}
135
+
136
+	/**
137
+	 * Set an or where clause for a pivot table column.
138
+	 *
139
+	 * @param string $column
140
+	 * @param string $operator
141
+	 * @param mixed  $value
142
+	 *
143
+	 * @return self
144
+	 */
145
+	public function orWherePivot($column, $operator = null, $value = null)
146
+	{
147
+		return $this->wherePivot($column, $operator, $value, 'or');
148
+	}
149
+
150
+	/**
151
+	 * Return Pivot attributes when available on a relationship.
152
+	 *
153
+	 * @return array
154
+	 */
155
+	public function getPivotAttributes()
156
+	{
157
+		return $this->pivotColumns;
158
+	}
159
+
160
+	/**
161
+	 * Execute the query and get the first result.
162
+	 *
163
+	 * @param array $columns
164
+	 *
165
+	 * @return mixed
166
+	 */
167
+	public function first($columns = ['*'])
168
+	{
169
+		$results = $this->take(1)->get($columns);
170
+
171
+		return count($results) > 0 ? $results->first() : null;
172
+	}
173
+
174
+	/**
175
+	 * Execute the query and get the first result or throw an exception.
176
+	 *
177
+	 * @param array $columns
178
+	 *
179
+	 * @throws EntityNotFoundException
180
+	 *
181
+	 * @return Mappable|self
182
+	 */
183
+	public function firstOrFail($columns = ['*'])
184
+	{
185
+		if (!is_null($entity = $this->first($columns))) {
186
+			return $entity;
187
+		}
188
+
189
+		throw new EntityNotFoundException();
190
+	}
191
+
192
+	/**
193
+	 * Execute the query as a "select" statement.
194
+	 *
195
+	 * @param array $columns
196
+	 *
197
+	 * @return \Illuminate\Support\Collection
198
+	 */
199
+	public function get($columns = ['*']) : Collection
200
+	{
201
+		// First we'll add the proper select columns onto the query so it is run with
202
+		// the proper columns. Then, we will get the results and hydrate out pivot
203
+		// models with the result of those columns as a separate model relation.
204
+		$columns = $this->query->getQuery()->columns ? [] : $columns;
205
+
206
+		$select = $this->getSelectColumns($columns);
207
+
208
+		$entities = $this->query->addSelect($select)->get()->all();
209
+
210
+		$entities = $this->hydratePivotRelation($entities);
211
+
212
+		return $this->relatedMap->newCollection($entities);
213
+	}
214
+
215
+	/**
216
+	 * Hydrate the pivot table relationship on the models.
217
+	 *
218
+	 * @param array $entities
219
+	 *
220
+	 * @return void
221
+	 */
222
+	protected function hydratePivotRelation(array $entities)
223
+	{
224
+		// TODO (note) We should definitely get rid of the pivot in a next
225
+		// release, as this is not quite relevant in a datamapper context.
226
+		$host = $this;
227
+
228
+		return array_map(function ($entity) use ($host) {
229
+			$entityWrapper = $this->factory->make($entity);
230
+
231
+			$pivot = $this->newExistingPivot($this->cleanPivotAttributes($entityWrapper));
232
+			$entityWrapper->setEntityAttribute('pivot', $pivot);
233
+
234
+			return $entityWrapper->getObject();
235
+		}, $entities);
236
+	}
237
+
238
+	/**
239
+	 * Get the pivot attributes from a model.
240
+	 *
241
+	 * @param  $entity
242
+	 *
243
+	 * @return array
244
+	 */
245
+	protected function cleanPivotAttributes(InternallyMappable $entity)
246
+	{
247
+		$values = [];
248
+
249
+		$attributes = $entity->getEntityAttributes();
250
+
251
+		foreach ($attributes as $key => $value) {
252
+			// To get the pivots attributes we will just take any of the attributes which
253
+			// begin with "pivot_" and add those to this arrays, as well as unsetting
254
+			// them from the parent's models since they exist in a different table.
255
+			if (strpos($key, 'pivot_') === 0) {
256
+				$values[substr($key, 6)] = $value;
257
+
258
+				unset($attributes[$key]);
259
+			}
260
+		}
261
+
262
+		// Rehydrate Entity with cleaned array.
263
+		$entity->setEntityAttributes($attributes);
264
+
265
+		return $values;
266
+	}
267
+
268
+	/**
269
+	 * Set the base constraints on the relation query.
270
+	 *
271
+	 * @return void
272
+	 */
273
+	public function addConstraints()
274
+	{
275
+		$this->setJoin();
276
+
277
+		if (static::$constraints) {
278
+			$this->setWhere();
279
+		}
280
+	}
281
+
282
+	/**
283
+	 * Add the constraints for a relationship count query.
284
+	 *
285
+	 * @param Query $query
286
+	 * @param Query $parent
287
+	 *
288
+	 * @return Query
289
+	 */
290
+	public function getRelationCountQuery(Query $query, Query $parent)
291
+	{
292
+		if ($parent->getQuery()->from == $query->getQuery()->from) {
293
+			return $this->getRelationCountQueryForSelfJoin($query, $parent);
294
+		}
295
+
296
+		$this->setJoin($query);
297
+
298
+		return parent::getRelationCountQuery($query, $parent);
299
+	}
300
+
301
+	/**
302
+	 * Add the constraints for a relationship count query on the same table.
303
+	 *
304
+	 * @param Query $query
305
+	 * @param Query $parent
306
+	 *
307
+	 * @return Query
308
+	 */
309
+	public function getRelationCountQueryForSelfJoin(Query $query, Query $parent)
310
+	{
311
+		$query->select(new Expression('count(*)'));
312
+
313
+		$tablePrefix = $this->query->getQuery()->getConnection()->getTablePrefix();
314
+
315
+		$query->from($this->table.' as '.$tablePrefix.$hash = $this->getRelationCountHash());
316
+
317
+		$key = $this->wrap($this->getQualifiedParentKeyName());
318
+
319
+		return $query->where($hash.'.'.$this->foreignKey, '=', new Expression($key));
320
+	}
321
+
322
+	/**
323
+	 * Get a relationship join table hash.
324
+	 *
325
+	 * @return string
326
+	 */
327
+	public function getRelationCountHash()
328
+	{
329
+		return 'self_'.md5(microtime(true));
330
+	}
331
+
332
+	/**
333
+	 * Set the select clause for the relation query.
334
+	 *
335
+	 * @param array $columns
336
+	 *
337
+	 * @return \Analogue\ORM\Relationships\BelongsToMany
338
+	 */
339
+	protected function getSelectColumns(array $columns = ['*'])
340
+	{
341
+		if ($columns == ['*']) {
342
+			$columns = [$this->relatedMap->getTable().'.*'];
343
+		}
344
+
345
+		return array_merge($columns, $this->getAliasedPivotColumns());
346
+	}
347
+
348
+	/**
349
+	 * Get the pivot columns for the relation.
350
+	 *
351
+	 * @return array
352
+	 */
353
+	protected function getAliasedPivotColumns()
354
+	{
355
+		$defaults = [$this->foreignKey, $this->otherKey];
356
+
357
+		// We need to alias all of the pivot columns with the "pivot_" prefix so we
358
+		// can easily extract them out of the models and put them into the pivot
359
+		// relationships when they are retrieved and hydrated into the models.
360
+		$columns = [];
361
+
362
+		foreach (array_merge($defaults, $this->pivotColumns) as $column) {
363
+			$columns[] = $this->table.'.'.$column.' as pivot_'.$column;
364
+		}
365
+
366
+		return array_unique($columns);
367
+	}
368
+
369
+	/**
370
+	 * Set the join clause for the relation query.
371
+	 *
372
+	 * @param  \Analogue\ORM\Query|null
373
+	 *
374
+	 * @return $this
375
+	 */
376
+	protected function setJoin($query = null)
377
+	{
378
+		$query = $query ?: $this->query;
379
+
380
+		// We need to join to the intermediate table on the related model's primary
381
+		// key column with the intermediate table's foreign key for the related
382
+		// model instance. Then we can set the "where" for the parent models.
383
+		$baseTable = $this->relatedMap->getTable();
384
+
385
+		$key = $baseTable.'.'.$this->relatedMap->getKeyName();
386
+
387
+		$query->join($this->table, $key, '=', $this->getOtherKey());
388
+
389
+		return $this;
390
+	}
391
+
392
+	/**
393
+	 * Set the where clause for the relation query.
394
+	 *
395
+	 * @return $this
396
+	 */
397
+	protected function setWhere()
398
+	{
399
+		$foreign = $this->getForeignKey();
400
+
401
+		$parentKey = $this->parentMap->getKeyName();
402
+
403
+		$this->query->where($foreign, '=', $this->parent->getEntityAttribute($parentKey));
404
+
405
+		return $this;
406
+	}
407
+
408
+	/**
409
+	 * Set the constraints for an eager load of the relation.
410
+	 *
411
+	 * @param array $results
412
+	 *
413
+	 * @return void
414
+	 */
415
+	public function addEagerConstraints(array $results)
416
+	{
417
+		$this->query->whereIn($this->getForeignKey(), $this->getKeysFromResults($results));
418
+	}
419
+
420
+	/**
421
+	 * Match Eagerly loaded relation to result.
422
+	 *
423
+	 * @param array  $results
424
+	 * @param string $relation
425
+	 *
426
+	 * @return array
427
+	 */
428
+	public function match(array $results, $relation)
429
+	{
430
+		$entities = $this->getEager();
431
+
432
+		// TODO; optimize this operation
433
+		$dictionary = $this->buildDictionary($entities);
434
+
435
+		$keyName = $this->parentMap->getKeyName();
436
+
437
+		$cache = $this->parentMapper->getEntityCache();
438
+
439
+		$host = $this;
440
+
441
+		// Once we have an array dictionary of child objects we can easily match the
442
+		// children back to their parent using the dictionary and the keys on the
443
+		// the parent models. Then we will return the hydrated models back out.
444
+		return array_map(function ($result) use ($dictionary, $keyName, $cache, $relation, $host) {
445
+			if (isset($dictionary[$key = $result[$keyName]])) {
446
+				$collection = $host->relatedMap->newCollection($dictionary[$key]);
447
+
448
+				$result[$relation] = $collection;
449
+
450
+				// TODO Refactor this
451
+				$cache->cacheLoadedRelationResult($key, $relation, $collection, $this);
452
+			} else {
453
+				$result[$relation] = $host->relatedMap->newCollection();
454
+			}
455
+
456
+			return $result;
457
+		}, $results);
458
+	}
459
+
460
+	/**
461
+	 * Build model dictionary keyed by the relation's foreign key.
462
+	 *
463
+	 * @param EntityCollection $results
464
+	 *
465
+	 * @return array
466
+	 */
467
+	protected function buildDictionary(EntityCollection $results)
468
+	{
469
+		$foreign = $this->foreignKey;
470
+
471
+		// First we will build a dictionary of child models keyed by the foreign key
472
+		// of the relation so that we will easily and quickly match them to their
473
+		// parents without having a possibly slow inner loops for every models.
474
+		$dictionary = [];
475
+
476
+		foreach ($results as $entity) {
477
+			$wrapper = $this->factory->make($entity);
478
+			$dictionary[$wrapper->getEntityAttribute('pivot')->$foreign][] = $entity;
479
+		}
480
+
481
+		return $dictionary;
482
+	}
483
+
484
+	/**
485
+	 * Get all of the IDs for the related models.
486
+	 *
487
+	 * @return array
488
+	 */
489
+	public function getRelatedIds()
490
+	{
491
+		$fullKey = $this->relatedMap->getQualifiedKeyName();
492
+
493
+		return $this->getQuery()->select($fullKey)->lists($this->relatedMap->getKeyName());
494
+	}
495
+
496
+	/**
497
+	 * Update Pivot.
498
+	 *
499
+	 * @param \Analogue\ORM\Entity $entity
500
+	 *
501
+	 * @return void
502
+	 */
503
+	public function updatePivot($entity)
504
+	{
505
+		$keyName = $this->relatedMap->getKeyName();
506
+
507
+		$this->updateExistingPivot(
508
+			$entity->getEntityAttribute($keyName),
509
+			$entity->getEntityAttribute('pivot')->getEntityAttributes()
510
+		);
511
+	}
512
+
513
+	/**
514
+	 * Update Multiple pivot.
515
+	 *
516
+	 * @param  $relatedEntities
517
+	 *
518
+	 * @return void
519
+	 */
520
+	public function updatePivots($relatedEntities)
521
+	{
522
+		foreach ($relatedEntities as $entity) {
523
+			$this->updatePivot($entity);
524
+		}
525
+	}
526
+
527
+	/**
528
+	 * Create Pivot Records.
529
+	 *
530
+	 * @param \Analogue\ORM\Entity[] $relatedEntities
531
+	 *
532
+	 * @return void
533
+	 */
534
+	public function createPivots($relatedEntities)
535
+	{
536
+		$keys = [];
537
+		$attributes = [];
538
+
539
+		$keyName = $this->relatedMap->getKeyName();
540
+
541
+		foreach ($relatedEntities as $entity) {
542
+			$keys[] = $entity->getEntityAttribute($keyName);
543
+		}
544
+
545
+		$records = $this->createAttachRecords($keys, $attributes);
546
+
547
+		$this->query->getQuery()->from($this->table)->insert($records);
548
+	}
549
+
550
+	/**
551
+	 * Update an existing pivot record on the table.
552
+	 *
553
+	 * @param mixed $id
554
+	 * @param array $attributes
555
+	 *
556
+	 * @throws \InvalidArgumentException
557
+	 *
558
+	 * @return int
559
+	 */
560
+	public function updateExistingPivot($id, array $attributes)
561
+	{
562
+		if (in_array($this->updatedAt(), $this->pivotColumns)) {
563
+			$attributes = $this->setTimestampsOnAttach($attributes, true);
564
+		}
565
+
566
+		return $this->newPivotStatementForId($id)->update($attributes);
567
+	}
568
+
569
+	/**
570
+	 * Attach a model to the parent.
571
+	 *
572
+	 * @param mixed $id
573
+	 * @param array $attributes
574
+	 *
575
+	 * @return void
576
+	 */
577
+	public function attach($id, array $attributes = [])
578
+	{
579
+		$query = $this->newPivotStatement();
580
+
581
+		$query->insert($this->createAttachRecords((array) $id, $attributes));
582
+	}
583
+
584
+	/**
585
+	 * @param array $entities
586
+	 *
587
+	 * @throws \InvalidArgumentException
588
+	 */
589
+	public function sync(array $entities)
590
+	{
591
+		$this->detachExcept($entities);
592
+	}
593
+
594
+	/**
595
+	 * Detach related entities that are not in $id.
596
+	 *
597
+	 * @param array $entities
598
+	 *
599
+	 * @throws \InvalidArgumentException
600
+	 *
601
+	 * @return void
602
+	 */
603
+	protected function detachExcept(array $entities = [])
604
+	{
605
+		$query = $this->newPivotQuery();
606
+
607
+		if (count($entities) > 0) {
608
+			$keys = $this->getKeys($entities);
609
+
610
+			$query->whereNotIn($this->otherKey, $keys);
611
+		}
612
+		$parentKey = $this->parentMap->getKeyName();
613
+
614
+		$query->where($this->foreignKey, '=', $this->parent->getEntityAttribute($parentKey));
615
+
616
+		$query->delete();
617
+
618
+		$query = $this->newPivotQuery();
619
+	}
620
+
621
+	/**
622
+	 * Create an array of records to insert into the pivot table.
623
+	 *
624
+	 * @param array $ids
625
+	 * @param array $attributes
626
+	 *
627
+	 * @return array
628
+	 */
629
+	protected function createAttachRecords($ids, array $attributes)
630
+	{
631
+		$records = [];
632
+
633
+		$timed = in_array($this->createdAt(), $this->pivotColumns);
634
+
635
+		// To create the attachment records, we will simply spin through the IDs given
636
+		// and create a new record to insert for each ID. Each ID may actually be a
637
+		// key in the array, with extra attributes to be placed in other columns.
638
+		foreach ($ids as $key => $value) {
639
+			$records[] = $this->attacher($key, $value, $attributes, $timed);
640
+		}
641
+
642
+		return $records;
643
+	}
644
+
645
+	/**
646
+	 * Create a full attachment record payload.
647
+	 *
648
+	 * @param int   $key
649
+	 * @param mixed $value
650
+	 * @param array $attributes
651
+	 * @param bool  $timed
652
+	 *
653
+	 * @return array
654
+	 */
655
+	protected function attacher($key, $value, $attributes, $timed)
656
+	{
657
+		list($id, $extra) = $this->getAttachId($key, $value, $attributes);
658
+
659
+		// To create the attachment records, we will simply spin through the IDs given
660
+		// and create a new record to insert for each ID. Each ID may actually be a
661
+		// key in the array, with extra attributes to be placed in other columns.
662
+		$record = $this->createAttachRecord($id, $timed);
663
+
664
+		return array_merge($record, $extra);
665
+	}
666
+
667
+	/**
668
+	 * Get the attach record ID and extra attributes.
669
+	 *
670
+	 * @param int   $key
671
+	 * @param mixed $value
672
+	 * @param array $attributes
673
+	 *
674
+	 * @return array
675
+	 */
676
+	protected function getAttachId($key, $value, array $attributes)
677
+	{
678
+		if (is_array($value)) {
679
+			return [$key, array_merge($value, $attributes)];
680
+		}
681
+
682
+		return [$value, $attributes];
683
+	}
684
+
685
+	/**
686
+	 * Create a new pivot attachment record.
687
+	 *
688
+	 * @param int  $id
689
+	 * @param bool $timed
690
+	 *
691
+	 * @return array
692
+	 */
693
+	protected function createAttachRecord($id, $timed)
694
+	{
695
+		$parentKey = $this->parentMap->getKeyName();
696
+
697
+		$record = [];
698
+
699
+		$record[$this->foreignKey] = $this->parent->getEntityAttribute($parentKey);
700
+
701
+		$record[$this->otherKey] = $id;
702
+
703
+		// If the record needs to have creation and update timestamps, we will make
704
+		// them by calling the parent model's "freshTimestamp" method which will
705
+		// provide us with a fresh timestamp in this model's preferred format.
706
+		if ($timed) {
707
+			$record = $this->setTimestampsOnAttach($record);
708
+		}
709
+
710
+		return $record;
711
+	}
712
+
713
+	/**
714
+	 * Set the creation and update timestamps on an attach record.
715
+	 *
716
+	 * @param array $record
717
+	 * @param bool  $exists
718
+	 *
719
+	 * @return array
720
+	 */
721
+	protected function setTimestampsOnAttach(array $record, $exists = false)
722
+	{
723
+		$fresh = $this->freshTimestamp();
724
+
725
+		if (!$exists) {
726
+			$record[$this->createdAt()] = $fresh;
727
+		}
728
+
729
+		$record[$this->updatedAt()] = $fresh;
730
+
731
+		return $record;
732
+	}
733
+
734
+	/**
735
+	 * @param EntityCollection $entities
736
+	 *
737
+	 * @return array
738
+	 */
739
+	protected function getModelKeysFromCollection(EntityCollection $entities)
740
+	{
741
+		$keyName = $this->relatedMap->getKeyName();
742
+
743
+		return array_map(function ($m) use ($keyName) {
744
+			return $m->$keyName;
745
+		}, $entities);
746
+	}
747
+
748
+	/**
749
+	 * Detach models from the relationship.
750
+	 *
751
+	 * @param int|array $ids
752
+	 *
753
+	 * @throws \InvalidArgumentException
754
+	 *
755
+	 * @return int
756
+	 */
757
+	public function detach($ids = [])
758
+	{
759
+		if ($ids instanceof EntityCollection) {
760
+			$ids = (array) $ids->modelKeys();
761
+		}
762
+
763
+		$query = $this->newPivotQuery();
764
+
765
+		// If associated IDs were passed to the method we will only delete those
766
+		// associations, otherwise all of the association ties will be broken.
767
+		// We'll return the numbers of affected rows when we do the deletes.
768
+		$ids = (array) $ids;
769
+
770
+		if (count($ids) > 0) {
771
+			$query->whereIn($this->otherKey, (array) $ids);
772
+		}
773
+
774
+		// Once we have all of the conditions set on the statement, we are ready
775
+		// to run the delete on the pivot table. Then, if the touch parameter
776
+		// is true, we will go ahead and touch all related models to sync.
777
+		return $query->delete();
778
+	}
779
+
780
+	/**
781
+	 * Create a new query builder for the pivot table.
782
+	 *
783
+	 * @throws \InvalidArgumentException
784
+	 *
785
+	 * @return \Illuminate\Database\Query\Builder
786
+	 */
787
+	protected function newPivotQuery()
788
+	{
789
+		$query = $this->newPivotStatement();
790
+
791
+		$parentKey = $this->parentMap->getKeyName();
792
+
793
+		return $query->where($this->foreignKey, $this->parent->getEntityAttribute($parentKey));
794
+	}
795
+
796
+	/**
797
+	 * Get a new plain query builder for the pivot table.
798
+	 *
799
+	 * @return \Illuminate\Database\Query\Builder
800
+	 */
801
+	public function newPivotStatement()
802
+	{
803
+		return $this->query->getQuery()->newQuery()->from($this->table);
804
+	}
805
+
806
+	/**
807
+	 * Get a new pivot statement for a given "other" ID.
808
+	 *
809
+	 * @param mixed $id
810
+	 *
811
+	 * @throws \InvalidArgumentException
812
+	 *
813
+	 * @return \Illuminate\Database\Query\Builder
814
+	 */
815
+	public function newPivotStatementForId($id)
816
+	{
817
+		$pivot = $this->newPivotStatement();
818
+
819
+		$parentKeyName = $this->parentMap->getKeyName();
820
+
821
+		$key = $this->parent->getEntityAttribute($parentKeyName);
822
+
823
+		return $pivot->where($this->foreignKey, $key)->where($this->otherKey, $id);
824
+	}
825
+
826
+	/**
827
+	 * Create a new pivot model instance.
828
+	 *
829
+	 * @param array $attributes
830
+	 * @param bool  $exists
831
+	 *
832
+	 * @return \Analogue\ORM\Relationships\Pivot
833
+	 */
834
+	public function newPivot(array $attributes = [], $exists = false)
835
+	{
836
+		$pivot = new Pivot($this->parent, $this->parentMap, $attributes, $this->table, $exists);
837
+
838
+		return $pivot->setPivotKeys($this->foreignKey, $this->otherKey);
839
+	}
840
+
841
+	/**
842
+	 * Create a new existing pivot model instance.
843
+	 *
844
+	 * @param array $attributes
845
+	 *
846
+	 * @return \Analogue\ORM\Relationships\Pivot
847
+	 */
848
+	public function newExistingPivot(array $attributes = [])
849
+	{
850
+		return $this->newPivot($attributes, true);
851
+	}
852
+
853
+	/**
854
+	 * Set the columns on the pivot table to retrieve.
855
+	 *
856
+	 * @param array $columns
857
+	 *
858
+	 * @return $this
859
+	 */
860
+	public function withPivot($columns)
861
+	{
862
+		$columns = is_array($columns) ? $columns : func_get_args();
863
+
864
+		$this->pivotColumns = array_merge($this->pivotColumns, $columns);
865
+
866
+		return $this;
867
+	}
868
+
869
+	/**
870
+	 * Specify that the pivot table has creation and update timestamps.
871
+	 *
872
+	 * @param mixed $createdAt
873
+	 * @param mixed $updatedAt
874
+	 *
875
+	 * @return \Analogue\ORM\Relationships\BelongsToMany
876
+	 */
877
+	public function withTimestamps($createdAt = null, $updatedAt = null)
878
+	{
879
+		return $this->withPivot($createdAt ?: $this->createdAt(), $updatedAt ?: $this->updatedAt());
880
+	}
881
+
882
+	/**
883
+	 * Get the key for comparing against the parent key in "has" query.
884
+	 *
885
+	 * @return string
886
+	 */
887
+	public function getHasCompareKey()
888
+	{
889
+		return $this->getForeignKey();
890
+	}
891
+
892
+	/**
893
+	 * Get the fully qualified foreign key for the relation.
894
+	 *
895
+	 * @return string
896
+	 */
897
+	public function getForeignKey()
898
+	{
899
+		return $this->table.'.'.$this->foreignKey;
900
+	}
901
+
902
+	/**
903
+	 * Get the fully qualified "other key" for the relation.
904
+	 *
905
+	 * @return string
906
+	 */
907
+	public function getOtherKey()
908
+	{
909
+		return $this->table.'.'.$this->otherKey;
910
+	}
911
+
912
+	/**
913
+	 * Get the fully qualified parent key name.
914
+	 *
915
+	 * @return string
916
+	 */
917
+	protected function getQualifiedParentKeyName()
918
+	{
919
+		return $this->parentMap->getQualifiedKeyName();
920
+	}
921
+
922
+	/**
923
+	 * Get the intermediate table for the relationship.
924
+	 *
925
+	 * @return string
926
+	 */
927
+	public function getTable()
928
+	{
929
+		return $this->table;
930
+	}
931
+
932
+	/**
933
+	 * Get the relationship name for the relationship.
934
+	 *
935
+	 * @return string
936
+	 */
937
+	public function getRelationName()
938
+	{
939
+		return $this->relation;
940
+	}
941 941
 }
Please login to merge, or discard this patch.
src/Relationships/MorphToMany.php 1 patch
Indentation   +168 added lines, -168 removed lines patch added patch discarded remove patch
@@ -7,172 +7,172 @@
 block discarded – undo
7 7
 
8 8
 class MorphToMany extends BelongsToMany
9 9
 {
10
-    /**
11
-     * The type of the polymorphic relation.
12
-     *
13
-     * @var string
14
-     */
15
-    protected $morphType;
16
-
17
-    /**
18
-     * The class name of the morph type constraint.
19
-     *
20
-     * @var string
21
-     */
22
-    protected $morphClass;
23
-
24
-    /**
25
-     * Indicates if we are connecting the inverse of the relation.
26
-     *
27
-     * This primarily affects the morphClass constraint.
28
-     *
29
-     * @var bool
30
-     */
31
-    protected $inverse;
32
-
33
-    protected static $hasPivot = true;
34
-
35
-    /**
36
-     * Create a new has many relationship instance.
37
-     *
38
-     * @param Mapper               $mapper
39
-     * @param \Analogue\ORM\Entity $parent
40
-     * @param string               $name
41
-     * @param string               $table
42
-     * @param string               $foreignKey
43
-     * @param string               $otherKey
44
-     * @param string|null          $relationName
45
-     * @param bool                 $inverse
46
-     */
47
-    public function __construct(Mapper $mapper, $parent, $name, $table, $foreignKey, $otherKey, $relationName = null, $inverse = false)
48
-    {
49
-        $this->inverse = $inverse;
50
-
51
-        $this->morphType = $name.'_type';
52
-
53
-        $this->morphClass = $inverse ? $mapper->getEntityMap()->getClass() : get_class($parent);
54
-
55
-        parent::__construct($mapper, $parent, $table, $foreignKey, $otherKey, $relationName);
56
-    }
57
-
58
-    /**
59
-     * Set the where clause for the relation query.
60
-     *
61
-     * @return self
62
-     */
63
-    protected function setWhere()
64
-    {
65
-        parent::setWhere();
66
-
67
-        $this->query->where($this->table.'.'.$this->morphType, $this->morphClass);
68
-
69
-        return $this;
70
-    }
71
-
72
-    /**
73
-     * Add the constraints for a relationship count query.
74
-     *
75
-     * @param Query $query
76
-     * @param Query $parent
77
-     *
78
-     * @return Query
79
-     */
80
-    public function getRelationCountQuery(Query $query, Query $parent)
81
-    {
82
-        $query = parent::getRelationCountQuery($query, $parent);
83
-
84
-        return $query->where($this->table.'.'.$this->morphType, $this->morphClass);
85
-    }
86
-
87
-    /**
88
-     * Set the constraints for an eager load of the relation.
89
-     *
90
-     * @param array $results
91
-     *
92
-     * @return void
93
-     */
94
-    public function addEagerConstraints(array $results)
95
-    {
96
-        parent::addEagerConstraints($results);
97
-
98
-        $this->query->where($this->table.'.'.$this->morphType, $this->morphClass);
99
-    }
100
-
101
-    /**
102
-     * Create a new pivot attachment record.
103
-     *
104
-     * @param int  $id
105
-     * @param bool $timed
106
-     *
107
-     * @return array
108
-     */
109
-    protected function createAttachRecord($id, $timed)
110
-    {
111
-        $record = parent::createAttachRecord($id, $timed);
112
-
113
-        return array_add($record, $this->morphType, $this->morphClass);
114
-    }
115
-
116
-    /**
117
-     * Create a new query builder for the pivot table.
118
-     *
119
-     * @throws \InvalidArgumentException
120
-     *
121
-     * @return \Illuminate\Database\Query\Builder
122
-     */
123
-    protected function newPivotQuery()
124
-    {
125
-        $query = parent::newPivotQuery();
126
-
127
-        return $query->where($this->morphType, $this->morphClass);
128
-    }
129
-
130
-    /**
131
-     * Create a new pivot model instance.
132
-     *
133
-     * @param array $attributes
134
-     * @param bool  $exists
135
-     *
136
-     * @return Pivot
137
-     */
138
-    public function newPivot(array $attributes = [], $exists = false)
139
-    {
140
-        $pivot = new MorphPivot($this->parent, $this->parentMap, $attributes, $this->table, $exists);
141
-
142
-        $pivot->setPivotKeys($this->foreignKey, $this->otherKey)
143
-            ->setMorphType($this->morphType)
144
-            ->setMorphClass($this->morphClass);
145
-
146
-        return $pivot;
147
-    }
148
-
149
-    /**
150
-     * Return Pivot attributes when available on a relationship.
151
-     *
152
-     * @return array
153
-     */
154
-    public function getPivotAttributes()
155
-    {
156
-        return $this->pivotColumns;
157
-    }
158
-
159
-    /**
160
-     * Get the foreign key "type" name.
161
-     *
162
-     * @return string
163
-     */
164
-    public function getMorphType()
165
-    {
166
-        return $this->morphType;
167
-    }
168
-
169
-    /**
170
-     * Get the class name of the parent model.
171
-     *
172
-     * @return string
173
-     */
174
-    public function getMorphClass()
175
-    {
176
-        return $this->morphClass;
177
-    }
10
+	/**
11
+	 * The type of the polymorphic relation.
12
+	 *
13
+	 * @var string
14
+	 */
15
+	protected $morphType;
16
+
17
+	/**
18
+	 * The class name of the morph type constraint.
19
+	 *
20
+	 * @var string
21
+	 */
22
+	protected $morphClass;
23
+
24
+	/**
25
+	 * Indicates if we are connecting the inverse of the relation.
26
+	 *
27
+	 * This primarily affects the morphClass constraint.
28
+	 *
29
+	 * @var bool
30
+	 */
31
+	protected $inverse;
32
+
33
+	protected static $hasPivot = true;
34
+
35
+	/**
36
+	 * Create a new has many relationship instance.
37
+	 *
38
+	 * @param Mapper               $mapper
39
+	 * @param \Analogue\ORM\Entity $parent
40
+	 * @param string               $name
41
+	 * @param string               $table
42
+	 * @param string               $foreignKey
43
+	 * @param string               $otherKey
44
+	 * @param string|null          $relationName
45
+	 * @param bool                 $inverse
46
+	 */
47
+	public function __construct(Mapper $mapper, $parent, $name, $table, $foreignKey, $otherKey, $relationName = null, $inverse = false)
48
+	{
49
+		$this->inverse = $inverse;
50
+
51
+		$this->morphType = $name.'_type';
52
+
53
+		$this->morphClass = $inverse ? $mapper->getEntityMap()->getClass() : get_class($parent);
54
+
55
+		parent::__construct($mapper, $parent, $table, $foreignKey, $otherKey, $relationName);
56
+	}
57
+
58
+	/**
59
+	 * Set the where clause for the relation query.
60
+	 *
61
+	 * @return self
62
+	 */
63
+	protected function setWhere()
64
+	{
65
+		parent::setWhere();
66
+
67
+		$this->query->where($this->table.'.'.$this->morphType, $this->morphClass);
68
+
69
+		return $this;
70
+	}
71
+
72
+	/**
73
+	 * Add the constraints for a relationship count query.
74
+	 *
75
+	 * @param Query $query
76
+	 * @param Query $parent
77
+	 *
78
+	 * @return Query
79
+	 */
80
+	public function getRelationCountQuery(Query $query, Query $parent)
81
+	{
82
+		$query = parent::getRelationCountQuery($query, $parent);
83
+
84
+		return $query->where($this->table.'.'.$this->morphType, $this->morphClass);
85
+	}
86
+
87
+	/**
88
+	 * Set the constraints for an eager load of the relation.
89
+	 *
90
+	 * @param array $results
91
+	 *
92
+	 * @return void
93
+	 */
94
+	public function addEagerConstraints(array $results)
95
+	{
96
+		parent::addEagerConstraints($results);
97
+
98
+		$this->query->where($this->table.'.'.$this->morphType, $this->morphClass);
99
+	}
100
+
101
+	/**
102
+	 * Create a new pivot attachment record.
103
+	 *
104
+	 * @param int  $id
105
+	 * @param bool $timed
106
+	 *
107
+	 * @return array
108
+	 */
109
+	protected function createAttachRecord($id, $timed)
110
+	{
111
+		$record = parent::createAttachRecord($id, $timed);
112
+
113
+		return array_add($record, $this->morphType, $this->morphClass);
114
+	}
115
+
116
+	/**
117
+	 * Create a new query builder for the pivot table.
118
+	 *
119
+	 * @throws \InvalidArgumentException
120
+	 *
121
+	 * @return \Illuminate\Database\Query\Builder
122
+	 */
123
+	protected function newPivotQuery()
124
+	{
125
+		$query = parent::newPivotQuery();
126
+
127
+		return $query->where($this->morphType, $this->morphClass);
128
+	}
129
+
130
+	/**
131
+	 * Create a new pivot model instance.
132
+	 *
133
+	 * @param array $attributes
134
+	 * @param bool  $exists
135
+	 *
136
+	 * @return Pivot
137
+	 */
138
+	public function newPivot(array $attributes = [], $exists = false)
139
+	{
140
+		$pivot = new MorphPivot($this->parent, $this->parentMap, $attributes, $this->table, $exists);
141
+
142
+		$pivot->setPivotKeys($this->foreignKey, $this->otherKey)
143
+			->setMorphType($this->morphType)
144
+			->setMorphClass($this->morphClass);
145
+
146
+		return $pivot;
147
+	}
148
+
149
+	/**
150
+	 * Return Pivot attributes when available on a relationship.
151
+	 *
152
+	 * @return array
153
+	 */
154
+	public function getPivotAttributes()
155
+	{
156
+		return $this->pivotColumns;
157
+	}
158
+
159
+	/**
160
+	 * Get the foreign key "type" name.
161
+	 *
162
+	 * @return string
163
+	 */
164
+	public function getMorphType()
165
+	{
166
+		return $this->morphType;
167
+	}
168
+
169
+	/**
170
+	 * Get the class name of the parent model.
171
+	 *
172
+	 * @return string
173
+	 */
174
+	public function getMorphClass()
175
+	{
176
+		return $this->morphClass;
177
+	}
178 178
 }
Please login to merge, or discard this patch.