Skip to content

Commit 94948cf

Browse files
committed
Fix Eloquent eager loading matching.
1 parent b65fa70 commit 94948cf

File tree

8 files changed

+53
-42
lines changed

8 files changed

+53
-42
lines changed

laravel/database/eloquent/query.php

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,11 @@ public function first($columns = array('*'))
6666
* Get all of the model results for the query.
6767
*
6868
* @param array $columns
69-
* @param bool $keyed
7069
* @return array
7170
*/
72-
public function get($columns = array('*'), $keyed = true)
71+
public function get($columns = array('*'))
7372
{
74-
return $this->hydrate($this->model, $this->table->get($columns), $keyed);
73+
return $this->hydrate($this->model, $this->table->get($columns));
7574
}
7675

7776
/**
@@ -100,10 +99,9 @@ public function paginate($per_page = null, $columns = array('*'))
10099
*
101100
* @param Model $model
102101
* @param array $results
103-
* @param bool $keyed
104102
* @return array
105103
*/
106-
public function hydrate($model, $results, $keyed = true)
104+
public function hydrate($model, $results)
107105
{
108106
$class = get_class($model);
109107

@@ -128,17 +126,7 @@ public function hydrate($model, $results, $keyed = true)
128126

129127
$new->original = $new->attributes;
130128

131-
// Typically, the resulting models are keyed by their primary key, but it
132-
// may be useful to not do this in some circumstances such as when we
133-
// are eager loading a *-to-* relationships which has duplicates.
134-
if ($keyed)
135-
{
136-
$models[$result[$this->model->key()]] = $new;
137-
}
138-
else
139-
{
140-
$models[] = $new;
141-
}
129+
$models[] = $new;
142130
}
143131

144132
if (count($results) > 0)
@@ -199,17 +187,7 @@ protected function load(&$results, $relationship, $constraints)
199187

200188
$query->initialize($results, $relationship);
201189

202-
// If we're eager loading a many-to-many relationship we will disable
203-
// the primary key indexing on the hydration since there could be
204-
// roles shared across users and we don't want to overwrite.
205-
if ( ! $query instanceof Has_Many_And_Belongs_To)
206-
{
207-
$query->match($relationship, $results, $query->get());
208-
}
209-
else
210-
{
211-
$query->match($relationship, $results, $query->get(array('*'), false));
212-
}
190+
$query->match($relationship, $results, $query->get());
213191
}
214192

215193
/**

laravel/database/eloquent/relationships/belongs_to.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,14 @@ public function match($relationship, &$children, $parents)
8787

8888
foreach ($children as &$child)
8989
{
90-
if (array_key_exists($child->$foreign, $parents))
90+
$parent = array_first($parents, function($k, $v) use ($child, $foreign)
9191
{
92-
$child->relationships[$relationship] = $parents[$child->$foreign];
92+
return $v->get_key() == $child->$foreign;
93+
});
94+
95+
if ( ! is_null($parent))
96+
{
97+
$child->relationships[$relationship] = $parent;
9398
}
9499
}
95100
}

laravel/database/eloquent/relationships/has_many.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,14 @@ public function match($relationship, &$parents, $children)
9191
{
9292
$foreign = $this->foreign_key();
9393

94-
foreach ($children as $key => $child)
94+
foreach ($parents as &$parent)
9595
{
96-
$parents[$child->$foreign]->relationships[$relationship][$child->get_key()] = $child;
96+
$matching = array_filter($children, function($v) use ($parent, $foreign)
97+
{
98+
return $v->$foreign == $parent->get_key();
99+
});
100+
101+
$parent->relationships[$relationship] = $matching;
97102
}
98103
}
99104

laravel/database/eloquent/relationships/has_many_and_belongs_to.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ public function initialize(&$parents, $relationship)
311311
*/
312312
public function eagerly_constrain($results)
313313
{
314-
$this->table->where_in($this->joining.'.'.$this->foreign_key(), array_keys($results));
314+
$this->table->where_in($this->joining.'.'.$this->foreign_key(), $this->keys($results));
315315
}
316316

317317
/**
@@ -325,14 +325,14 @@ public function match($relationship, &$parents, $children)
325325
{
326326
$foreign = $this->foreign_key();
327327

328-
// For each child we'll just get the parent that connects to the child and set the
329-
// child model on the relationship array using the keys. Once we're done looping
330-
// through the children all of the proper relations will be set.
331-
foreach ($children as $key => $child)
328+
foreach ($parents as &$parent)
332329
{
333-
$parent =& $parents[$child->pivot->$foreign];
330+
$matching = array_filter($children, function($v) use ($parent, $foreign)
331+
{
332+
return $v->pivot->$foreign == $parent->get_key();
333+
});
334334

335-
$parent->relationships[$relationship][$child->{$child->key()}] = $child;
335+
$parent->relationships[$relationship] = $matching;
336336
}
337337
}
338338

laravel/database/eloquent/relationships/has_one.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,14 @@ public function match($relationship, &$parents, $children)
3838
{
3939
$foreign = $this->foreign_key();
4040

41-
foreach ($children as $key => $child)
41+
foreach ($parents as &$parent)
4242
{
43-
$parents[$child->$foreign]->relationships[$relationship] = $child;
43+
$matching = array_first($children, function($k, $v) use ($parent, $foreign)
44+
{
45+
return $v->$foreign == $parent->get_key();
46+
});
47+
48+
$parent->relationships[$relationship] = $matching;
4449
}
4550
}
4651

laravel/database/eloquent/relationships/has_one_or_many.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ protected function constrain()
5353
*/
5454
public function eagerly_constrain($results)
5555
{
56-
$this->table->where_in($this->foreign_key(), array_keys($results));
56+
$this->table->where_in($this->foreign_key(), $this->keys($results));
5757
}
5858

5959
}

laravel/database/eloquent/relationships/relationship.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,22 @@ public function foreign_key()
101101
return static::foreign($this->base, $this->foreign);
102102
}
103103

104+
/**
105+
* Gather all the primary keys from a result set.
106+
*
107+
* @param array $results
108+
* @return array
109+
*/
110+
public function keys($results)
111+
{
112+
$keys = array();
113+
114+
foreach ($results as $result)
115+
{
116+
$keys[] = $result->get_key();
117+
}
118+
119+
return array_unique($keys);
120+
}
121+
104122
}

laravel/error.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public static function exception($exception, $trace = true)
1313
{
1414
static::log($exception);
1515

16-
ob_get_level() and ob_end_clean();
16+
//ob_get_level() and ob_end_clean();
1717

1818
// If detailed errors are enabled, we'll just format the exception into
1919
// a simple error message and display it on the screen. We don't use a

0 commit comments

Comments
 (0)