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

Joh*_*lor 9 join left-join laravel eloquent laravel-4

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

LEFT JOIN content_userdata
ON content_id = content.id
AND user_id = $user_id
Run Code Online (Sandbox Code Playgroud)

我发现我可以使用扩展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);
    });
}
Run Code Online (Sandbox Code Playgroud)

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

left join `content_userdata`
on `content_id` = `content`.`id`
and `user_id` = `10`
Run Code Online (Sandbox Code Playgroud)

所以现在我有两个问题.

  1. 使用查询范围时,我无法将$ user_id放入join函数中
  2. 即使我可以,我也无法向连接发送变量,因为它始终将其解释为列名

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

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

Hal*_*zed 23

您需要使用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));
    });
}
Run Code Online (Sandbox Code Playgroud)

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


pro*_*mer 6

在接受的答案中,只是DB::raw在查询部分周围添加引号将不能完全保护它免受sql注入.只需传递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)));
}
Run Code Online (Sandbox Code Playgroud)

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

更新:泰勒补充说 joinWhere,leftJoinWhere...如果你有一个函数连接只是使用->where->orWhere从闭包内.


Joh*_*lor 5

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

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.'"'));
    });
}
Run Code Online (Sandbox Code Playgroud)

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

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

性能:需要注意的一点是,当使用整数而不是字符串时,MySQL查询会快得多,并且如果用引号括起来将它解释为字符串.我现在并不担心这一点,但我认为如果其他人正在使用它作为解决方案,我应该提一下.