-
Notifications
You must be signed in to change notification settings - Fork 203
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a menu provider registering builders as services
- Loading branch information
Showing
11 changed files
with
386 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
namespace Knp\Bundle\MenuBundle\DependencyInjection\Compiler; | ||
|
||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; | ||
|
||
/** | ||
* This compiler pass registers the menu builders in the BuilderServiceProvider. | ||
* | ||
* @author Christophe Coevoet <stof@notk.org> | ||
*/ | ||
class MenuBuilderPass implements CompilerPassInterface | ||
{ | ||
public function process(ContainerBuilder $container) | ||
{ | ||
$definition = $container->getDefinition('knp_menu.menu_provider.builder_service'); | ||
|
||
$menuBuilders = array(); | ||
foreach ($container->findTaggedServiceIds('knp_menu.menu_builder') as $id => $tags) { | ||
foreach ($tags as $attributes) { | ||
if (empty($attributes['alias'])) { | ||
throw new \InvalidArgumentException(sprintf('The alias is not defined in the "knp_menu.menu_builder" tag for the service "%s"', $id)); | ||
} | ||
if (empty($attributes['method'])) { | ||
throw new \InvalidArgumentException(sprintf('The method is not defined in the "knp_menu.menu_builder" tag for the service "%s"', $id)); | ||
} | ||
$menuBuilders[$attributes['alias']] = array($id, $attributes['method']); | ||
} | ||
} | ||
$definition->replaceArgument(1, $menuBuilders); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?php | ||
|
||
namespace Knp\Bundle\MenuBundle\Provider; | ||
|
||
use Knp\Menu\Provider\MenuProviderInterface; | ||
use Symfony\Component\DependencyInjection\ContainerInterface; | ||
|
||
/** | ||
* This provider uses methods of services to build menus. | ||
* | ||
* @author Christophe Coevoet <stof@notk.org> | ||
*/ | ||
class BuilderServiceProvider implements MenuProviderInterface | ||
{ | ||
private $container; | ||
private $menuBuilders; | ||
|
||
public function __construct(ContainerInterface $container, array $menuBuilders = array()) | ||
{ | ||
$this->container = $container; | ||
$this->menuBuilders = $menuBuilders; | ||
} | ||
|
||
public function get($name, array $options = array()) | ||
{ | ||
if (!isset($this->menuBuilders[$name])) { | ||
throw new \InvalidArgumentException(sprintf('The menu "%s" is not defined.', $name)); | ||
} | ||
|
||
if (!is_array($this->menuBuilders[$name]) || 2 !== count($this->menuBuilders[$name])) { | ||
throw new \InvalidArgumentException(sprintf('The menu builder definition for the menu "%s" is invalid. It should be an array (serviceId, method)', $name)); | ||
} | ||
|
||
list($id, $method) = $this->menuBuilders[$name]; | ||
|
||
return $this->container->get($id)->$method($options); | ||
} | ||
|
||
public function has($name, array $options = array()) | ||
{ | ||
return isset($this->menuBuilders[$name]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
Disabling the Core Menu Providers | ||
================================= | ||
|
||
To be able to use different menu providers together (the builder-service-based | ||
one, the container-based one and the convention-based one for instance), | ||
a chain provider is used. However, it is not used when only one provider | ||
is enabled to increase performance by getting rid of the wrapping. If you | ||
don't want to use the built-in providers, you can disable them through the | ||
configuration: | ||
|
||
.. code-block:: yaml | ||
#app/config/config.yml | ||
knp_menu: | ||
providers: | ||
builder_alias: false # disable the builder-alias-based provider | ||
builder_service: false | ||
container_aware: true # keep this one enabled. Can be omitted as it is the default | ||
.. note:: | ||
|
||
All providers are enabled by default. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
Creating Menu Builders as Services | ||
================================== | ||
|
||
This bundle gives you a really convenient way to create menus by following | ||
a convention and - if needed - injecting the entire container. | ||
|
||
However, if you want to, you can instead choose to create a service for your | ||
menu builder. The advantage of this method is that you can inject the exact | ||
dependencies that your menu builder needs, instead of injecting the entire | ||
service container. This can lead to code that is more testable and also potentially | ||
more reusable. The disadvantage is that it needs just a little more setup. | ||
|
||
Start by creating a builder for your menu. You can stick as many menus into | ||
a builder as you want, so you may only have one (or just a few) of these | ||
builder classes in your application: | ||
|
||
.. code-block:: php | ||
// src/AppBundle/Menu/MenuBuilder.php | ||
namespace AppBundle\Menu; | ||
use Knp\Menu\FactoryInterface; | ||
use Symfony\Component\HttpFoundation\RequestStack; | ||
class MenuBuilder | ||
{ | ||
private $factory; | ||
/** | ||
* @param FactoryInterface $factory | ||
* | ||
* Add any other dependency you need | ||
*/ | ||
public function __construct(FactoryInterface $factory) | ||
{ | ||
$this->factory = $factory; | ||
} | ||
public function createMainMenu(array $options) | ||
{ | ||
$menu = $this->factory->createItem('root'); | ||
$menu->addChild('Home', array('route' => 'homepage')); | ||
// ... add more children | ||
return $menu; | ||
} | ||
} | ||
Next, register your menu builder as service and register its ``createMainMenu`` method as a menu builder: | ||
|
||
.. code-block:: yaml | ||
# app/config/services.yml | ||
services: | ||
app.menu_builder: | ||
class: AppBundle\Menu\MenuBuilder | ||
arguments: ["@knp_menu.factory"] | ||
tags: | ||
- { name: knp_menu.menu_builder, method: createMainMenu, alias: main } # The alias is what is used to retrieve the menu | ||
# ... | ||
.. note:: | ||
|
||
The menu service must be public as it will be retrieved at runtime to keep | ||
it lazy-loaded. | ||
|
||
You can now render the menu directly in a template via the name given in the | ||
``alias`` key above: | ||
|
||
.. code-block:: html+jinja | ||
|
||
{{ knp_menu_render('main') }} | ||
|
||
Suppose now we need to create a second menu for the sidebar. The process | ||
is simple! Start by adding a new method to your builder: | ||
|
||
.. code-block:: php | ||
// src/AppBundle/Menu/MenuBuilder.php | ||
// ... | ||
class MenuBuilder | ||
{ | ||
// ... | ||
public function createSidebarMenu(array $options) | ||
{ | ||
$menu = $this->factory->createItem('sidebar'); | ||
if (isset($options['include_homepage']) && $options['include_homepage']) { | ||
$menu->addChild('Home', array('route' => 'homepage')); | ||
} | ||
// ... add more children | ||
return $menu; | ||
} | ||
} | ||
Now, create a service for *just* your new menu, giving it a new name, like | ||
``sidebar``: | ||
|
||
.. code-block:: yaml | ||
# app/config/services.yml | ||
services: | ||
app.menu_builder: | ||
class: AppBundle\Menu\MenuBuilder | ||
arguments: ["@knp_menu.factory"] | ||
tags: | ||
- { name: knp_menu.menu_builder, method: createMainMenu, alias: main } # the previous menu | ||
- { name: knp_menu.menu_builder, method: createSidebarMenu, alias: sidebar } # Named "sidebar" this time | ||
# ... | ||
It can now be rendered, just like the other menu: | ||
|
||
.. code-block:: html+jinja | ||
|
||
{% set menu = knp_menu_get('sidebar', {include_homepage: false}) %} | ||
{{ knp_menu_render(menu) }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.