【问题标题】:Laravel Eloquent model id as string return wrong value inLaravel Eloquent 模型 id 作为字符串返回错误值
【发布时间】:2016-11-22 15:34:50
【问题描述】:

在 Laravel 5.2 中有 $client->id 没有返回正确值的 OauthClient 模型。

"lucadegasperi/oauth2-server-laravel": "^5.1" 用于迁移 $table->string('id', 40)->primary();

但是,当在刀片模板中使用 $client->id 时,我会返回 "0" 。使用 dd($client) 在 id 属性中显示正确的值。

可能出了什么问题?

dd() 的模型输出

OauthClient {#254 ▼
  #connection: null
  #table: null
  #primaryKey: "id"
  #keyType: "int"
  #perPage: 15
  +incrementing: true
  +timestamps: true
  #attributes: array:7 [▼
    "id" => "wISw4JmlMQCCrMupjojcuDTK3k4hwtkb"
    "secret" => "nnw3CPTzeQSIfT4KpR0d3XzWIKKoghB3"
    "name" => "http://example.com"
    "package" => "free"
    "user_id" => 2
    "created_at" => "2016-07-19 15:36:28"
    "updated_at" => "2016-07-19 15:36:28"
  ]
  #original: array:7 [▶]
  #relations: []
  #hidden: []
  #visible: []
  #appends: []
  #fillable: []
  #guarded: array:1 [▼
    0 => "*"
  ]
  #dates: []
  #dateFormat: null
  #casts: []
  #touches: []
  #observables: []
  #with: []
  #morphClass: null
  +exists: true
  +wasRecentlyCreated: false
}

来自“show create table oauth_clients”的表结构

CREATE TABLE `oauth_clients` (
  `id` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
  `secret` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `package` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `user_id` int(10) unsigned NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `oauth_clients_id_secret_unique` (`id`,`secret`),
  KEY `oauth_clients_user_id_foreign` (`user_id`),
  CONSTRAINT `oauth_clients_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

【问题讨论】:

  • 你能把dd($client)的输出贴出来
  • 数据模型中包含id 属性的情况并不常见。通常所有属性都保存在一个属性数组中,并且有一个神奇的__get 方法可以获取适当的属性。我们需要看看你的OauthClientmodel 是什么样子的。
  • 添加 dd() 输出和创建表语法

标签: php laravel oauth laravel-5 eloquent


【解决方案1】:

这是因为默认情况下主键被转换为int,除非另有明确说明。

(int) "wISw4JmlMQCCrMupjojcuDTK3k4hwtkb" == 0

该值仍然以字符串形式存在,但如果您使用$model->id,它将通过Illuminate\Database\Eloquent\Model 类中定义的神奇__get() 方法。

我不会反对将 id 字段用作字符串,但如果您这样做并且还想使用 $model->id 获取字符串值,则必须在模型中将其转换为字符串定义。您可以使用一个受保护的 $casts 数组。只需将以下内容添加到您的 OauthClient 模型中:

protected $casts = ['id' => 'string'];

这将起到作用并将 id 属性转换为字符串而不是默认整数。尽管我建议首先不要将 id 用作字符串。

更新:

还有一个$incrementing 属性,你可以在你的模型上设置为false,告诉 Laravel 你想要非递增或非数字的主键。像这样在你的模型上设置它:

public $incrementing = false;

更新 2:

这方面的信息现在也被添加到官方文档中。 在Eloquent docs 查找主键部分:

此外,Eloquent 假设主键是递增的 整数值,这意味着默认情况下主键将是 自动转换为 int。如果您希望使用非递增或 非数字主键,您必须设置公共 $incrementing 模型上的属性为 false。如果您的主键不是 整数,您应该在模型上设置受保护的 $keyType 属性 串起来。

【讨论】:

  • 非常感谢。它在使用这个库时解决了很多问题!
  • casts() 似乎不会影响find() 的工作方式。它只作用于 setter 和 getter。如果我使用上述两种解决方案(Laravel 5.6)执行find(123),它将返回一个ID为123abc的模型实例——对我来说这是一个可以被利用的严重安全问题。这里的类型转换发生在数据库上(手动选择返回相同的 wrong 行)。在执行find() 时,需要告知 Eloquent 将 ID 显式转换为字符串。我看不到在模型中执行此操作的方法(可能覆盖 find() 除外)。
  • 谢谢,我应该在 5 小时前用 Google 搜索一下……出于好奇,嗨[f]w 我们应该在不阅读整个 Laravel 核心代码的情况下知道这一点吗?
  • @sandman 至少在最新的 Laravel 文档中,有一节解释了这一点。搜索Primary Keys 但总的来说,作为一名程序员通常意味着阅读大量核心代码;)那里有很多项目,文档很少或过时,所以除了阅读代码之外别无他法。然而,这样做是最好的学习方式,很快就会成为你的第二天性:)
【解决方案2】:

设置 public $incrementing = false; 对我有用。

http://www.laravel.io/forum/12-14-2015-id-as-string

【讨论】:

  • 这是 Laravel 5.4 更优雅的解决方案
猜你喜欢
  • 2013-10-09
  • 2015-01-08
  • 2020-05-24
  • 2019-11-16
  • 2017-12-13
  • 1970-01-01
  • 2017-09-02
  • 1970-01-01
  • 2013-03-14
相关资源
最近更新 更多