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.