Laravel does not cast string primary key

Viewed 1512

I have an eloquent model with a string primary key:

protected $keyType = 'string';

If I run this:

PaymentProvider::find('stripe');
PaymentProvider::find(0);

Expected output:

  • the row where id = 'stripe'
  • null

Actual output:

  • the Stripe row
  • the Stripe row (or the first row in the table)

This seems to be a quirk with MySQL, where id = 0 returns all rows when the primary key is a string.

Route Model Binding handles this correctly, the generated query is searching for a string rather than an integer:

1 => array:3 [▼
    "query" => "select * from `payment_providers` where `id` = ? and `payment_providers`.`deleted_at` is null limit 1"
    "bindings" => array:1 [▼
      0 => "0"
    ]
    "time" => 0.32
  ]

And it seems pivot relations are designed to cast a string primary key as well: https://github.com/laravel/framework/blob/7.x/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php#L654:L667

This seems like something that has been considered elsewhere in the framework so i'm not sure if this is a genuine bug or by design.

Why aren't string primary keys cast to a string?

1 Answers

Eloquent assumes that the primary key is an incrementing integer value, which means that by default the primary key will automatically be cast to an int. If you wish to use a non-incrementing or a non-numeric primary key you must set the public $incrementing property on your model to false:

public $incrementing = false;
protected $keyType = 'string';

Check docs.

Related