<?php
namespace App\Security\Voter;
use App\Entity\ProcesVerval;
use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Security;
class ProcesVervalVoter extends Voter
{
const VIEW = 'view';
const EDIT = 'edit';
const DELETE = 'delete';
private Security $security;
public function __construct(Security $security)
{
$this->security = $security;
}
protected function supports(string $attribute, $subject): bool
{
return in_array($attribute, [self::VIEW, self::EDIT, self::DELETE])
&& $subject instanceof ProcesVerval;
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
$user = $token->getUser();
// User must be logged in
if (!$user instanceof User) {
return false;
}
// Admin can do everything
if ($this->security->isGranted('ROLE_ADMIN')) {
return true;
}
/** @var ProcesVerval $procesVerval */
$procesVerval = $subject;
switch ($attribute) {
case self::VIEW:
return $this->canView($procesVerval, $user);
case self::EDIT:
return $this->canEdit($procesVerval, $user);
case self::DELETE:
return $this->canDelete($procesVerval, $user);
}
return false;
}
/**
* User can view if:
* - They are the owner (created the PV)
* - They belong to the same client organization
* - Legacy mode: PV has no owner set (created before migration)
*/
private function canView(ProcesVerval $procesVerval, User $user): bool
{
// Legacy mode: if PV has no user/client set, allow access
// This handles records created before the migration was run
if ($procesVerval->getUser() === null && $procesVerval->getClient() === null) {
return true;
}
// Owner can always view
if ($procesVerval->getUser() === $user) {
return true;
}
// User from same client can view
$pvClient = $procesVerval->getClient();
$userClient = $user->getClient();
if ($pvClient !== null && $userClient !== null && $pvClient === $userClient) {
return true;
}
return false;
}
/**
* User can edit if:
* - They can view it
* - The PV is editable (draft or in_progress)
*/
private function canEdit(ProcesVerval $procesVerval, User $user): bool
{
// Must be able to view first
if (!$this->canView($procesVerval, $user)) {
return false;
}
// PV must be editable (not completed)
return $procesVerval->isEditable();
}
/**
* User can delete if:
* - They are the owner (or legacy mode: no owner set)
* - The PV is not completed
*/
private function canDelete(ProcesVerval $procesVerval, User $user): bool
{
// Legacy mode: if PV has no owner, allow delete
$pvUser = $procesVerval->getUser();
if ($pvUser !== null && $pvUser !== $user) {
return false;
}
// Can't delete completed PVs
return $procesVerval->isEditable();
}
}