I attempted implement this toturial https://laracasts.com/series/whats-new-in-laravel-5-1/episodes/16 in laravel 10 and it turned breaking.
these are all section of the code:
- AuthServiceProvider
<?php
namespace App\Providers;
use App\Models\Permission;
use Exception;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
class AuthServiceProvider extends ServiceProvider
{
/**
* The model to policy mappings for the application.
*
* @var array<class-string, class-string>
*/
protected $policies = [
];
/**
* Register any authentication / authorization services.
*
* @param GateContract $gate
* @return void
*
* @throws Exception
*/
public function boot(GateContract $gate)
{
$this->registerPolicies();
// $gate->before(function ($user) {
// return $user->isSuperAdmin();
// });
// $gate->define('course_edit',function ($user){
// return true;
// });
try {
if (Schema::hasTable('permissions')) {
foreach ($this->getPermissions() as $permission) {
$gate->define($permission->name, function ($user) use ($permission) {
return $user->hasPermissions($permission);
});
}
}
} catch (Exception $e) {
Log::error($e->getMessage());
}
}
protected function getPermissions()
{
return Permission::with('roles')->get();
}
}
- The test Route
Route::get('authorization', function (){
if(\Illuminate\Support\Facades\Gate::denies('course_edit', \auth()->user())){
return abort(403);
}
return \auth()->user();
})->name('authorization');
- Feature Test
<?php
namespace Tests\Feature;
use App\Models\Permission;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\Supports\AuthorizationSupport;
use Tests\TestCase;
class AuthorizationTest extends TestCase
{
use RefreshDatabase, AuthorizationSupport, WithFaker;
/** @test */
public function user_has_permission_to_access_resource(){
$user = User::factory()->create();
$roles = $this->makeRoles($this->makePermissions());
$user = User::factory()->create();
$user->assignRoles($roles);
//Special permission
$permission = Permission::factory()->create([
'name' => $this->faker->randomElement(['editor_right', 'admin_right'])
]);
$user->assignPermissions($permission);
$this->actingAs($user)
->get(route('authorization'))
->assertOk();
}
}
- The result
Expected response status code [200] but received 403.
Failed asserting that 200 is identical to 403.
- My findings
When i use a string, for example "course_edit" in the gate
$gate->define('course_edit',function ($user){
return true;
});
it worked. But when I get the permission from the database as show below, it will fail.
if (Schema::hasTable('permissions')) {
foreach (Permission::with('roles')->get() as $permission) {
$gate->define($permission->name, function ($user) use ($permission) {
return $user->hasPermissions($permission);
});
}
}
What i figured out is that the boot method called even before the database is been created and seeded which makes the permission table not to exist and everything crashed. So i guide the foreach statement with Schema::hasTable('permissions'). However, this prevent the definition of all the permissions.
I need help on this, specifically:
if (Schema::hasTable('permissions')) {
foreach (Permission::with('roles')->get() as $permission) {
$gate->define($permission->name, function ($user) use ($permission) {
return $user->hasPermissions($permission);
});
}
}
Hope someone come through for me. Thank you in advance.