Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make Policy Auto-Discovery new Laravel feature work with my models in a different folder?

I have just updated my Laravel to 5.8 and can't make my Policies auto-discovery work.

I think it's because all my models are in app/Models. The documentation says that I can change the default behavior using this gate.

Gate::guessPolicyNamesUsing(function ($modelClass) {
    // return policy class name...
});

But I can't make it work. The check function '''$user->can()''' always return false for all my Policies and models. Is it really the problem? The models folder, or I'm missing somenting?

By the way, everything works great if I map it manually in the $policies array at AuthServiceProvider.php

Thank you!

like image 230
Mondini Avatar asked Mar 31 '19 13:03

Mondini


2 Answers

If anyone has this problem, here is how I corrected it.

It turned out that the App/Models structure was the problem. The magic done by laravel to guess the policy name considers the location of the model.

To bypass this behavior put the code below inside app/Providers/AuthServiceProvider.php in the boot function.

Gate::guessPolicyNamesUsing(function ($modelClass) {
    return 'App\\Policies\\' . class_basename($modelClass) . 'Policy';
});

It will force to look at App/Policies instead of App/Models/Policies. (change accordingly)

And then I realized that the Policies folder should be allocated inside App/Models 'cause it is where the model live in, but hey, who knows? I guess that putting my models in a different folder will make my life harder.

Bye, hope to help someone in the future.

like image 122
Mondini Avatar answered Oct 10 '22 14:10

Mondini


Just in case someone has changed App folder name, as I did, you can use the following code:

    Gate::guessPolicyNamesUsing(function ($modelClass) {
        $classDirnameArray = explode('\\', str_replace('/', '\\', dirname(str_replace('\\', '/', $modelClass))));
        if ($classDirnameArray[0] === app()::APP_FOLDER) {
            $classDirnameArray =  array_slice($classDirnameArray, 1);
        }
        return app()::APP_FOLDER.'\\Policies\\'. implode("\\",$classDirnameArray) . "\\" . class_basename ( $modelClass).'Policy';
    });

Bear in mind you probably have changed the App name path in the Application.php file, so what I did was to create a constant variable APP_FOLDER that contains the string of the app folder name and I can just call it wherever I am using app()::APP_FOLDER.

I.E. if you have a model MyApp\Models\Core\User the guess policy name would be MyApp\Policies\Models\Core\User.

Any concerns don't hesitate to ask me about it, and I hope this could help too.

PS: I used PHP v7.2.9 and Laravel v5.8.37

like image 44
DiMiGi Avatar answered Oct 10 '22 15:10

DiMiGi