Laravel bigInteger 在关系中四舍五入为 int

2021-12-26 00:00:00 php laravel eloquent

好的,这是我的迁移...

公共函数 up(){Schema::create('instagrams', function (Blueprint $table) {$table->bigInteger('id')->unsigned()->primary();//...});}公共函数 up(){Schema::create('users', function (Blueprint $table) {$table->increments('id');$table->bigInteger('instagram_id')->unsigned()->nullable();//...});}

我有一个用户模型和一个 instagram 模型.这是我的 Instagram 模型:

class Instagram 扩展模型{公共函数用户(){返回 $this->hasOne('AppUser');}}

我的问题是 Instagram 与用户的关系不起作用.我无法从 Instagram 访问用户,即使他们都在数据库中.

<预><代码>>>>$u = AppUser::first()=>应用用户 {#695编号:1,instagram_id: "3620243170",}>>>$i = AppInstagram::first()=>应用Instagram {#696id: "3620243170",}>>>$i->用户=>空值

所以,我花了很长时间绞尽脑汁,直到找到这些有用的修补方法……这就是它给我的:

<预><代码>>>>$i->user()->toSql()=>从`users` 中选择* 其中`users`.`instagram_id` = ? 并且`users`.`instagram_id` 不为空">>>$i->user()->getBindings()=>[2147483647,]

除了 ID 被隐藏在 Laravel 中的任何代码限制在 32 位限制之外,一切都井然有序……ID 需要大于 32 位,因为 Instagram 的 ID 就是这样存储的.我怎样才能让这种关系发挥作用?

解决方案

听起来您使用的是 32 位版本的 PHP,其中最大整数值为 2147483647.

问题是当关系查询获取Instagram 实例的键值来查询用户时,它会自动将该id 值转换为$keyType 模型上的属性.此属性默认为 int.

因此,即使您的 Instagram 实例 ID 是 "3620243170",它也会被转换为 int,在 32 位 PHP 中会将其转换为 2147483647.

您可以尝试几种方法来缓解此问题:

  1. 使用 64 位版本的 PHP.64 位 PHP 的最大 int 大小与可用于有符号 bigint 字段的最大 int 匹配.但是,如果您使用的是未签名的 bigint,一旦您的 ID 超过 9223372036854775807(不太可能),您就会再次遇到此问题.

  2. Instagram 模型上的 $keyType 属性更改为 float,或者可能是 string.这只会影响 Eloquent 在 PHP 中对变量的转换,不会影响它们在数据库中的存储方式.
    protected $keyType = 'float'; 添加到您的 Instagram 模型中.

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('AppUser');
    }
}

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 = AppUser::first()
=> AppUser {#695
     id: 1,
     instagram_id: "3620243170",
   }
>>> $i = AppInstagram::first()
=> AppInstagram {#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?

解决方案

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.

相关文章