Ad

Laravel 5: Model Object Could Call Builder Method. How Does Laravel Do That?

In the Laravel package, the model User is derived from Model class. Although Model class does not have "join" method, I could still use join method on the user object.

I am not clear how does Laravel do that.

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

The above code is to get all related groups of the user. Because the $user is derived from Model class, but the Model class dos not have "join" method...

Here is the User definition.

<?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;
Ad

Answer

This is because Eloquent uses Illuminate\Database\Query\Builder behind the scenes and you can find all those methods in this Builder class.

When you run function that does not exist in Users model in this case, magic method __call is used:

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);
}

as you see in this method newQuery method is executed. And when you look at this method definitions you can see here:

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

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

    return $builder;
}

and further, when you look at newQueryWithoutScopes you'll see there:

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

and this newEloquentBuilder method returns new Builder($query); so it's an Illuminate\Database\Query\Builder object

Ad
source: stackoverflow.com
Ad