Skip to content

[7.x] FindOrFail being passed null as value on string key returns a model with empty string as key #34029

@RikSomers

Description

@RikSomers
  • Laravel Version: 7.26.0
  • PHP Version: 7.3.3
  • Database Driver & Version: SQL Server 2017

Description:

When you try to fetch a model with a string key with findOrFail, if you pass the value null, it can find a row where the key is an empty string, where previously it would fail to find the model.

Steps To Reproduce:

Given that you have a model with a string primary key:

 public $incrementing = false;

 protected $keyType = 'string';

And given that you have a row in the database with the key being " " (so an empty string).

When you try to fetch the model by passing null to findOrFail

Model::findOrFail(null)

You will receive the row in the database with the empty string.

This has been broken since #33930, as it has been working before on laravel 7.25.0 when this method hadn't been changed.

Our Case

We use a database (not in our control how the database is structured) that has default "empty" keys so it can create cyclic relationships. So for example, a user needs to be created by a user, but for that you need there to be a default user that's created by itself. So this database gets created with foreign key checks disabled, and then afterwards they enable them, because there is now a default "empty" user.

Currently, what we are doing in several places in our code is fetching something based on a value passed in a form request. So what our code currently is doing, is basically the following:

$documentGrp = DocumentGrp::findOrFail(request('doc-grp-code'));

// some other code

$documentGrp->documents()->map(function ($document) {
   // do something with the documents
});

What happened previously was that the findOrFail would fail, because it tried to fetch a model where the key was the literal null value. Since #33930 however, it will typecast the null to a string, so then in turn it will try to find a model that has an empty string as its key.

So instead of executing

Model::findOrFail(null)

In essence, you would be executing the following:

Model::findOrFail('');

Which to me is a completely different findOrFail being executed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions