phplaravel

In Spatie Permission::join, where does the join method come from?


When using Spatie in Laravel one can use the following statement to manually retrieve the permissions for a given role:

$rolePermissions = Permission::join("role_has_permissions","role_has_permissions.permission_id","=","permissions.id")
           ->where("role_has_permissions.role_id",$role_id)
           ->get();

I know the join method is defined in Eloquent's Builder.php file: vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php

However, the Permission class (vendor/spatie/laravel-permission/src/Models/Permission.php) does not define a join method, and neither does the Model class (vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php) that is extended by Permission. Meanwhile, the Model class also does not include a join method and does not extend any other classes, like for example the Builder class.

So, how come that the Permission class can invoque the join method?


Solution

  • To answer your specific question of:

    So, how come that the Permission class can invoque the join method?

    You will probably find your answer here.

    Model.php line# 2475 (if this is the correct version, I just checked github)

    The reason it works is because if a method is not found in the instances scope (eg the method can not be called on the object) at call time then the magic methods __call or __callStatic are called. You can provide access to other instances through those methods allowing access to other objects and there methods etc. It's a common pattern known as overloading.

    public static function __callStatic($method, $parameters)
    {
        if (static::isScopeMethodWithAttribute($method)) {
            return static::query()->$method(...$parameters);
        }
    
        return (new static)->$method(...$parameters);
    }
    

    For more information on the topic see the manual.

    https://www.php.net/manual/en/language.oop5.overloading.php