src/Twig/Runtime/AclRuntime.php line 113

Open in your IDE?
  1. <?php
  2.     /** @noinspection ALL */
  3.     namespace App\Twig\Runtime;
  4.     use App\Constants\ACL;
  5.     use App\Entity\Parameter;
  6.     use App\Entity\SliderItem;
  7.     use App\Entity\User;
  8.     use App\Model\Product;
  9.     use App\Services\Back\ParameterService;
  10.     use App\Services\Common\AclServiceV2;
  11.     use Doctrine\ORM\EntityManagerInterface;
  12.     use Psr\Cache\InvalidArgumentException;
  13.     use Symfony\Component\HttpFoundation\RequestStack;
  14.     use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
  15.     use Symfony\Component\Security\Core\Security;
  16.     use Symfony\Component\Security\Core\User\UserInterface;
  17.     use Twig\Extension\RuntimeExtensionInterface;
  18.     use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
  19.     /**
  20.      * Rassemble toute les fonction disponible dans twig qui touchent aux ACL et à l'affichage des données via les règles acl ou les systèmes paralèlles (roles, jobs sur les entités comme pour les slider ou les documents)
  21.      */
  22.     class AclRuntime implements RuntimeExtensionInterface
  23.     {
  24.         private AclServiceV2 $aclService;
  25.         private RequestStack $requestStack;
  26.         private ParameterService $parameterService;
  27.         private Security $security;
  28.         private RoleHierarchyInterface $roleHierarchy;
  29.         private EntityManagerInterface $em;
  30.         public function __construct(
  31.             AclServiceV2 $aclService,
  32.             RequestStack     $requestStack,
  33.             ParameterService $parameterService,
  34.             Security $security,
  35.             RoleHierarchyInterface $roleHierarchy,
  36.             EntityManagerInterface $em
  37.         )
  38.         {
  39.             $this->aclService $aclService;
  40.             $this->requestStack     $requestStack;
  41.             $this->parameterService $parameterService;
  42.             $this->security $security;
  43.             $this->roleHierarchy $roleHierarchy;
  44.             $this->em $em;
  45.         }
  46.         /**
  47.          * Permet de savoir si le user a le droit d'accéder à la route
  48.          * @param User|null $user
  49.          * @param string $route
  50.          * @param array $params
  51.          * @param string $env
  52.          * @return bool
  53.          */
  54.         public function userIsGrantedRoute(
  55.             ?User $user,
  56.             string $route,
  57.             array $params = [],
  58.             string $env ACL::FRONT_ENV,
  59.             bool $debug FALSE
  60.         )
  61.         {
  62.             $config = [
  63.                 'route' => $route,
  64.                 'params' => $params,
  65.                 'component' => ACL::ACL_NO_COMPONENT,
  66.                 'slug' => ACL::ACL_NO_SLUG,
  67.                 'action' => ACL::READ,
  68.                 'env' => $env,
  69.             ];
  70.             return $this->aclService->userIsGranted$user$config$debug );
  71.         }
  72.         /**
  73.          * Permet de savoir si un user peut faire une action en fonction de son rôle ou de son job
  74.          *
  75.          * @param User|null $user
  76.          * @param string    $slug
  77.          * @param string    $action
  78.          * @param string    $env
  79.          *
  80.          * @return bool
  81.          *
  82.          * @throws InvalidArgumentException
  83.          */
  84.         public function userIsGranted(
  85.             ?User $user,
  86.             string $component,
  87.             string $slug ACL::ACL_NO_SLUG,
  88.             string $action ACL::READ,
  89.             string $env ACL::FRONT_ENV,
  90.             string $route NULL,
  91.             string $params NULL,
  92.             bool $debug FALSE
  93.         ): bool
  94.         {
  95.             $currentRoute $route ?? $this->requestStack->getCurrentRequest()->get'_route' );
  96.             $currentParams $params ?? $this->requestStack->getCurrentRequest()->get'_route_params' );
  97.             if ($currentRoute === NULL){
  98.                 return $this->checkWhenRouteIsNull();
  99.             }
  100.             $config = [
  101.                 'route' => $currentRoute,
  102.                 'params' => $this->aclService->getRouteParamsForAcl($currentRoute$currentParams),
  103.                 'component' => $component,
  104.                 'slug' => $slug,
  105.                 'action' => $action,
  106.                 'env' => $env,
  107.             ];
  108.             return $this->aclService->userIsGranted$user$config$debug );
  109.         }
  110.         /**
  111.          * Logique pour éviter des erreurs 500 si jamais une route est évaluée à NULL
  112.          * Si on est dans le cas d'une exception on autorise la visualition
  113.          * @return true
  114.          * @throws \Exception
  115.          */
  116.         private function checkWhenRouteIsNull()
  117.         {
  118.             $request $this->requestStack->getCurrentRequest();
  119.             $exeption $request->attributes->get('exception');
  120.             if ($exeption !== null) {
  121.                 return TRUE;
  122.             }
  123.             throw new \Exception('Une erreur est survenue, la route ne peut pas être null et ne pas être une exception');
  124.         }
  125.         /**
  126.          * Permet de savoir si le current user à le droit de voir le catalogue par son slug
  127.          * @param $catalogue
  128.          * @return bool
  129.          * @throws InvalidArgumentException
  130.          */
  131.         public function userIsGrantedCatalogue($catalogue)
  132.         {
  133.             $currentUser $this->security->getUser();
  134.             return $this->aclService->userIsGrantedCatalogue($currentUser$catalogue);
  135.         }
  136.         /**
  137.          * Permet de savoir si le current user à le droit de voir le produit
  138.          * @param Product $product
  139.          *
  140.          * @return bool
  141.          * @throws \JsonException
  142.          */
  143.         public function userIsGrantedProduct(Product $product)
  144.         {
  145.             $currentUser $this->security->getUser();
  146.             return $this->aclService->userIsGrantedProduct($currentUser$product);
  147.         }
  148.         /**
  149.          * Retourne le slug du premier catalogue qui contient le produit et qui est accèssible au user courant
  150.          * @param Product $product
  151.          *
  152.          * @return mixed|null
  153.          * @throws \JsonException
  154.          */
  155.         public function getUserFirstGrantedCatalogSlugForProduct(Product $product)
  156.         {
  157.             $currentUser $this->security->getUser();
  158.             return $this->aclService->getUserFirstGrantedCatalogSlugForProduct($currentUser$product);
  159.         }
  160.         /**
  161.          * Défini si l'utilisateur à le droit de voir le document
  162.          *
  163.          * @param User|null $user
  164.          * @param Parameter $document
  165.          *
  166.          * @return bool
  167.          *
  168.          * @throws \JsonException
  169.          */
  170.         public function canDisplayDocument( ?User $userParameter $document ): bool
  171.         {
  172.             return $this->aclService->userIsGrantedOnDocument$user$document );
  173.         }
  174.         /**
  175.          * Lors des documents personnalisé, permet de savoit si le user peut voir le document
  176.          *
  177.          * @param User|null $user
  178.          * @param           $id
  179.          *
  180.          * @return bool
  181.          *
  182.          * @throws \JsonException
  183.          */
  184.         public function isDocumentSelectedForUser( ?User $user$id ): bool
  185.         {
  186.             return $this->parameterService->isDocumentSelectedForUser$user$id );
  187.         }
  188.         /**
  189.          * Permet de savoir si on component est visible par le user courant
  190.          *
  191.          * Ne doit être utilisé que pour l'affichage twig des components en front
  192.          *
  193.          * @param array|null $componentOptions
  194.          * @param bool $debug
  195.          * @return bool
  196.          * @throws InvalidArgumentException
  197.          */
  198.         public function canDisplayComponentByAcl(?array $componentOptionsbool $debug FALSE)
  199.         {
  200.             if ($componentOptions === NULL || $componentOptions === []){
  201.                 return TRUE;
  202.             }
  203.             $item $componentOptions['item'] ?? $componentOptions;
  204.             // Le component est actif sur la page ?
  205.             $canDisplay = (bool)$item'enabled' ] ?? TRUE;
  206.             if (!$canDisplay) {
  207.                 return FALSE;
  208.             }
  209.             // on regarde s'il peut s'afficher sur la page via la clef display
  210.             $canDisplay $this->canDisplayOnPageByConfig($item['display'], $debug);
  211.             if (!$canDisplay) {
  212.                 return FALSE;
  213.             }
  214.             /** @var User $currentUser */
  215.             $currentUser $this->security->getUser();
  216.             // on recherche l'acl si on peut récupérer son slug data-component-acl
  217.             if ( isset($item['data']['data-component-acl'])){
  218.                 $canDisplay $this->userIsGranted($currentUser$item['data']['data-component-acl'] ?? ACL::ACL_NO_COMPONENT);
  219.             }
  220.             if (!$canDisplay) {
  221.                 return FALSE;
  222.             }
  223.             // on regarde s'il y a des univers... on verifie le currentUser car le component peut être utilisé en partie security
  224.             if ($currentUser !== NULL && isset($item['univers'])){
  225.                 if ( $canDisplay && !$currentUser->isDeveloper() && !$currentUser->isSuperAdmin() && isset($item['univers'])){
  226.                     $canDisplay $this->aclService->canDisplayByUniverses($currentUser$item['univers']);
  227.                 }
  228.             }
  229.             return $canDisplay;
  230.         }
  231.         /**
  232.          * Défini si un component s'affiche via la clef display
  233.          *
  234.          * Elle contient 2 enfants:
  235.          * enabled_on : array (tableau de route)|null
  236.          * disabled_on : array (tableau de route)|null
  237.          * Si disabled_on est a autre chose que null, alors c'est lui qui prend l'ascendant
  238.          * Afficher partout => enabled_on: null + disabled_on: [] ou null
  239.          *
  240.          * @param array $display
  241.          *
  242.          * @return bool
  243.          */
  244.         private function canDisplayOnPageByConfig(array $displaybool $debug FALSE)
  245.         {
  246.             $currentRoute $this->requestStack->getCurrentRequest()->get'_route' );
  247.             if ($currentRoute === NULL){
  248.                 return $this->checkWhenRouteIsNull();
  249.             }
  250.             $canDisplay   TRUE// par défaut on affiche
  251.             // On prend la config du disabled_on si elle n'est pas nulle
  252.             $displayByDisabled FALSE;
  253.             if (isset($display['disabled_on']) && $display['disabled_on'] !== NULL){
  254.                 $displayByDisabled TRUE;
  255.             }
  256.             // On prend la config enbaled_on
  257.             if (isset($display['enabled_on']) && !$displayByDisabled){
  258.                 $arrayRoute $display['enabled_on'];
  259.                 if(gettype($display['enabled_on']) === "string") {
  260.                     $arrayRoute json_decode($display['enabled_on'], true);
  261.                 }
  262.                 switch (TRUE){
  263.                     // tableau vide, ce n'est pas visible
  264.                     case $arrayRoute === []:
  265.                         $canDisplay FALSE;
  266.                         break;
  267.                     // NULL ou valeur qui n'est pas un tableau, on considère que c'est visible
  268.                     // ainsi si enabled_on et disabled_on sont NULL, on affiche
  269.                     case $arrayRoute === NULL:
  270.                     case !is_array($arrayRoute):
  271.                         $canDisplay TRUE;
  272.                         break;
  273.                     // on regarde si la route actuelle est dans le tableau pour l'afficher
  274.                     default:
  275.                         $canDisplay in_array$currentRoute$arrayRouteTRUE );
  276.                         break;
  277.                 }
  278.             }
  279.             // on prend la config disabled_on
  280.             if (isset($display['disabled_on']) && $displayByDisabled){
  281.                 $arrayRoute $display['disabled_on'];
  282.                 if(gettype($display['disabled_on']) === "string") {
  283.                     $arrayRoute json_decode($display['disabled_on'], true);
  284.                 }
  285.                 switch (TRUE){
  286.                     // tableau vide, c'est visible partout
  287.                     case $arrayRoute === []:
  288.                         $canDisplay TRUE;
  289.                         break;
  290.                     // NULL ou valeur qui n'est pas un tableau, on refuse l'affichage
  291.                     // Normalement on ne tombe pas dans cette configuration puisque $displayByDisabled est FALSE
  292.                     case $arrayRoute === NULL:
  293.                     case !is_array($arrayRoute):
  294.                         $canDisplay FALSE;
  295.                         break;
  296.                     // on regarde si la route actuelle est dans le tableau pour refuser l'affichage
  297.                     default:
  298.                         $canDisplay = !in_array$currentRoute$arrayRouteTRUE );
  299.                         break;
  300.                 }
  301.             }
  302.             return $canDisplay;
  303.         }
  304.         /**
  305.          * Permet de savoir si le user peut voir le slider
  306.          *
  307.          * Les acl du slider sont intégré à l'édition de l'entité
  308.          *
  309.          * @param User       $user
  310.          * @param SliderItem $item
  311.          *
  312.          * @return bool
  313.          */
  314.         public function canDisplaySliderItem(?User $userSliderItem $item): bool
  315.         {
  316.             if(!$user) return FALSE;
  317.             $jobs      $item->getDisplayJob();
  318.             $universes $item->getDisplayUniverses();
  319.             // Le superadmin et dev doivent pouvoir tout voir...
  320.             if ( $user->isDeveloper() || $user->isSuperAdmin() ) {
  321.                 return TRUE;
  322.             }
  323.             // Par défaut, tout s'affiche
  324.             $canDisplay TRUE;
  325.             // SI config par job on regarde si ça match
  326.             if ( $jobs !== NULL && !in_array$user->getJob(), $jobsTRUE ) ) {
  327.                 $canDisplay FALSE;
  328.             }
  329.             // Si config par univers on regarde si ça match
  330.             if ( $universes !== NULL ) {
  331.                 foreach ( $user->getUniverses() as $userUnivers ) {
  332.                     if ( in_array$userUnivers->getSlug(), $universesTRUE ) ) {
  333.                         $canDisplay TRUE;
  334.                         break;
  335.                     }
  336.                     $canDisplay FALSE;
  337.                 }
  338.             }
  339.             return $canDisplay;
  340.         }
  341.         /**
  342.          * Normalise la transformation de l'array qui contient les params d'une route pour la transformer en string
  343.          * @param array $params
  344.          *
  345.          * @return false|string
  346.          * @throws \JsonException
  347.          */
  348.         public function formatParamsToString(array $params)
  349.         {
  350.             return $this->aclService->formatArrayParamsToString($params);
  351.         }
  352.         /**
  353.          * Retourne un tableau avec la liste de roles et les jobs relatif à ces roles
  354.          *
  355.          * @return array[]
  356.          */
  357.         public function getDefaultRolesAndJobs()
  358.         {
  359.             return $this->aclService->getDefaultRoleAndJob();
  360.         }
  361.         /**
  362.          * @return UserInterface|null
  363.          */
  364.         public function getOriginalUser(): ?UserInterface
  365.         {
  366.             $token $this->security->getToken();
  367.             if ($token instanceof SwitchUserToken)
  368.             {
  369.                 $user $token->getOriginalToken()->getUser();
  370.                 $user $this->em->getRepository(User::class)->findOneBy(['email' => $user->getEmail()]);
  371.                 return $user;
  372.             }
  373.             return $this->security->getUser();
  374.         }
  375.         /**
  376.          * @param User   $user
  377.          * @param string $role
  378.          *
  379.          * @return bool
  380.          */
  381.         public function hasRole(User $userstring $role): bool
  382.         {
  383.             $reachableRoles $this->roleHierarchy->getReachableRoleNames($user->getRoles());
  384.             return in_array($role$reachableRoles);
  385.         }
  386.     }