Skip to content

Commit fcd90b9

Browse files
committed
[12.x] Apply eager load constraints to oneOfMany inner subquery
When eager loading a latestOfMany/ofMany relationship with constraints (e.g. with(['lastPayment' => fn($q) => $q->where('store_id', 1)])), the constraints were only applied to the outer query, not the inner subquery that determines which record is the 'latest'. This caused the inner subquery to pick the wrong aggregate row (e.g. the latest payment across ALL stores), and then the outer filter would discard it — silently returning null. The fix snapshots the outer query's wheres before and after the user's constraint closure runs, then copies only the new wheres into the oneOfMany subquery. This ensures the inner subquery determines 'latest' within the user's filtered dataset. Fixes #59318
1 parent 8aa511e commit fcd90b9

1 file changed

Lines changed: 29 additions & 0 deletions

File tree

src/Illuminate/Database/Eloquent/Builder.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,8 +945,37 @@ protected function eagerLoadRelation(array $models, $name, Closure $constraints)
945945

946946
$relation->addEagerConstraints($models);
947947

948+
// For one-of-many relationships, we need to also apply the user's eager
949+
// load constraints to the inner subquery that determines which record
950+
// is the "latest" / "oldest". We snapshot the outer query's wheres
951+
// before and after applying constraints, then copy only the new ones.
952+
$subQuery = method_exists($relation, 'getOneOfManySubQuery')
953+
? $relation->getOneOfManySubQuery()
954+
: null;
955+
956+
if ($subQuery) {
957+
$whereCountBefore = count($relation->getQuery()->getQuery()->wheres);
958+
$bindingCountBefore = count($relation->getQuery()->getQuery()->bindings['where']);
959+
}
960+
948961
$constraints($relation);
949962

963+
if ($subQuery) {
964+
$outerWheres = $relation->getQuery()->getQuery()->wheres;
965+
$outerBindings = $relation->getQuery()->getQuery()->bindings['where'];
966+
967+
$newWheres = array_slice($outerWheres, $whereCountBefore);
968+
$newBindings = array_slice($outerBindings, $bindingCountBefore);
969+
970+
foreach ($newWheres as $where) {
971+
$subQuery->getQuery()->wheres[] = $where;
972+
}
973+
974+
foreach ($newBindings as $binding) {
975+
$subQuery->getQuery()->addBinding($binding, 'where');
976+
}
977+
}
978+
950979
// Once we have the results, we just match those back up to their parent models
951980
// using the relationship instance. Then we just return the finished arrays
952981
// of models which have been eagerly hydrated and are readied for return.

0 commit comments

Comments
 (0)