vendor/sonata-project/admin-bundle/src/Menu/Provider/GroupMenuProvider.php line 53

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of the Sonata Project package.
  5.  *
  6.  * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
  7.  *
  8.  * For the full copyright and license information, please view the LICENSE
  9.  * file that was distributed with this source code.
  10.  */
  11. namespace Sonata\AdminBundle\Menu\Provider;
  12. use Knp\Menu\FactoryInterface;
  13. use Knp\Menu\ItemInterface;
  14. use Knp\Menu\Provider\MenuProviderInterface;
  15. use Sonata\AdminBundle\Admin\Pool;
  16. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  17. use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
  18. /**
  19.  * Menu provider based on group options.
  20.  *
  21.  * @author Alexandru Furculita <alex@furculita.net>
  22.  *
  23.  * @phpstan-import-type Item from Pool
  24.  * @phpstan-import-type Group from Pool
  25.  */
  26. final class GroupMenuProvider implements MenuProviderInterface
  27. {
  28.     private FactoryInterface $menuFactory;
  29.     private Pool $pool;
  30.     private AuthorizationCheckerInterface $checker;
  31.     public function __construct(FactoryInterface $menuFactoryPool $poolAuthorizationCheckerInterface $checker)
  32.     {
  33.         $this->menuFactory $menuFactory;
  34.         $this->pool $pool;
  35.         $this->checker $checker;
  36.     }
  37.     /**
  38.      * Retrieves the menu based on the group options.
  39.      *
  40.      * @param array<string, mixed> $options
  41.      *
  42.      * @throws \InvalidArgumentException if the menu does not exist
  43.      */
  44.     public function get(string $name, array $options = []): ItemInterface
  45.     {
  46.         if (!isset($options['name']) || !\is_string($options['name'])) {
  47.             throw new \InvalidArgumentException('The option "name" is required.');
  48.         }
  49.         $menuItem $this->menuFactory->createItem($options['name']);
  50.         if (!isset($options['group'])) {
  51.             throw new \InvalidArgumentException('The option "group" is required.');
  52.         }
  53.         /** @phpstan-var Group $group */
  54.         $group $options['group'];
  55.         if (false === $group['on_top']) {
  56.             foreach ($group['items'] as $item) {
  57.                 if ($this->canGenerateMenuItem($item$group)) {
  58.                     $menuItem->addChild($this->generateMenuItem($item$group));
  59.                 }
  60.             }
  61.             if (false === $menuItem->hasChildren()) {
  62.                 $menuItem->setDisplay(false);
  63.             } elseif ($group['keep_open']) {
  64.                 $menuItem->setAttribute('class''keep-open');
  65.                 $menuItem->setExtra('keep_open'$group['keep_open']);
  66.             }
  67.         } elseif (
  68.             === \count($group['items'])
  69.             && $this->canGenerateMenuItem($group['items'][0], $group)
  70.         ) {
  71.             $menuItem $this->generateMenuItem($group['items'][0], $group);
  72.             $menuItem->setExtra('on_top'$group['on_top']);
  73.         } else {
  74.             $menuItem->setDisplay(false);
  75.         }
  76.         $menuItem->setLabel($group['label']);
  77.         return $menuItem;
  78.     }
  79.     /**
  80.      * Checks whether a menu exists in this provider.
  81.      *
  82.      * @param mixed[] $options
  83.      */
  84.     public function has(string $name, array $options = []): bool
  85.     {
  86.         return 'sonata_group_menu' === $name;
  87.     }
  88.     /**
  89.      * @phpstan-param Item $item
  90.      * @phpstan-param Group $group
  91.      */
  92.     private function canGenerateMenuItem(array $item, array $group): bool
  93.     {
  94.         // NEXT_MAJOR: Remove the '' check
  95.         if (isset($item['admin']) && '' !== $item['admin']) {
  96.             $admin $this->pool->getInstance($item['admin']);
  97.             // skip menu item if no `list` url is available or user doesn't have the LIST access rights
  98.             return $admin->hasRoute('list') && $admin->hasAccess('list');
  99.         }
  100.         // Making the checker behave affirmatively even if it's globally unanimous
  101.         // Still must be granted unanimously to group and item
  102.         $isItemGranted true;
  103.         if (isset($item['roles']) && [] !== $item['roles']) {
  104.             $isItemGranted false;
  105.             foreach ($item['roles'] as $role) {
  106.                 if ($this->checker->isGranted($role)) {
  107.                     $isItemGranted true;
  108.                     break;
  109.                 }
  110.             }
  111.         }
  112.         $isGroupGranted true;
  113.         if (isset($group['roles']) && [] !== $group['roles']) {
  114.             $isGroupGranted false;
  115.             foreach ($group['roles'] as $role) {
  116.                 if ($this->checker->isGranted($role)) {
  117.                     $isGroupGranted true;
  118.                     break;
  119.                 }
  120.             }
  121.         }
  122.         return $isItemGranted && $isGroupGranted;
  123.     }
  124.     /**
  125.      * @phpstan-param Item $item
  126.      * @phpstan-param Group $group
  127.      */
  128.     private function generateMenuItem(array $item, array $group): ItemInterface
  129.     {
  130.         // NEXT_MAJOR: Remove the '' check
  131.         if (isset($item['admin']) && '' !== $item['admin']) {
  132.             $admin $this->pool->getInstance($item['admin']);
  133.             $options $admin->generateMenuUrl(
  134.                 'list',
  135.                 $item['route_params'],
  136.                 $item['route_absolute'] ? UrlGeneratorInterface::ABSOLUTE_URL UrlGeneratorInterface::ABSOLUTE_PATH
  137.             );
  138.             $options['extras'] = [
  139.                 'label_catalogue' => $admin->getTranslationDomain(), // NEXT_MAJOR: Remove this line.
  140.                 'translation_domain' => $admin->getTranslationDomain(),
  141.                 'admin' => $admin,
  142.             ];
  143.             return $this->menuFactory->createItem($admin->getLabel() ?? ''$options);
  144.         }
  145.         \assert(isset($item['label']));
  146.         return $this->menuFactory->createItem($item['label'], [
  147.             'route' => $item['route'],
  148.             'routeParameters' => $item['route_params'],
  149.             'routeAbsolute' => $item['route_absolute'],
  150.             'extras' => [
  151.                 'translation_domain' => $group['translation_domain'],
  152.                 'label_catalogue' => $group['label_catalogue'] ?? ''// NEXT_MAJOR: Remove this line.
  153.             ],
  154.         ]);
  155.     }
  156. }