Completed
Pull Request — 5.1 (#144)
by
unknown
04:21
created
src/Relationships/BelongsToMany.php 1 patch
Indentation   +929 added lines, -929 removed lines patch added patch discarded remove patch
@@ -12,938 +12,938 @@
 block discarded – undo
12 12
 
13 13
 class BelongsToMany extends Relationship
14 14
 {
15
-    /**
16
-     * The intermediate table for the relation.
17
-     *
18
-     * @var string
19
-     */
20
-    protected $table;
21
-
22
-    /**
23
-     * The foreign key of the parent model.
24
-     *
25
-     * @var string
26
-     */
27
-    protected $foreignKey;
28
-
29
-    /**
30
-     * The associated key of the relation.
31
-     *
32
-     * @var string
33
-     */
34
-    protected $otherKey;
35
-
36
-    /**
37
-     * The "name" of the relationship.
38
-     *
39
-     * @var string
40
-     */
41
-    protected $relationName;
42
-
43
-    /**
44
-     * The pivot table columns to retrieve.
45
-     *
46
-     * @var array
47
-     */
48
-    protected $pivotColumns = [];
49
-
50
-    /**
51
-     * This relationship has pivot attributes
52
-     *
53
-     * @var boolean
54
-     */
55
-    protected static $hasPivot = true;
56
-
57
-    /**
58
-     * Create a new has many relationship instance.
59
-     *
60
-     * @param Mapper   $mapper
61
-     * @param Mappable $parent
62
-     * @param string   $table
63
-     * @param string   $foreignKey
64
-     * @param string   $otherKey
65
-     * @param string   $relationName
66
-     */
67
-    public function __construct(Mapper $mapper, $parent, $table, $foreignKey, $otherKey, $relationName = null)
68
-    {
69
-        $this->table = $table;
70
-        $this->otherKey = $otherKey;
71
-        $this->foreignKey = $foreignKey;
72
-        $this->relationName = $relationName;
73
-
74
-        parent::__construct($mapper, $parent);
75
-    }
76
-
77
-    /**
78
-     * @param  $related
79
-     * @return mixed
80
-     */
81
-    public function attachTo($related)
82
-    {
83
-    }
84
-
85
-    /**
86
-     * @param  $related
87
-     * @return mixed
88
-     */
89
-    public function detachFrom($related)
90
-    {
91
-        $ids = $this->getIdsFromHashes([$related]);
92
-
93
-        $this->detach($ids);
94
-    }
95
-
96
-    /**
97
-     * @param $related
98
-     */
99
-    public function detachMany($related)
100
-    {
101
-        $ids = $this->getIdsFromHashes($related);
102
-
103
-        $this->detach($ids);
104
-    }
105
-
106
-    /**
107
-     * @param array $hashes
108
-     * @return array
109
-     */
110
-    protected function getIdsFromHashes(array $hashes)
111
-    {
112
-        $ids = [];
113
-
114
-        foreach ($hashes as $hash) {
115
-            $split = explode('.', $hash);
116
-            $ids[] = $split[1];
117
-        }
118
-        return $ids;
119
-    }
120
-
121
-    /**
122
-     * Get the results of the relationship.
123
-     *
124
-     * @param $relation
125
-     *
126
-     * @return EntityCollection
127
-     */
128
-    public function getResults($relation)
129
-    {
130
-        $results = $this->get();
131
-
132
-        $this->cacheRelation($results, $relation);
133
-
134
-        return $results;
135
-    }
136
-
137
-    /**
138
-     * Set a where clause for a pivot table column.
139
-     *
140
-     * @param  string $column
141
-     * @param  string $operator
142
-     * @param  mixed  $value
143
-     * @param  string $boolean
144
-     * @return self
145
-     */
146
-    public function wherePivot($column, $operator = null, $value = null, $boolean = 'and')
147
-    {
148
-        return $this->where($this->table . '.' . $column, $operator, $value, $boolean);
149
-    }
150
-
151
-    /**
152
-     * Set an or where clause for a pivot table column.
153
-     *
154
-     * @param  string $column
155
-     * @param  string $operator
156
-     * @param  mixed  $value
157
-     * @return self
158
-     */
159
-    public function orWherePivot($column, $operator = null, $value = null)
160
-    {
161
-        return $this->wherePivot($column, $operator, $value, 'or');
162
-    }
163
-
164
-    /**
165
-     * Return Pivot attributes when available on a relationship
166
-     *
167
-     * @return array
168
-     */
169
-    public function getPivotAttributes()
170
-    {
171
-        return $this->pivotColumns;
172
-    }
173
-
174
-    /**
175
-     * Execute the query and get the first result.
176
-     *
177
-     * @param  array $columns
178
-     * @return mixed
179
-     */
180
-    public function first($columns = ['*'])
181
-    {
182
-        $results = $this->take(1)->get($columns);
183
-
184
-        return count($results) > 0 ? $results->first() : null;
185
-    }
186
-
187
-    /**
188
-     * Execute the query and get the first result or throw an exception.
189
-     *
190
-     * @param  array $columns
191
-     *
192
-     * @throws EntityNotFoundException
193
-     *
194
-     * @return Mappable|self
195
-     */
196
-    public function firstOrFail($columns = ['*'])
197
-    {
198
-        if (!is_null($entity = $this->first($columns))) {
199
-            return $entity;
200
-        }
201
-
202
-        throw new EntityNotFoundException;
203
-    }
204
-
205
-    /**
206
-     * Execute the query as a "select" statement.
207
-     *
208
-     * @param  array $columns
209
-     * @return \Analogue\ORM\EntityCollection
210
-     */
211
-    public function get($columns = ['*'])
212
-    {
213
-        // First we'll add the proper select columns onto the query so it is run with
214
-        // the proper columns. Then, we will get the results and hydrate out pivot
215
-        // models with the result of those columns as a separate model relation.
216
-        $columns = $this->query->getQuery()->columns ? [] : $columns;
217
-
218
-        $select = $this->getSelectColumns($columns);
219
-
220
-        $entities = $this->query->addSelect($select)->getEntities();
221
-
222
-        $this->hydratePivotRelation($entities);
223
-
224
-        // If we actually found models we will also eager load any relationships that
225
-        // have been specified as needing to be eager loaded. This will solve the
226
-        // n + 1 query problem for the developer and also increase performance.
227
-        if (count($entities) > 0) {
228
-            $entities = $this->query->eagerLoadRelations($entities);
229
-        }
230
-
231
-        return $this->relatedMap->newCollection($entities);
232
-    }
233
-
234
-    /**
235
-     * Hydrate the pivot table relationship on the models.
236
-     *
237
-     * @param  array $entities
238
-     * @return void
239
-     */
240
-    protected function hydratePivotRelation(array $entities)
241
-    {
242
-        // To hydrate the pivot relationship, we will just gather the pivot attributes
243
-        // and create a new Pivot model, which is basically a dynamic model that we
244
-        // will set the attributes, table, and connections on so it they be used.
245
-
246
-        foreach ($entities as $entity) {
247
-            $entityWrapper = $this->factory->make($entity);
248
-
249
-            $pivot = $this->newExistingPivot($this->cleanPivotAttributes($entityWrapper));
250
-
251
-            $entityWrapper->setEntityAttribute('pivot', $pivot);
252
-        }
253
-    }
254
-
255
-    /**
256
-     * Get the pivot attributes from a model.
257
-     *
258
-     * @param  $entity
259
-     * @return array
260
-     */
261
-    protected function cleanPivotAttributes(InternallyMappable $entity)
262
-    {
263
-        $values = [];
264
-
265
-        $attributes = $entity->getEntityAttributes();
266
-
267
-        foreach ($attributes as $key => $value) {
268
-            // To get the pivots attributes we will just take any of the attributes which
269
-            // begin with "pivot_" and add those to this arrays, as well as unsetting
270
-            // them from the parent's models since they exist in a different table.
271
-            if (strpos($key, 'pivot_') === 0) {
272
-                $values[substr($key, 6)] = $value;
273
-
274
-                unset($attributes[$key]);
275
-            }
276
-        }
277
-
278
-        // Rehydrate Entity with cleaned array.
279
-        $entity->setEntityAttributes($attributes);
280
-
281
-        return $values;
282
-    }
283
-
284
-    /**
285
-     * Set the base constraints on the relation query.
286
-     *
287
-     * @return void
288
-     */
289
-    public function addConstraints()
290
-    {
291
-        $this->setJoin();
292
-
293
-        if (static::$constraints) {
294
-            $this->setWhere();
295
-        }
296
-    }
297
-
298
-    /**
299
-     * Add the constraints for a relationship count query.
300
-     *
301
-     * @param  Query $query
302
-     * @param  Query $parent
303
-     * @return Query
304
-     */
305
-    public function getRelationCountQuery(Query $query, Query $parent)
306
-    {
307
-        if ($parent->getQuery()->from == $query->getQuery()->from) {
308
-            return $this->getRelationCountQueryForSelfJoin($query, $parent);
309
-        }
310
-
311
-        $this->setJoin($query);
312
-
313
-        return parent::getRelationCountQuery($query, $parent);
314
-    }
315
-
316
-    /**
317
-     * Add the constraints for a relationship count query on the same table.
318
-     *
319
-     * @param  Query $query
320
-     * @param  Query $parent
321
-     * @return Query
322
-     */
323
-    public function getRelationCountQueryForSelfJoin(Query $query, Query $parent)
324
-    {
325
-        $query->select(new Expression('count(*)'));
326
-
327
-        $tablePrefix = $this->query->getQuery()->getConnection()->getTablePrefix();
328
-
329
-        $query->from($this->table . ' as ' . $tablePrefix . $hash = $this->getRelationCountHash());
330
-
331
-        $key = $this->wrap($this->getQualifiedParentKeyName());
332
-
333
-        return $query->where($hash . '.' . $this->foreignKey, '=', new Expression($key));
334
-    }
335
-
336
-    /**
337
-     * Get a relationship join table hash.
338
-     *
339
-     * @return string
340
-     */
341
-    public function getRelationCountHash()
342
-    {
343
-        return 'self_' . md5(microtime(true));
344
-    }
345
-
346
-    /**
347
-     * Set the select clause for the relation query.
348
-     *
349
-     * @param  array $columns
350
-     * @return \Analogue\ORM\Relationships\BelongsToMany
351
-     */
352
-    protected function getSelectColumns(array $columns = ['*'])
353
-    {
354
-        if ($columns == ['*']) {
355
-            $columns = [$this->relatedMap->getTable() . '.*'];
356
-        }
357
-
358
-        return array_merge($columns, $this->getAliasedPivotColumns());
359
-    }
360
-
361
-    /**
362
-     * Get the pivot columns for the relation.
363
-     *
364
-     * @return array
365
-     */
366
-    protected function getAliasedPivotColumns()
367
-    {
368
-        $defaults = [$this->foreignKey, $this->otherKey];
369
-
370
-        // We need to alias all of the pivot columns with the "pivot_" prefix so we
371
-        // can easily extract them out of the models and put them into the pivot
372
-        // relationships when they are retrieved and hydrated into the models.
373
-        $columns = [];
374
-
375
-        foreach (array_merge($defaults, $this->pivotColumns) as $column) {
376
-            $columns[] = $this->table . '.' . $column . ' as pivot_' . $column;
377
-        }
378
-
379
-        return array_unique($columns);
380
-    }
381
-
382
-    /**
383
-     * Set the join clause for the relation query.
384
-     *
385
-     * @param  \Analogue\ORM\Query|null
386
-     * @return $this
387
-     */
388
-    protected function setJoin($query = null)
389
-    {
390
-        $query = $query ?: $this->query;
391
-
392
-        // We need to join to the intermediate table on the related model's primary
393
-        // key column with the intermediate table's foreign key for the related
394
-        // model instance. Then we can set the "where" for the parent models.
395
-        $baseTable = $this->relatedMap->getTable();
396
-
397
-        $key = $baseTable . '.' . $this->relatedMap->getKeyName();
398
-
399
-        $query->join($this->table, $key, '=', $this->getOtherKey());
400
-
401
-        return $this;
402
-    }
403
-
404
-    /**
405
-     * Set the where clause for the relation query.
406
-     *
407
-     * @return $this
408
-     */
409
-    protected function setWhere()
410
-    {
411
-        $foreign = $this->getForeignKey();
412
-
413
-        $parentKey = $this->parentMap->getKeyName();
414
-
415
-        $this->query->where($foreign, '=', $this->parent->getEntityAttribute($parentKey));
416
-
417
-        return $this;
418
-    }
419
-
420
-    /**
421
-     * Set the constraints for an eager load of the relation.
422
-     *
423
-     * @param  array $entities
424
-     * @return void
425
-     */
426
-    public function addEagerConstraints(array $entities)
427
-    {
428
-        $this->query->whereIn($this->getForeignKey(), $this->getKeys($entities));
429
-    }
430
-
431
-    /**
432
-     * Initialize the relation on a set of eneities.
433
-     *
434
-     * @param  array  $entities
435
-     * @param  string $relation
436
-     * @return array
437
-     */
438
-    public function initRelation(array $entities, $relation)
439
-    {
440
-        foreach ($entities as $entity) {
441
-            $entity = $this->factory->make($entity);
442
-
443
-            $entity->setEntityAttribute($relation, $this->relatedMap->newCollection());
444
-        }
445
-
446
-        return $entities;
447
-    }
448
-
449
-    /**
450
-     * Match the eagerly loaded results to their parents.
451
-     *
452
-     * @param  array            $entities
453
-     * @param  EntityCollection $results
454
-     * @param  string           $relation
455
-     * @return array
456
-     */
457
-    public function match(array $entities, EntityCollection $results, $relation)
458
-    {
459
-        $dictionary = $this->buildDictionary($results);
460
-
461
-        $keyName = $this->relatedMap->getKeyName();
462
-
463
-        $cache = $this->parentMapper->getEntityCache();
464
-
465
-        // Once we have an array dictionary of child objects we can easily match the
466
-        // children back to their parent using the dictionary and the keys on the
467
-        // the parent models. Then we will return the hydrated models back out.
468
-        foreach ($entities as $entity) {
469
-            $wrapper = $this->factory->make($entity);
470
-
471
-            if (isset($dictionary[$key = $wrapper->getEntityAttribute($keyName)])) {
472
-                $collection = $this->relatedMap->newCollection($dictionary[$key]);
473
-
474
-                $wrapper->setEntityAttribute($relation, $collection);
475
-
476
-                $cache->cacheLoadedRelationResult($entity, $relation, $collection, $this);
477
-            }
478
-        }
479
-
480
-        return $entities;
481
-    }
482
-
483
-    /**
484
-     * Build model dictionary keyed by the relation's foreign key.
485
-     *
486
-     * @param  EntityCollection $results
487
-     * @return array
488
-     */
489
-    protected function buildDictionary(EntityCollection $results)
490
-    {
491
-        $foreign = $this->foreignKey;
492
-
493
-        $foreign = $this->relatedMap->getAttributeNameForColumn($foreign);
494
-
495
-        // First we will build a dictionary of child models keyed by the foreign key
496
-        // of the relation so that we will easily and quickly match them to their
497
-        // parents without having a possibly slow inner loops for every models.
498
-        $dictionary = [];
499
-
500
-        foreach ($results as $entity) {
501
-            $wrapper = $this->factory->make($entity);
502
-
503
-            $dictionary[$wrapper->getEntityAttribute('pivot')->$foreign][] = $entity;
504
-        }
505
-
506
-        return $dictionary;
507
-    }
508
-
509
-    /**
510
-     * Get all of the IDs for the related models.
511
-     *
512
-     * @return array
513
-     */
514
-    public function getRelatedIds()
515
-    {
516
-        $fullKey = $this->relatedMap->getQualifiedKeyName();
517
-
518
-        return $this->getQuery()->select($fullKey)->lists($this->relatedMap->getKeyName());
519
-    }
520
-
521
-    /**
522
-     * Update Pivot
523
-     *
524
-     * @param  \Analogue\ORM\Entity $entity
525
-     * @return void
526
-     */
527
-    public function updatePivot($entity)
528
-    {
529
-        $keyName = $this->relatedMap->getKeyName();
530
-
531
-        $this->updateExistingPivot(
532
-            $entity->getEntityAttribute($keyName),
533
-            $entity->getEntityAttribute('pivot')->getEntityAttributes()
534
-        );
535
-    }
536
-
537
-    /**
538
-     * Update Multiple pivot
539
-     *
540
-     * @param  $relatedEntities
541
-     * @return void
542
-     */
543
-    public function updatePivots($relatedEntities)
544
-    {
545
-        foreach ($relatedEntities as $entity) {
546
-            $this->updatePivot($entity);
547
-        }
548
-    }
549
-
550
-    /**
551
-     * Create Pivot Records
552
-     *
553
-     * @param \Analogue\ORM\Entity[] $relatedEntities
554
-     * @return void
555
-     */
556
-    public function createPivots($relatedEntities)
557
-    {
558
-        $keys = [];
559
-        $attributes = [];
560
-
561
-        $keyName = $this->relatedMap->getKeyName();
562
-
563
-        foreach ($relatedEntities as $entity) {
564
-            $keys[] = $entity->getEntityAttribute($keyName);
565
-        }
566
-
567
-        $records = $this->createAttachRecords($keys, $attributes);
568
-
569
-        $this->query->getQuery()->from($this->table)->insert($records);
570
-    }
571
-
572
-    /**
573
-     * Update an existing pivot record on the table.
574
-     *
575
-     * @param  mixed $id
576
-     * @param  array $attributes
577
-     * @throws \InvalidArgumentException
578
-     * @return integer
579
-     */
580
-    public function updateExistingPivot($id, array $attributes)
581
-    {
582
-        if (in_array($this->updatedAt(), $this->pivotColumns)) {
583
-            $attributes = $this->setTimestampsOnAttach($attributes, true);
584
-        }
585
-
586
-        return $this->newPivotStatementForId($id)->update($attributes);
587
-    }
588
-
589
-    /**
590
-     * Attach a model to the parent.
591
-     *
592
-     * @param  mixed $id
593
-     * @param  array $attributes
594
-     * @return void
595
-     */
596
-    public function attach($id, array $attributes = [])
597
-    {
598
-        $query = $this->newPivotStatement();
599
-
600
-        $query->insert($this->createAttachRecords((array) $id, $attributes));
601
-    }
602
-
603
-    /**
604
-     * @param  array $entities
605
-     *
606
-     * @throws \InvalidArgumentException
607
-     */
608
-    public function sync(array $entities)
609
-    {
610
-        $this->detachExcept($entities);
611
-    }
612
-
613
-    /**
614
-     * Detach related entities that are not in $id
615
-     *
616
-     * @param  array $entities
617
-     *
618
-     * @throws \InvalidArgumentException
619
-     *
620
-     * @return void
621
-     */
622
-    protected function detachExcept(array $entities = [])
623
-    {
624
-        $query = $this->newPivotQuery();
625
-
626
-        if (count($entities) > 0) {
627
-            $keys = $this->getKeys($entities);
628
-
629
-            $query->whereNotIn($this->otherKey, $keys);
630
-        }
631
-        $parentKey = $this->parentMap->getKeyName();
632
-
633
-        $query->where($this->foreignKey, '=', $this->parent->getEntityAttribute($parentKey));
15
+	/**
16
+	 * The intermediate table for the relation.
17
+	 *
18
+	 * @var string
19
+	 */
20
+	protected $table;
21
+
22
+	/**
23
+	 * The foreign key of the parent model.
24
+	 *
25
+	 * @var string
26
+	 */
27
+	protected $foreignKey;
28
+
29
+	/**
30
+	 * The associated key of the relation.
31
+	 *
32
+	 * @var string
33
+	 */
34
+	protected $otherKey;
35
+
36
+	/**
37
+	 * The "name" of the relationship.
38
+	 *
39
+	 * @var string
40
+	 */
41
+	protected $relationName;
42
+
43
+	/**
44
+	 * The pivot table columns to retrieve.
45
+	 *
46
+	 * @var array
47
+	 */
48
+	protected $pivotColumns = [];
49
+
50
+	/**
51
+	 * This relationship has pivot attributes
52
+	 *
53
+	 * @var boolean
54
+	 */
55
+	protected static $hasPivot = true;
56
+
57
+	/**
58
+	 * Create a new has many relationship instance.
59
+	 *
60
+	 * @param Mapper   $mapper
61
+	 * @param Mappable $parent
62
+	 * @param string   $table
63
+	 * @param string   $foreignKey
64
+	 * @param string   $otherKey
65
+	 * @param string   $relationName
66
+	 */
67
+	public function __construct(Mapper $mapper, $parent, $table, $foreignKey, $otherKey, $relationName = null)
68
+	{
69
+		$this->table = $table;
70
+		$this->otherKey = $otherKey;
71
+		$this->foreignKey = $foreignKey;
72
+		$this->relationName = $relationName;
73
+
74
+		parent::__construct($mapper, $parent);
75
+	}
76
+
77
+	/**
78
+	 * @param  $related
79
+	 * @return mixed
80
+	 */
81
+	public function attachTo($related)
82
+	{
83
+	}
84
+
85
+	/**
86
+	 * @param  $related
87
+	 * @return mixed
88
+	 */
89
+	public function detachFrom($related)
90
+	{
91
+		$ids = $this->getIdsFromHashes([$related]);
92
+
93
+		$this->detach($ids);
94
+	}
95
+
96
+	/**
97
+	 * @param $related
98
+	 */
99
+	public function detachMany($related)
100
+	{
101
+		$ids = $this->getIdsFromHashes($related);
102
+
103
+		$this->detach($ids);
104
+	}
105
+
106
+	/**
107
+	 * @param array $hashes
108
+	 * @return array
109
+	 */
110
+	protected function getIdsFromHashes(array $hashes)
111
+	{
112
+		$ids = [];
113
+
114
+		foreach ($hashes as $hash) {
115
+			$split = explode('.', $hash);
116
+			$ids[] = $split[1];
117
+		}
118
+		return $ids;
119
+	}
120
+
121
+	/**
122
+	 * Get the results of the relationship.
123
+	 *
124
+	 * @param $relation
125
+	 *
126
+	 * @return EntityCollection
127
+	 */
128
+	public function getResults($relation)
129
+	{
130
+		$results = $this->get();
131
+
132
+		$this->cacheRelation($results, $relation);
133
+
134
+		return $results;
135
+	}
136
+
137
+	/**
138
+	 * Set a where clause for a pivot table column.
139
+	 *
140
+	 * @param  string $column
141
+	 * @param  string $operator
142
+	 * @param  mixed  $value
143
+	 * @param  string $boolean
144
+	 * @return self
145
+	 */
146
+	public function wherePivot($column, $operator = null, $value = null, $boolean = 'and')
147
+	{
148
+		return $this->where($this->table . '.' . $column, $operator, $value, $boolean);
149
+	}
150
+
151
+	/**
152
+	 * Set an or where clause for a pivot table column.
153
+	 *
154
+	 * @param  string $column
155
+	 * @param  string $operator
156
+	 * @param  mixed  $value
157
+	 * @return self
158
+	 */
159
+	public function orWherePivot($column, $operator = null, $value = null)
160
+	{
161
+		return $this->wherePivot($column, $operator, $value, 'or');
162
+	}
163
+
164
+	/**
165
+	 * Return Pivot attributes when available on a relationship
166
+	 *
167
+	 * @return array
168
+	 */
169
+	public function getPivotAttributes()
170
+	{
171
+		return $this->pivotColumns;
172
+	}
173
+
174
+	/**
175
+	 * Execute the query and get the first result.
176
+	 *
177
+	 * @param  array $columns
178
+	 * @return mixed
179
+	 */
180
+	public function first($columns = ['*'])
181
+	{
182
+		$results = $this->take(1)->get($columns);
183
+
184
+		return count($results) > 0 ? $results->first() : null;
185
+	}
186
+
187
+	/**
188
+	 * Execute the query and get the first result or throw an exception.
189
+	 *
190
+	 * @param  array $columns
191
+	 *
192
+	 * @throws EntityNotFoundException
193
+	 *
194
+	 * @return Mappable|self
195
+	 */
196
+	public function firstOrFail($columns = ['*'])
197
+	{
198
+		if (!is_null($entity = $this->first($columns))) {
199
+			return $entity;
200
+		}
201
+
202
+		throw new EntityNotFoundException;
203
+	}
204
+
205
+	/**
206
+	 * Execute the query as a "select" statement.
207
+	 *
208
+	 * @param  array $columns
209
+	 * @return \Analogue\ORM\EntityCollection
210
+	 */
211
+	public function get($columns = ['*'])
212
+	{
213
+		// First we'll add the proper select columns onto the query so it is run with
214
+		// the proper columns. Then, we will get the results and hydrate out pivot
215
+		// models with the result of those columns as a separate model relation.
216
+		$columns = $this->query->getQuery()->columns ? [] : $columns;
217
+
218
+		$select = $this->getSelectColumns($columns);
219
+
220
+		$entities = $this->query->addSelect($select)->getEntities();
221
+
222
+		$this->hydratePivotRelation($entities);
223
+
224
+		// If we actually found models we will also eager load any relationships that
225
+		// have been specified as needing to be eager loaded. This will solve the
226
+		// n + 1 query problem for the developer and also increase performance.
227
+		if (count($entities) > 0) {
228
+			$entities = $this->query->eagerLoadRelations($entities);
229
+		}
230
+
231
+		return $this->relatedMap->newCollection($entities);
232
+	}
233
+
234
+	/**
235
+	 * Hydrate the pivot table relationship on the models.
236
+	 *
237
+	 * @param  array $entities
238
+	 * @return void
239
+	 */
240
+	protected function hydratePivotRelation(array $entities)
241
+	{
242
+		// To hydrate the pivot relationship, we will just gather the pivot attributes
243
+		// and create a new Pivot model, which is basically a dynamic model that we
244
+		// will set the attributes, table, and connections on so it they be used.
245
+
246
+		foreach ($entities as $entity) {
247
+			$entityWrapper = $this->factory->make($entity);
248
+
249
+			$pivot = $this->newExistingPivot($this->cleanPivotAttributes($entityWrapper));
250
+
251
+			$entityWrapper->setEntityAttribute('pivot', $pivot);
252
+		}
253
+	}
254
+
255
+	/**
256
+	 * Get the pivot attributes from a model.
257
+	 *
258
+	 * @param  $entity
259
+	 * @return array
260
+	 */
261
+	protected function cleanPivotAttributes(InternallyMappable $entity)
262
+	{
263
+		$values = [];
264
+
265
+		$attributes = $entity->getEntityAttributes();
266
+
267
+		foreach ($attributes as $key => $value) {
268
+			// To get the pivots attributes we will just take any of the attributes which
269
+			// begin with "pivot_" and add those to this arrays, as well as unsetting
270
+			// them from the parent's models since they exist in a different table.
271
+			if (strpos($key, 'pivot_') === 0) {
272
+				$values[substr($key, 6)] = $value;
273
+
274
+				unset($attributes[$key]);
275
+			}
276
+		}
277
+
278
+		// Rehydrate Entity with cleaned array.
279
+		$entity->setEntityAttributes($attributes);
280
+
281
+		return $values;
282
+	}
283
+
284
+	/**
285
+	 * Set the base constraints on the relation query.
286
+	 *
287
+	 * @return void
288
+	 */
289
+	public function addConstraints()
290
+	{
291
+		$this->setJoin();
292
+
293
+		if (static::$constraints) {
294
+			$this->setWhere();
295
+		}
296
+	}
297
+
298
+	/**
299
+	 * Add the constraints for a relationship count query.
300
+	 *
301
+	 * @param  Query $query
302
+	 * @param  Query $parent
303
+	 * @return Query
304
+	 */
305
+	public function getRelationCountQuery(Query $query, Query $parent)
306
+	{
307
+		if ($parent->getQuery()->from == $query->getQuery()->from) {
308
+			return $this->getRelationCountQueryForSelfJoin($query, $parent);
309
+		}
310
+
311
+		$this->setJoin($query);
312
+
313
+		return parent::getRelationCountQuery($query, $parent);
314
+	}
315
+
316
+	/**
317
+	 * Add the constraints for a relationship count query on the same table.
318
+	 *
319
+	 * @param  Query $query
320
+	 * @param  Query $parent
321
+	 * @return Query
322
+	 */
323
+	public function getRelationCountQueryForSelfJoin(Query $query, Query $parent)
324
+	{
325
+		$query->select(new Expression('count(*)'));
326
+
327
+		$tablePrefix = $this->query->getQuery()->getConnection()->getTablePrefix();
328
+
329
+		$query->from($this->table . ' as ' . $tablePrefix . $hash = $this->getRelationCountHash());
330
+
331
+		$key = $this->wrap($this->getQualifiedParentKeyName());
332
+
333
+		return $query->where($hash . '.' . $this->foreignKey, '=', new Expression($key));
334
+	}
335
+
336
+	/**
337
+	 * Get a relationship join table hash.
338
+	 *
339
+	 * @return string
340
+	 */
341
+	public function getRelationCountHash()
342
+	{
343
+		return 'self_' . md5(microtime(true));
344
+	}
345
+
346
+	/**
347
+	 * Set the select clause for the relation query.
348
+	 *
349
+	 * @param  array $columns
350
+	 * @return \Analogue\ORM\Relationships\BelongsToMany
351
+	 */
352
+	protected function getSelectColumns(array $columns = ['*'])
353
+	{
354
+		if ($columns == ['*']) {
355
+			$columns = [$this->relatedMap->getTable() . '.*'];
356
+		}
357
+
358
+		return array_merge($columns, $this->getAliasedPivotColumns());
359
+	}
360
+
361
+	/**
362
+	 * Get the pivot columns for the relation.
363
+	 *
364
+	 * @return array
365
+	 */
366
+	protected function getAliasedPivotColumns()
367
+	{
368
+		$defaults = [$this->foreignKey, $this->otherKey];
369
+
370
+		// We need to alias all of the pivot columns with the "pivot_" prefix so we
371
+		// can easily extract them out of the models and put them into the pivot
372
+		// relationships when they are retrieved and hydrated into the models.
373
+		$columns = [];
374
+
375
+		foreach (array_merge($defaults, $this->pivotColumns) as $column) {
376
+			$columns[] = $this->table . '.' . $column . ' as pivot_' . $column;
377
+		}
378
+
379
+		return array_unique($columns);
380
+	}
381
+
382
+	/**
383
+	 * Set the join clause for the relation query.
384
+	 *
385
+	 * @param  \Analogue\ORM\Query|null
386
+	 * @return $this
387
+	 */
388
+	protected function setJoin($query = null)
389
+	{
390
+		$query = $query ?: $this->query;
391
+
392
+		// We need to join to the intermediate table on the related model's primary
393
+		// key column with the intermediate table's foreign key for the related
394
+		// model instance. Then we can set the "where" for the parent models.
395
+		$baseTable = $this->relatedMap->getTable();
396
+
397
+		$key = $baseTable . '.' . $this->relatedMap->getKeyName();
398
+
399
+		$query->join($this->table, $key, '=', $this->getOtherKey());
400
+
401
+		return $this;
402
+	}
403
+
404
+	/**
405
+	 * Set the where clause for the relation query.
406
+	 *
407
+	 * @return $this
408
+	 */
409
+	protected function setWhere()
410
+	{
411
+		$foreign = $this->getForeignKey();
412
+
413
+		$parentKey = $this->parentMap->getKeyName();
414
+
415
+		$this->query->where($foreign, '=', $this->parent->getEntityAttribute($parentKey));
416
+
417
+		return $this;
418
+	}
419
+
420
+	/**
421
+	 * Set the constraints for an eager load of the relation.
422
+	 *
423
+	 * @param  array $entities
424
+	 * @return void
425
+	 */
426
+	public function addEagerConstraints(array $entities)
427
+	{
428
+		$this->query->whereIn($this->getForeignKey(), $this->getKeys($entities));
429
+	}
430
+
431
+	/**
432
+	 * Initialize the relation on a set of eneities.
433
+	 *
434
+	 * @param  array  $entities
435
+	 * @param  string $relation
436
+	 * @return array
437
+	 */
438
+	public function initRelation(array $entities, $relation)
439
+	{
440
+		foreach ($entities as $entity) {
441
+			$entity = $this->factory->make($entity);
442
+
443
+			$entity->setEntityAttribute($relation, $this->relatedMap->newCollection());
444
+		}
445
+
446
+		return $entities;
447
+	}
448
+
449
+	/**
450
+	 * Match the eagerly loaded results to their parents.
451
+	 *
452
+	 * @param  array            $entities
453
+	 * @param  EntityCollection $results
454
+	 * @param  string           $relation
455
+	 * @return array
456
+	 */
457
+	public function match(array $entities, EntityCollection $results, $relation)
458
+	{
459
+		$dictionary = $this->buildDictionary($results);
460
+
461
+		$keyName = $this->relatedMap->getKeyName();
462
+
463
+		$cache = $this->parentMapper->getEntityCache();
464
+
465
+		// Once we have an array dictionary of child objects we can easily match the
466
+		// children back to their parent using the dictionary and the keys on the
467
+		// the parent models. Then we will return the hydrated models back out.
468
+		foreach ($entities as $entity) {
469
+			$wrapper = $this->factory->make($entity);
470
+
471
+			if (isset($dictionary[$key = $wrapper->getEntityAttribute($keyName)])) {
472
+				$collection = $this->relatedMap->newCollection($dictionary[$key]);
473
+
474
+				$wrapper->setEntityAttribute($relation, $collection);
475
+
476
+				$cache->cacheLoadedRelationResult($entity, $relation, $collection, $this);
477
+			}
478
+		}
479
+
480
+		return $entities;
481
+	}
482
+
483
+	/**
484
+	 * Build model dictionary keyed by the relation's foreign key.
485
+	 *
486
+	 * @param  EntityCollection $results
487
+	 * @return array
488
+	 */
489
+	protected function buildDictionary(EntityCollection $results)
490
+	{
491
+		$foreign = $this->foreignKey;
492
+
493
+		$foreign = $this->relatedMap->getAttributeNameForColumn($foreign);
494
+
495
+		// First we will build a dictionary of child models keyed by the foreign key
496
+		// of the relation so that we will easily and quickly match them to their
497
+		// parents without having a possibly slow inner loops for every models.
498
+		$dictionary = [];
499
+
500
+		foreach ($results as $entity) {
501
+			$wrapper = $this->factory->make($entity);
502
+
503
+			$dictionary[$wrapper->getEntityAttribute('pivot')->$foreign][] = $entity;
504
+		}
505
+
506
+		return $dictionary;
507
+	}
508
+
509
+	/**
510
+	 * Get all of the IDs for the related models.
511
+	 *
512
+	 * @return array
513
+	 */
514
+	public function getRelatedIds()
515
+	{
516
+		$fullKey = $this->relatedMap->getQualifiedKeyName();
517
+
518
+		return $this->getQuery()->select($fullKey)->lists($this->relatedMap->getKeyName());
519
+	}
520
+
521
+	/**
522
+	 * Update Pivot
523
+	 *
524
+	 * @param  \Analogue\ORM\Entity $entity
525
+	 * @return void
526
+	 */
527
+	public function updatePivot($entity)
528
+	{
529
+		$keyName = $this->relatedMap->getKeyName();
530
+
531
+		$this->updateExistingPivot(
532
+			$entity->getEntityAttribute($keyName),
533
+			$entity->getEntityAttribute('pivot')->getEntityAttributes()
534
+		);
535
+	}
536
+
537
+	/**
538
+	 * Update Multiple pivot
539
+	 *
540
+	 * @param  $relatedEntities
541
+	 * @return void
542
+	 */
543
+	public function updatePivots($relatedEntities)
544
+	{
545
+		foreach ($relatedEntities as $entity) {
546
+			$this->updatePivot($entity);
547
+		}
548
+	}
549
+
550
+	/**
551
+	 * Create Pivot Records
552
+	 *
553
+	 * @param \Analogue\ORM\Entity[] $relatedEntities
554
+	 * @return void
555
+	 */
556
+	public function createPivots($relatedEntities)
557
+	{
558
+		$keys = [];
559
+		$attributes = [];
560
+
561
+		$keyName = $this->relatedMap->getKeyName();
562
+
563
+		foreach ($relatedEntities as $entity) {
564
+			$keys[] = $entity->getEntityAttribute($keyName);
565
+		}
566
+
567
+		$records = $this->createAttachRecords($keys, $attributes);
568
+
569
+		$this->query->getQuery()->from($this->table)->insert($records);
570
+	}
571
+
572
+	/**
573
+	 * Update an existing pivot record on the table.
574
+	 *
575
+	 * @param  mixed $id
576
+	 * @param  array $attributes
577
+	 * @throws \InvalidArgumentException
578
+	 * @return integer
579
+	 */
580
+	public function updateExistingPivot($id, array $attributes)
581
+	{
582
+		if (in_array($this->updatedAt(), $this->pivotColumns)) {
583
+			$attributes = $this->setTimestampsOnAttach($attributes, true);
584
+		}
585
+
586
+		return $this->newPivotStatementForId($id)->update($attributes);
587
+	}
588
+
589
+	/**
590
+	 * Attach a model to the parent.
591
+	 *
592
+	 * @param  mixed $id
593
+	 * @param  array $attributes
594
+	 * @return void
595
+	 */
596
+	public function attach($id, array $attributes = [])
597
+	{
598
+		$query = $this->newPivotStatement();
599
+
600
+		$query->insert($this->createAttachRecords((array) $id, $attributes));
601
+	}
602
+
603
+	/**
604
+	 * @param  array $entities
605
+	 *
606
+	 * @throws \InvalidArgumentException
607
+	 */
608
+	public function sync(array $entities)
609
+	{
610
+		$this->detachExcept($entities);
611
+	}
612
+
613
+	/**
614
+	 * Detach related entities that are not in $id
615
+	 *
616
+	 * @param  array $entities
617
+	 *
618
+	 * @throws \InvalidArgumentException
619
+	 *
620
+	 * @return void
621
+	 */
622
+	protected function detachExcept(array $entities = [])
623
+	{
624
+		$query = $this->newPivotQuery();
625
+
626
+		if (count($entities) > 0) {
627
+			$keys = $this->getKeys($entities);
628
+
629
+			$query->whereNotIn($this->otherKey, $keys);
630
+		}
631
+		$parentKey = $this->parentMap->getKeyName();
632
+
633
+		$query->where($this->foreignKey, '=', $this->parent->getEntityAttribute($parentKey));
634 634
         
635
-        $query->delete();
636
-
637
-        $query = $this->newPivotQuery();
638
-    }
639
-
640
-
641
-    /**
642
-     * Create an array of records to insert into the pivot table.
643
-     *
644
-     * @param  array $ids
645
-     * @param  array $attributes
646
-     * @return array
647
-     */
648
-    protected function createAttachRecords($ids, array $attributes)
649
-    {
650
-        $records = [];
651
-
652
-        $timed = in_array($this->createdAt(), $this->pivotColumns);
653
-
654
-        // To create the attachment records, we will simply spin through the IDs given
655
-        // and create a new record to insert for each ID. Each ID may actually be a
656
-        // key in the array, with extra attributes to be placed in other columns.
657
-        foreach ($ids as $key => $value) {
658
-            $records[] = $this->attacher($key, $value, $attributes, $timed);
659
-        }
635
+		$query->delete();
636
+
637
+		$query = $this->newPivotQuery();
638
+	}
639
+
640
+
641
+	/**
642
+	 * Create an array of records to insert into the pivot table.
643
+	 *
644
+	 * @param  array $ids
645
+	 * @param  array $attributes
646
+	 * @return array
647
+	 */
648
+	protected function createAttachRecords($ids, array $attributes)
649
+	{
650
+		$records = [];
651
+
652
+		$timed = in_array($this->createdAt(), $this->pivotColumns);
653
+
654
+		// To create the attachment records, we will simply spin through the IDs given
655
+		// and create a new record to insert for each ID. Each ID may actually be a
656
+		// key in the array, with extra attributes to be placed in other columns.
657
+		foreach ($ids as $key => $value) {
658
+			$records[] = $this->attacher($key, $value, $attributes, $timed);
659
+		}
660 660
         
661
-        return $records;
662
-    }
663
-
664
-    /**
665
-     * Create a full attachment record payload.
666
-     *
667
-     * @param  int   $key
668
-     * @param  mixed $value
669
-     * @param  array $attributes
670
-     * @param  bool  $timed
671
-     * @return array
672
-     */
673
-    protected function attacher($key, $value, $attributes, $timed)
674
-    {
675
-        list($id, $extra) = $this->getAttachId($key, $value, $attributes);
661
+		return $records;
662
+	}
663
+
664
+	/**
665
+	 * Create a full attachment record payload.
666
+	 *
667
+	 * @param  int   $key
668
+	 * @param  mixed $value
669
+	 * @param  array $attributes
670
+	 * @param  bool  $timed
671
+	 * @return array
672
+	 */
673
+	protected function attacher($key, $value, $attributes, $timed)
674
+	{
675
+		list($id, $extra) = $this->getAttachId($key, $value, $attributes);
676 676
         
677
-        // To create the attachment records, we will simply spin through the IDs given
678
-        // and create a new record to insert for each ID. Each ID may actually be a
679
-        // key in the array, with extra attributes to be placed in other columns.
680
-        $record = $this->createAttachRecord($id, $timed);
681
-
682
-        return array_merge($record, $extra);
683
-    }
684
-
685
-    /**
686
-     * Get the attach record ID and extra attributes.
687
-     *
688
-     * @param  int   $key
689
-     * @param  mixed $value
690
-     * @param  array $attributes
691
-     * @return array
692
-     */
693
-    protected function getAttachId($key, $value, array $attributes)
694
-    {
695
-        if (is_array($value)) {
696
-            return [$key, array_merge($value, $attributes)];
697
-        }
698
-
699
-        return [$value, $attributes];
700
-    }
701
-
702
-    /**
703
-     * Create a new pivot attachment record.
704
-     *
705
-     * @param  int  $id
706
-     * @param  bool $timed
707
-     * @return array
708
-     */
709
-    protected function createAttachRecord($id, $timed)
710
-    {
711
-        $parentKey = $this->parentMap->getKeyName();
712
-
713
-        $record = [];
714
-
715
-        $record[$this->foreignKey] = $this->parent->getEntityAttribute($parentKey);
716
-
717
-        $record[$this->otherKey] = $id;
718
-
719
-        // If the record needs to have creation and update timestamps, we will make
720
-        // them by calling the parent model's "freshTimestamp" method which will
721
-        // provide us with a fresh timestamp in this model's preferred format.
722
-        if ($timed) {
723
-            $record = $this->setTimestampsOnAttach($record);
724
-        }
725
-
726
-        return $record;
727
-    }
728
-
729
-    /**
730
-     * Set the creation and update timestamps on an attach record.
731
-     *
732
-     * @param  array $record
733
-     * @param  bool  $exists
734
-     * @return array
735
-     */
736
-    protected function setTimestampsOnAttach(array $record, $exists = false)
737
-    {
738
-        $fresh = $this->freshTimestamp();
739
-
740
-        if (!$exists) {
741
-            $record[$this->createdAt()] = $fresh;
742
-        }
743
-
744
-        $record[$this->updatedAt()] = $fresh;
745
-
746
-        return $record;
747
-    }
748
-
749
-    /**
750
-     * @param EntityCollection $entities
751
-     * @return array
752
-     */
753
-    protected function getModelKeysFromCollection(EntityCollection $entities)
754
-    {
755
-        $keyName = $this->relatedMap->getKeyName();
756
-
757
-        return array_map(function ($m) use ($keyName) {
758
-            return $m->$keyName;
759
-        }, $entities);
760
-    }
761
-
762
-    /**
763
-     * Detach models from the relationship.
764
-     *
765
-     * @param  int|array $ids
766
-     * @throws \InvalidArgumentException
767
-     * @return int
768
-     */
769
-    public function detach($ids = [])
770
-    {
771
-        if ($ids instanceof EntityCollection) {
772
-            $ids = (array) $ids->modelKeys();
773
-        }
774
-
775
-        $query = $this->newPivotQuery();
776
-
777
-        // If associated IDs were passed to the method we will only delete those
778
-        // associations, otherwise all of the association ties will be broken.
779
-        // We'll return the numbers of affected rows when we do the deletes.
780
-        $ids = (array) $ids;
781
-
782
-        if (count($ids) > 0) {
783
-            $query->whereIn($this->otherKey, (array) $ids);
784
-        }
785
-
786
-        // Once we have all of the conditions set on the statement, we are ready
787
-        // to run the delete on the pivot table. Then, if the touch parameter
788
-        // is true, we will go ahead and touch all related models to sync.
789
-        return $query->delete();
790
-    }
677
+		// To create the attachment records, we will simply spin through the IDs given
678
+		// and create a new record to insert for each ID. Each ID may actually be a
679
+		// key in the array, with extra attributes to be placed in other columns.
680
+		$record = $this->createAttachRecord($id, $timed);
681
+
682
+		return array_merge($record, $extra);
683
+	}
684
+
685
+	/**
686
+	 * Get the attach record ID and extra attributes.
687
+	 *
688
+	 * @param  int   $key
689
+	 * @param  mixed $value
690
+	 * @param  array $attributes
691
+	 * @return array
692
+	 */
693
+	protected function getAttachId($key, $value, array $attributes)
694
+	{
695
+		if (is_array($value)) {
696
+			return [$key, array_merge($value, $attributes)];
697
+		}
698
+
699
+		return [$value, $attributes];
700
+	}
701
+
702
+	/**
703
+	 * Create a new pivot attachment record.
704
+	 *
705
+	 * @param  int  $id
706
+	 * @param  bool $timed
707
+	 * @return array
708
+	 */
709
+	protected function createAttachRecord($id, $timed)
710
+	{
711
+		$parentKey = $this->parentMap->getKeyName();
712
+
713
+		$record = [];
714
+
715
+		$record[$this->foreignKey] = $this->parent->getEntityAttribute($parentKey);
716
+
717
+		$record[$this->otherKey] = $id;
718
+
719
+		// If the record needs to have creation and update timestamps, we will make
720
+		// them by calling the parent model's "freshTimestamp" method which will
721
+		// provide us with a fresh timestamp in this model's preferred format.
722
+		if ($timed) {
723
+			$record = $this->setTimestampsOnAttach($record);
724
+		}
725
+
726
+		return $record;
727
+	}
728
+
729
+	/**
730
+	 * Set the creation and update timestamps on an attach record.
731
+	 *
732
+	 * @param  array $record
733
+	 * @param  bool  $exists
734
+	 * @return array
735
+	 */
736
+	protected function setTimestampsOnAttach(array $record, $exists = false)
737
+	{
738
+		$fresh = $this->freshTimestamp();
739
+
740
+		if (!$exists) {
741
+			$record[$this->createdAt()] = $fresh;
742
+		}
743
+
744
+		$record[$this->updatedAt()] = $fresh;
745
+
746
+		return $record;
747
+	}
748
+
749
+	/**
750
+	 * @param EntityCollection $entities
751
+	 * @return array
752
+	 */
753
+	protected function getModelKeysFromCollection(EntityCollection $entities)
754
+	{
755
+		$keyName = $this->relatedMap->getKeyName();
756
+
757
+		return array_map(function ($m) use ($keyName) {
758
+			return $m->$keyName;
759
+		}, $entities);
760
+	}
761
+
762
+	/**
763
+	 * Detach models from the relationship.
764
+	 *
765
+	 * @param  int|array $ids
766
+	 * @throws \InvalidArgumentException
767
+	 * @return int
768
+	 */
769
+	public function detach($ids = [])
770
+	{
771
+		if ($ids instanceof EntityCollection) {
772
+			$ids = (array) $ids->modelKeys();
773
+		}
774
+
775
+		$query = $this->newPivotQuery();
776
+
777
+		// If associated IDs were passed to the method we will only delete those
778
+		// associations, otherwise all of the association ties will be broken.
779
+		// We'll return the numbers of affected rows when we do the deletes.
780
+		$ids = (array) $ids;
781
+
782
+		if (count($ids) > 0) {
783
+			$query->whereIn($this->otherKey, (array) $ids);
784
+		}
785
+
786
+		// Once we have all of the conditions set on the statement, we are ready
787
+		// to run the delete on the pivot table. Then, if the touch parameter
788
+		// is true, we will go ahead and touch all related models to sync.
789
+		return $query->delete();
790
+	}
791 791
     
792
-    /**
793
-     * Create a new query builder for the pivot table.
794
-     *
795
-     * @throws \InvalidArgumentException
796
-     *
797
-     * @return \Illuminate\Database\Query\Builder
798
-     */
799
-    protected function newPivotQuery()
800
-    {
801
-        $query = $this->newPivotStatement();
802
-
803
-        $parentKey = $this->parentMap->getKeyName();
804
-
805
-        return $query->where($this->foreignKey, $this->parent->getEntityAttribute($parentKey));
806
-    }
807
-
808
-    /**
809
-     * Get a new plain query builder for the pivot table.
810
-     *
811
-     * @return \Illuminate\Database\Query\Builder
812
-     */
813
-    public function newPivotStatement()
814
-    {
815
-        return $this->query->getQuery()->newQuery()->from($this->table);
816
-    }
817
-
818
-    /**
819
-     * Get a new pivot statement for a given "other" ID.
820
-     *
821
-     * @param  mixed $id
822
-     *
823
-     * @throws \InvalidArgumentException
824
-     *
825
-     * @return \Illuminate\Database\Query\Builder
826
-     */
827
-    public function newPivotStatementForId($id)
828
-    {
829
-        $pivot = $this->newPivotStatement();
830
-
831
-        $parentKeyName = $this->parentMap->getKeyName();
832
-
833
-        $key = $this->parent->getEntityAttribute($parentKeyName);
834
-
835
-        return $pivot->where($this->foreignKey, $key)->where($this->otherKey, $id);
836
-    }
837
-
838
-    /**
839
-     * Create a new pivot model instance.
840
-     *
841
-     * @param  array $attributes
842
-     * @param  bool  $exists
843
-     * @return \Analogue\ORM\Relationships\Pivot
844
-     */
845
-    public function newPivot(array $attributes = [], $exists = false)
846
-    {
847
-        $pivot = new Pivot($this->parent, $this->parentMap, $attributes, $this->table, $exists);
792
+	/**
793
+	 * Create a new query builder for the pivot table.
794
+	 *
795
+	 * @throws \InvalidArgumentException
796
+	 *
797
+	 * @return \Illuminate\Database\Query\Builder
798
+	 */
799
+	protected function newPivotQuery()
800
+	{
801
+		$query = $this->newPivotStatement();
802
+
803
+		$parentKey = $this->parentMap->getKeyName();
804
+
805
+		return $query->where($this->foreignKey, $this->parent->getEntityAttribute($parentKey));
806
+	}
807
+
808
+	/**
809
+	 * Get a new plain query builder for the pivot table.
810
+	 *
811
+	 * @return \Illuminate\Database\Query\Builder
812
+	 */
813
+	public function newPivotStatement()
814
+	{
815
+		return $this->query->getQuery()->newQuery()->from($this->table);
816
+	}
817
+
818
+	/**
819
+	 * Get a new pivot statement for a given "other" ID.
820
+	 *
821
+	 * @param  mixed $id
822
+	 *
823
+	 * @throws \InvalidArgumentException
824
+	 *
825
+	 * @return \Illuminate\Database\Query\Builder
826
+	 */
827
+	public function newPivotStatementForId($id)
828
+	{
829
+		$pivot = $this->newPivotStatement();
830
+
831
+		$parentKeyName = $this->parentMap->getKeyName();
832
+
833
+		$key = $this->parent->getEntityAttribute($parentKeyName);
834
+
835
+		return $pivot->where($this->foreignKey, $key)->where($this->otherKey, $id);
836
+	}
837
+
838
+	/**
839
+	 * Create a new pivot model instance.
840
+	 *
841
+	 * @param  array $attributes
842
+	 * @param  bool  $exists
843
+	 * @return \Analogue\ORM\Relationships\Pivot
844
+	 */
845
+	public function newPivot(array $attributes = [], $exists = false)
846
+	{
847
+		$pivot = new Pivot($this->parent, $this->parentMap, $attributes, $this->table, $exists);
848 848
         
849
-        return $pivot->setPivotKeys($this->foreignKey, $this->otherKey);
850
-    }
851
-
852
-    /**
853
-     * Create a new existing pivot model instance.
854
-     *
855
-     * @param  array $attributes
856
-     * @return \Analogue\ORM\Relationships\Pivot
857
-     */
858
-    public function newExistingPivot(array $attributes = [])
859
-    {
860
-        return $this->newPivot($attributes, true);
861
-    }
862
-
863
-    /**
864
-     * Set the columns on the pivot table to retrieve.
865
-     *
866
-     * @param  array $columns
867
-     * @return $this
868
-     */
869
-    public function withPivot($columns)
870
-    {
871
-        $columns = is_array($columns) ? $columns : func_get_args();
872
-
873
-        $this->pivotColumns = array_merge($this->pivotColumns, $columns);
874
-
875
-        return $this;
876
-    }
877
-
878
-    /**
879
-     * Specify that the pivot table has creation and update timestamps.
880
-     *
881
-     * @param  mixed $createdAt
882
-     * @param  mixed $updatedAt
883
-     * @return \Analogue\ORM\Relationships\BelongsToMany
884
-     */
885
-    public function withTimestamps($createdAt = null, $updatedAt = null)
886
-    {
887
-        return $this->withPivot($createdAt ?: $this->createdAt(), $updatedAt ?: $this->updatedAt());
888
-    }
889
-
890
-    /**
891
-     * Get the key for comparing against the parent key in "has" query.
892
-     *
893
-     * @return string
894
-     */
895
-    public function getHasCompareKey()
896
-    {
897
-        return $this->getForeignKey();
898
-    }
899
-
900
-    /**
901
-     * Get the fully qualified foreign key for the relation.
902
-     *
903
-     * @return string
904
-     */
905
-    public function getForeignKey()
906
-    {
907
-        return $this->table . '.' . $this->foreignKey;
908
-    }
909
-
910
-    /**
911
-     * Get the fully qualified "other key" for the relation.
912
-     *
913
-     * @return string
914
-     */
915
-    public function getOtherKey()
916
-    {
917
-        return $this->table . '.' . $this->otherKey;
918
-    }
919
-
920
-    /**
921
-     * Get the fully qualified parent key name.
922
-     *
923
-     * @return string
924
-     */
925
-    protected function getQualifiedParentKeyName()
926
-    {
927
-        return $this->parentMap->getQualifiedKeyName();
928
-    }
929
-
930
-    /**
931
-     * Get the intermediate table for the relationship.
932
-     *
933
-     * @return string
934
-     */
935
-    public function getTable()
936
-    {
937
-        return $this->table;
938
-    }
939
-
940
-    /**
941
-     * Get the relationship name for the relationship.
942
-     *
943
-     * @return string
944
-     */
945
-    public function getRelationName()
946
-    {
947
-        return $this->relationName;
948
-    }
849
+		return $pivot->setPivotKeys($this->foreignKey, $this->otherKey);
850
+	}
851
+
852
+	/**
853
+	 * Create a new existing pivot model instance.
854
+	 *
855
+	 * @param  array $attributes
856
+	 * @return \Analogue\ORM\Relationships\Pivot
857
+	 */
858
+	public function newExistingPivot(array $attributes = [])
859
+	{
860
+		return $this->newPivot($attributes, true);
861
+	}
862
+
863
+	/**
864
+	 * Set the columns on the pivot table to retrieve.
865
+	 *
866
+	 * @param  array $columns
867
+	 * @return $this
868
+	 */
869
+	public function withPivot($columns)
870
+	{
871
+		$columns = is_array($columns) ? $columns : func_get_args();
872
+
873
+		$this->pivotColumns = array_merge($this->pivotColumns, $columns);
874
+
875
+		return $this;
876
+	}
877
+
878
+	/**
879
+	 * Specify that the pivot table has creation and update timestamps.
880
+	 *
881
+	 * @param  mixed $createdAt
882
+	 * @param  mixed $updatedAt
883
+	 * @return \Analogue\ORM\Relationships\BelongsToMany
884
+	 */
885
+	public function withTimestamps($createdAt = null, $updatedAt = null)
886
+	{
887
+		return $this->withPivot($createdAt ?: $this->createdAt(), $updatedAt ?: $this->updatedAt());
888
+	}
889
+
890
+	/**
891
+	 * Get the key for comparing against the parent key in "has" query.
892
+	 *
893
+	 * @return string
894
+	 */
895
+	public function getHasCompareKey()
896
+	{
897
+		return $this->getForeignKey();
898
+	}
899
+
900
+	/**
901
+	 * Get the fully qualified foreign key for the relation.
902
+	 *
903
+	 * @return string
904
+	 */
905
+	public function getForeignKey()
906
+	{
907
+		return $this->table . '.' . $this->foreignKey;
908
+	}
909
+
910
+	/**
911
+	 * Get the fully qualified "other key" for the relation.
912
+	 *
913
+	 * @return string
914
+	 */
915
+	public function getOtherKey()
916
+	{
917
+		return $this->table . '.' . $this->otherKey;
918
+	}
919
+
920
+	/**
921
+	 * Get the fully qualified parent key name.
922
+	 *
923
+	 * @return string
924
+	 */
925
+	protected function getQualifiedParentKeyName()
926
+	{
927
+		return $this->parentMap->getQualifiedKeyName();
928
+	}
929
+
930
+	/**
931
+	 * Get the intermediate table for the relationship.
932
+	 *
933
+	 * @return string
934
+	 */
935
+	public function getTable()
936
+	{
937
+		return $this->table;
938
+	}
939
+
940
+	/**
941
+	 * Get the relationship name for the relationship.
942
+	 *
943
+	 * @return string
944
+	 */
945
+	public function getRelationName()
946
+	{
947
+		return $this->relationName;
948
+	}
949 949
 }
Please login to merge, or discard this patch.