0

I need some help or rather some advice.

I have a core bundle with some general functionality and several additional bundles with more specific functionality.

For example my core bundle is responsible for rendering a main menu for my application but I want other bundles to be able to add menu items only by registering the bundle. (In the end those menu items will be available menu items not necessarily actually active ones.)

I have a solution for that but I am not really sure if it is a good one.

My CoreBundle also contains a CoreBundleInterface:

namespace CoreBundle;

use CoreBundle\Menu\MenuBuilder;

interface CoreBundleInterface
{
    public function getMenuItems(MenuBuilder $menuItem);
}

So any other bundle can implement this interface:

namespace AddressBundle;

use CoreBundle\CoreBundleInterface;
use CoreBundle\Menu\MenuBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class AddressBundle extends Bundle implements CoreBundleInterface
{
    public function getMenuItems(MenuBuilder $menuBuilder)
    {
        $menuBuilder->addItem(['name' => 'addresses', 'label' => 'Addresses']);
    }
}

My CoreBundle has a MenuBuilder class which walks through the registered bundles and calls the interface methods:

namespace CoreBundle\Menu;

use CoreBundle\CoreBundleInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class MenuBuilder
{
    private $items;

    public function __construct(ContainerInterface $container)
    {
        $this->addItem(['name' => 'home', 'label' => 'Home']);

        $bundles = $container->get('kernel')->getBundles();
        foreach ($bundles as $bundle) {
            if (is_callable(array($bundle, 'getMenuItems')) && $bundle instanceof CoreBundleInterface) {
                call_user_func(array($bundle, 'getMenuItems'), $this);
            }
        }
    }

    ...

}

I also tried to visualize what structure I want:

enter image description here

Any hint to a better practice to achieve this structure would be very appreciated.

Markus Kottländer
  • 8,228
  • 4
  • 37
  • 61
  • Not so sure about your design. How about having your core bundle implement some sort of menu listener then have other bundles send menu add events? Or maybe have a compiler pass in which bundles would access a menu service and add items? Maybe even use semantic configuration so you can add items in a config file? Putting this kind of stuff directly into a bundle just does not seem right. – Cerad Mar 17 '15 at 01:38
  • How should such a listener look? And it is important to me that menu items or for example some sort of widgets are available in the core bundle as soon as another bundle, which provides menu items or widgets, is registered. – Markus Kottländer Mar 17 '15 at 10:09
  • I don't understand the "as soon as another bundle .. is registered" requirement. I have not seen any code that tries to do much in the bundle object itself. It seems to me that as long as your menu builder is ready when it is need then all is well. Have you looked at some of the other menu bundles out there? – Cerad Mar 17 '15 at 13:47
  • It is not just about the menu but extending core functionality by other bundles. E.g. let a bundle register menu items, widgets, settings options and more so that the core bundle can use them. But I already found a solution with tagged services and compiler passes (http://symfony.com/doc/current/components/dependency_injection/tags.html). – Markus Kottländer Mar 17 '15 at 15:04

0 Answers0