Laravel bigInteger being rounded to int in relatio

2020-03-31 06:14发布

问题:

Alright, so here's my migrations...

public function up()
{
    Schema::create('instagrams', function (Blueprint $table) {
        $table->bigInteger('id')->unsigned()->primary();
        // ...
    });
}


public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->increments('id');
        $table->bigInteger('instagram_id')->unsigned()->nullable();
        // ...
    });
}

I have a user model, and an instagram model. Here's my instagram model:

class Instagram extends Model
{
    public function user()
    {
        return $this->hasOne('App\User');
    }
}

My problem is the instagram's relationship with the user isn't working. I can't access the user from an instagram, even when they're both in the database.

>>> $u = App\User::first()
=> App\User {#695
     id: 1,
     instagram_id: "3620243170",
   }
>>> $i = App\Instagram::first()
=> App\Instagram {#696
     id: "3620243170",
   }
>>> $i->user
=> null

So, I spent a long time wracking my brain until I found these helpful tinker methods... here's what it's giving me:

>>> $i->user()->toSql()
=> "select * from `users` where `users`.`instagram_id` = ? and `users`.`instagram_id` is not null"
>>> $i->user()->getBindings()
=> [
     2147483647,
   ]

Everything is in order except the ID is being maxed at the 32 bit limit by whatever code is hiding in laravel... the ID needs to be bigger than 32 bits because that's how instagram's IDs are stored. How can I get this relationship to work?

回答1:

It sounds like you're using a 32-bit version of PHP, where the max integer value is 2147483647.

The issue is that when the relationship query gets the key value of the Instagram instance to query the users, it automatically casts that id value to the type defined by the $keyType property on the model. This property is int by default.

So, even though your Instagram instance id is "3620243170", it is cast to an int, which in 32-bit PHP will turn it into 2147483647.

There are a couple things you can try to mitigate this issue:

  1. Use a 64-bit version of PHP. The max int size for 64-bit PHP matches the max int available for a signed bigint field. However, if you're using an unsigned bigint, you will run into this issue again once your ids exceed 9223372036854775807 (not likely).

  2. Change the $keyType property on your Instagram model to float, or possibly string. This only affects Eloquent's casting of the variables in PHP, it does not affect how they are stored in the database.
    Add protected $keyType = 'float'; to your Instagram model.