Laravel 4 Eloquent 返回错误的 ID

Posted

技术标签:

【中文标题】Laravel 4 Eloquent 返回错误的 ID【英文标题】:Laravel 4 Eloquent returns wrong ID 【发布时间】:2013-10-09 02:33:12 【问题描述】:

我的数据库中有 3 个表:

    广告系列 用户 公司

一家公司可能有一些用户。一位用户可能有一些活动。用户(具有管理员权限)可以对属于其公司的任何活动执行某些操作。所以,我想检查是否 他是否在他的竞选活动中执行这些操作(在最后一种情况下,我返回类似“访问被拒绝”之类的内容)。

我的情况

Campaign::join('users', 'users.id', '=', 'campaigns.user_id')
        ->where('users.company_id', '=', Auth::user()->company->id)
        ->where('campaigns.id', '=', Input::get('id'))
        ->first();

因此,如果我有独特的活动 - 没关系,如果我得到 null - 出了点问题,我向用户发送“拒绝访问”,因为他正在处理其他公司的活动。

这段代码产生下一个查询:

array(3) 
  ["query"]=>
  string(148) "select * from `campaigns` inner join `users` on `users`.`id` = `campaigns`.`user_id` where `users`.`company_id` = ? and `campaigns`.`id` = ? limit 1"
  ["bindings"]=>
  array(2) 
    [0]=>
    string(1) "2"
    [1]=>
    string(2) "13"
  
  ["time"]=>
  float(0.42)

使用 phpmyadmin 我尝试了相同的查询并获得了 ID = 13 的广告系列。 但是当我调试我的应用程序时,我发现

dd($campaign->id);

改为返回 8。 8 也等于campaigns.user_id(该记录同时具有campaigns.idcampaigns.user_id = 8)。

我不知道为什么会这样。即使我的 SQL 查询有问题(我怀疑 phpmyadmin 返回了正确的结果),我也得到了条件campaigns.id = Input::get('id')Input::get('id') = 13。为什么要更改 id?

当然,我可以分两步进行此安全检查,例如先获取广告系列,然后检查 $campaign->user->company->id = Auth::user()->company->id 但只是想知道...

【问题讨论】:

【参考方案1】:

如果您在 phpMyAdmin 中运行此查询,您应该能够看到结果包含多个名为“id”的列。当 PHP 将查询结果解析为关联数组或对象时,键必须是唯一的!如果键发生冲突,将使用最后一列!

例子:

SQL 结果:

id    user_id    name    id    name    company_id
1     2          Camp1   2     Pelle   1

PHP结果:

array (size=1)
  0 => 
    object(stdClass)[131]
      public 'id' => string '2' (length=1)
      public 'user_id' => string '2' (length=1)
      public 'name' => string 'Pelle' (length=5)
      public 'company_id' => string '1' (length=1)

要解决这个问题,您可以添加一个选择子句来仅选择广告系列列:

Campaign::select('campaigns.*')
    ->join('users', 'users.id', '=', 'campaigns.user_id')
    ->where('users.company_id', '=', Auth::user()->company->id)
    ->where('campaigns.id', '=', Input::get('id'))
    ->first();

【讨论】:

感谢您的帮助,Laravel 5 也一样 :)【参考方案2】:

如果您想控制使用重复列的实际表,只需按特定顺序将表添加到数组中。最后一个是->id 属性。

        ->select([
            'table1.*',
            'table2.*',
            'tags.*',
            'companies.*',
            'users.*',
        ])

这样您就可以保留使用join 选择的所有唯一列。 如果您想要特定表中的特定列,您可以使用AS

        ->select([
            'table1.*',
            'table2.*',
            'tags.*',
            'companies.*',
            'users.*',
            'table1.id AS table1_id',
            'tags.name AS tag_name',
            'companies.name AS company_name',
        ])

【讨论】:

【参考方案3】:

这似乎是 Eloquent 库中的一个限制。与其使用最后一个“id”,不如更主动地搜索查询的主表的“id”。或者在 SQL 语句中使用“as”。

另一种解决方案是对每个表的 id 字段进行唯一命名。例如user.user_id,campaigns.campaign_id。这会与其他表中的外键发生冲突,因此将外键命名为campaign.user_fid。

【讨论】:

以上是关于Laravel 4 Eloquent 返回错误的 ID的主要内容,如果未能解决你的问题,请参考以下文章

带有 Codeception 的 Laravel 4 模型单元测试 - 未找到“Eloquent”类

Laravel Eloquent groupBy() 并且还返回每个组的计数

遍历数组集合并返回命名键值对(Laravel/Eloquent)

laravel 返回与 eloquent 和 laravel 的关系

Laravel - 在 Eloquent 模型中返回自定义额外数据

在 Laravel 中,哪些 Eloquent 方法返回数据,哪些返回对象?