【问题标题】:Declaration of App\Http\Requests\UserUpdateRequest::user() should be compatible with Illuminate\Http\Request::user($guard = NULL)App\Http\Requests\UserUpdateRequest::user() 的声明应该与 Illuminate\Http\Request::user($guard = NULL) 兼容
【发布时间】:2020-04-06 09:44:27
【问题描述】:

我正在尝试支持并实现 FormRequest 对象以进行验证。我已经成功地为我的所有模型设置了表单请求,除了用户模型。我收到以下错误Declaration of App\Http\Requests\UserUpdateRequest::user() should be compatible with Illuminate\Http\Request::user($guard = NULL)。研究此错误似乎是我通过策略处理授权的方式存在问题。请注意,UserStoreRequest 有效,但 UserUpdateRequest 返回错误。

用户存储请求

<?php

namespace App\Http\Requests;

use App\User;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;

class UserStoreRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        // Authorize action - create-user
        return Gate::allows('create', User::class);
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name'      => 'required|string',
            'email'     => 'required|email|unique:users',
            'password'  => 'required|string|min:8|confirmed',
            'markets'   => 'required|array',
            'roles'     => 'required|array',
        ];
    }

    /**
     * Save the user.
     *
     * @return \App\User
     */
    public function save()
    {
        // Create the user
        $user = new User($this->validated());

        // Set the password
        $user->password = Hash::make($this->validated()['password']);
        $user->setRememberToken(Str::random(60));

        // Save the user
        $user->save();

        // Set users markets
        $user->markets()->sync($this->validated()['markets']);

        // Update the users role if included in the request
        if ($this->validated()['roles']) {
            foreach ($this->validated()['roles'] as $role) {
                $user->roles()->sync($role);

                if ($user->hasRole('admin')) {
                    $user->markets()->sync(Market::all());
                }
            }
        }

        return $user;
    }

    /**
     * Get the error messages for the defined validation rules.
     *
     * @return array
     */
    public function messages()
    {
        return [
            'name.required'      => 'The name is required.',
            'email.required'     => 'The email is required.',
            'email.unique'       => 'The email must be unique.',
            'password.required'  => 'The password is required.',
            'password.confirmed' => 'The passwords do not match.',
            'password.min'       => 'The password must be at least 8 characters.',
            'markets.required'   => 'A market is required.',
            'roles.required'     => 'A role is required.',
        ];
    }
}

用户更新请求

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;

class UserUpdateRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        // Authorize action - update-user
        return Gate::allows('update', $this->user);
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name'     => 'required|string',
        ];
    }

    /**
     * Get the user from the route.
     *
     * @return \App\User
     */
    public function user()
    {
        return $this->route('user');
    }

    /**
     * Save the email role.
     *
     * @return \App\Role
     */
    public function save()
    {
        // Update the user
        $this->user->update($this->validated());

        // // Check to see if password is being updated
        // if ($this->validated()['password']) {
        //     $this->user->password = Hash::make($this->validated()['password']);

        //     $this->user->setRememberToken(Str::random(60));
        // }

        // // Set users markets
        // $this->user->markets()->sync($this->validated()['markets']);

        // // Set users roles
        // // // Update the users role if included in the request
        // if ($this->validated()['roles']) {
        //     foreach ($this->validated()['roles'] as $role) {
        //         $this->user->roles()->sync($role);

        //         if ($this->user->hasRole('admin')) {
        //             $this->user->markets()->sync(Market::all());
        //         }
        //     }
        // }

        // // Save the user
        // $this->user->save();

        return $this->user;
    }

    /**
     * Get the error messages for the defined validation rules.
     *
     * @return array
     */
    public function messages()
    {
        return [
            'name.required'      => 'The name is required.',
            'email.required'     => 'The email is required.',
            'email.unique'       => 'The email must be unique.',
            'markets.required'   => 'A market is required.',
            'roles.required'     => 'A role is required.',
        ];
    }
}

如您所见,我已将 UpdateRequest 的大部分代码注释掉以进行故障排除。似乎问题出在authorize() 方法上。以下是 UserPolicy

中的代码

用户策略

/**
 * Determine whether the user can create models.
 *
 * @param \App\User $user
 *
 * @return mixed
 */
public function create(User $user)
{
    return $user->hasPermission('create-user');
}

/**
 * Determine whether the user can update the model.
 *
 * @param \App\User $user
 * @param \App\User $model
 *
 * @return mixed
 */
public function update(User $user, User $model)
{
    return $user->hasPermission('update-user');
}

用户控制器

/**
 * Store a newly created resource in storage.
 *
 * @param \Illuminate\Http\UserStoreRequest $request
 *
 * @return \Illuminate\Http\Response
 */
public function store(UserStoreRequest $request)
{
    return redirect($request->save()->path());
}

/**
 * Update the specified resource in storage.
 *
 * @param \Illuminate\Http\UserUpdateRequest $request
 * @param \App\User                          $user
 *
 * @return \Illuminate\Http\Response
 */
public function update(UserUpdateRequest $request, User $user)
{
    return redirect($request->save()->path());
}

我正在为此系统使用基于权限的授权。用户有 hasPermission() 方法来验证用户是否具有执行操作所需的权限。我担心我对这个设置感到困惑并且我没有正确验证。在尝试在 User 模型上实现这一点之前,一切都已经完成。

hasPermission()

/**
 * Check to see if the model has a permission assigned.
 *
 * @param string $permission
 *
 * @return bool
 */
public function hasPermission($permission)
{
    if (is_string($permission)) {
        if (is_null(Permission::whereName($permission)->first())) {
            return false;
        } else {
            return $this->hasRole(Permission::where('name', $permission)->first()->roles);
        }
    }

    return $this->hasRole($permission->roles);
}

hasRole()

/**
 * Check to see if model has a role assigned.
 *
 * @param string $role
 *
 * @return bool
 */
public function hasRole($role)
{
    if (is_string($role)) {
        return $this->roles->contains('name', $role);
    }

    return (bool) $role->intersect($this->roles)->count();
}

更新

我尝试将 UserUpdateRequest 中的 user() 方法重命名为 frank() 以解决覆盖 Request 用户的任何问题。这清除了上面列出的错误,但随后未经授权返回响应。登录的用户具有允许更新用户的权限。这在使用Gate::allowsauthorize() 方法中调用。我只是不确定它是在检查登录用户还是模型用户。

我进一步调查发现,将方法更改为frank()后出现了新的错误。我收到Call to a member function update() on null。我应该返回从 frank 方法中提取的用户,但它似乎返回 null。

更新的 UserUpdateRequest

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;

class UserUpdateRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        // Authorize action - update-user
        return Gate::allows('update', $this->frank);
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name'     => 'required|string',
        ];
    }

    /**
     * Get the user from the route.
     *
     * @return \App\User
     */
    public function frank()
    {
        return $this->route('user');
    }

    /**
     * Save the email role.
     *
     * @return \App\Role
     */
    public function save()
    {
        // Update the user
        $this->frank->update($this->validated());

        // // Check to see if password is being updated
        // if ($this->validated()['password']) {
        //     $this->user->password = Hash::make($this->validated()['password']);

        //     $this->user->setRememberToken(Str::random(60));
        // }

        // // Set users markets
        // $this->user->markets()->sync($this->validated()['markets']);

        // // Set users roles
        // // // Update the users role if included in the request
        // if ($this->validated()['roles']) {
        //     foreach ($this->validated()['roles'] as $role) {
        //         $this->user->roles()->sync($role);

        //         if ($this->user->hasRole('admin')) {
        //             $this->user->markets()->sync(Market::all());
        //         }
        //     }
        // }

        // // Save the user
        // $this->user->save();

        return $this->frank;
    }

    /**
     * Get the error messages for the defined validation rules.
     *
     * @return array
     */
    public function messages()
    {
        return [
            'name.required'      => 'The name is required.',
            'email.required'     => 'The email is required.',
            'email.unique'       => 'The email must be unique.',
            'markets.required'   => 'A market is required.',
            'roles.required'     => 'A role is required.',
        ];
    }
}

【问题讨论】:

    标签: laravel laravel-formrequest laravel-gate


    【解决方案1】:

    问题在于您在 UserUpdateRequest 类中定义的 user() 方法。

    UserUpdateRequest 扩展 Illuminate\Foundation\Http\FormRequest,进而扩展 Illuminate\Http\RequestIlluminate\Http\Request 已经定义了 user() 方法,因此您的 UserUpdateRequest 类中的 user() 方法正在尝试覆盖此定义。

    由于您的 UserUpdateRequest::user() 方法与 Illuminate\Http\Request::user($guard = null) 签名不匹配,因此您遇到了该错误。

    您可以:

    1. UserUpdateRequest 类中删除user() 方法,或者
    2. UserUpdateRequest 类上重命名user() 方法,或者
    3. $guard = null 参数添加到UserUpdateRequest 类的user() 方法中,使其与基user() 方法的签名相匹配。

    【讨论】:

    • 感谢您的及时回复。我曾认为 user() 方法可能是导致问题的原因,所以我尝试将其更改为 frank() 进行测试。然后我得到该操作未经授权的响应。这似乎是正确的,只是用户确实有权限。似乎策略正在检查用户模型的权限而不是登录用户。该策略接受(用户 $user,用户 $model)。在 UserUpdateRequest 下,我正在发送“更新”和模型用户。该策略是否会自动拉取经过身份验证的用户?
    • @jon3laze 这可能与您正在检查的功能 (update) 与您的 UserPolicy (edit) 上定义的方法之间的脱节有关。尝试将您的 UserPolicy edit() 方法重命名为 update()
    • 抱歉,我在来自 UserPolicy 的问题中放置了错误的代码。我有一个检查更新用户权限的更新方法。我更新了代码以显示 UserPolicy 下的相关方法。我非常感谢您的帮助。看来我要么遗漏了某些东西,要么误解了某些东西的工作原理。
    • 我想你已经用解决方案#3 解决了我的问题,添加了 $guard = NULL。我想知道您是否可以帮助进一步解释为什么这样做有效。当我使用解决方案 1 和 2 时,我无法访问我试图从路线编辑的用户。我想这是因为它被路由模型绑定自动拉出。我只是想确保更改用户方法是我这样做的正确方法,或者是否还有其他方法。
    猜你喜欢
    • 1970-01-01
    • 2014-09-28
    • 2019-09-25
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    • 2018-04-11
    • 2019-12-07
    相关资源
    最近更新 更多