Skip to content

Prioritize sorted orderBy item when already present in QueryBuilder#350

Open
jonmldr wants to merge 1 commit into
KnpLabs:masterfrom
jonmldr:jon/prioritize-sorted-order-by-item
Open

Prioritize sorted orderBy item when already present in QueryBuilder#350
jonmldr wants to merge 1 commit into
KnpLabs:masterfrom
jonmldr:jon/prioritize-sorted-order-by-item

Conversation

@jonmldr
Copy link
Copy Markdown

@jonmldr jonmldr commented Jul 26, 2025

This MR ensures that a sorted orderBy item is always prioritized as the first in the list, especially when it is already present in the QueryBuilder. This ensures that the query prioritizes the sorted property first, as intended.

The change guarantees that array_unshift is always used. When the sorted orderBy item is already present in the QueryBuilder, it removes the duplicate item instead of modifying the direction of the existing one.

@jonmldr jonmldr changed the title Prioritize sorted order by item when already present in querybuilder Prioritize sorted orderBy item when already present in QueryBuilder Jul 26, 2025
@garak
Copy link
Copy Markdown
Collaborator

garak commented Jul 26, 2025

Please add tests

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the Doctrine ORM sortable OrderByWalker so the requested sort field is always placed first in the generated ORDER BY, even when the same field is already present in the query’s existing ordering.

Changes:

  • Removes an existing matching ORDER BY item (for alias.field) before prepending the requested sort item.
  • Always prepends (array_unshift) the requested sort item when an OrderByClause already exists.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 73 to 88
if ($AST->orderByClause) {
$set = false;
foreach ($AST->orderByClause->orderByItems as $item) {
$orderByItems = &$AST->orderByClause->orderByItems;
foreach ($orderByItems as $orderByIndex => $item) {
if (
$item->expression instanceof PathExpression &&
$item->expression->identificationVariable === $alias &&
$item->expression->field === $field
) {
$item->type = $direction;
$set = true;
unset($orderByItems[$orderByIndex]);

break;
}
}
if (!$set) {
array_unshift($AST->orderByClause->orderByItems, $orderByItem);
}

array_unshift($orderByItems, $orderByItem);
} else {
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change alters behavior when the sorted field is already present in an existing ORDER BY (it now removes the existing item and prepends the sorted one). There doesn’t appear to be test coverage for the “existing ORDER BY contains the same field” scenario in the Doctrine ORM sortable tests; please add/adjust a test to assert (1) the sorted field becomes the first ORDER BY item and (2) no duplicate ORDER BY entry remains.

Copilot uses AI. Check for mistakes.
Comment on lines 76 to 80
if (
$item->expression instanceof PathExpression &&
$item->expression->identificationVariable === $alias &&
$item->expression->field === $field
) {
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The duplicate-removal logic only matches existing ORDER BY items where the expression is a PathExpression (alias.field). Sorts that use a result/scalar alias (e.g., the existing test case that sorts by counter) or other expression types won’t be de-duplicated, so you can still end up with duplicate ORDER BY entries even though the PR description says duplicates are removed when already present. If de-duplication is intended broadly, extend the match to handle non-PathExpression expressions when $alias === false (and/or other AST expression node types).

Copilot uses AI. Check for mistakes.
Comment on lines +82 to 83

break;
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loop stops after unsetting the first matching ORDER BY item. If the query already contains the same alias/field multiple times (e.g., repeated addOrderBy calls), additional duplicates will remain and you'll still end up with multiple ORDER BY entries for the same expression. Consider removing all matching items (don’t break; keep scanning) before unshifting the new item, or filtering the array to exclude matches.

Suggested change
break;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants