mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-30 02:25:00 +00:00
165 lines
4.8 KiB
PHP
165 lines
4.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* Chill is a software for social workers
|
|
*
|
|
* For the full copyright and license information, please view
|
|
* the LICENSE file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Chill\MainBundle\Routing;
|
|
|
|
use Knp\Menu\FactoryInterface;
|
|
use Knp\Menu\ItemInterface;
|
|
use Knp\Menu\MenuItem;
|
|
use Symfony\Component\Routing\RouterInterface;
|
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
|
|
/**
|
|
* This class permit to build menu from the routing information
|
|
* stored in each bundle.
|
|
*/
|
|
final readonly class MenuComposer
|
|
{
|
|
public function __construct(
|
|
private RouterInterface $router,
|
|
private FactoryInterface $menuFactory,
|
|
private TranslatorInterface $translator,
|
|
/**
|
|
* @var iterable<LocalMenuBuilderInterface>
|
|
*/
|
|
private iterable $localMenuBuilders,
|
|
) {}
|
|
|
|
public function getMenuFor($menuId, array $parameters = []): ItemInterface
|
|
{
|
|
$routes = $this->getRoutesForInternal($menuId, $parameters);
|
|
/** @var MenuItem $menu */
|
|
$menu = $this->menuFactory->createItem($menuId);
|
|
|
|
// build menu from routes
|
|
foreach ($routes as $order => $route) {
|
|
$menu->addChild($this->translator->trans($route['label']), [
|
|
'route' => $route['key'],
|
|
'routeParameters' => $parameters['args'],
|
|
'order' => $order,
|
|
])
|
|
->setExtras([
|
|
// 'icon' => $route['icon'],
|
|
// sf4 check: commented to avoid error: `An exception has been thrown during the rendering of a template ("Notice: Undefined index: icon").`
|
|
'order' => $order,
|
|
]);
|
|
}
|
|
|
|
foreach ($this->localMenuBuilders as $builder) {
|
|
if (in_array($menuId, $builder::getMenuIds(), true)) {
|
|
$builder->buildMenu($menuId, $menu, $parameters);
|
|
}
|
|
}
|
|
|
|
$this->reorderMenu($menu);
|
|
|
|
return $menu;
|
|
}
|
|
|
|
/**
|
|
* Return an array of routes added to $menuId,
|
|
* The array is aimed to build route with MenuTwig.
|
|
*
|
|
* @deprecated
|
|
*
|
|
* @param array $parameters see https://redmine.champs-libres.coop/issues/179
|
|
*/
|
|
public function getRoutesFor(string $menuId, array $parameters = []): array
|
|
{
|
|
return $this->getRoutesForInternal($menuId, $parameters);
|
|
}
|
|
|
|
private function getRoutesForInternal(string $menuId, array $parameters = []): array
|
|
{
|
|
$routes = [];
|
|
$routeCollection = $this->router->getRouteCollection();
|
|
|
|
foreach ($routeCollection->all() as $routeKey => $route) {
|
|
if ($route->hasOption('menus')) {
|
|
if (\array_key_exists($menuId, $route->getOption('menus'))) {
|
|
$route = $route->getOption('menus')[$menuId];
|
|
|
|
$route['key'] = $routeKey;
|
|
|
|
$order = $this->resolveOrder($routes, $route['order']);
|
|
// we do not want to duplicate order information
|
|
unset($route['order']);
|
|
$routes[$order] = $route;
|
|
}
|
|
}
|
|
}
|
|
|
|
ksort($routes);
|
|
|
|
return $routes;
|
|
}
|
|
|
|
/**
|
|
* Return true if the menu has at least one builder.
|
|
*
|
|
* This function is a helper to determine if the method `getMenuFor`
|
|
* should be used, or `getRouteFor`. The method `getMenuFor` should be used
|
|
* if the result is true (it **does** exists at least one menu builder.
|
|
*
|
|
* @deprecated
|
|
*/
|
|
public function hasLocalMenuBuilder(string $menuId): bool
|
|
{
|
|
foreach ($this->localMenuBuilders as $localMenuBuilder) {
|
|
if (in_array($menuId, $localMenuBuilder::getMenuIds(), true)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private function reorderMenu(ItemInterface $menu)
|
|
{
|
|
$ordered = [];
|
|
$unordered = [];
|
|
|
|
foreach ($menu->getChildren() as $name => $item) {
|
|
$order = $item->getExtra('order');
|
|
|
|
if (null !== $order) {
|
|
$ordered[$this->resolveOrder($ordered, $order)] = $name;
|
|
} else {
|
|
$unordered = $name;
|
|
}
|
|
}
|
|
|
|
ksort($ordered);
|
|
|
|
$menus = \array_merge(\array_values($ordered), $unordered);
|
|
$menu->reorderChildren($menus);
|
|
}
|
|
|
|
/**
|
|
* recursive function to resolve the order of a array of routes.
|
|
* If the order chosen in routing.yml is already in used, find the
|
|
* first next order available.
|
|
*
|
|
* @param array $routes the routes previously added
|
|
* @param int $order
|
|
*
|
|
* @return int
|
|
*/
|
|
private function resolveOrder($routes, $order)
|
|
{
|
|
if (isset($routes[$order])) {
|
|
return $this->resolveOrder($routes, $order + 1);
|
|
}
|
|
|
|
return $order;
|
|
}
|
|
}
|