Override Sorting in Eloquent
A very peculiar use case: in a Laravel application, within a complex flow of encapsulated functions which builds different types of Eloquent queries, I always have to orderBy()
the created_at
timestamp. Except in one situation.
The proper way to fix should be to pass a extra parameter to handle that singular case. But today I'm too lazy to refactorize that block of code, so I've found a more brutal, hackish and dirty fix: revert the previously attached orderBy()
from the query, and replace it.
In Illuminate\Database\Query\Builder
(which is the base building block for Illuminate\Database\Eloquent\Builder
) it already exists a function named removeExistingOrdersFor()
, doing exactly what its name suggests, but is protected
and not accessible function. On the other hand, the attribute $orders
- holding the current ordering for the query - is public and can be shamelessly manipulated.
Taking some inspiration from removeExistingOrdersFor()
, it is possible to write:
// Access the actual Query\Builder from the Eloquent\Builder
$subquery = $query->getQuery();
// Access the Collection of ordering parameters, and remove the
// reference to the previously used column
$subquery->orders = Illuminate\Support\Collection::make($subquery->orders)
->reject(function ($order) {
return isset($order['column']) ? $order['column'] === 'old_column' : false;
})->values()->all();
// Order by the intended column
$query->orderBy('new_column', 'asc');
Duck taped.