Skip to content

Commit

Permalink
Move relation join/orderBy stuff to EVENT_AFTER_PREPARE
Browse files Browse the repository at this point in the history
Fixes a bug where the orderBy value ends up getting retained if a query is executed directly, and then re-executed with eager-loading. orderBy gets applied to the eager-loading params via getCriteria() and causes a SQL error because the relation table isn’t joined in.
  • Loading branch information
brandonkelly committed Feb 7, 2024
1 parent 2e38cba commit 158a815
Showing 1 changed file with 29 additions and 35 deletions.
64 changes: 29 additions & 35 deletions src/fields/BaseRelationField.php
Original file line number Diff line number Diff line change
Expand Up @@ -646,42 +646,9 @@ public function normalizeValue(mixed $value, ?ElementInterface $element): mixed

$relationsAlias = sprintf('relations_%s', StringHelper::randomString(10));

if ($this->sortable && !$this->maintainHierarchy) {
$query->attachBehavior(self::class, new EventBehavior([
ElementQuery::EVENT_BEFORE_PREPARE => function(
CancelableEvent $event,
ElementQuery $query,
) use ($relationsAlias) {
if ($query->orderBy === '') {
$query->orderBy(["$relationsAlias.sortOrder" => SORT_ASC]);
}
},
]));
}

// join the relations table via EVENT_BEFORE_PREPARE so it gets joined for cloned queries as well
$query->attachBehavior(sprintf('%s-once', self::class), new EventBehavior([
ElementQuery::EVENT_BEFORE_PREPARE => function(
CancelableEvent $event,
ElementQuery $query,
) use ($element, $relationsAlias) {
$query->innerJoin(
[$relationsAlias => DbTable::RELATIONS],
[
'and',
"[[$relationsAlias.targetId]] = [[elements.id]]",
[
"$relationsAlias.sourceId" => $element->id,
"$relationsAlias.fieldId" => $this->id,
],
[
'or',
["$relationsAlias.sourceSiteId" => null],
["$relationsAlias.sourceSiteId" => $element->siteId],
],
]
);

ElementQuery::EVENT_BEFORE_PREPARE => function(CancelableEvent $event, ElementQuery $query) {
if ($this->maintainHierarchy && $query->id === null) {
$structuresService = Craft::$app->getStructures();

Expand All @@ -700,7 +667,34 @@ public function normalizeValue(mixed $value, ?ElementInterface $element): mixed
$query->id(array_map(fn(ElementInterface $element) => $element->id, $structureElements));
}
},
], true));
ElementQuery::EVENT_AFTER_PREPARE => function(
CancelableEvent $event,
ElementQuery $query,
) use ($element, $relationsAlias) {
foreach ([$query->query, $query->subQuery] as $q) {
$q->innerJoin(
[$relationsAlias => DbTable::RELATIONS],
[
'and',
"[[$relationsAlias.targetId]] = [[elements.id]]",
[
"$relationsAlias.sourceId" => $element->id,
"$relationsAlias.fieldId" => $this->id,
],
[
'or',
["$relationsAlias.sourceSiteId" => null],
["$relationsAlias.sourceSiteId" => $element->siteId],
],
]
);

if ($this->sortable && !$this->maintainHierarchy && !$q->orderBy) {
$q->orderBy(["$relationsAlias.sortOrder" => SORT_ASC]);
}
}
},
]));

// Prepare the query for lazy eager loading
$query->prepForEagerLoading($this->handle, $element);
Expand Down

0 comments on commit 158a815

Please sign in to comment.