AshMenhennett
AshMenhennett

Reputation: 1095

Multiple Policies for a Model in Laravel

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.

Upvotes: 11

Views: 10184

Answers (3)

Mahen Nakar
Mahen Nakar

Reputation: 394

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

Upvotes: 1

Matt McDonald
Matt McDonald

Reputation: 5050

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;
}

Upvotes: 15

user2108628
user2108628

Reputation:

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.

Upvotes: 7

Related Questions