You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义UserCrudController致Laravel Backpack权限管理器角色/权限无法加载

问题描述

使用Laravel ^10、Backpack Pro ^1.6、Laravel-permission ^5.10及Laravel Backpack Permission Manager ^6.0,基于PermissionManager原生控制器自定义了UserCrudController,用于处理模型验证需求和列表额外列显示,遇到以下问题:

  • 编辑用户时,角色UI正常加载,但原有角色值无法回显
  • 修改角色后无法保存到数据库
  • 列表页面中角色显示正常,且User模型已正确引入CrudTrait和HasRoles
  • 使用原生UserCrudController时编辑功能正常,但因User表无name字段导致验证失败

自定义UserCrudController代码:

<?php

namespace App\Http\Controllers\Admin;

use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\PermissionManager\app\Http\Requests\UserStoreCrudRequest as StoreRequest;
use App\Http\Requests\UserUpdateCrudRequest as UpdateRequest;
use Illuminate\Support\Facades\Hash;

/**
 * Class UserCrudController
 * @package App\Http\Controllers\Admin
 * @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
 */
class UserCrudController extends CrudController
{
    use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation {
        store as traitStore;
    }
    use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation {
        update as traitUpdate;
    }
    use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;

    /**
     * Configure the CrudPanel object. Apply settings to all operations.
     *
     * @return void
     */
    public function setup()
    {
        $this->crud->setModel(config('backpack.permissionmanager.models.user'));
        $this->crud->setEntityNameStrings(
            trans('backpack::permissionmanager.user'),
            trans('backpack::permissionmanager.users')
        );
        $this->crud->setRoute(backpack_url('user'));
    }

    /**
     * Define what happens when the List operation is loaded.
     *
     * @see  https://backpackforlaravel.com/docs/crud-operation-list-entries
     * @return void
     */
    protected function setupListOperation()
    {
        $this->crud->addColumns([
            [
                'name' => 'username',
                'type' => 'text',
            ],
            [
                'name' => 'name',
                'type' => 'text',
                'value' => function ($entry) {
                    return $entry->profileName();
                },
                'searchLogic' => function ($query, $column, $searchTerm) {
                    $query->orWhereHas('profile', function ($q) use (
                        $column,
                        $searchTerm
                    ) {
                        $q->where('first_name', 'like', '%' . $searchTerm . '%')
                            ->orWhere(
                                'last_name',
                                'like',
                                '%' . $searchTerm . '%'
                            )
                            ->orWhere(
                                'middle_name',
                                'like',
                                '%' . $searchTerm . '%'
                            );
                    });
                },
            ],
            [
                'name' => 'email',
                'label' => trans('backpack::permissionmanager.email'),
                'type' => 'email',
            ],
            [
                // n-n relationship (with pivot table)
                'label' => trans('backpack::permissionmanager.roles'), // Table column heading
                'type' => 'select_multiple',
                'name' => 'roles', // the method that defines the relationship in your Model
                'entity' => 'roles', // the method that defines the relationship in your Model
                'attribute' => 'name', // foreign key attribute that is shown to user
                'model' => config('permission.models.role'), // foreign key model
            ],
            [
                // n-n relationship (with pivot table)
                'label' => trans(
                    'backpack::permissionmanager.extra_permissions'
                ), // Table column heading
                'type' => 'select_multiple',
                'name' => 'permissions', // the method that defines the relationship in your Model
                'entity' => 'permissions', // the method that defines the relationship in your Model
                'attribute' => 'name', // foreign key attribute that is shown to user
                'model' => config('permission.models.permission'), // foreign key model
            ],
        ]);

        if (backpack_pro()) {
            // Role Filter
            $this->crud->addFilter(
                [
                    'name' => 'role',
                    'type' => 'dropdown',
                    'label' => trans('backpack::permissionmanager.role'),
                ],
                config('permission.models.role')
                    ::all()
                    ->pluck('name', 'id')
                    ->toArray(),
                function ($value) {
                    // if the filter is active
                    $this->crud->addClause('whereHas', 'roles', function (
                        $query
                    ) use ($value) {
                        $query->where('role_id', '=', $value);
                    });
                }
            );

            // Extra Permission Filter
            $this->crud->addFilter(
                [
                    'name' => 'permissions',
                    'type' => 'select2',
                    'label' => trans(
                        'backpack::permissionmanager.extra_permissions'
                    ),
                ],
                config('permission.models.permission')
                    ::all()
                    ->pluck('name', 'id')
                    ->toArray(),
                function ($value) {
                    // if the filter is active
                    $this->crud->addClause('whereHas', 'permissions', function (
                        $query
                    ) use ($value) {
                        $query->where('permission_id', '=', $value);
                    });
                }
            );
        }
    }

    public function setupCreateOperation()
    {
        $this->addUserFields();
        $this->crud->setValidation(StoreRequest::class);
    }

    public function setupUpdateOperation()
    {
        $this->addUserFields();
        $this->crud->setValidation(UpdateRequest::class);
    }

    /**
     * Store a newly created resource in the database.
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function store()
    {
        $this->crud->setRequest($this->crud->validateRequest());
        $this->crud->setRequest(
            $this->handlePasswordInput($this->crud->getRequest())
        );
        $this->crud->unsetValidation(); // validation has already been run

        return $this->traitStore();
    }

    /**
     * Update the specified resource in the database.
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function update()
    {
        $this->crud->setRequest($this->crud->validateRequest());
        $this->crud->setRequest(
            $this->handlePasswordInput($this->crud->getRequest())
        );
        $this->crud->unsetValidation(); // validation has already been run

        return $this->traitUpdate();
    }

    /**
     * Handle password input fields.
     */
    protected function handlePasswordInput($request)
    {
        // Remove fields not present on the user.
        $request->request->remove('password_confirmation');
        $request->request->remove('roles_show');
        $request->request->remove('permissions_show');

        // Encrypt password if specified.
        if ($request->input('password')) {
            $request->request->set(
                'password',
                Hash::make($request->input('password'))
            );
        } else {
            $request->request->remove('password');
        }

        return $request;
    }

    protected function addUserFields()
    {
        $this->crud->addFields([
            [
                'name' => 'username',
                'type' => 'text',
            ],
            [
                'name' => 'email',
                'label' => trans('backpack::permissionmanager.email'),
                'type' => 'email',
            ],
            [
                'name' => 'password',
                'label' => trans('backpack::permissionmanager.password'),
                'type' => 'password',
            ],
            [
                'name' => 'password_confirmation',
                'label' => trans(
                    'backpack::permissionmanager.password_confirmation'
                ),
                'type' => 'password',
            ],
            [
                // two interconnected entities
                'label' => trans(
                    'backpack::permissionmanager.user_role_permission'
                ),
                'field_unique_name' => 'user_role_permission',
                'type' => 'checklist_dependency',
                'name' => 'roles,permissions',
                'subfields' => [
                    'primary' => [
                        'label' => trans('backpack::permissionmanager.roles'),
                        'name' => 'roles', // the method that defines the relationship in your Model
                        'entity' => 'roles', // the method that defines the relationship in your Model
                        'entity_secondary' => 'permissions', // the method that defines the relationship in your Model
                        'attribute' => 'name', // foreign key attribute that is shown to user
                        'model' => config('permission.models.role'), // foreign key model
                        'pivot' => true, // on create&update, do you need to add/delete pivot table entries?]
                        'number_columns' => 3, //can be 1,2,3,4,6
                    ],
                    'secondary' => [
                        'label' => mb_ucfirst(
                            trans(
                                'backpack::permissionmanager.permission_plural'
                            )
                        ),
                        'name' => 'permissions', // the method that defines the relationship in your Model
                        'entity' => 'permissions', // the method that defines the relationship in your Model
                        'entity_primary' => 'roles', // the method that defines the relationship in your Model
                        'attribute' => 'name', // foreign key attribute that is shown to user
                        'model' => config('permission.models.permission'), // foreign key model
                        'pivot' => true, // on create&update, do you need to add/delete pivot table entries?]
                        'number_columns' => 3, //can be 1,2,3,4,6
                    ],
                ],
            ],
        ]);
    }
}
解决方案

问题根源在于handlePasswordInput方法中移除了roles_show和permissions_show字段,这两个字段是checklist_dependency组件回显已有角色/权限的关键参数;同时更新逻辑中缺少角色和权限的同步处理。具体修复步骤:

  1. 恢复必要的回显字段
    删除handlePasswordInput方法中的以下两行代码:

    $request->request->remove('roles_show');
    $request->request->remove('permissions_show');
    
  2. 补充角色和权限同步逻辑
    修改update方法,在执行原生更新后手动同步角色和权限:

    public function update()
    {
        $this->crud->setRequest($this->crud->validateRequest());
        $request = $this->handlePasswordInput($this->crud->getRequest());
        $this->crud->setRequest($request);
        $this->crud->unsetValidation();
    
        // 执行原生更新逻辑
        $response = $this->traitUpdate();
        
        // 同步角色和权限
        $entry = $this->crud->getCurrentEntry();
        if ($request->has('roles')) {
            $entry->syncRoles($request->input('roles'));
        }
        if ($request->has('permissions')) {
            $entry->syncPermissions($request->input('permissions'));
        }
    
        return $response;
    }
    
  3. 修正验证规则
    在自定义的UserUpdateCrudRequest中移除对name字段的验证要求,示例:

    // app/Http/Requests/UserUpdateCrudRequest.php
    public function rules()
    {
        return [
            'username' => 'required|string|max:255',
            'email' => 'required|email|unique:users,email,'.$this->route('user'),
            // 移除name字段的验证规则
        ];
    }
    

内容的提问来源于stack exchange,提问作者waffl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 21:40:26