Laravel 5: 模型对象可以调用生成器方法。 Laravel 是怎么做到的?

Laravel 5: Model object could call Builder method. How does Laravel do that?

在Laravel包中,模型User派生自模型class。 虽然模型 class 没有 "join" 方法,但我仍然可以在用户对象上使用 join 方法。

我不清楚 Laravel 是怎么做到的。

$user = Users::find($id);
$user->
    join('GroupMember', 'GroupMember.UserID', '=', 'users.id')->
    join('Groups', 'GroupMember.GroupID', '=', 'Groups.GroupID')->
    where('users.id','=', $user->id)->get();

以上代码是获取用户的所有相关组。 因为 $user 是从模型 class 派生的,但是模型 class 没有 "join" 方法...

这是用户定义。

<?php namespace App;

use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;


class User extends Model implements AuthenticatableContract, CanResetPasswordContract {

    use Authenticatable, CanResetPassword;

这是因为 Eloquent 在幕后使用了 Illuminate\Database\Query\Builder,您可以在 Builder class.

中找到所有这些方法

当你运行函数在Users模型中不存在在这种情况下,magic method __call被使用:

public function __call($method, $parameters)
{
    if (in_array($method, ['increment', 'decrement'])) {
        return call_user_func_array([$this, $method], $parameters);
    }

    $query = $this->newQuery();

    return call_user_func_array([$query, $method], $parameters);
}

如您在此方法中所见,newQuery 方法已执行。当您查看此方法定义时,您可以在此处看到:

public function newQuery()
{
    $builder = $this->newQueryWithoutScopes();

    foreach ($this->getGlobalScopes() as $identifier => $scope) {
        $builder->withGlobalScope($identifier, $scope);
    }

    return $builder;
}

此外,当您查看 newQueryWithoutScopes 时,您会看到:

$builder = $this->newEloquentBuilder(
        $this->newBaseQueryBuilder()
);

和这个 newEloquentBuilder 方法 returns new Builder($query); 所以它是一个 Illuminate\Database\Query\Builder 对象

$user = Users::find($id); returns eloquent 用户模型或空。所以你不能在它上面使用 'join' 因为它不是构建器对象。

$user = Users::whereId($id); 将 return 一个查询生成器,因此您可以在上面使用 'join'。

或者你也可以这样写-

$user = Users::find($id);
$user->with([
'GroupMember' => function ($query) {
    $query->where('GroupMember.UserID', '=', 'users.id')
},
'Groups' => function ($query) {
    $query->where('GroupMember.GroupID', '=', 'Groups.GroupID')
}]),
->where('users.id','=', $user->id)
->get();