<?php
namespace App\Security\Voter\RequestDuplication;
use App\Helper\UserRequest\MdmProviderInterface;
use App\Manager\UserRequestManager;
use Psr\Log\LoggerInterface;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use WebServiceCollectionBundle\Model\AtlasPce\UserRequestRequestModel;
class CategoryCanBeDuplicated extends Voter
{
public const REQUEST_DUPLICATION_ATTR = 'REQUEST_DUPLICATION';
/**
* @var LoggerInterface
*/
protected $logger;
/**
* @var MdmProviderInterface
*/
protected $mdmProvider;
/**
* @param LoggerInterface $logger
* @param MdmProviderInterface $mdmProvider
*/
public function __construct(
LoggerInterface $logger,
MdmProviderInterface $mdmProvider
) {
$this->logger = $logger;
$this->mdmProvider = $mdmProvider;
}
/**
* {@inheritdoc}
*/
public function supports($attribute, $subject)
{
$isAttributeCopyCheck = static::REQUEST_DUPLICATION_ATTR === $attribute;
$isRequestValidObject = !is_null($subject) && (get_class($subject) === UserRequestRequestModel::class);
return $isAttributeCopyCheck && $isRequestValidObject;
}
/**
* {@inheritdoc}
*/
public function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
$accessor = PropertyAccess::createPropertyAccessor();
$data = $subject->getData();
$categoryId = $accessor->getValue($data, '[requestCategory][id]');
$this->logger->info('[COPY CATEGORY] trying to duplicate request with category {categoryId}', [
'categoryId' => $categoryId,
]);
// In case category hasn't been set already
if (!$categoryId) {
return true;
}
$user = $token->getUser();
$userRoles = $user->getRoles();
// if we take only categories, roles are lost.
$categories = $this->mdmProvider->getAll(UserRequestManager::PCE_REQUEST_TYPE)['categories'];
$this->logger->info('[COPY CATEGORY] User roles {userRoles}', [
'userRoles' => json_encode($userRoles),
]);
// Keep categories that either have no role restrictions or those what that user has ALL roles required by the category
$categories = array_filter($categories, function(array $category) use ($userRoles) {
if (empty($category['roles'])) {
$this->logger->info('[COPY CATEGORY] Category {categoryLabel} does not require any roles, it may be duplicated by anyone', [
'categoryLabel' => $category['label'],
]);
return true;
}
$this->logger->info('[COPY CATEGORY] Category {categoryLabel} requires roles {roles}', [
'categoryLabel' => $category['label'],
'roles' => json_encode($category['roles']),
]);
return array_reduce($category['roles'], function($carry, $roleInCategory) use ($userRoles) {
return $carry && in_array($roleInCategory, $userRoles);
}, true);
});
$this->logger->info('[COPY CATEGORY] Categories the user may copy {categories}', [
'categories' => json_encode($categories),
]);
// Key = category id
$categoriesIds = array_keys($categories);
$this->logger->info('[COPY CATEGORY] Request category incuded? {theAnswer}', [
'theAnswer' => in_array($categoryId, $categoriesIds),
]);
// Check if user has access to category
return in_array($categoryId, $categoriesIds);
}
}