在Laravel中,你可以很容易地 Select define abilities个,然后在用户请求时使用它们来执行不同的操作:

$gate->define('update-post', function ($user, $post) {
    return $user->id === $post->user_id;
});

But almost all my defined abilities has this part $user->id === $model->user_id in it. I don't like it as it's a kind of repeating a condition over and over which I think could be more abstract.

Most of my defined abilities are according to updating/deleting records, so it would be better if I could make a global condition applied to all of them or if there could be a group ability defining which is like to what we do in routing.

有什么解决方法吗?我真的很喜欢干的.

推荐答案

Laravel的一切都是可扩展的,这是其服务Provider 的力量所在.

You can extend the Gate object to a MyCustomGate object and do whatever you want in that object. Here's an example:

MyCustomGate.php

class MyCustomGate extends \Illuminate\Auth\Access\Gate
{
    protected $hasOwnershipVerification = [];

    /**
     * Define a new ability.
     *
     * @param  string  $ability
     * @param  callable|string  $callback
     * @return $this
     *
     * @throws \InvalidArgumentException
     */
    public function defineWithOwnership($ability, $callback, $foreignUserIdKey = "user_id")
    {
        // We will add this 
        $this->hasOwnershipVerification[$ability] = $foreignUserIdKey;

        return $this->define($ability, $callback);
    }

    /**
     * Resolve and call the appropriate authorization callback.
     *
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
     * @param  string  $ability
     * @param  array  $arguments
     * @return bool
     */
    protected function callAuthCallback($user, $ability, array $arguments)
    {
        $callback = $this->resolveAuthCallback(
            $user, $ability, $arguments
        );

        // We will assume that the model is ALWAYS the first key
        $model = is_array($arguments) ? $arguments[0] : $arguments;

        return $this->checkDirectOwnership($ability, $user, $model) && call_user_func_array(
            $callback, array_merge([$user], $arguments)
        );
    }

    /**
     * Check if the user owns a model.
     *
     * @param  string  $ability
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return bool
     */
    protected function checkDirectOwnership($ability, $user, $model)
    {
        if(!isset($this->hasOwnershipVerification[$ability])) {
            return true
        }

        $userIdKey = $this->hasOwnershipVerification[$ability];

        // getAuthIdentifier() is just ->id, but it's better in case the pk of a user is different that id
        return $user->getAuthIdentifier() == $model->{$userIdKey};
    }
}

Then, you will have to tell Laravel to use your gate instead of the default one. You ca do that in your AuthServiceProvider (assuming that it's extending Illuminate\Auth\AuthServiceProvider, just add the following method.

AuthServiceProvider

/**
 * Register the access gate service.
 *
 * @return void
 */
protected function registerAccessGate()
{
    $this->app->singleton(\Illuminate\Contracts\Auth\Access\Gate::class, function ($app) {
        return new MyCustomGate($app, function () use ($app) {
            return $app['auth']->user();
        });
    });
}

这样,你可以用defineWithOwnership()而不是define()来定义能力.对于不需要所有权验证的能力,你仍然可以使用define().第三个参数defineWithOwnership()$foreignUserIdKey;当一个模型的用户id有不同的字段时,就会使用这个选项.

注意:我在运行中编写了代码,但没有try ,它可能有错误,但你明白了.

Laravel相关问答推荐

Laravel将变量从模板到已发布的供应商模板

Laravel-如何按第三表关系对数据进行分类

如何获得每种类型的总和

RuntimeException 未安装 Zip PHP 扩展

处理程序类中的错误 - Laravel

Laravel Eloquent - 随叫随到的加密/解密数据

如何为路由 laravel 5 使用OR中间件

具有实时和 WebSockets 的 Angular2 + Laravel

Laravel 5.1 是否与 PHP 7 兼容

Laravel 查询构建器 - 如何按别名分组,或进行原始 groupBy

不支持驱动Driver[] - Laravel 5.3

从 Laravel Cashier 获取下一个账单日期

如何在 laravel 中解码 Json 对象并在 laravel 中应用 foreach 循环

Laravel 迁移命名约定

在 Laravel 的数据透视表中添加 id 列有什么好处?

在 laravel 中安装 vue 3.0

如何在 Laravel 中 Refresh刷新用户对象?

使用迁移更改表 Laravel 5

找不到 HOME 环境 -- 扩展 `~'

Laravel 将附加参数传递给函数