mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-12 13:24:25 +00:00
integration of knp menu bundle
This commit is contained in:
parent
5c045abda4
commit
395787f1bb
@ -11,6 +11,7 @@ use Chill\MainBundle\DependencyInjection\RoleProvidersCompilerPass;
|
|||||||
use Chill\MainBundle\DependencyInjection\CompilerPass\ExportsCompilerPass;
|
use Chill\MainBundle\DependencyInjection\CompilerPass\ExportsCompilerPass;
|
||||||
use Chill\MainBundle\DependencyInjection\CompilerPass\WidgetsCompilerPass;
|
use Chill\MainBundle\DependencyInjection\CompilerPass\WidgetsCompilerPass;
|
||||||
use Chill\MainBundle\DependencyInjection\CompilerPass\NotificationCounterCompilerPass;
|
use Chill\MainBundle\DependencyInjection\CompilerPass\NotificationCounterCompilerPass;
|
||||||
|
use Chill\MainBundle\DependencyInjection\CompilerPass\MenuCompilerPass;
|
||||||
|
|
||||||
|
|
||||||
class ChillMainBundle extends Bundle
|
class ChillMainBundle extends Bundle
|
||||||
@ -25,5 +26,6 @@ class ChillMainBundle extends Bundle
|
|||||||
$container->addCompilerPass(new ExportsCompilerPass());
|
$container->addCompilerPass(new ExportsCompilerPass());
|
||||||
$container->addCompilerPass(new WidgetsCompilerPass());
|
$container->addCompilerPass(new WidgetsCompilerPass());
|
||||||
$container->addCompilerPass(new NotificationCounterCompilerPass());
|
$container->addCompilerPass(new NotificationCounterCompilerPass());
|
||||||
|
$container->addCompilerPass(new MenuCompilerPass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
|||||||
$loader->load('services/validator.yml');
|
$loader->load('services/validator.yml');
|
||||||
$loader->load('services/widget.yml');
|
$loader->load('services/widget.yml');
|
||||||
$loader->load('services/controller.yml');
|
$loader->load('services/controller.yml');
|
||||||
|
$loader->load('services/routing.yml');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConfiguration(array $config, ContainerBuilder $container)
|
public function getConfiguration(array $config, ContainerBuilder $container)
|
||||||
|
49
DependencyInjection/CompilerPass/MenuCompilerPass.php
Normal file
49
DependencyInjection/CompilerPass/MenuCompilerPass.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Champs Libres Cooperative <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
namespace Chill\MainBundle\DependencyInjection\CompilerPass;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
|
use Chill\MainBundle\Routing\MenuComposer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class MenuCompilerPass implements CompilerPassInterface
|
||||||
|
{
|
||||||
|
public function process(ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
if (!$container->hasDefinition('chill.main.menu_composer')) {
|
||||||
|
throw new \LogicException(sprintf("The service %s does not exists in "
|
||||||
|
. "container.", MenuComposer::class));
|
||||||
|
}
|
||||||
|
|
||||||
|
$menuComposerDefinition = $container->getDefinition('chill.main.menu_composer');
|
||||||
|
|
||||||
|
foreach ($container->findTaggedServiceIds('chill.menu_builder') as $id => $tags) {
|
||||||
|
$class = $container->getDefinition($id)->getClass();
|
||||||
|
foreach ($class::getMenuIds() as $menuId) {
|
||||||
|
$menuComposerDefinition
|
||||||
|
->addMethodCall('addLocalMenuBuilder', [new Reference($id), $menuId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,27 +2,6 @@ parameters:
|
|||||||
# cl_chill_main.example.class: Chill\MainBundle\Example
|
# cl_chill_main.example.class: Chill\MainBundle\Example
|
||||||
|
|
||||||
services:
|
services:
|
||||||
chill.main.routes_loader:
|
|
||||||
class: Chill\MainBundle\Routing\Loader\ChillRoutesLoader
|
|
||||||
arguments:
|
|
||||||
- "%chill_main.routing.resources%"
|
|
||||||
tags:
|
|
||||||
- { name: routing.loader }
|
|
||||||
|
|
||||||
chill.main.menu_composer:
|
|
||||||
class: Chill\MainBundle\Routing\MenuComposer
|
|
||||||
#must be set in function to avoid circular reference with chill.main.twig.chill_menu
|
|
||||||
calls:
|
|
||||||
- [setContainer, ["@service_container"]]
|
|
||||||
|
|
||||||
chill.main.twig.chill_menu:
|
|
||||||
class: Chill\MainBundle\Routing\MenuTwig
|
|
||||||
arguments:
|
|
||||||
- "@chill.main.menu_composer"
|
|
||||||
calls:
|
|
||||||
- [setContainer, ["@service_container"]]
|
|
||||||
tags:
|
|
||||||
- { name: twig.extension }
|
|
||||||
|
|
||||||
twig_intl:
|
twig_intl:
|
||||||
class: Twig_Extensions_Extension_Intl
|
class: Twig_Extensions_Extension_Intl
|
||||||
|
23
Resources/config/services/routing.yml
Normal file
23
Resources/config/services/routing.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
services:
|
||||||
|
chill.main.menu_composer:
|
||||||
|
class: Chill\MainBundle\Routing\MenuComposer
|
||||||
|
arguments:
|
||||||
|
- '@Symfony\Component\Routing\RouterInterface'
|
||||||
|
- '@Knp\Menu\FactoryInterface'
|
||||||
|
Chill\MainBundle\Routing\MenuComposer: '@chill.main.menu_composer'
|
||||||
|
|
||||||
|
chill.main.routes_loader:
|
||||||
|
class: Chill\MainBundle\Routing\Loader\ChillRoutesLoader
|
||||||
|
arguments:
|
||||||
|
- "%chill_main.routing.resources%"
|
||||||
|
tags:
|
||||||
|
- { name: routing.loader }
|
||||||
|
|
||||||
|
chill.main.twig.chill_menu:
|
||||||
|
class: Chill\MainBundle\Routing\MenuTwig
|
||||||
|
arguments:
|
||||||
|
- "@chill.main.menu_composer"
|
||||||
|
calls:
|
||||||
|
- [setContainer, ["@service_container"]]
|
||||||
|
tags:
|
||||||
|
- { name: twig.extension }
|
@ -24,8 +24,8 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<ul class="submenu width-11-em">
|
<ul class="submenu width-11-em">
|
||||||
{% for route in routes %}
|
{% for menu in menus %}
|
||||||
<li><a href="{{ path(route.key, args ) }}" style="font-family: 'Open Sans'; font-weight:300; font-size: 0.9em;">{% if route.icon is defined %}<i class="fa fa-{{ route.icon }}"></i> {% endif %}{{ route.label|trans }}</a></li>
|
<li><a href="{{ menu.uri }}" style="font-family: 'Open Sans'; font-weight:300; font-size: 0.9em;">{% if menu.extras.icon is defined %}<i class="fa fa-{{ menu.extras.icon }}"></i> {% endif %}{{ menu.label|trans }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
38
Routing/LocalMenuBuilderInterface.php
Normal file
38
Routing/LocalMenuBuilderInterface.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Champs Libres Cooperative <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
namespace Chill\MainBundle\Routing;
|
||||||
|
|
||||||
|
use Knp\Menu\MenuItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
interface LocalMenuBuilderInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* return an array of menu ids
|
||||||
|
*
|
||||||
|
* @internal this method is static to 1. keep all config in the class,
|
||||||
|
* instead of tags arguments; 2. avoid a "supports" method, which could lead
|
||||||
|
* to parsing all instances to get only one or two working instance.
|
||||||
|
*/
|
||||||
|
public static function getMenuIds(): array;
|
||||||
|
|
||||||
|
public function buildMenu($menuId, MenuItem $menu, array $parameters);
|
||||||
|
}
|
@ -3,8 +3,9 @@
|
|||||||
namespace Chill\MainBundle\Routing;
|
namespace Chill\MainBundle\Routing;
|
||||||
|
|
||||||
use Symfony\Component\Routing\RouteCollection;
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
use Symfony\Component\Routing\RouterInterface;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Knp\Menu\FactoryInterface;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class permit to build menu from the routing information
|
* This class permit to build menu from the routing information
|
||||||
@ -14,27 +15,34 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||||||
*
|
*
|
||||||
* @author julien
|
* @author julien
|
||||||
*/
|
*/
|
||||||
class MenuComposer implements ContainerAwareInterface
|
class MenuComposer
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @var ContainerInterface
|
* @var RouterInterface
|
||||||
*/
|
*/
|
||||||
private $container;
|
private $router;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @internal using the service router in container cause circular references
|
* @var FactoryInterface
|
||||||
* @param ContainerInterface $container
|
|
||||||
*/
|
*/
|
||||||
public function setContainer(ContainerInterface $container = null)
|
private $menuFactory;
|
||||||
{
|
|
||||||
if (NULL === $container) {
|
/**
|
||||||
throw new \LogicException('container should not be null');
|
*
|
||||||
}
|
* @var
|
||||||
//see remark in MenuComposer::setRouteCollection
|
*/
|
||||||
$this->container = $container;
|
private $localMenuBuilders = [];
|
||||||
|
|
||||||
|
|
||||||
|
function __construct(
|
||||||
|
RouterInterface $router,
|
||||||
|
FactoryInterface $menuFactory
|
||||||
|
) {
|
||||||
|
$this->router = $router;
|
||||||
|
$this->menuFactory = $menuFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,7 +69,7 @@ class MenuComposer implements ContainerAwareInterface
|
|||||||
public function getRoutesFor($menuId, array $parameters = array())
|
public function getRoutesFor($menuId, array $parameters = array())
|
||||||
{
|
{
|
||||||
$routes = array();
|
$routes = array();
|
||||||
$routeCollection = $this->container->get('router')->getRouteCollection();
|
$routeCollection = $this->router->getRouteCollection();
|
||||||
|
|
||||||
foreach ($routeCollection->all() as $routeKey => $route) {
|
foreach ($routeCollection->all() as $routeKey => $route) {
|
||||||
if ($route->hasOption('menus')) {
|
if ($route->hasOption('menus')) {
|
||||||
@ -83,6 +91,35 @@ class MenuComposer implements ContainerAwareInterface
|
|||||||
return $routes;
|
return $routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMenuFor($menuId, array $parameters = array())
|
||||||
|
{
|
||||||
|
$routes = $this->getRoutesFor($menuId, $parameters);
|
||||||
|
$menu = $this->menuFactory->createItem($menuId);
|
||||||
|
|
||||||
|
// build menu from routes
|
||||||
|
foreach ($routes as $order => $route) {
|
||||||
|
$menu->addChild($route['label'], [
|
||||||
|
'route' => $route['key'],
|
||||||
|
'routeParameters' => $parameters,
|
||||||
|
'order' => $order
|
||||||
|
])
|
||||||
|
->setExtras([
|
||||||
|
'icon' => $route['icon'],
|
||||||
|
'order' => $order
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->hasLocalMenuBuilder($menuId)) {
|
||||||
|
foreach ($this->localMenuBuilders[$menuId] as $builder) {
|
||||||
|
/* @var $builder LocalMenuBuilderInterface */
|
||||||
|
$builder->buildMenu($menuId, $menu, $parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $menu;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* recursive function to resolve the order of a array of routes.
|
* recursive function to resolve the order of a array of routes.
|
||||||
* If the order chosen in routing.yml is already in used, find the
|
* If the order chosen in routing.yml is already in used, find the
|
||||||
@ -99,5 +136,25 @@ class MenuComposer implements ContainerAwareInterface
|
|||||||
return $order;
|
return $order;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addLocalMenuBuilder(LocalMenuBuilderInterface $menuBuilder, $menuId)
|
||||||
|
{
|
||||||
|
$this->localMenuBuilders[$menuId][] = $menuBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param string $menuId
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasLocalMenuBuilder($menuId): bool
|
||||||
|
{
|
||||||
|
return \array_key_exists($menuId, $this->localMenuBuilders);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,10 @@ class MenuTwig extends \Twig_Extension implements ContainerAwareInterface
|
|||||||
public function getFunctions()
|
public function getFunctions()
|
||||||
{
|
{
|
||||||
return [new \Twig_SimpleFunction('chill_menu',
|
return [new \Twig_SimpleFunction('chill_menu',
|
||||||
array($this, 'chillMenu'), array('is_safe' => array('html')))
|
array($this, 'chillMenu'), array(
|
||||||
|
'is_safe' => array('html'),
|
||||||
|
'needs_environment' => true
|
||||||
|
))
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,17 +84,22 @@ class MenuTwig extends \Twig_Extension implements ContainerAwareInterface
|
|||||||
* @param string $menuId
|
* @param string $menuId
|
||||||
* @param mixed[] $params
|
* @param mixed[] $params
|
||||||
*/
|
*/
|
||||||
public function chillMenu($menuId, array $params = array())
|
public function chillMenu(\Twig_Environment $env, $menuId, array $params = array())
|
||||||
{
|
{
|
||||||
$resolvedParams = array_merge($this->defaultParams, $params);
|
$resolvedParams = array_merge($this->defaultParams, $params);
|
||||||
|
|
||||||
$layout = $resolvedParams['layout'];
|
$layout = $resolvedParams['layout'];
|
||||||
unset($resolvedParams['layout']);
|
unset($resolvedParams['layout']);
|
||||||
|
|
||||||
$resolvedParams['routes'] = $this->menuComposer->getRoutesFor($menuId);
|
if ($this->menuComposer->hasLocalMenuBuilder($menuId) === false) {
|
||||||
|
$resolvedParams['routes'] = $this->menuComposer->getRoutesFor($menuId, $resolvedParams);
|
||||||
|
|
||||||
return $this->container->get('templating')
|
return $env->render($layout, $resolvedParams);
|
||||||
->render($layout, $resolvedParams);
|
} else {
|
||||||
|
$resolvedParams['menus'] = $this->menuComposer->getMenuFor($menuId, $resolvedParams);
|
||||||
|
|
||||||
|
return $env->render($layout, $resolvedParams);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
"doctrine/doctrine-migrations-bundle": "~1.3",
|
"doctrine/doctrine-migrations-bundle": "~1.3",
|
||||||
"doctrine/migrations": "~1.0",
|
"doctrine/migrations": "~1.0",
|
||||||
"phpoffice/phpspreadsheet": "~1.2",
|
"phpoffice/phpspreadsheet": "~1.2",
|
||||||
"sensio/distribution-bundle": "^5.0"
|
"sensio/distribution-bundle": "^5.0",
|
||||||
|
"knplabs/knp-menu-bundle": "^2.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"symfony/dom-crawler": "~3.4",
|
"symfony/dom-crawler": "~3.4",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user