【问题标题】:Roles in Laravel aren't working as intendedLaravel 中的角色没有按预期工作
【发布时间】:2019-10-23 22:57:26
【问题描述】:

我已经按照书本制作了我的 laravel 程序的角色。问题发生在一个特定的实例中,用户模型中的方法之一总是“弹出”......无论用户拥有 role_id,方法总是显示某个角色的名称,在这种情况下是“主持人”。不知道有什么问题,至少我看不到……

这是用户模型:

<?php

    namespace App;

    use Illuminate\Notifications\Notifiable;
    use Illuminate\Contracts\Auth\MustVerifyEmail;
    use Illuminate\Foundation\Auth\User as Authenticatable;

    class User extends Authenticatable
    {
        use Notifiable;

        /**
         * The attributes that are mass assignable.
         *
         * @var array
         */
        protected $fillable = [
            'name', 'email', 'password',"avatar"
        ];

        /**
         * The attributes that should be hidden for arrays.
         *
         * @var array
         */
        protected $hidden = [
            'password', 'remember_token',
        ];

        /**
         * The attributes that should be cast to native types.
         *
         * @var array
         */
        protected $casts = [
            'email_verified_at' => 'datetime',
        ];

        public function rola(){
            return $this->belongsTo("App\Roles", "id");
        }

        public function posts(){
            return $this->hasMany("App\Post");
        }

        public function comments(){
            return $this->hasMany("App\Comment");
        }

        public function isAdmin()
        {//dd($user);

            return $this->rola()->where('role', 'administrator');
        }

        public function isModerator()
        {//dd($user);

            return $this->rola()->where('role', 'moderator');
        }

        public function isUser()
        {//dd($user);

            return $this->rola()->where('role', 'user');
        }

        public function isPeon()
        {//dd($user);

            return $this->rola()->where('role', 'peon');        
        }

}

这是角色模型:

<?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Roles extends Model
    {
        public function rola(){
            return $this->hasMany("App\User", "role_id");
        }
    }

例如,如果只是在任何视图中显示:

    {{auth()->user()->rola->id}} <br> // 2 <- correct
    {{auth()->user()->role_id}} // 3 <- this should be 2 also.

这是我的数据库架构的图像:

以及角色表的图像:

默认情况下,每当新用户注册时,它会自动接收 id 为 4 的“peon”角色。 不知道我的错误在哪里,也许我什么都没看到......

编辑1:

这里是 github repo 的链接,供那些想要了解它的人使用。

【问题讨论】:

  • return $this-&gt;belongsTo("App\Roles", "id"); 应该使用role_id 来表示关系,而不是id

标签: laravel roles


【解决方案1】:

要改进您的应用程序,不要为您拥有的每个角色使用一个功能。 假设您在角色表上有 100 个角色,使用当前代码,您还需要 100 个函数,例如 isAdminisSomething

添加如下内容:

    public function hasRole($roleName)
    {
        return $this->rola()->where('role', $roleName);
    }

    /**
    * Check if the user has any of the given roles.
    */
    public function hasAnyRole(array $roleNames)
    {
        $userRole = $this->rola;
        return in_array($userRole->name, $roleNames);
    }

现在您可以检查角色了:

    $user->hasRole('admin'); //If the user has the admin role, returns true. Otherwise returns false.

在刀片视图中检查角色:

@if(Auth::check())
    @if(Auth::user()->hasRole('role-name') || Auth::user()->hasRoles('another-role-name'))
        //Your markup here
    @endif
@endif

对于多个角色:

@if(Auth::check())
    @if(Auth::user()->hasAnyRoles(['role-name', 'another-role-name']))
        //Your markup here
    @endif
@endif

希望对你有帮助。

【讨论】:

  • 一个问题...如何在视图中实现它,例如我现在有 @if(Auth::check() && (Auth::user()->isAdmin() || Auth::user()->isModerator())) //一些标记 @endif 可能像这样: Auth::user()->hasRole("administrator") ?多个角色如何?
  • 我不知道你到底是什么意思。我将您的示例添加到我的答案中。你想检查像@if(Auth::user()-&gt;hasAnyRole(['admin', 'another-role'])) //some markup @endif这样的角色吗?
【解决方案2】:

问题出在您的rola() 函数中。 您在 belongsTo 中使用了错误的外键。应该是role_id,而不是id(目前是这样)。

这是一个经过一些改进的代码 sn-p:

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',"avatar"
    ];
     /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
    * The attributes that should be cast to native types.
    *
    * @var array
    */

    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function rola(){
        return $this->belongsTo("App\Roles", "role_id");
        //Or just return $this->belongsTo(Roles::class);
    }

    public function posts(){
        return $this->hasMany("App\Post");
    }

    public function comments(){
        return $this->hasMany("App\Comment");
    }

    public function isAdmin()
    {//dd($user);
        return $this->hasRole('admin');
    }

    public function isModerator()
    {//dd($user);
       return $this->hasRole('moderator');
    }

    public function isUser()
    {//dd($user);
        return 
        return $this->hasRole('user');
    }

    public function isPeon()
    {//dd($user);
        return $this->hasRole('peon');
    }

    public function hasRole($role)
    {
        return $this->rola->role === $role;
    }
}

我建议您将 Roles 模型中的 rola 函数重命名为 users,因为它会返回所有具有某些角色的用户。

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class Roles extends Model
{
    public function users(){
        return $this->hasMany(User::class, 'role_id');
    }
}

还有一件事:看看this package。它确实可以帮助您处理用户、权限和权限组。

希望对你有帮助。

【讨论】:

  • 角色表没有“user_id”。用户表有role_id。它可以连接的唯一方法是通过引用特定用户的 id 字段......没关系......你是对的,除了我没有来自 |roleToUser|,但只有来自“UserToRole”......虽然,它非常有帮助查找具有特定角色的所有用户 ...
  • 现在已编辑。老实说,我在回答问题时并没有注意到我更改了外键。但也要重命名你的函数,这是一个很好的实践问题。
  • 向您的User 模型添加一个新功能,称为hasAnyRole。该函数接收role names的数组,并检查该数组是否包含当前用户角色。
【解决方案3】:

好吧,我认为问题出在 User.php 文件中的 rola() 函数中:您正在定义 belongsTo 关系的外键,这里是 id

它应该是role_id,因为这是 Eloquent 尝试映射到 Roles 模型的 id 的关键。 See the documentation了解更多信息

【讨论】:

  • 是的!我在SO的某个地方看到了这样做的方式(最初),我猜关系的第一个参数是模型,第二个(对于外键)是当前模型中保存所述外键值的字段的名称?那是对的吗? IE。返回 $this->belongsTo(tableWhichholdsValueOfForeignKey, FieldInModelsTableThatConnectsToFirstParameterViaId); ?
  • 好吧,我也会避免使用许多isAdminisModerator 等...我建议你只使用一个function isRole($roleName) { return $this-&gt;rola()-&gt;where('role', $roleName); }
  • 我也看到了这种方法。我想尝试这个更简单的,只是为了确保所有的关系、政策和一切都首先由书本决定。感谢您的洞察力。
猜你喜欢
  • 2022-06-14
  • 2018-12-19
  • 2018-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-09
  • 2021-05-22
  • 1970-01-01
相关资源
最近更新 更多