laravel-mongodb - Issue #3506: Builder::orderBy() does not handle the new SortDirection enum from Laravel 13.8

XMLWordPrintableJSON

    • None
    • Needed
    • Hide

      Starting PHP 8.6 (or using the symfony/php86-polyfill), it's possible to use the SortDirection enum to indicate the sort order in the orderBy method of the query builder.

      Show
      Starting PHP 8.6 (or using the symfony/php86-polyfill), it's possible to use the SortDirection enum to indicate the sort order in the orderBy method of the query builder.
    • None
    • None
    • None
    • None
    • None
    • None

      babaduk47 has created Issue #3506: Builder::orderBy() does not handle the new SortDirection enum from Laravel 13.8 in laravel-mongodb. This Jira ticket was filed by GromNaN

      Issue Text:

      • Laravel-mongodb Version: 5.7.1
      • PHP Version: 8.5.0
      • Database Driver & Version: ext-mongodb 2.1.4 / mongodb/mongodb 2.1.2 (Laravel framework: v13.8.0)

      Description:

      Laravel 13.8 introduced a new `Illuminate\Database\Query\SortDirection` enum and started passing its cases (`SortDirection::Ascending` / `SortDirection::Descending`) as the `$direction` argument to `orderBy()` from several internal call paths (e.g. `latest()`, `oldest()`, `reorder()`, default Eloquent relation ordering). See laravel/framework#59865.

      `MongoDB\Laravel\Query\Builder::orderBy()` overrides the base method and only normalizes string values:

      https://github.com/mongodb/laravel-mongodb/blob/5.7.1/src/Query/Builder.php#L669-L687

      ```php
      public function orderBy($column, $direction = 'asc')
      {
      if (is_string($direction)) {
      $direction = match ($direction)

      { 'asc', 'ASC' => 1, 'desc', 'DESC' => -1, default => throw new InvalidArgumentException('Order direction must be "asc" or "desc".'), }

      ;
      }

      $column = (string) $column;
      if ($column === 'natural')

      { $this->orders['$natural'] = $direction; }

      else

      { $this->orders[$column] = $direction; }

      return $this;
      }
      ```

      When `$direction` is a `SortDirection` enum instance the `is_string()` branch is skipped, the enum is stored as-is in `$this->orders`, and the MongoDB PHP driver later fails to serialize it:

      ```
      Non-backed enum SortDirection cannot be serialized for field path "_id"
      ```

      This breaks any query that goes through an internal code path now passing the enum — `Model::latest()->first()`, `Model::oldest()`, default `created_at DESC` ordering on relations, etc.

      The same handling is likely needed in any other places in the package that compare `$direction` against `'asc'`/`'desc'` strings (e.g. `removeExistingOrdersFor`, raw-order builders).

      Steps to reproduce

      1. Install `laravel/framework: ^13.8` together with `mongodb/laravel-mongodb: ^5.7`.
      2. Define any Eloquent model on the MongoDB connection (e.g. `User`).
      3. Run a query that uses an internal helper now passing the enum, or pass the enum directly:

      ```php
      use Illuminate\Database\Query\SortDirection;

      User::query()>latest()>first();
      // or
      User::query()>orderBy('created_at', SortDirection::Descending)>get();
      ```

      Expected behaviour

      `Builder::orderBy()` should accept `SortDirection::Ascending` / `SortDirection::Descending` and convert them to the MongoDB integer direction (`1` / `1`), the same way it normalizes the `'asc'` / `'desc'` strings — so `Model::latest()>first()` keeps working on Laravel 13.8.

      Suggested fix:

      ```php
      public function orderBy($column, $direction = 'asc')
      {
      if ($direction instanceof \Illuminate\Database\Query\SortDirection)

      { $direction = $direction === \Illuminate\Database\Query\SortDirection::Ascending ? 1 : -1; }

      elseif (is_string($direction)) {
      $direction = match ($direction)

      { 'asc', 'ASC' => 1, 'desc', 'DESC' => -1, default => throw new InvalidArgumentException('Order direction must be "asc" or "desc".'), }

      ;
      }

      // …unchanged…
      }
      ```

      The `SortDirection` reference must stay compatible with Laravel < 13.8 (e.g. via `class_exists()` guard or string-FQN check), since the enum does not exist in earlier versions.

      Actual behaviour

      The query throws:

      ```
      Non-backed enum SortDirection cannot be serialized for field path "_id"
      ```

      Stack trace points at the BSON serializer, called when the driver tries to encode `$this->orders`, which now contains a `SortDirection` enum instance instead of `1` / `-1`.

            Assignee:
            Jérôme Tamarelle
            Reporter:
            TPM Jira Automations Bot
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: