<?php
namespace App\Security\Voter;
use App\Entity\Product;
use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
// https://symfony.com/doc/current/security/voters.html
class ProductVoter extends Voter
{
const CAN_SHOW_PRODUCT = 'show_product';
const CAN_BUY_PRODUCT = 'buy_product';
public function __construct()
{
}
protected function supports($attribute, $subject): bool
{
// if the attribute isn't one we support, return false
if (!in_array($attribute, [self::CAN_SHOW_PRODUCT, self::CAN_BUY_PRODUCT])) {
return false;
}
// only vote on `Product` objects
if (!$subject instanceof Product) {
return false;
}
return true;
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
/** @var User */
$loggedUser = $token->getUser();
// you know $subject is a Product object, thanks to `supports()`
/** @var Product $product */
$product = $subject;
return match ($attribute) {
self::CAN_SHOW_PRODUCT => $this->canShow($product, $loggedUser),
self::CAN_BUY_PRODUCT => $this->canBuy($product, $loggedUser),
default => throw new \LogicException('This code should not be reached!')
};
}
private function canShow(Product $product, ?User $loggedUser): bool
{
if ($loggedUser && $product->isOnlyAdults() && !$loggedUser->getIsAdult()) {
// the user must be +18y
return false;
}
if (
$product->getIsDraft() ||
$product->getIsScheduled() ||
$product->getIsBlocked() ||
// $product->getIsFinished() ||
$product->getIsFinishedPlusExtra()
) {
return false;
}
return true;
}
private function canBuy(Product $product, ?User $loggedUser): bool
{
if (!$loggedUser) {
// the user must be logged in; if not, deny access
return false;
}
if ($product->isOnlyAdults() && !$loggedUser->getIsAdult()) {
// the user must be +18y
return false;
}
if (
$product->getIsDraft() ||
$product->getIsScheduled() ||
$product->getIsBlocked() ||
$product->getIsFinished()
) {
return false;
}
return true;
}
}