首页 文章

Laravel 4 Eloquent Query Builder - 复杂的变量连接

提问于
浏览
9

我正在尝试使用laravel查询构建器来复制连接:

LEFT JOIN content_userdata
ON content_id = content.id
AND user_id = $user_id

我发现我可以使用扩展Eloquent的模型中的以下函数来执行其他“ons”

public function scopeJoinUserData($query, $user_id)
{
    return $query->leftJoin('content_userdata', function($join)
    {
        $join->on('content_userdata_content_id', '=', 'content.content_id')->on('content_userdata_user_id', '=', 10);
    });
}

但这会产生两个问题 . 首先,我无法将$ user_id变量放入函数中,其次,即使我将其硬编码用于测试目的,如上所述(对于“10”),Laravel将其包含在`意味着它应该被解释为列名时不是这样的:

left join `content_userdata`
on `content_id` = `content`.`id`
and `user_id` = `10`

所以现在我有两个问题 .

  • 使用查询范围时,我无法将$ user_id输入到join函数中

  • 即使我可以,我也无法向连接发送变量,因为它总是将其解释为列名

Why would I want to do this? 我意识到一个回应可能是把它放在哪里 . 但是我试图这样做,因为连接可能不一定返回任何结果(因此左连接),因为content_userdata表包含诸如用户对一段内容的评级之类的内容 . 如果我使用where,那么content_userdata表中没有任何内容的结果将不会被返回,就好像我可以将它放入连接中那样,由于左连接,它们将被返回 .

无论如何在Laravel中实现这一目标,如果没有替代方案,显然完全改变了放弃Laravel是最重要的,但我能想到的唯一选择是在单独的查询中获取用户数据 .

5 回答

  • -1

    您需要使用 use 关键字将变量传递给闭包 - 它将变量导入范围 . 例:

    public function scopeJoinUserData($query, $user_id)
    {
        return $query->leftJoin('content_userdata', function($join) use ($user_id)
        {
            $join->on('content_userdata_content_id', '=', 'content.content_id')
                 ->on('content_userdata_user_id',    '=', DB::raw($user_id));
        });
    }
    

    这是与PHP语法相关的问题,而不是Laravel限制!

  • 4

    在接受的答案中,只需在查询 will not fully protect it from sql injectionDB::raw 部分周围添加引号 . 只需传递user_id中的一些引号即可 . 要参数化,您可以执行以下操作:

    public function scopeJoinUserData($query, $user_id)
    {
        return $query->leftJoin('content_userdata', function($join)
            {
                $join->on('content_userdata_content_id', '=', 'content.content_id')
                     ->on('content_userdata_user_id',    '=', DB::raw('?'));
            }
        ->setBindings(array_merge($query->getBindings(),array($user_id)));
    }
    

    请注意,在此示例中,您不必将变量传递给闭包 . 或者你可以尝试编写这个部分completely raw .

    UPDATETaylor added joinWhereleftJoinWhere ...如果你有一个函数连接,只需在Closure中使用 ->where->orWhere .

  • 6

    我自己设法解决了这个问题,底部有一个注释,说明为什么它不是完全最优的,但无论如何这里都是如何做到的:

    public function scopeJoinUserData($query, $user_id)
    {
        return $query->leftJoin('content_userdata', function($join) use ($user_id)
        {
            $join->on('content_userdata_content_id', '=', 'content.content_id')->on('content_userdata_user_id', '=', DB::raw('"'.$user_id.'"'));
        });
    }
    

    请注意@Half Crazed建议使用“use($ user_id)” .

    DB :: raw()用于将$ user_id包装在引号中,即使它是整数而不是字符串 . 这将使用`自动停止Laravel,这使得MySQL将其解释为列名 .

    Performance: 有一点需要注意的是,当使用整数而不是字符串时,MySQL查询可以相当快,并且如果它现在不用担心它会将其解释为字符串,但我想如果其他人正在使用它我应该提到它这是一个解决方案 .

  • 5

    你为什么不用关系?这是ORM like Eloquent的全部意义?

    像这样的东西;

    class User extends Eloquent {
        public function userdata()
        {
            return $this->hasOne('Userdata');
        }
    }
    
    $result= User::find(1)->userdata();
    

    编辑以显示您可以通过关系做任何您想做的事情

    选项1:

    $place = new Place;
    
    $array = $place->with(array('users' => function($query)
    {
        $query->where('user_id', $user_id);
    }))->get();
    
    var_dump($array->toArray());
    

    或选项2:

    $place = new Place;
    
    $array = $place->with('users')->where('user_id', $user_id)->get();
    
    var_dump($array->toArray());
    

    两者都给出了不同的结果 - 但你明白了

  • 23

    你的第一个问题:你应该使用PHP语法进行闭包作为Half的答案 . 关于你的第二个问题,我认为查询的部分 AND user_id = $user_id 不属于JOIN子句而是属于WHERE子句,因为它只依赖于一个表,而不是两个都在这个连接关系中 . 我认为你应该使用这样的子查询:

    public function scopeJoinUserData($query, $user_id)
    {
        return $query->leftJoin(\DB:raw("(SELECT * FROM content_userdata WHERE user_id = {$user_id}) AS t"), function($join)
        {
            $join->on('t.content_id', '=', 'content.content_id');
        });
    }
    

    但是,如您所见,请确保 $user_id 变量是安全的,因为我们使用 \DB:raw 方法 .

相关问题