src/Services/Common/AclServiceV2.php line 144

Open in your IDE?
  1. <?php
  2.     namespace App\Services\Common;
  3.     use App\Constants\ACL;
  4.     use App\Constants\UserExtension;
  5.     use App\Entity\AclSetting;
  6.     use App\Entity\Parameter;
  7.     use App\Entity\Univers;
  8.     use App\Entity\User;
  9.     use App\Model\AclSettingConfig;
  10.     use App\Model\Product;
  11.     use App\Services\Back\ParameterService;
  12.     use App\Services\Front\Catalogue\JsonCatalogueService;
  13.     use Doctrine\ORM\EntityManagerInterface;
  14.     use JsonException;
  15.     use League\Csv\Exception;
  16.     use Psr\Log\LoggerInterface;
  17.     use Symfony\Component\Routing\RouterInterface;
  18.     use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  19.     /**
  20.      * Service pour la gestion des ACL V2 coté Plateforme
  21.      */
  22.     class AclServiceV2
  23.     {
  24.         private RouterInterface        $router;
  25.         private TokenStorageInterface  $tokenStorage;
  26.         private ParameterService       $parameterService;
  27.         private EntityManagerInterface $em;
  28.         private ModuleSettingService   $moduleSettingService;
  29.         private JsonCatalogueService   $jsonCatalogueService;
  30.         private CommunityService       $communityService;
  31.         private LoggerInterface        $logger;
  32.         public function __construct(
  33.                 RouterInterface $router,
  34.                 ParameterService $parameterService,
  35.                 TokenStorageInterface $tokenStorage,
  36.                 EntityManagerInterface $em,
  37.                 ModuleSettingService $moduleSettingService,
  38.                 JsonCatalogueService $jsonCatalogueService,
  39.                 CommunityService $communityService,
  40.                 LoggerInterface $logger
  41.         ) {
  42.             $this->router               $router;
  43.             $this->parameterService     $parameterService;
  44.             $this->tokenStorage         $tokenStorage;
  45.             $this->em                   $em;
  46.             $this->moduleSettingService $moduleSettingService;
  47.             $this->jsonCatalogueService $jsonCatalogueService;
  48.             $this->communityService     $communityService;
  49.             $this->logger               $logger;
  50.         }
  51.         /**
  52.          * @param $config
  53.          *
  54.          * @return false|mixed|string
  55.          *
  56.          * @throws JsonException
  57.          */
  58.         public function getNormalizedAclSettingConfigParams($config)
  59.         {
  60.             $config $config instanceof AclSettingConfig $config->toArray() : $config;
  61.             $params $config'params' ] ?? ACL::ACL_NO_PARAMS;
  62.             if (is_array($params)) {
  63.                 if ($config'route' ] !== NULL) {
  64.                     $params $this->getRouteParamsForAcl($config'route' ], $params);
  65.                 } else {
  66.                     $params $this->formatArrayParamsToString($params);
  67.                 }
  68.             } elseif (in_array($params, [NULL''], TRUE)) {
  69.                 $params ACL::ACL_NO_PARAMS;
  70.             }
  71.             return $params;
  72.         }
  73.         /**
  74.          * Retourne les params sous forme de string pour les ACL
  75.          *
  76.          * Supprime les params inutiles comme "_env"
  77.          * Supprime les params qui ne sont pas configurés pour être pris en compte dans la route
  78.          *
  79.          * @param string|null       $routeName
  80.          * @param array|string|null $params
  81.          *
  82.          * @return string
  83.          *
  84.          */
  85.         public function getRouteParamsForAcl(?string $routeName$params): string
  86.         {
  87.             // cette fonction doit être capable de normalizer les params qui sont en string ou en array
  88.             if (is_string($params)) {
  89.                 try {
  90.                     $params json_decode($paramsTRUE512JSON_THROW_ON_ERROR);
  91.                 } catch (JsonException $e) {
  92.                     $this->logger->error($e->getMessage());
  93.                     $params = [];
  94.                 }
  95.             }
  96.             //unset de la clef _env présente en back_office
  97.             if (isset($params'_env' ])) {
  98.                 unset($params'_env' ]);
  99.             }
  100.             $paramsOptions $this->getAclRouteOptions($routeName);
  101.             foreach ($paramsOptions as $key => $value) {
  102.                 if (isset($params$key ]) && !$value) {
  103.                     unset($params$key ]);
  104.                 }
  105.             }
  106.             return $this->formatArrayParamsToString($params);
  107.         }
  108.         /**
  109.          * Retourne les informations de la clef acl dans les options de la route
  110.          *
  111.          * Certains params ne doivent pas être pris en compte pour la création des ACL (ex id d'une commande)
  112.          * Il faut ajouter dans les options de la route le tableau suivant
  113.          * acl :
  114.          *     id : false   <=== le params ID ne doit pas peser dans la règle des ACL
  115.          *
  116.          * @param string|null $routeName
  117.          *
  118.          * @return array|mixed|null
  119.          */
  120.         public function getAclRouteOptions(?string $routeName)
  121.         {
  122.             if ($routeName === NULL) {
  123.                 return [];
  124.             }
  125.             // Récupère les informations complètes de la route courante
  126.             $route $this->router->getRouteCollection()->get($routeName);
  127.             if ($route === NULL) {
  128.                 return [];
  129.             }
  130.             return $route->getOption('acl') ?? [];
  131.         }
  132.         /**
  133.          * Normalise le json_encode des params pour la transformation array to string
  134.          *
  135.          * @param array|null $params
  136.          *
  137.          * @return string
  138.          */
  139.         public function formatArrayParamsToString(?array $params): string
  140.         {
  141.             if ($params === NULL) {
  142.                 return ACL::ACL_NO_PARAMS;
  143.             }
  144.             try {
  145.                 return json_encode($paramsJSON_THROW_ON_ERROR JSON_UNESCAPED_UNICODE);
  146.             } catch (JsonException $e) {
  147.                 $this->logger->error($e->getMessage());
  148.                 return ACL::ACL_NO_PARAMS;
  149.             }
  150.         }
  151.         /**
  152.          * Récupère l'environnement d'une route (front ou back) par le début du routename
  153.          *
  154.          * @param string $routeName
  155.          *
  156.          * @return string
  157.          */
  158.         public function getEnvByRoute(string $routeName): string
  159.         {
  160.             if (str_contains($routeNameACL::START_ROUTE_BACK)) {
  161.                 return ACL::BACK_ENV;
  162.             }
  163.             return ACL::FRONT_ENV;
  164.         }
  165.         /**
  166.          * Remplit le fichier d'ACL avec les données lors du POST de la modale
  167.          *
  168.          * @param AclSettingConfig $config
  169.          * @param array            $acl
  170.          * @param bool             $debug
  171.          *
  172.          * @return array
  173.          */
  174.         public function setAllData(AclSettingConfig $config, array $acl = [], bool $debug FALSE): array
  175.         {
  176.             $acls = [];
  177.             foreach ($acl as $role => $jobs) {
  178.                 $config->setRole($role);
  179.                 foreach ($jobs as $job => $value) {
  180.                     $config->setJob($job);
  181.                     $acls[] = $this->setData($config$valueFALSE);
  182.                 }
  183.             }
  184.             // reset de la config si on en a besoin ultérieurement
  185.             $config
  186.                     ->setRole(NULL)
  187.                     ->setJob(NULL)
  188.             ;
  189.             $this->em->flush();
  190.             return $acls;
  191.         }
  192.         /**
  193.          * Set 1 ligne d'acl uniquement
  194.          *
  195.          * @param AclSettingConfig $config
  196.          * @param bool             $value
  197.          * @param bool             $withFlush
  198.          * @param bool             $debug
  199.          *
  200.          * @return AclSetting|float|int|mixed|string|null
  201.          */
  202.         public function setData(AclSettingConfig $configbool $valuebool $withFlush TRUEbool $debug FALSE)
  203.         {
  204.             // SI pas de role set, on met par défaut le ROLE_USER
  205.             // TODO voir si on retourne une erreur à la place
  206.             if ($config->getRole() === NULL) {
  207.                 $config->setRole('ROLE_USER');
  208.             }
  209.             // Si pas de job set, on met la constant ACL_NO_JOB
  210.             if ($config->getJob() === NULL) {
  211.                 $config->setRole(ACL::ACL_NO_JOB);
  212.             }
  213.             // vérifications des params en fonction de la configuration des routes
  214.             $params $this->getRouteParamsForAcl($config->getRoute(), $config->getParams());
  215.             $config->setParams($params);
  216.             $registeredAcl $this->em->getRepository(AclSetting::class)->getAclSettingsFor($configTRUE);
  217.             if ($registeredAcl === NULL) {
  218.                 $aclSetting = (new AclSetting())
  219.                         ->setFromAclSettingConfig($config)
  220.                         ->setConcatKey($config->getConcatKey())
  221.                 ;
  222.                 $this->em->persist($aclSetting);
  223.             } else {
  224.                 $aclSetting $registeredAcl;
  225.             }
  226.             $aclSetting
  227.                     ->setValue($value)
  228.             ;
  229.             if ($withFlush) {
  230.                 $this->em->flush();
  231.             }
  232.             return $aclSetting;
  233.         }
  234.         /**
  235.          * @param $config
  236.          *
  237.          * @return string
  238.          * @deprecated
  239.          */
  240.         private function getConcatKey($config): string
  241.         {
  242.             $default = [
  243.                     'env'       => ACL::FRONT_ENV,
  244.                     'route'     => NULL,
  245.                     'params'    => ACL::ACL_NO_PARAMS,
  246.                     'component' => ACL::ACL_NO_COMPONENT,
  247.                     'slug'      => ACL::ACL_NO_SLUG,
  248.                     'action'    => ACL::READ,
  249.             ];
  250.             $config array_merge($default$config);
  251.             return $config'env' ] . ACL::ACL_KEY_SEPARATOR . ($config'route' ] ?? '') . ACL::ACL_KEY_SEPARATOR $config'params' ] . ACL::ACL_KEY_SEPARATOR $config'component' ] . ACL::ACL_KEY_SEPARATOR $config'slug' ] . ACL::ACL_KEY_SEPARATOR $config'action' ];
  252.         }
  253.         /**
  254.          * Retourne l'objet utilisé pour construire le tableau d'ACL dans la modale
  255.          *
  256.          * @param AclSettingConfig $config
  257.          *
  258.          * @return array
  259.          */
  260.         public function getAclConfig(AclSettingConfig $config): array
  261.         {
  262.             // on garde la route d'origine en mémoire
  263.             $routeName $config->getRoute();
  264.             if (NULL === $routeName) {
  265.                 return [];
  266.             }
  267.             // on transforme les valeurs pour correspondre aux différents cas
  268.             $config $this->transformAclVariables($config);
  269.             $aclItems $this->getAclItems($config);
  270.             $tables = [];
  271.             foreach ($aclItems as $role => $jobs) {
  272.                 $rows   = [];
  273.                 $rows[] = array_merge([$role], array_values($jobs));
  274.                 $tables$role ] = [
  275.                         'header' => [array_keys($jobs)],
  276.                         'row'    => $rows,
  277.                 ];
  278.                 // Ajoute au début du tableau $jobs le $role
  279.                 $rows = [array_merge([$role], array_values($jobs))];
  280.                 $tables$role ] = [
  281.                         'rows'   => $rows,
  282.                         'header' => array_keys($jobs),
  283.                 ];
  284.             }
  285.             $data = [
  286.                     'method'    => 'NaN',
  287.                     'env'       => $config->getEnv(),
  288.                     'route'     => $config->getRoute(),
  289.                     'params'    => $config->getParams(),
  290.                     'component' => $config->getComponent(),
  291.                     'slug'      => $config->getSlug(),
  292.                     'action'    => $config->getAction(),
  293.                     'tables'    => $tables,
  294.             ];
  295.             $route $this->router->getRouteCollection()->get($routeName);
  296.             if ($route !== NULL) {
  297.                 $defaults $route->getDefaults();
  298.                 // On remplace ':' par '::' pour pouvoir utiliser la reflection
  299.                 $re    '/(.*\w):(\w.*)/m';
  300.                 $subst "$1::$2";
  301.                 $defaults'_controller' ] = preg_replace($re$subst$defaults'_controller' ]);
  302.                 $method                    explode('::'$defaults'_controller' ]);
  303.                 if (method_exists($method], $method])) {
  304.                     $data'method' ] = $defaults'_controller' ];
  305.                 }
  306.             }
  307.             $data'routeName' ] = $routeName;
  308.             return $data;
  309.         }
  310.         /**
  311.          * Prépare les variables d'ACL en fonction de cas particulier
  312.          *
  313.          * - slug pas toujours obligatoire
  314.          * - les composants "commun" (header, footer) ne dépendent pas de la route
  315.          * - les catalogues ne dépendent pas des routes
  316.          *
  317.          * @param AclSettingConfig $config
  318.          *
  319.          * @return AclSettingConfig
  320.          */
  321.         private function transformAclVariables(AclSettingConfig $config): AclSettingConfig
  322.         {
  323.             // le slug n'est pas toujours obligatoire
  324.             if (in_array($config->getSlug(), [''NULL], TRUE)) {
  325.                 $config->setSlug(ACL::ACL_NO_SLUG);
  326.             }
  327.             // les components dans la partie common ne sont pas dépendant de la page
  328.             if (strpos($config->getComponent(), 'common.') === 0) {
  329.                 $config->setRoute(ACL::ACL_ROUTE_FRONT_ALL);
  330.                 $config->setParams(ACL::ACL_NO_PARAMS);
  331.             }
  332.             // même principe pour le header dans le back office
  333.             if ($config->getEnv() === ACL::BACK_ENV && strpos($config->getComponent(), 'header.') === 0) {
  334.                 $config->setRoute(ACL::ACL_ROUTE_BACK_ALL);
  335.                 $config->setParams(ACL::ACL_NO_PARAMS);
  336.             }
  337.             // on s'occupe d'un acl global de catalogue
  338.             if (strpos($config->getSlug(), ACL::ACL_KEY_SLUG_SHOP_CATALOG) === 0) {
  339.                 $config->setRoute(ACL::ACL_ROUTE_SHOP_CONFIG);
  340.                 $config->setParams(ACL::ACL_NO_PARAMS);
  341.                 $config->setEnv(ACL::FRONT_ENV);
  342.             }
  343.             return $config;
  344.         }
  345.         /**
  346.          * Donne l'ACL correspondant à l'environnement, la route, au composant et à l'action demandés et retourne un
  347.          * tableau formaté pour l'affichage de la modale d'édition
  348.          *
  349.          * @param AclSettingConfig $config
  350.          *
  351.          * @return array
  352.          */
  353.         private function getAclItems(AclSettingConfig $config): array
  354.         {
  355.             $currentUser $this->tokenStorage->getToken() !== NULL $this->tokenStorage->getToken()->getUser() : NULL;
  356.             // on est obligé de transformer les clefs en premier en fonction des conditions
  357.             $config $this->transformAclVariables($config);
  358.             $rolesAndJobs $this->getDefaultRoleAndJob();
  359.             $acls         = [];
  360.             foreach ($rolesAndJobs as $role => $jobs) {
  361.                 $config->setRole($role);
  362.                 foreach ($jobs as $job => $value) {
  363.                     $config->setJob($job);
  364.                     $acls[] = $this->getAclItemForRoleAndJob($configTRUEFALSE);
  365.                 }
  366.             }
  367.             $formattedResult = [];
  368.             // Pour chaque acl, injecte dans $formattedResult les roles et jobs voulus
  369.             /** @var AclSetting $acl */
  370.             foreach ($acls as $acl) {
  371.                 $formattedResult$acl->getRole() ][ $acl->getJob() ] = $acl->getValue();
  372.             }
  373.             // Si on est ROLE_ADMIN, on a accès au tableau pour les ROLE_USER
  374.             if ($currentUser instanceof User && $currentUser->isAdmin()) {
  375.                 unset($formattedResult'ROLE_SUPER_ADMIN' ], $formattedResult'ROLE_DEVELOPER' ]);
  376.             }
  377.             // Si on est ROLE_SUPER_ADMIN, on a accès au tableau pour les ROLE_USER, et ROLE_ADMIN
  378.             if ($currentUser instanceof User && $currentUser->isSuperAdmin()) {
  379.                 unset($formattedResult'ROLE_DEVELOPER' ]);
  380.             }
  381.             return $formattedResult;
  382.         }
  383.         /**
  384.          * Retourne le tableau des roles et job en fonction de la configuration YAML
  385.          *
  386.          * Si un role n'a pas de job, le système des acls le considère avec le job ACL::ACL_NO_JOB
  387.          *
  388.          * @return array[]
  389.          */
  390.         public function getDefaultRoleAndJob(bool $debug FALSE): array
  391.         {
  392.             $tree $this->communityService->getTreeJobs();
  393.             $roles = [
  394.                     'ROLE_USER'        => array_merge(array_keys(array_filter($tree, static function ($item) {
  395.                         return !isset($item'role' ]) || $item'role' ] === 'ROLE_USER';
  396.                     })), [ACL::ACL_NO_JOB]),
  397.                     'ROLE_ADMIN'       => array_merge(array_keys(array_filter($tree, static function ($item) {
  398.                         return isset($item'role' ]) && $item'role' ] === 'ROLE_ADMIN';
  399.                     })), [ACL::ACL_NO_JOB]),
  400.                     'ROLE_SUPER_ADMIN' => array_merge(array_keys(array_filter($tree, static function ($item) {
  401.                         return isset($item'role' ]) && $item'role' ] === 'ROLE_SUPER_ADMIN';
  402.                     })), [ACL::ACL_NO_JOB]),
  403.             ];
  404.             if (isset($roles'ROLE_DEVELOPER' ])) {
  405.                 unset($roles'ROLE_DEVELOPER' ]);
  406.             }
  407.             return array_map(static function ($role) {
  408.                 // Si $role est vide, ajoute une clé 'ACL::ACL_NO_JOB'
  409.                 if (count($role) === 0) {
  410.                     return [ACL::ACL_NO_JOB => TRUE];
  411.                 }
  412.                 return array_map(static function () {
  413.                     return TRUE;
  414.                 }, array_flip($role));
  415.             }, $roles);
  416.         }
  417.         /**
  418.          * Retourne une règle d'ACL complète
  419.          *
  420.          * Retourne une règle existante ou en créé une nouvelle par rapport au contexte
  421.          * Force la valeur à FALSE pour la création d'une règle qui concerne le back + un ROLE_USER
  422.          *
  423.          * @param AclSettingConfig $config    config complète contexte + ROLE + JOB
  424.          * @param bool             $withFlush ajoute un flush dans la fonction pour enregistrer AclSetting
  425.          * @param bool             $debug
  426.          *
  427.          * @return AclSetting|float|int|mixed|string|null
  428.          */
  429.         public function getAclItemForRoleAndJob(AclSettingConfig $configbool $withFlush TRUEbool $debug FALSE)
  430.         {
  431.             $acl $this->em->getRepository(AclSetting::class)->getAclSettingsFor($configTRUETRUE);
  432.             // si les clefs n'existent pas, on les set pour chaque role/job
  433.             if ($acl === NULL)
  434.             {
  435.                 // Si la règle concerne le back pour un ROLE_USER, on set à FALSE par défaut
  436.                 if ($config->getEnv() === ACL::BACK_ENV && $config->getRole() === "ROLE_USER") {
  437.                     $defaultValue FALSE;
  438.                 }
  439.                 else
  440.                 {
  441.                     $defaultValues $this->getDefaultRoleAndJob();
  442.                     try {
  443.                         $defaultValue = (bool)$defaultValues$config->getRole() ][ $config->getJob() ];
  444.                     } catch (\Exception $e) {
  445.                         $this->logger->error($e->getMessage());
  446.                         $defaultValue FALSE;
  447.                     }
  448.                 }
  449.                 $acl $this->setData(
  450.                         $config,
  451.                         $defaultValue,
  452.                         $withFlush,
  453.                         $debug,
  454.                 );
  455.             }
  456.             return $acl;
  457.         }
  458.         /**
  459.          * Vérifie si le user à le droit de voir le produit
  460.          *
  461.          * Vérifie les catalogues où est présent le produit et recherche les droits d'accès du user sur ces catalogues
  462.          * Retourne TRUE au premier qui match
  463.          *
  464.          * @param User|null $user
  465.          * @param Product   $product
  466.          *
  467.          * @return bool
  468.          *
  469.          * @throws JsonException
  470.          */
  471.         public function userIsGrantedProduct(?User $userProduct $product): bool
  472.         {
  473.             foreach ($product->getCatalogues() as $catalogue) {
  474.                 //if ($this->userIsGrantedCatalogue($user, $catalogue) && $this->jsonCatalogueService->isProductInCatalogue($product->getSku(), $catalogue)) {
  475.                 //TODO @Manu la vérification pour savoir si le produit est dans le catalogue est lourde, sans doute redondante si on a déjà récupéré le produit via le JSON pour obtenir la variable $product
  476.                 if ($this->userIsGrantedCatalogue($user$catalogue)) {
  477.                     return TRUE;
  478.                 }
  479.             }
  480.             return FALSE;
  481.         }
  482.         /**
  483.          * Retourne si l'utilisateur peut voir ou non le catalogue via son slug, prend en compte les Univers si
  484.          * l'option est active
  485.          *
  486.          * @param User|null $user
  487.          * @param string    $catalogueSlug
  488.          * @param bool      $debug
  489.          *
  490.          * @return bool
  491.          *
  492.          * @throws JsonException
  493.          */
  494.         public function userIsGrantedCatalogue(?User $userstring $catalogueSlugbool $debug FALSE): bool
  495.         {
  496.             $isGranted $this->userIsGranted(
  497.                     $user,
  498.                     [
  499.                             'route'     => ACL::ACL_ROUTE_SHOP_CONFIG,
  500.                             'params'    => ACL::ACL_NO_PARAMS,
  501.                             'component' => ACL::ACL_NO_COMPONENT,
  502.                             'slug'      => ACL::ACL_KEY_SLUG_SHOP_CATALOG '.' $catalogueSlug,
  503.                             'env'       => ACL::FRONT_ENV,
  504.                     ],
  505.             );
  506.             // en cas d'univers il faut vérifier si on a le droit de voir quand on est ni dev, ni super admin
  507.             $universActive $this->moduleSettingService->isModuleActive('univers');
  508.             if ($universActive && $user !== NULL && !$user->isSuperAdmin() && !$user->isDeveloper()) {
  509.                 $catalogueHasUnivers $this->em->getRepository(Univers::class)->findUniversForUserAndCatalogSlug($user$catalogueSlug);
  510.                 $isGranted $catalogueHasUnivers !== [];
  511.             }
  512.             return $isGranted;
  513.         }
  514.         /**
  515.          * Indique si un utilisateur a les droits d'accès de la page ou du composant avec son action
  516.          *
  517.          * Retourne TRUE si on est sur un component qui s'affiche coté security (non logué)
  518.          * Retourne TRUE si on est ROLE_DEVELOPER
  519.          * Retourne FALSE si la règle n'est pas trouvée ou qu'aucune règle n'est TRUE
  520.          * Retourne TRUE à la première règle dont la valeur est TRUE (si le user à plusieurs roles par exemple)
  521.          *
  522.          * @param User|null $user
  523.          * @param array     $config
  524.          * @param bool      $debug
  525.          *
  526.          * @return bool
  527.          * @throws JsonException
  528.          */
  529.         public function userIsGranted(
  530.                 ?User $user,
  531.                 array $config,
  532.                 bool $debug FALSE
  533.         ): bool
  534.         {
  535.             $default = [
  536.                     'route'     => NULL,
  537.                     'params'    => ACL::ACL_NO_PARAMS,
  538.                     'component' => ACL::ACL_NO_COMPONENT,
  539.                     'slug'      => ACL::ACL_NO_SLUG,
  540.                     'action'    => ACL::READ,
  541.                     'env'       => ACL::FRONT_ENV,
  542.             ];
  543.             $config array_merge($default$config);
  544.             // cette étape normalise la variable params que ça soit une string ou un array.
  545.             $config'params' ] = $this->getRouteParamsForAcl($config'route' ], $config'params' ]);
  546.             //Si c'est un component qui vient de la clef security alors on autorise
  547.             // @todo passer par l'array des routes concernée par la security ?
  548.             // security_path dans twig.yaml
  549.             if (strpos($config'component' ], 'security.'0) !== FALSE || in_array($config'route' ], ACL::ACL_SECURITY_ROUTESTRUE)) {
  550.                 return TRUE;
  551.             }
  552.             // Utilisateur non connecté
  553.             if (!$user instanceof User) return FALSE;
  554.             // Aucune restriction pour le ROLE_DEVELOPER
  555.             if ($user->isDeveloper()) return TRUE;
  556.             $isGranted FALSE;
  557.             foreach ($user->getRoles() as $role)
  558.             {
  559.                 $aclConfig =
  560.                     (new AclSettingConfig())
  561.                             ->setFromArray($config)
  562.                             ->setRole($role)
  563.                             ->setJob($user->getJob() ?? ACL::ACL_NO_JOB)
  564.                 ;
  565.                 $aclConfig $this->transformAclVariables($aclConfig);
  566.                 $aclItem $this->getAclItemForRoleAndJob($aclConfigTRUE$debug);
  567.                 $isGranted $aclItem->getValue();
  568.                 if ($isGranted) break;
  569.             }
  570.             return $isGranted;
  571.         }
  572.         /**
  573.          * Retourne le slug du premier catalogue où le user a les accès ACL
  574.          *
  575.          * @param User|null $user
  576.          * @param Product   $product
  577.          *
  578.          * @return mixed|null
  579.          * @throws JsonException
  580.          */
  581.         public function getUserFirstGrantedCatalogSlugForProduct(?User $userProduct $product)
  582.         {
  583.             foreach ($product->getCatalogues() as $catalogue) {
  584.                 //TODO @manu la vérification pour savoir si le produit est dans le catalogue est lourde, sans doute redondante si on a déjà récupéré le produit via le JSON pour obtenir la variable $product
  585.                 if ($this->userIsGrantedCatalogue($user$catalogue/*&& $this->jsonCatalogueService->isProductInCatalogue($product->getSku(), $catalogue)*/) {
  586.                     return $catalogue;
  587.                 }
  588.             }
  589.             return NULL;
  590.         }
  591.         /**
  592.          * Indique si un user a les droits d'accès au document
  593.          *
  594.          * Les ACL du document se font lors de la création de l'entité
  595.          * Choix des roles => si pas de choix tout le monde voit
  596.          * Choix des jobs => si pas de choix tout le monde voit
  597.          * Choix des univers => si pas de choix tout le monde voit
  598.          *
  599.          * @param User|null $user
  600.          * @param Parameter $document
  601.          *
  602.          * @return bool
  603.          *
  604.          * @throws JsonException
  605.          * @throws Exception
  606.          */
  607.         public function userIsGrantedOnDocument(?User $userParameter $document): bool
  608.         {
  609.             if ($user === NULL) {
  610.                 return TRUE;
  611.             }
  612.             $isGranted TRUE;
  613.             //Check sur job
  614.             if ($document->getDisplayJob() !== NULL
  615.                 && !in_array($user->getJob(), $document->getDisplayJob(), TRUE)
  616.             ) {
  617.                 return FALSE;
  618.             }
  619.             //Check sur le role
  620.             if ($document->getDisplayRole() !== NULL && array_diff(
  621.                                                                 $user->getRoles(),
  622.                                                                 $document->getDisplayRole(),
  623.                                                         ) !== []) {
  624.                 return FALSE;
  625.             }
  626.             $universes $document->getDisplayUniverses();
  627.             // Si config par univers on regarde si ça match
  628.             if ($universes !== NULL) {
  629.                 $isGranted FALSE;
  630.                 foreach ($user->getUniverses() as $userUnivers) {
  631.                     if (in_array($userUnivers->getSlug(), $universesTRUE)) {
  632.                         $isGranted TRUE;
  633.                         break;
  634.                     }
  635.                 }
  636.                 if (!$isGranted) {
  637.                     return FALSE;
  638.                 }
  639.             }
  640.             // Check si la selection des documents est activé sur des parents dont il dépend et qui ont une extension
  641.             if ($user->getParents()->getValues() !== []) {
  642.                 $isGranted $this->parameterService->isDocumentSelectedByUserParents($user$document->getId());
  643.             }
  644.             // sur le user lui-même si une extension existe
  645.             $currentUserDocumentSelected $user->getExtensionBySlug(UserExtension::DOCUMENT_SELECTION);
  646.             if ($currentUserDocumentSelected !== NULL) {
  647.                 $isGranted $this->parameterService->isDocumentSelectedForUser($user$document->getId());
  648.             }
  649.             return $isGranted;
  650.         }
  651.         /**
  652.          * Définit si un element d'un formType est visible en fonction de ses droits configurés dans le yaml
  653.          *
  654.          * @param AclSettingConfig|null $aclConfig
  655.          * @param array                 $config
  656.          * @param bool                  $debug
  657.          *
  658.          * @return bool
  659.          * @throws JsonException
  660.          */
  661.         public function currentUserIsGrantedByConfigFormType(?AclSettingConfig $aclConfig, array $config = [], bool $debug FALSE): bool
  662.         {
  663.             // Pas de config, tout le monde voit
  664.             if ($aclConfig === NULL &&
  665.                 !array_key_exists('jobs'$config) &&
  666.                 !array_key_exists('roles'$config) &&
  667.                 !array_key_exists('univers'$config)) {
  668.                 return TRUE;
  669.             }
  670.             $tokenStorage $this->tokenStorage->getToken();
  671.             $currentUser  $tokenStorage $tokenStorage->getUser() : NULL;
  672.             if (!$currentUser instanceof User) {
  673.                 return FALSE;
  674.             }
  675.             // Le super_admin et dev doivent pouvoir tout voir
  676.             if ($currentUser->isDeveloper() || $currentUser->isSuperAdmin()) {
  677.                 return TRUE;
  678.             }
  679.             if (array_key_exists('jobs'$config) && $config'jobs' ] !== null) {
  680.                 return $this->canDisplayByJobs($currentUser$config'jobs' ]);
  681.             }
  682.             if (array_key_exists('roles'$config) && $config'roles' ] !== null) {
  683.                 return $this->canDisplayByRoles($currentUser$config'roles' ]);
  684.             }
  685.             $universesConfig = isset($config'univers' ]) && count($config'univers' ]) > 0;
  686.             // cas 2 $aclConfig + config  => on ne garde que les univers pour le moment, $aclConfig prend le dessus.
  687.             $isGranted = !$aclConfig || $this->userIsGranted($currentUser$aclConfig->toArray(), $debug);
  688.             if ($isGranted && $universesConfig) {
  689.                 return $this->canDisplayByUniverses($currentUser$config'univers' ]);
  690.             }
  691.             return $isGranted;
  692.         }
  693.         /**
  694.          * Vérifie si on peut afficher un élément en fonction du roles
  695.          *
  696.          * @param User  $user
  697.          * @param array $roles
  698.          *
  699.          * @return bool
  700.          */
  701.         public function canDisplayByRoles(User $user, array $roles): bool
  702.         {
  703.             $userRole $user->getRoles();
  704.             if(array_diff($userRole$roles) === []) {
  705.                 return TRUE;
  706.             }
  707.             return FALSE;
  708.         }
  709.         /**
  710.          * Vérifie si on peut afficher un élément en fonction du jobs
  711.          *
  712.          * @param User  $user
  713.          * @param array $jobs
  714.          *
  715.          * @return bool
  716.          */
  717.         public function canDisplayByJobs(User $user, array $jobs): bool
  718.         {
  719.             $userJob $user->getJob();
  720.             if(in_array($userJob$jobs)) {
  721.                 return TRUE;
  722.             }
  723.             return FALSE;
  724.         }
  725.         /**
  726.          * Vérifie si on peut afficher un élément en fonction des univers de l'utilisateur
  727.          *
  728.          * @param User  $user
  729.          * @param array $universes
  730.          *
  731.          * @return bool
  732.          */
  733.         public function canDisplayByUniverses(User $user, array $universes): bool
  734.         {
  735.             $userUniverses $user->getUniverses();
  736.             foreach ($userUniverses as $univers) {
  737.                 if (in_array($univers->getSlug(), $universesTRUE)) {
  738.                     return TRUE;
  739.                 }
  740.             }
  741.             return FALSE;
  742.         }
  743.     }