Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

MikelMedina's avatar

Before method in Policies

Hello everyone,

I'm building a REST API and while writing the before() method of one of my policies, I started wondering if this is actually a good use case for it or if I'm abusing the method.

This is the code:

public function before(User $user, string $ability)
{
    if (in_array($ability, ['create', 'viewAny'])) {

        $actualTrainerId = request()
            ->mesocycle
            ->macrocycle
            ->user
            ->actualTrainer?->first()?->id;

        return $user->id == $actualTrainerId ? true : null;
    }

    if (in_array($ability, ['view', 'update', 'delete'])) {

        $actualTrainerId = request()
            ->microcycle
            ->mesocycle
            ->macrocycle
            ->user
            ->actualTrainer?->first()?->id;

        return $user->id == $actualTrainerId ? true : null;
    }

    return null;
}

The idea is:

  • If the authenticated user is the current trainer of the client who owns the microcycle/mesocycle, the request should automatically pass authorization through the before() method.
  • Otherwise, the authorization flow should continue to the corresponding policy ability method (view, update, etc.).

So my question is:

Is this a correct/clean way to use the before() method in Laravel policies, or should this logic live somewhere else?

I'm also not sure if accessing route models directly through request() inside policies is considered good practice.

0 likes
9 replies
Glukinho's avatar

It seems you just put in before logic that should be in actual create, viewAny, ...etc policies (you literally refer to them in your code), so I don't see the point here.

before is for cases that are completely out of a regular policy, for example "if a user is main admin then everything is allowed".

I'm also not sure if accessing route models directly through request() inside policies is considered good practice.

No, it's bad practice. Policies shouldn't know about your HTTP request, they just answer a question: can specific user do specific action or not?

Imagine your app is accessed other than via HTTP, let's say from console command. In that case calling request() in a policy is pointless.

Instead, you should apply a policy to a route with a middleware: https://laravel.com/docs/13.x/authorization#via-middleware

Laravel will take a user from a request and apply a policy to it.

Also I suggest comparing models using built-in method is():

if ($user->is($actualTrainer)) { ... }

Comparing integer ids is less readable and can be wrong when using multiple database connections. is() method handles it right way.

1 like
MikelMedina's avatar

"It seems you just put in before logic that should be in actual create, viewAny, ...etc policies (you literally refer to them in your code), so I don't see the point here."

is it okay even if i repeat the code in most of policies?

so, they should receive the extra information from the controller (or requests)?

Glukinho's avatar

is it okay even if i repeat the code in most of policies?

If you extract code which defines actualTrainer to a private method (or public method of a model maybe) and refer to it in each policy - yes, it's fine. Just don't repeat complicated logic, extract it somewhere and reuse where you need it.

so, they should receive the extra information from the controller (or requests)?

Sorry I don't get what you mean.

MikelMedina's avatar

something like this looks better?: /** * Determine whether the user can view any models. */ public function viewAny(User $user, Mesocycle $mesocycle): bool { //verlo el entrenador o el user return $user->is($mesocycle->actualTrainer()) || $user->is($mesocycle->user()); }

/**
 * Determine whether the user can view the model.
 */
public function view(User $user, Microcycle $microcycle): bool
{
    return $user->is($microcycle->actualTrainer()) || $user->is($microcycle->user());
}

/**
 * Determine whether the user can create models.
 */
public function create(User $user, User $actual_trainer): bool
{
    return $user->is($actual_trainer);
}

/**
 * Determine whether the user can update the model.
 */
public function update(User $user, User $actual_trainer): bool
{
    return $user->is($actual_trainer);
}

/**
 * Determine whether the user can delete the model.
 */
public function delete(User $user, User $actual_trainer): bool
{
    return $user->is($actual_trainer);
}
Glukinho's avatar

Yes, something like this looks fine for me. You should agree this is clean and simple.

1 like
MikelMedina's avatar

yees, thx for your help I really appreciate it :)

ghabriel25's avatar

I'm more curious about this though

request()
    ->mesocycle
    ->macrocycle
    ->user
    ->actualTrainer

and this

request()
    ->microcycle
    ->mesocycle
    ->macrocycle
    ->user
    ->actualTrainer

Couldn't just make helper method inside User model to determine this and compare it using ->is() just like @glukinho mentioned above?

MikelMedina's avatar

Yes, I realized that while I was writing the post, thx

Please or to participate in this conversation.