src/Component/TwigExtension/MenuBuilder.php line 114

Open in your IDE?
  1. <?php /** @noinspection PhpUndefinedClassInspection */
  2. namespace App\Component\TwigExtension;
  3. use App\Component\Traits\RepositoryTrait;
  4. use App\Entity\MenuTree;
  5. use App\Entity\User;
  6. use App\Service\MenuService;
  7. use App\Service\RepositoryService;
  8. use Doctrine\Common\Annotations\Reader;
  9. use Exception;
  10. use Psr\Cache\InvalidArgumentException;
  11. use Symfony\Component\Cache\Adapter\TraceableAdapter;
  12. use Symfony\Component\DependencyInjection\ContainerAwareInterface;
  13. use Symfony\Component\DependencyInjection\ContainerAwareTrait;
  14. use Symfony\Component\Routing\RouterInterface;
  15. use Symfony\Component\Security\Core\Security;
  16. use Symfony\Contracts\Cache\ItemInterface;
  17. use Symfony\Contracts\Cache\TagAwareCacheInterface;
  18. use Twig\Environment;
  19. use Twig\Error\LoaderError;
  20. use Twig\Error\RuntimeError;
  21. use Twig\Error\SyntaxError;
  22. use Twig\Extension\AbstractExtension;
  23. use Twig\TwigFunction;
  24. /**
  25. * Class MenuBuilder
  26. * @package App\Component\TwigExtension
  27. */
  28. class MenuBuilder extends AbstractExtension implements ContainerAwareInterface
  29. {
  30. use ContainerAwareTrait;
  31. const CACHE_LIFETIME = 86400;
  32. /** @var Environment $templating */
  33. private Environment $templating;
  34. /** @var TraceableAdapter */
  35. private $cache;
  36. /** @var Security */
  37. private Security $security;
  38. /** @var RouterInterface */
  39. private RouterInterface $router;
  40. /** @var Reader */
  41. private Reader $annotationReader;
  42. /** @var MenuService */
  43. private MenuService $menuService;
  44. /** @var RepositoryService */
  45. private RepositoryService $repositoryService;
  46. /**
  47. * MenuBuilder constructor.
  48. * @param Environment $templating
  49. * @param TagAwareCacheInterface $cache
  50. * @param Security $security
  51. * @param RouterInterface $router
  52. * @param Reader $annotationReader
  53. * @param MenuService $menuService
  54. * @param RepositoryService $repositoryService
  55. */
  56. public function __construct(Environment $templating, TagAwareCacheInterface $cache, Security $security,
  57. RouterInterface $router, Reader $annotationReader, MenuService $menuService,
  58. RepositoryService $repositoryService)
  59. {
  60. $this->templating = $templating;
  61. $this->cache = $cache;
  62. $this->security = $security;
  63. $this->router = $router;
  64. $this->annotationReader = $annotationReader;
  65. $this->menuService = $menuService;
  66. $this->repositoryService = $repositoryService;
  67. }
  68. /**
  69. * @return array|TwigFunction[]
  70. */
  71. public function getFunctions(): array
  72. {
  73. return [
  74. new TwigFunction('createMenu', [$this, 'createMenu']),
  75. ];
  76. }
  77. /**
  78. * @param string $menu
  79. * @return string|array
  80. * @throws LoaderError
  81. * @throws RuntimeError
  82. * @throws SyntaxError
  83. * @throws Exception
  84. * @throws InvalidArgumentException
  85. *
  86. * @example php bin/console cache:pool:clear cache.app => pour vider le cache
  87. */
  88. public function createMenu(string $menu = 'sidebar'): array|string
  89. {
  90. $currentRoute = $this->container->get('request_stack')->getCurrentRequest()->get('_route');
  91. /** @var User $user */
  92. $user = $this->security->getUser();
  93. $userKey = $user ? $user->getId() : 0;
  94. if ($menu === 'sidebar') {
  95. $l1 = explode('_', $currentRoute);
  96. $l1 = $l1[0] . '_' . $l1[1] . '_';
  97. return $this->templating->render('/sidebar/menu.html.twig', [
  98. 'currentRoute' => $currentRoute,
  99. 'currentL1' => $l1,
  100. 'currentL2' => $currentRoute,
  101. 'menuTree' => $this->getCachedSidebarMenu($userKey),
  102. ]);
  103. } elseif ($menu === 'breadcrumb') {
  104. return $this->getCachedBreadcrumb($currentRoute);
  105. } else {
  106. // $menu = 'buttons'
  107. return $this->getCachedButtons($currentRoute, $userKey);
  108. }
  109. }
  110. /**
  111. * @param int $userKey
  112. * @return mixed
  113. * @throws InvalidArgumentException
  114. */
  115. private function getCachedSidebarMenu(int $userKey)
  116. {
  117. return $this->cache->get('menu_sidebar_' . $userKey, function (ItemInterface $item) use ($userKey) {
  118. $item->expiresAfter(self::CACHE_LIFETIME);
  119. $item->tag(['user_' . $userKey]);
  120. $repository = $this->repositoryService->getMenuTree();
  121. $rootNode = $repository->findOneBy(['libelle' => 'App']);
  122. return $this->getAccessibleHierarchy($repository, $rootNode);
  123. });
  124. }
  125. private function getAccessibleHierarchy($repository, $rootNode): array
  126. {
  127. $menuTree = $repository->childrenHierarchy(
  128. $rootNode,
  129. false,
  130. ['decorate' => false],
  131. false
  132. );
  133. if (!is_array($menuTree)) {
  134. return [];
  135. }
  136. $children = '__children';
  137. foreach ($menuTree as $key1 => $menuLevel1) {
  138. if ($menuLevel1['icon'] === "0"){
  139. unset($menuTree[$key1]);
  140. continue;
  141. }
  142. if ($menuLevel1['level'] == 3) {
  143. if (!$menuLevel1['route'] || !$this->menuService->hasAccess($menuLevel1['route'])) {
  144. unset($menuTree[$key1]);
  145. }
  146. } else {
  147. if(is_array($menuLevel1[$children])) {
  148. foreach ($menuLevel1[$children] as $key2 => $menuLevel2) {
  149. if (!$this->menuService->hasAccess($menuLevel2['route'])) {
  150. unset($menuTree[$key1][$children][$key2]);
  151. }
  152. }
  153. }
  154. if (empty($menuTree[$key1][$children])) {
  155. unset($menuTree[$key1]);
  156. }
  157. }
  158. }
  159. return $menuTree;
  160. }
  161. /**
  162. * @param string $currentRoute
  163. * @return mixed
  164. * @throws InvalidArgumentException
  165. */
  166. private function getCachedBreadcrumb(string $currentRoute)
  167. {
  168. return $this->cache->get('menu_breadcrumb_' . $currentRoute, function (ItemInterface $item) use ($currentRoute) {
  169. $item->expiresAfter(self::CACHE_LIFETIME);
  170. $item->tag(['menu']);
  171. $routeArray = explode('_', $currentRoute);
  172. $action = array_pop($routeArray);
  173. $repository = $this->repositoryService->getMenuTree();
  174. $element = $repository->findOneLeafByRoute($currentRoute);
  175. if (!$element instanceof MenuTree) {
  176. $element = $repository->findOneLeafByRoute(implode('_', $routeArray) . '_index');
  177. }
  178. if ($element instanceof MenuTree) {
  179. $path = $repository->getPath($element);
  180. $breadcrumb = [];
  181. foreach ($path as $elem) {
  182. /** @var MenuTree $elem */
  183. if ($elem->getLevel() == 0 || !$elem->getLibelle()) {
  184. continue;
  185. }
  186. if($elem->getLevel() == 1 && $elem->getLibelle() == 'Autres') {
  187. continue;
  188. }
  189. if($elem->getLevel() == 3 && $elem->getLibelle() == 'Update') {
  190. $elem->setLibelle('Modification');
  191. }
  192. $breadcrumb[] = $elem->getLibelle();
  193. }
  194. }
  195. switch ($action) {
  196. case 'add':
  197. $breadcrumb[] = 'Ajout';
  198. break;
  199. case 'edit':
  200. $breadcrumb[] = 'Modification';
  201. break;
  202. case 'index':
  203. default:
  204. break;
  205. }
  206. if (empty($breadcrumb)) {
  207. $breadcrumb[] = 'Proxidriver';
  208. }
  209. return implode(' > ', $breadcrumb);
  210. });
  211. }
  212. /**
  213. * @param string $currentRoute
  214. * @param int $userKey
  215. * @return mixed
  216. * @throws InvalidArgumentException
  217. */
  218. private function getCachedButtons(string $currentRoute, int $userKey): array
  219. {
  220. return $this->cache->get('menu_buttons_' . $currentRoute . '_' . $userKey, function (ItemInterface $item) use ($currentRoute, $userKey) {
  221. $item->expiresAfter(self::CACHE_LIFETIME);
  222. $item->tag(['user_' . $userKey]);
  223. $repository = $this->repositoryService->getMenuTree();
  224. /** @var MenuTree $rootNode */
  225. $rootNode = $repository->findOneLeafByRoute($currentRoute);
  226. if (!$rootNode) {
  227. $tmp = explode('_', $currentRoute);
  228. $tmp[count($tmp) - 1] = 'index';
  229. $currentRoute = implode('_', $tmp);
  230. $rootNode = $repository->findOneLeafByRoute($currentRoute);
  231. }
  232. if ($rootNode instanceof MenuTree && $rootNode->getLevel() == 3) {
  233. $rootNode = $rootNode->getParent();
  234. } else {
  235. return [];
  236. }
  237. return $this->getAccessibleHierarchy($repository, $rootNode);
  238. });
  239. }
  240. }