mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-11-04 11:18:25 +00:00 
			
		
		
		
	integration of knp menu bundle
This commit is contained in:
		@@ -11,6 +11,7 @@ use Chill\MainBundle\DependencyInjection\RoleProvidersCompilerPass;
 | 
			
		||||
use Chill\MainBundle\DependencyInjection\CompilerPass\ExportsCompilerPass;
 | 
			
		||||
use Chill\MainBundle\DependencyInjection\CompilerPass\WidgetsCompilerPass;
 | 
			
		||||
use Chill\MainBundle\DependencyInjection\CompilerPass\NotificationCounterCompilerPass;
 | 
			
		||||
use Chill\MainBundle\DependencyInjection\CompilerPass\MenuCompilerPass;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ChillMainBundle extends Bundle
 | 
			
		||||
@@ -25,5 +26,6 @@ class ChillMainBundle extends Bundle
 | 
			
		||||
        $container->addCompilerPass(new ExportsCompilerPass());
 | 
			
		||||
        $container->addCompilerPass(new WidgetsCompilerPass());
 | 
			
		||||
        $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/widget.yml');
 | 
			
		||||
        $loader->load('services/controller.yml'); 
 | 
			
		||||
        $loader->load('services/routing.yml');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
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:
 | 
			
		||||
        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>
 | 
			
		||||
	</div>
 | 
			
		||||
    <ul class="submenu width-11-em">
 | 
			
		||||
        {% for route in routes %}
 | 
			
		||||
            <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>
 | 
			
		||||
        {% for menu in menus %}
 | 
			
		||||
            <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 %}
 | 
			
		||||
    </ul>
 | 
			
		||||
</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;
 | 
			
		||||
 | 
			
		||||
use Symfony\Component\Routing\RouteCollection;
 | 
			
		||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
 | 
			
		||||
use Symfony\Component\DependencyInjection\ContainerInterface;
 | 
			
		||||
use Symfony\Component\Routing\RouterInterface;
 | 
			
		||||
use Knp\Menu\FactoryInterface;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class permit to build menu from the routing information
 | 
			
		||||
@@ -14,27 +15,34 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 | 
			
		||||
 *
 | 
			
		||||
 * @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
 | 
			
		||||
     * @param ContainerInterface $container
 | 
			
		||||
     *
 | 
			
		||||
     * @var FactoryInterface
 | 
			
		||||
     */
 | 
			
		||||
    public function setContainer(ContainerInterface $container = null)
 | 
			
		||||
    {
 | 
			
		||||
        if (NULL === $container) {
 | 
			
		||||
            throw new \LogicException('container should not be null');
 | 
			
		||||
        }
 | 
			
		||||
        //see remark in MenuComposer::setRouteCollection
 | 
			
		||||
        $this->container = $container;
 | 
			
		||||
    private $menuFactory;
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @var 
 | 
			
		||||
     */
 | 
			
		||||
    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())
 | 
			
		||||
    {
 | 
			
		||||
        $routes = array();
 | 
			
		||||
        $routeCollection = $this->container->get('router')->getRouteCollection();
 | 
			
		||||
        $routeCollection = $this->router->getRouteCollection();
 | 
			
		||||
 | 
			
		||||
        foreach ($routeCollection->all() as $routeKey => $route) {
 | 
			
		||||
            if ($route->hasOption('menus')) {
 | 
			
		||||
@@ -83,6 +91,35 @@ class MenuComposer implements ContainerAwareInterface
 | 
			
		||||
        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.
 | 
			
		||||
     * If the order chosen in routing.yml is already in used, find the 
 | 
			
		||||
@@ -99,5 +136,25 @@ class MenuComposer implements ContainerAwareInterface
 | 
			
		||||
            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()
 | 
			
		||||
    {
 | 
			
		||||
        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 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);
 | 
			
		||||
 | 
			
		||||
        $layout = $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')
 | 
			
		||||
                ->render($layout, $resolvedParams);
 | 
			
		||||
            return $env->render($layout, $resolvedParams);
 | 
			
		||||
        } else {
 | 
			
		||||
            $resolvedParams['menus'] = $this->menuComposer->getMenuFor($menuId, $resolvedParams);
 | 
			
		||||
            
 | 
			
		||||
            return $env->render($layout, $resolvedParams);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public function getName()
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,8 @@
 | 
			
		||||
        "doctrine/doctrine-migrations-bundle": "~1.3",
 | 
			
		||||
        "doctrine/migrations": "~1.0",
 | 
			
		||||
        "phpoffice/phpspreadsheet": "~1.2",
 | 
			
		||||
        "sensio/distribution-bundle": "^5.0"
 | 
			
		||||
        "sensio/distribution-bundle": "^5.0",
 | 
			
		||||
        "knplabs/knp-menu-bundle": "^2.2"
 | 
			
		||||
    },
 | 
			
		||||
    "require-dev": {
 | 
			
		||||
        "symfony/dom-crawler": "~3.4",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user