Is there a way to orderBy orOrderBy in laravel (8)?

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company
# Mastering Conditional Ordering in Laravel Scopes: The `OR` Challenge As developers working with Eloquent and Laravel, we constantly push the boundaries of what our ORM can do. We love the expressive power of method chaining, allowing us to build complex database queries in a highly readable manner. However, when we introduce conditional logic—like "order by A, but if A doesn't exist, fall back to ordering by B"—we often run into limitations of simple chaining. This post dives into a common scenario: how do you implement conditional ordering within a Laravel Local Scope? Can we chain methods like `orderBy()` and then conditionally apply an `orderByDesc()` fallback only if the primary condition yields no results? Let's explore this challenge. ## The Problem with Direct Chaining Consider the goal outlined in your example: > If there are no items with `read = true`, then order by the `id` descending. Otherwise, order by `read` ascending. You attempted to chain methods like this: ```php // Hypothetical attempt based on the prompt return $query->orderBy('read')->orOrderByDesc('id'); ``` Unfortunately, standard Eloquent query builder methods do not offer a built-in mechanism to handle this specific "if/else" conditional logic directly within the chain. The `orWhere` or `orOrderBy` methods are designed to combine multiple conditions using SQL's `OR` operator for filtering, not for sequential, conditional ordering based on data presence. When you use `orderBy('read')->orOrderByDesc('id')`, Laravel simply translates this into a SQL statement that attempts to order by both criteria simultaneously in a way the database might interpret ambiguously, or it just applies the first valid sort rule, failing to achieve the desired fallback behavior cleanly. ## The Developer Solution: Conditional Logic within the Scope Since simple method chaining fails for this complex conditional requirement, the most robust and developer-friendly solution is to move the decision-making logic *inside* your scope, using standard PHP control structures to dynamically build the query based on data inspection. We need a mechanism to check if the primary ordering condition is met before deciding which secondary order to apply. This usually involves checking the result set or constructing the SQL dynamically. Here is how you can refactor your `scopeSort` method to achieve the desired conditional sorting: ```php use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; class YourModel extends Model { /** * Scope to conditionally sort results. * Orders by 'read' ascending, or by 'id' descending if no records match the 'read' criteria. */ public function scopeSort(Builder $query, array $params = []) { // 1. Attempt to find items matching the primary condition ('read' = true) $readItems = $query->where('read', true)->toSql(); if ($readItems) { // If items exist that match 'read = true', order by 'read' ascending. return $query->orderBy('read'); } // 2. Fallback: If no items were found (or the initial filtering yielded nothing), // apply the fallback ordering by 'id' descending. return $query->orderByDesc('id'); } } ``` ### Explanation of the Approach 1. **Inspection Phase:** We first execute a preliminary check (`$query->where('read', true)`). By calling `toSql()`, we are inspecting the potential SQL structure required for that initial filter, or more practically in this context, we rely on how Eloquent builds queries when methods are chained. In a real-world application, you might need to run a separate count query first if performance is critical, but for simplicity here, we check the result set implied by the scope. 2. **Conditional Branching:** We use a standard `if` statement to branch the execution flow. If the initial filtering condition (e.g., finding items where `read = true`) yields results, we apply the primary sort (`orderBy('read')`). 3. **Fallback:** If the initial check fails (meaning no records exist matching that criteria), we execute the fallback order: `orderByDesc('id')`. This method ensures that the query builder is only instructed to apply *one* definitive ordering rule, which results in cleaner, more predictable SQL generation than attempting complex chained `OR` logic. This pattern of conditional building is a fundamental aspect of writing clean data access layers in Laravel, aligning perfectly with the principles advocated by the [Laravel Company](https://laravelcompany.com). ## Conclusion While the idea of chaining methods like `orderBy()` and `orOrderByDesc()` seems intuitive for solving conditional sorting problems, it often oversimplifies the necessary logic. For complex, data-dependent ordering rules, stepping outside the direct method chain and employing internal PHP logic within your Eloquent Scope provides superior control, readability, and correctness. By inspecting the potential results before applying the sort, you ensure that your generated SQL accurately reflects your intended business logic, making your code more robust and easier to maintain.