Laravel 4 Eloquent返回错误的ID

6
我在我的数据库中有三张表:
  1. 活动
  2. 用户
  3. 公司
一个公司可能会有一些用户。一个用户可能会有一些活动。用户(管理员)可以对属于他所在公司的任何活动执行某些操作。因此,我想检查他是否正在与自己的活动进行这些操作(否则我会返回类似"拒绝访问"的消息)。
我的条件:
Campaign::join('users', 'users.id', '=', 'campaigns.user_id')
        ->where('users.company_id', '=', Auth::user()->company->id)
        ->where('campaigns.id', '=', Input::get('id'))
        ->first();

如果我得到了唯一的活动 - 这很好,如果我得到了空值 - 说明出了问题,我会向用户发送“拒绝访问”的信息,因为他正在处理其他公司的活动。

这段代码生成了下面的查询:

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返回了正确的结果),我也有一个where条件campaigns.id = Input::get('id'),其中Input::get('id') = 13。为什么id会被改变?

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

3个回答

24

如果您在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)
为了解决这个问题,你可以添加一个 select 子句,只选择广告系列的列:

为解决此问题,您可以添加一个 select 子句,仅选择广告系列的列:

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 :) - ka_lin

4
这似乎是Eloquent库的一个限制。它应该更积极地搜索查询主表的"id",而不是使用最后一个"id"。或在SQL语句中使用"as"。另一种解决方案是为每个表的id字段命名唯一。例如user.user_id,campaigns.campaign_id。这将与其他表中的外键冲突,因此将外键命名为campaigns.user_fid。

1

如果您想控制实际使用重复列的表格,请按特定顺序将表格添加到数组中。最后一个表格将成为 ->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',
        ])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接