Skip to content

In-memory model hydration bug masks id after Model::create() #3549

Description

@ahmdadl
  • Laravel-mongodb Version: 5.8.2
  • PHP Version: 8.3 / 8.4
  • Database Driver & Version: MongoDB (Custom Connection Extension)

Description:

The integer id manually generated and assigned inside the creating model event works perfectly upon database insertion and subsequent retrieval via queries (e.g., ::find(), ::first()). However, immediately following a Model::create() operation, the returned in-memory model instance drops the custom integer id value when serialized via toArray(), replacing it with the auto-generated MongoDB hexadecimal _id string instead.

Steps to reproduce

  1. Extend the database connection to map a custom Mongo connection handling integer primary keys in AppServiceProvider:
use Illuminate\Support\Facades\DB;

DB::extend("mongodb", function ($config, $name) {
    $config["name"] = $name;
    return new CustomMongoConnection($config); 
});
DB::purge("mongodb");
  1. Define the model targeting the custom primary key and hooks:
use MongoDB\Laravel\Eloquent\Model;

class Request extends Model
{
    protected $connection = 'mongodb';
    protected $primaryKey = 'id';
    protected $keyType = 'int';

    protected static function booted(): void
    {
        static::creating(function ($model) {
            $generateId = fn() => random_int(100000000, 999999999);
            $modelId = $generateId();

            if (!$model->id) {
                $model->id = $modelId;
            }
            $model->cid = $modelId;
        });
    }
}
  1. Execute a create() command and compare the inline model output with a freshly queried document model instance:
$request = Request::create([]);
dump($request->toArray()); 

$fetchedRequest = Request::latest()->first();
dd($fetchedRequest->toArray());

Expected behaviour

Both toArray() outputs should yield identical structures, retaining the assigned integer id attribute without mutating it post-save.

array:5 [
  "_id" => "6a5e0a40a3c1417750053505"
  "id" => 285028729
  "cid" => 285028729
  "updated_at" => "2026-07-20T11:45:04.368000Z"
  "created_at" => "2026-07-20T11:45:04.368000Z"
]

Actual behaviour

The model returned directly from Request::create() masks the integer id with the MongoDB _id string, while the fetched model displays the correct attributes:

Output 1: Freshly created instance (dump($request->toArray());)

array:4 [
  "id" => "6a5e0a40a3c1417750053505" // BUG: Overwritten by MongoDB string _id, integer value lost in memory
  "cid" => 285028729
  "updated_at" => "2026-07-20T11:45:04.368000Z"
  "created_at" => "2026-07-20T11:45:04.368000Z"
]

Output 2: Freshly fetched from DB (dd($fetchedRequest->toArray());)

array:5 [
  "_id" => "6a5e0a40a3c1417750053505"
  "id" => 285028729                     // Works perfectly here!
  "cid" => 285028729
  "updated_at" => "2026-07-20T11:45:04.368000Z"
  "created_at" => "2026-07-20T11:45:04.368000Z"
]
Logs: No exception is thrown. The bug is limited to an inconsistent internal state mapping on the `Eloquent\Model` attribute dictionary immediately following a `save()` pipeline operation.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions