Multiple Policies for a Model in Laravel
Asked Answered
M

3

11

Does Laravel allow us to add multiple Policies for a Model? I.e. consider App\Providers\ASuthServiceProvider's $policies property:

protected $policies = [
    'App\Team' => 'App\Policies\TeamPolicy',
    'App\Team' => 'App\Policies\RoundPolicy',
    'App\Team' => 'App\Policies\AnotherPolicy',
];

I haven't tested it in an application, because even if it worked, I would be here asking a similar question, regarding whether this is considered bad practise or prone to unexpected behaviour.

The alternative I have is a very messy Policy, containing policies relating to several controllers, named in camel case:

/**
 * Allows coach of Team and admin to see the Team management view.
 * Used in TeamManagementController
 *
 * @param  App\User   $user
 * @param  App\Team   $team
 * @return boolean
 */
public function manage(User $user, Team $team)
{
    return  $user->id === $team->user_id || $user->isAdmin();
}

/**
 * Allows a coach to detach themself from a Team.
 * Used in TeamController
 *
 * @param  App\User   $user
 * @param  App\Team   $team
 * @return boolean
 */
public function detach(User $user, Team $team)
{
    return  $user->id === $team->user_id;
}

/**
 * Below function are used for controllers other than TeamController and TeamManagementController.
 * Reason: We need to authorize, based on a Team. Hence, using this Policy.
 */

/**
 * Allows coach of Team, as well as admin to view players of a Team.
 * Used in PlayerController
 *
 * @param  App\User   $user
 * @param  App\Team   $team
 * @return boolean
 */
public function indexPlayers(User $user, Team $team)
{
    return  $user->id === $team->user_id || $user->isAdmin();
}

/**
 * Allows coach of Team, as well as admin to view players of a Team as an array.
 * Used in PlayerController
 *
 * @param  App\User   $user
 * @param  App\Team   $team
 * @return boolean
 */
public function fetchPlayers(User $user, Team $team)
{
    return  $user->id === $team->user_id || $user->isAdmin();
}

etc. etc.

Madelainemadeleine answered 12/1, 2017 at 2:37 Comment(1)
Maybe you can just extend a policy class to add more functionalityWill
S
7

The $policies variable uses the model as key and as value a policy. Keys are unique so you can only set one policy per model. However you can use a policy on multiple models.

In your case the App\Policies\AnotherPolicy is the only one which will be used. Also assigning multiple models the same policy really depends on what you want to do. Basically you do not want messy or gross code. So if you create a policy for two models and the policy code becomes too large, it is time to consider if creating another policy would make the code simpler/less gross.

Selmore answered 22/3, 2017 at 16:8 Comment(0)
E
15

You could use traits to separate the logic for your policy.

You would create a base TeamPolicy and then multiple traits with the various methods that you would want within the base class.

<?php

class TeamPolicy
{
    use RoundPolicy, AnotherPolicy;
}
Elver answered 2/8, 2018 at 14:19 Comment(0)
S
7

The $policies variable uses the model as key and as value a policy. Keys are unique so you can only set one policy per model. However you can use a policy on multiple models.

In your case the App\Policies\AnotherPolicy is the only one which will be used. Also assigning multiple models the same policy really depends on what you want to do. Basically you do not want messy or gross code. So if you create a policy for two models and the policy code becomes too large, it is time to consider if creating another policy would make the code simpler/less gross.

Selmore answered 22/3, 2017 at 16:8 Comment(0)
P
1

You need to create a model class that will be associated with the policy.

protected $policies = [
    'App\Team' => 'App\Policies\TeamPolicy',
    'App\Round' => 'App\Policies\RoundPolicy',
    'App\Another' => 'App\Policies\AnotherPolicy',
];

Create model classes which extend the Team class. The advantage of this approach is to have separate relationships and functions for respective business logic.

namespace App\Models;    
class Round extend Team
Piero answered 7/7, 2022 at 14:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.