Search code examples
phplaravellaravel-6laravel-gate

How can I get my custom gate working in Laravel?


I am trying to create a custom gate that allows users of the "Administrator" team to access the Users index page. However, it functions exactly the opposite of what I want to achieve and I do not seem to understand where am I wrong here.

It always returns "false" regardless of the user belongs to an Admin team or not.

Help is appreciated. Thank you.

User.php :

public function AdminTeam(string $team)
{
   return null !== $this->teams()->where('name', $team)->first();
}

AuthServiceProvider.php :

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    Gate::define('is-admin', function ($user){
       return $user->AdminTeam('Administrator');
    });
}

UserController.php :

 /**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
public function index()
{
    if (Gate::allows('is-admin')) {
        return view('admin.users.index', ['users' => User::paginate(10)]);
    }
    dd('you need to be admin!');
    
}

index.blade.php :

@can('is-admin')
                @foreach($users as $user)
                    <tr>
                        <th scope="row">{{ $user->user_id }}</th>
                        <td>{{ $user->name }}</td>
                        <td>{{ $user->email }}</td>
                        <td>{{ $user->created_at }}</td>
                        <td>{{ $user->updated_at }}</td>
                        <td>
                            <a class="btn btn-sm btn-primary" href="{{ route('admin.users.edit', $user->user_id) }}"
                               role="button">Bearbeiten</a>
                            <button type="button" class="btn btn-sm btn-danger"
                                    onclick="event.preventDefault();
                                        document.getElementById('delete-user-form-{{ $user->user_id }}').submit()">
                                Löschen
                            </button>
                            <form id="delete-user-form-{{ $user->user_id }}"
                                  action="{{ route('admin.users.destroy', $user->user_id) }}" method="POST"
                                  style="display: none">
                                @csrf
                                @method("DELETE")
                            </form>
                        </td>
                    </tr>
                @endforeach
            @endcan

Output :

Image


Solution

  • So after a couple of days of debugging, I realized that my teams() method should be team() inside the User model as the user has only one team and BelongsTo relation will only return one record.

    Credits: https://www.reddit.com/r/laravel/comments/ldvtgd/custom_admin_gate_not_working/ https://laracasts.com/discuss/channels/laravel/admin-gate-not-working?page=1#reply=687840

    Here are the changes :

    User.php

    public function team()
        {
            return $this->belongsTo(Team::class);
        }
    
         /**
         * Check if the user belongs to Admin Team
         * @param string $team
         * @return bool
         */
    
        public function isAdmin(string $team)
        {
    
            return $this->team()->where('name', $team)->exists();
    
        }
    

    AuthServiceProvider.php

    public function boot()
        {
            $this->registerPolicies();
    
            Gate::define('is-admin', function (User $user){
               return $user->isAdmin('Admin');
            });
        }
    

    UserController.php

    public function index()
        {
            if (Gate::allows('is-admin')) {
                return view('admin.users.index', ['users' => User::paginate(10)]);
    
            }
    
            dd('you need to be admin!');
            
        }