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

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.     public function __construct(
  29.         private FactoryInterface $menuFactory,
  30.         private Pool $pool,
  31.         private AuthorizationCheckerInterface $checker,
  32.     ) {
  33.     }
  34.     /**
  35.      * Retrieves the menu based on the group options.
  36.      *
  37.      * @param array<string, mixed> $options
  38.      *
  39.      * @throws \InvalidArgumentException if the menu does not exist
  40.      */
  41.     public function get(string $name, array $options = []): ItemInterface
  42.     {
  43.         if (!isset($options['name']) || !\is_string($options['name'])) {
  44.             throw new \InvalidArgumentException('The option "name" is required.');
  45.         }
  46.         $menuItem $this->menuFactory->createItem($options['name']);
  47.         if (!isset($options['group'])) {
  48.             throw new \InvalidArgumentException('The option "group" is required.');
  49.         }
  50.         /** @phpstan-var Group $group */
  51.         $group $options['group'];
  52.         if (false === $group['on_top']) {
  53.             foreach ($group['items'] as $item) {
  54.                 if ($this->canGenerateMenuItem($item$group)) {
  55.                     $menuItem->addChild($this->generateMenuItem($item$group));
  56.                 }
  57.             }
  58.             if (false === $menuItem->hasChildren()) {
  59.                 $menuItem->setDisplay(false);
  60.             } elseif ($group['keep_open']) {
  61.                 $menuItem->setAttribute('class''keep-open');
  62.                 $menuItem->setExtra('keep_open'$group['keep_open']);
  63.             }
  64.         } elseif (
  65.             === \count($group['items'])
  66.             && $this->canGenerateMenuItem($group['items'][0], $group)
  67.         ) {
  68.             $menuItem $this->generateMenuItem($group['items'][0], $group);
  69.             $menuItem->setExtra('on_top'$group['on_top']);
  70.         } else {
  71.             $menuItem->setDisplay(false);
  72.         }
  73.         $menuItem->setLabel($group['label']);
  74.         return $menuItem;
  75.     }
  76.     /**
  77.      * Checks whether a menu exists in this provider.
  78.      *
  79.      * @param mixed[] $options
  80.      */
  81.     public function has(string $name, array $options = []): bool
  82.     {
  83.         return 'sonata_group_menu' === $name;
  84.     }
  85.     /**
  86.      * @phpstan-param Item $item
  87.      * @phpstan-param Group $group
  88.      */
  89.     private function canGenerateMenuItem(array $item, array $group): bool
  90.     {
  91.         // NEXT_MAJOR: Remove the '' check
  92.         if (isset($item['admin']) && '' !== $item['admin']) {
  93.             $admin $this->pool->getInstance($item['admin']);
  94.             // skip menu item if no `list` url is available or user doesn't have the LIST access rights
  95.             return $admin->hasRoute('list') && $admin->hasAccess('list');
  96.         }
  97.         // Making the checker behave affirmatively even if it's globally unanimous
  98.         // Still must be granted unanimously to group and item
  99.         $isItemGranted true;
  100.         if (isset($item['roles']) && [] !== $item['roles']) {
  101.             $isItemGranted false;
  102.             foreach ($item['roles'] as $role) {
  103.                 if ($this->checker->isGranted($role)) {
  104.                     $isItemGranted true;
  105.                     break;
  106.                 }
  107.             }
  108.         }
  109.         $isGroupGranted true;
  110.         if (isset($group['roles']) && [] !== $group['roles']) {
  111.             $isGroupGranted false;
  112.             foreach ($group['roles'] as $role) {
  113.                 if ($this->checker->isGranted($role)) {
  114.                     $isGroupGranted true;
  115.                     break;
  116.                 }
  117.             }
  118.         }
  119.         return $isItemGranted && $isGroupGranted;
  120.     }
  121.     /**
  122.      * @phpstan-param Item $item
  123.      * @phpstan-param Group $group
  124.      */
  125.     private function generateMenuItem(array $item, array $group): ItemInterface
  126.     {
  127.         // NEXT_MAJOR: Remove the '' check
  128.         if (isset($item['admin']) && '' !== $item['admin']) {
  129.             $admin $this->pool->getInstance($item['admin']);
  130.             $options $admin->generateMenuUrl(
  131.                 'list',
  132.                 $item['route_params'],
  133.                 $item['route_absolute'] ? UrlGeneratorInterface::ABSOLUTE_URL UrlGeneratorInterface::ABSOLUTE_PATH
  134.             );
  135.             $options['extras'] = [
  136.                 'label_catalogue' => $admin->getTranslationDomain(), // NEXT_MAJOR: Remove this line.
  137.                 'translation_domain' => $admin->getTranslationDomain(),
  138.                 'admin' => $admin,
  139.             ];
  140.             return $this->menuFactory->createItem($admin->getLabel() ?? ''$options);
  141.         }
  142.         \assert(isset($item['label']));
  143.         \assert(isset($item['route']));
  144.         return $this->menuFactory->createItem($item['label'], [
  145.             'route' => $item['route'],
  146.             'routeParameters' => $item['route_params'],
  147.             'routeAbsolute' => $item['route_absolute'],
  148.             'extras' => [
  149.                 'translation_domain' => $group['translation_domain'],
  150.                 'label_catalogue' => $group['label_catalogue'] ?? ''// NEXT_MAJOR: Remove this line.
  151.             ],
  152.         ]);
  153.     }
  154. }