浏览代码

Added support for events in menu builder

Martin Hasoň 10 年之前
父节点
当前提交
6a027145b3

+ 55 - 0
Event/ConfigureMenuEvent.php

@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the Sonata package.
+ *
+ * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Sonata\AdminBundle\Event;
+
+use Knp\Menu\FactoryInterface;
+use Knp\Menu\ItemInterface;
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Menu builder event. Used for extending the menus.
+ *
+ * @author  Martin Hasoň <martin.hason@gmail.com>
+ */
+class ConfigureMenuEvent extends Event
+{
+    const SIDEBAR = 'sonata.admin.event.configure.menu.sidebar';
+
+    private $factory;
+    private $menu;
+
+    /**
+     * @param FactoryInterface $factory
+     * @param ItemInterface    $menu
+     */
+    public function __construct(FactoryInterface $factory, ItemInterface $menu)
+    {
+        $this->factory = $factory;
+        $this->menu = $menu;
+    }
+
+    /**
+     * @return FactoryInterface
+     */
+    public function getFactory()
+    {
+        return $this->factory;
+    }
+
+    /**
+     * @return ItemInterface
+     */
+    public function getMenu()
+    {
+        return $this->menu;
+    }
+}

+ 13 - 5
Menu/MenuBuilder.php

@@ -15,6 +15,8 @@ use Knp\Menu\FactoryInterface;
 use Knp\Menu\ItemInterface;
 use Knp\Menu\Provider\MenuProviderInterface;
 use Sonata\AdminBundle\Admin\Pool;
+use Sonata\AdminBundle\Event\ConfigureMenuEvent;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -28,19 +30,22 @@ class MenuBuilder
     private $factory;
     private $provider;
     private $request;
+    private $eventDispatcher;
 
     /**
      * Constructor.
      *
-     * @param Pool                  $pool
-     * @param FactoryInterface      $factory
-     * @param MenuProviderInterface $provider
+     * @param Pool                     $pool
+     * @param FactoryInterface         $factory
+     * @param MenuProviderInterface    $provider
+     * @param EventDispatcherInterface $eventDispatcher
      */
-    public function __construct(Pool $pool, FactoryInterface $factory, MenuProviderInterface $provider)
+    public function __construct(Pool $pool, FactoryInterface $factory, MenuProviderInterface $provider, EventDispatcherInterface $eventDispatcher)
     {
         $this->pool = $pool;
         $this->factory = $factory;
         $this->provider = $provider;
+        $this->eventDispatcher = $eventDispatcher;
     }
 
     /**
@@ -120,7 +125,10 @@ class MenuBuilder
             }
         }
 
-        return $menu;
+        $event = new ConfigureMenuEvent($this->factory, $menu);
+        $this->eventDispatcher->dispatch(ConfigureMenuEvent::SIDEBAR, $event);
+
+        return $event->getMenu();
     }
 
     /**

+ 1 - 0
Resources/config/menu.xml

@@ -9,6 +9,7 @@
             <argument type="service" id="sonata.admin.pool" />
             <argument type="service" id="knp_menu.factory" />
             <argument type="service" id="knp_menu.menu_provider" />
+            <argument type="service" id="event_dispatcher" />
             <call method="setRequest"><argument type="service" id="request" on-invalid="null" strict="false" /></call>
         </service>
 

+ 41 - 2
Resources/doc/cookbook/recipe_knp_menu.rst

@@ -1,7 +1,7 @@
 KnpMenu
 =======
 
-The admin comes with `KnpMenu <https://github.com/KnpLabs/KnpMenu>`_ integration.
+The admin comes with `KnpMenu`_ integration.
 It integrates a menu with the KnpMenu library. This menu can be a SonataAdmin service, a menu created with a Knp menu provider or a route of a custom controller.
 
 Add a custom controller entry in the menu
@@ -81,7 +81,7 @@ The following configuration uses a menu provider to populate the menu group ``my
                     provider:        'MyBundle:MyMenuProvider:getMyMenu'
                     icon:            '<i class="fa fa-edit"></i>'
 
-With KnpMenuBundle you can create a custom menu by using a builder class or by declaring it as a service. Please see the `Knp documentation <http://symfony.com/doc/current/bundles/KnpMenuBundle/index.html#create-your-first-menu>`_ for further information.
+With KnpMenuBundle you can create a custom menu by using a builder class or by declaring it as a service. Please see the `Knp documentation`_ for further information.
 
 In sonata, whatever the implementation you choose, you only have to provide the menu alias to the provider config key:
 
@@ -94,3 +94,42 @@ In sonata, whatever the implementation you choose, you only have to provide the
         </service>
 
 Please note that when using the provider option, you can't set the menu label via the configuration. It is done in your custom menu.
+
+Extending the menu
+------------------
+
+You can modify the menu via events easily. You can register as many listeners as you want for the event with name ``sonata.admin.event.configure.menu.sidebar``:
+
+.. code-block:: php
+
+    // src/AppBundle/EventListener/MenuBuilderListener.php
+    namespace AppBundle\EventListener;
+
+    use Sonata\AdminBundle\Event\ConfigureMenuEvent;
+
+    class MenuBuilderListener
+    {
+        public function addMenuItems(ConfigureMenuEvent $event)
+        {
+            $menu = $event->getMenu();
+
+            $menu->addChild('reports', array(
+                'route' => 'app_reports_index',
+                'labelAttributes' => array('icon' => 'glyphicon glyphicon-stats'),
+            ))->setLabel('Daily and monthly reports');
+        }
+    }
+
+.. code-block:: yaml
+
+    services:
+        app.menu_listener:
+            class: AppBundle\EventListener\MenuBuilderListener
+            tags:
+                - { name: kernel.event_listener, event: sonata.admin.event.configure.menu.sidebar, method: addMenuItems }
+
+Please see the `Using events to allow a menu to be extended`_ for further information.
+
+.. _KnpMenu: https://github.com/KnpLabs/KnpMenu
+.. _Knp documentation: http://symfony.com/doc/current/bundles/KnpMenuBundle/index.html#create-your-first-menu
+.. _Using events to allow a menu to be extended: http://symfony.com/doc/master/bundles/KnpMenuBundle/events.html

+ 27 - 1
Tests/Menu/MenuBuilderTest.php

@@ -19,6 +19,7 @@ class MenuBuilderTest extends \PHPUnit_Framework_TestCase
     private $pool;
     private $provider;
     private $factory;
+    private $eventDispatcher;
     private $builder;
 
     protected function setUp()
@@ -26,8 +27,9 @@ class MenuBuilderTest extends \PHPUnit_Framework_TestCase
         $this->pool = $this->getMockBuilder('Sonata\AdminBundle\Admin\Pool')->disableOriginalConstructor()->getMock();
         $this->provider = $this->getMock('Knp\Menu\Provider\MenuProviderInterface');
         $this->factory = new MenuFactory();
+        $this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
 
-        $this->builder = new MenuBuilder($this->pool, $this->factory, $this->provider);
+        $this->builder = new MenuBuilder($this->pool, $this->factory, $this->provider, $this->eventDispatcher);
     }
 
     public function testGetKnpMenu()
@@ -243,6 +245,30 @@ class MenuBuilderTest extends \PHPUnit_Framework_TestCase
         }
     }
 
+    public function testGetKnpMenuAndDispatchEvent()
+    {
+        $adminGroups = array(
+            "bar" => array(
+                "label" => "foo",
+                "icon"  => '<i class="fa fa-edit"></i>',
+                "label_catalogue"  => 'SonataAdminBundle',
+                "items" => array(),
+                "item_adds" => array(),
+                "roles"     => array(),
+            ),
+        );
+
+        $this->preparePool($adminGroups);
+
+        $this->eventDispatcher
+            ->expects($this->once())
+            ->method('dispatch')
+            ->with($this->equalTo('sonata.admin.event.configure.menu.sidebar'), $this->isInstanceOf('Sonata\AdminBundle\Event\ConfigureMenuEvent'))
+        ;
+
+        $this->builder->createSidebarMenu();
+    }
+
     private function preparePool($adminGroups, $admin = null)
     {
         $this->pool->expects($this->once())