.gitignore 0000666 00000000027 13052362206 0006536 0 ustar 00 composer.lock
vendor/*
.travis.yml 0000666 00000001560 13052362206 0006662 0 ustar 00 language: php
sudo: false
cache:
directory:
- $HOME/.composer/cache/files
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
matrix:
include:
- php: 5.3
env: COMPOSER_FLAGS='--prefer-lowest --prefer-stable' SYMFONY_DEPRECATIONS_HELPER=weak
- php: 5.6
env: DEPENDENCIES='dev' SYMFONY_VERSION='2.8.*@dev'
- php: 5.6
env: SYMFONY_VERSION='2.3.*'
- php: 5.6
env: SYMFONY_VERSION='3.0.*@dev'
before_install:
- composer self-update # remove this once the Travis upgrade of February 2015 is deployed
- if [ "$DEPENDENCIES" == "dev" ]; then perl -pi -e 's/^}$/,"minimum-stability":"dev"}/' composer.json; fi;
- if [ "$SYMFONY_VERSION" != "" ]; then composer require symfony/symfony:${SYMFONY_VERSION}; fi;
install: composer update $COMPOSER_FLAGS
script: phpunit -v
CHANGELOG.md 0000666 00000002165 13052362206 0006364 0 ustar 00 ## 2.1.2 (2016-06-21)
* Menu extensions now also work if you replace the knp_menu.factory service with an alias
* Menu items are translated in the default template
## 2.1.1 (2015-12-15)
* Support Symfony 3
* Documentation fixes
## 2.1.0 (2015-09-28)
* Added a priority to allow controlling the order of voters
* Added new templating features to the templating helper
* Added the necessary configuration for new Twig features of KnpMenu 2.1
* Added a menu provider registering builders as services
* Removed usage of deprecated API to run on Symfony 2.7 without warning
## 2.0.0 (2014-08-01)
* Updated to KnpMenu 2 stable
## 2.0.0 alpha 1 (2013-06-23)
* Updated the bundle for KnpMenu 2.0.0 alpha1
## 1.1.2 (2013-05-25)
* Updated the composer constraint to allow Symfony 2.3 and above
## 1.1.1 (2012-11-28)
* Made the bundle compatible with Symfony 2.2
## 1.1.0 (2012-05-17)
* Updated bundle for KnpMenu 1.1
* Added bundle inheritance support in the BundleAliasProvider
* Added parameters for the default options of the ListRenderer and TwigRenderer
## 1.0.0 (2012-05-03)
* Initial release of the new bundle based on KnpMenu
DependencyInjection/Compiler/AddExtensionsPass.php 0000666 00000003076 13052362206 0016360 0 ustar 00
*/
class AddExtensionsPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->has('knp_menu.factory')) {
return;
}
$taggedServiceIds = $container->findTaggedServiceIds('knp_menu.factory_extension');
if (0 === count($taggedServiceIds)) {
return;
}
$definition = $container->findDefinition('knp_menu.factory');
if (!method_exists($container->getParameterBag()->resolveValue($definition->getClass()), 'addExtension')) {
throw new InvalidConfigurationException(sprintf(
'To use factory extensions, the service of class "%s" registered as knp_menu.factory must implement the "addExtension" method',
$definition->getClass()
));
}
foreach ($taggedServiceIds as $id => $tags) {
foreach ($tags as $tag) {
$priority = isset($tag['priority']) ? $tag['priority'] : 0;
$definition->addMethodCall('addExtension', array(new Reference($id), $priority));
}
}
}
}
DependencyInjection/Compiler/AddProvidersPass.php 0000666 00000002520 13052362206 0016167 0 ustar 00
*/
class AddProvidersPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('knp_menu.menu_provider.chain')) {
return;
}
$providers = array();
foreach ($container->findTaggedServiceIds('knp_menu.provider') as $id => $tags) {
$providers[] = new Reference($id);
}
if (1 === count($providers)) {
// Use an alias instead of wrapping it in the ChainProvider for performances
// when using only one (the default case as the bundle defines one provider)
$container->setAlias('knp_menu.menu_provider', (string) reset($providers));
} else {
$definition = $container->getDefinition('knp_menu.menu_provider.chain');
$definition->replaceArgument(0, $providers);
$container->setAlias('knp_menu.menu_provider', 'knp_menu.menu_provider.chain');
}
}
}
DependencyInjection/Compiler/AddRenderersPass.php 0000666 00000002211 13052362206 0016140 0 ustar 00
*/
class AddRenderersPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('knp_menu.renderer_provider')) {
return;
}
$definition = $container->getDefinition('knp_menu.renderer_provider');
$renderers = array();
foreach ($container->findTaggedServiceIds('knp_menu.renderer') as $id => $tags) {
foreach ($tags as $attributes) {
if (empty($attributes['alias'])) {
throw new \InvalidArgumentException(sprintf('The alias is not defined in the "knp_menu.renderer" tag for the service "%s"', $id));
}
$renderers[$attributes['alias']] = $id;
}
}
$definition->replaceArgument(2, $renderers);
}
}
DependencyInjection/Compiler/AddTemplatePathPass.php 0000666 00000002213 13052362206 0016601 0 ustar 00
*/
class AddTemplatePathPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$loaderDefinition = null;
if ($container->hasDefinition('twig.loader.filesystem')) {
$loaderDefinition = $container->getDefinition('twig.loader.filesystem');
} elseif ($container->hasDefinition('twig.loader')) {
// Symfony 2.0 and 2.1 were not using an alias for the filesystem loader
$loaderDefinition = $container->getDefinition('twig.loader');
}
if (null === $loaderDefinition) {
return;
}
$refl = new \ReflectionClass('Knp\Menu\ItemInterface');
$path = dirname($refl->getFileName()).'/Resources/views';
$loaderDefinition->addMethodCall('addPath', array($path));
}
}
DependencyInjection/Compiler/AddVotersPass.php 0000666 00000002746 13052362206 0015506 0 ustar 00
*/
class AddVotersPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('knp_menu.matcher')) {
return;
}
$definition = $container->getDefinition('knp_menu.matcher');
$listener = $container->getDefinition('knp_menu.listener.voters');
$voters = array();
foreach ($container->findTaggedServiceIds('knp_menu.voter') as $id => $tags) {
foreach ($tags as $tag) {
$priority = isset($tag['priority']) ? (int) $tag['priority'] : 0;
$voters[$priority][] = $id;
if (isset($tag['request']) && $tag['request']) {
$listener->addMethodCall('addVoter', array(new Reference($id)));
}
}
}
if (empty($voters)) {
return;
}
krsort($voters);
$sortedVoters = call_user_func_array('array_merge', $voters);
foreach ($sortedVoters as $id) {
$definition->addMethodCall('addVoter', array(new Reference($id)));
}
}
}
DependencyInjection/Compiler/MenuBuilderPass.php 0000666 00000003446 13052362206 0016024 0 ustar 00
*/
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) {
$builderDefinition = $container->getDefinition($id);
if (!$builderDefinition->isPublic()) {
throw new \InvalidArgumentException(sprintf('Menu builder services must be public but "%s" is a private service.', $id));
}
if ($builderDefinition->isAbstract()) {
throw new \InvalidArgumentException(sprintf('Abstract services cannot be registered as menu builders but "%s" is.', $id));
}
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);
}
}
DependencyInjection/Compiler/MenuPass.php 0000666 00000002005 13052362206 0014503 0 ustar 00 hasDefinition('knp_menu.menu_provider.container_aware')) {
return;
}
$definition = $container->getDefinition('knp_menu.menu_provider.container_aware');
$menus = array();
foreach ($container->findTaggedServiceIds('knp_menu.menu') 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" tag for the service "%s"', $id));
}
$menus[$attributes['alias']] = $id;
}
}
$definition->replaceArgument(1, $menus);
}
}
DependencyInjection/Configuration.php 0000666 00000003047 13052362206 0014014 0 ustar 00
*/
class Configuration implements ConfigurationInterface
{
/**
* Generates the configuration tree.
*
* @return TreeBuilder
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('knp_menu');
$rootNode
->children()
->arrayNode('providers')
->addDefaultsIfNotSet()
->children()
->booleanNode('builder_alias')->defaultTrue()->end()
->booleanNode('container_aware')->defaultTrue()->end()
->booleanNode('builder_service')->defaultTrue()->end()
->end()
->end()
->arrayNode('twig')
->addDefaultsIfNotSet()
->canBeUnset()
->children()
->scalarNode('template')->defaultValue('KnpMenuBundle::menu.html.twig')->end()
->end()
->end()
->booleanNode('templating')->defaultFalse()->end()
->scalarNode('default_renderer')->cannotBeEmpty()->defaultValue('twig')->end()
->end();
return $treeBuilder;
}
}
DependencyInjection/KnpMenuExtension.php 0000666 00000003336 13052362206 0014460 0 ustar 00 load('menu.xml');
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
foreach ($config['providers'] as $builder => $enabled) {
if ($enabled) {
$container->getDefinition(sprintf('knp_menu.menu_provider.%s', $builder))->addTag('knp_menu.provider');
}
}
if (isset($config['twig'])) {
$loader->load('twig.xml');
$container->setParameter('knp_menu.renderer.twig.template', $config['twig']['template']);
}
if ($config['templating']) {
$loader->load('templating.xml');
}
$container->setParameter('knp_menu.default_renderer', $config['default_renderer']);
}
/**
* {@inheritdoc}
*/
public function getNamespace()
{
return 'http://knplabs.com/schema/dic/menu';
}
/**
* {@inheritdoc}
*/
public function getXsdValidationBasePath()
{
return __DIR__ . '/../Resources/config/schema';
}
}
EventListener/VoterInitializerListener.php 0000666 00000002366 13052362206 0015067 0 ustar 00
*/
class VoterInitializerListener implements EventSubscriberInterface
{
protected $voters = array();
public function onKernelRequest(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
foreach ($this->voters as $voter) {
if (method_exists($voter, 'setRequest')) {
$voter->setRequest($event->getRequest());
}
}
}
/**
* Adds a voter in the matcher.
*
* @param VoterInterface $voter
*/
public function addVoter(VoterInterface $voter)
{
$this->voters[] = $voter;
}
public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => 'onKernelRequest',
);
}
}
KnpMenuBundle.php 0000666 00000002276 13052362206 0007776 0 ustar 00 addCompilerPass(new MenuPass());
$container->addCompilerPass(new MenuBuilderPass());
$container->addCompilerPass(new AddExtensionsPass());
$container->addCompilerPass(new AddProvidersPass());
$container->addCompilerPass(new AddRenderersPass());
$container->addCompilerPass(new AddTemplatePathPass());
$container->addCompilerPass(new AddVotersPass());
}
}
LICENSE 0000666 00000002064 13052362206 0005556 0 ustar 00 Copyright (c) 2011 KnpLabs - http://www.knplabs.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Provider/BuilderAliasProvider.php 0000666 00000010447 13052362206 0013133 0 ustar 00
*/
class BuilderAliasProvider implements MenuProviderInterface
{
private $kernel;
private $container;
private $menuFactory;
private $builders = array();
public function __construct(KernelInterface $kernel, ContainerInterface $container, FactoryInterface $menuFactory)
{
$this->kernel = $kernel;
$this->container = $container;
$this->menuFactory = $menuFactory;
}
/**
* Looks for a menu with the bundle:class:method format
*
* For example, AcmeBundle:Builder:mainMenu would create and instantiate
* an Acme\DemoBundle\Menu\Builder class and call the mainMenu() method
* on it. The method is passed the menu factory.
*
* @param string $name The alias name of the menu
* @param array $options
*
* @return \Knp\Menu\ItemInterface
* @throws \InvalidArgumentException
*/
public function get($name, array $options = array())
{
if (!$this->has($name)) {
throw new \InvalidArgumentException(sprintf('Invalid pattern passed to AliasProvider - expected "bundle:class:method", got "%s".', $name));
}
list($bundleName, $className, $methodName) = explode(':', $name);
$builder = $this->getBuilder($bundleName, $className);
if (!method_exists($builder, $methodName)) {
throw new \InvalidArgumentException(sprintf('Method "%s" was not found on class "%s" when rendering the "%s" menu.', $methodName, $className, $name));
}
$menu = $builder->$methodName($this->menuFactory, $options);
if (!$menu instanceof ItemInterface) {
throw new \InvalidArgumentException(sprintf('Method "%s" did not return an ItemInterface menu object for menu "%s"', $methodName, $name));
}
return $menu;
}
/**
* Verifies if the given name follows the bundle:class:method alias syntax.
*
* @param string $name The alias name of the menu
* @param array $options
*
* @return Boolean
*/
public function has($name, array $options = array())
{
return 2 == substr_count($name, ':');
}
/**
* Creates and returns the builder that lives in the given bundle
*
* The convention is to look in the Menu namespace of the bundle for
* this class, to instantiate it with no arguments, and to inject the
* container if the class is ContainerAware.
*
* @param string $bundleName
* @param string $className The class name of the builder
*
* @throws \InvalidArgumentException If the class does not exist
*/
protected function getBuilder($bundleName, $className)
{
$name = sprintf('%s:%s', $bundleName, $className);
if (!isset($this->builders[$name])) {
$class = null;
$logs = array();
$bundles = array();
foreach ($this->kernel->getBundle($bundleName, false) as $bundle) {
$try = $bundle->getNamespace().'\\Menu\\'.$className;
if (class_exists($try)) {
$class = $try;
break;
}
$logs[] = sprintf('Class "%s" does not exist for menu builder "%s".', $try, $name);
$bundles[] = $bundle->getName();
}
if (null === $class) {
if (1 === count($logs)) {
throw new \InvalidArgumentException($logs[0]);
}
throw new \InvalidArgumentException(sprintf('Unable to find menu builder "%s" in bundles %s.', $name, implode(', ', $bundles)));
}
$builder = new $class();
if ($builder instanceof ContainerAwareInterface) {
$builder->setContainer($this->container);
}
$this->builders[$name] = $builder;
}
return $this->builders[$name];
}
}
Provider/BuilderServiceProvider.php 0000666 00000002455 13052362206 0013502 0 ustar 00
*/
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]);
}
}
Provider/ContainerAwareProvider.php 0000666 00000001516 13052362206 0013472 0 ustar 00 container = $container;
$this->menuIds = $menuIds;
}
public function get($name, array $options = array())
{
if (!isset($this->menuIds[$name])) {
throw new \InvalidArgumentException(sprintf('The menu "%s" is not defined.', $name));
}
return $this->container->get($this->menuIds[$name]);
}
public function has($name, array $options = array())
{
return isset($this->menuIds[$name]);
}
}
README.md 0000666 00000002623 13052362206 0006031 0 ustar 00 KnpMenuBundle
=============
The `KnpMenuBundle` integrates the [KnpMenu](https://github.com/KnpLabs/KnpMenu)
PHP library with Symfony. This means easy-to-implement and feature-rich menus
in your Symfony application!
[![Build Status](https://secure.travis-ci.org/KnpLabs/KnpMenuBundle.png)](http://travis-ci.org/KnpLabs/KnpMenuBundle)
[![Latest Stable Version](https://poser.pugx.org/knplabs/knp-menu-bundle/v/stable.png)](https://packagist.org/packages/knplabs/knp-menu-bundle)
[![Latest Unstable Version](https://poser.pugx.org/knplabs/knp-menu-bundle/v/unstable.png)](https://packagist.org/packages/knplabs/knp-menu-bundle)
[![knpbundles.com](http://knpbundles.com/KnpLabs/KnpMenuBundle/badge-short)](http://knpbundles.com/KnpLabs/KnpMenuBundle)
### What now?
Documentation! The documentation for this bundle is available in the `Resources/doc`
directory of the bundle:
* Read the [KnpMenuBundle documentation](http://symfony.com/doc/master/bundles/KnpMenuBundle/index.html)
This bundle's job is to integrate a standalone PHP menu library called [KnpMenu](https://github.com/KnpLabs/KnpMenu).
You can learn a lot more about how this library works by reading that library's
documentation.
## Credits
This bundle was originally ported from [ioMenuPlugin](http://github.com/weaverryan/ioMenuPlugin),
a menu plugin for symfony1. It has since been developed by [knpLabs](http://www.knplabs.com) and
the Symfony community.
Renderer/ContainerAwareProvider.php 0000666 00000001767 13052362206 0013456 0 ustar 00 container = $container;
$this->rendererIds = $rendererIds;
$this->defaultRenderer = $defaultRenderer;
}
public function get($name = null)
{
if (null === $name) {
$name = $this->defaultRenderer;
}
if (!isset($this->rendererIds[$name])) {
throw new \InvalidArgumentException(sprintf('The renderer "%s" is not defined.', $name));
}
return $this->container->get($this->rendererIds[$name]);
}
public function has($name)
{
return isset($this->rendererIds[$name]);
}
}
Resources/config/menu.xml 0000666 00000010632 13052362206 0011456 0 ustar 00
Knp\Menu\MenuFactory
Knp\Menu\Integration\Symfony\RoutingExtension
Knp\Menu\Twig\Helper
Knp\Menu\Matcher\Matcher
Knp\Menu\Provider\ChainProvider
Knp\Bundle\MenuBundle\Provider\ContainerAwareProvider
Knp\Bundle\MenuBundle\Provider\BuilderAliasProvider
Knp\Bundle\MenuBundle\Renderer\ContainerAwareProvider
Knp\Menu\Renderer\ListRenderer
Knp\Bundle\MenuBundle\EventListener\VoterInitializerListener
Knp\Menu\Matcher\Voter\RouteVoter
Resources/config/schema/menu-1.0.xsd 0000666 00000002201 13052362206 0013201 0 ustar 00
Resources/config/templating.xml 0000666 00000001473 13052362206 0012661 0 ustar 00
Knp\Bundle\MenuBundle\Templating\Helper\MenuHelper
Resources/config/twig.xml 0000666 00000002565 13052362206 0011472 0 ustar 00
Knp\Menu\Twig\MenuExtension
Knp\Menu\Renderer\TwigRenderer
Resources/doc/custom_provider.rst 0000666 00000005214 13052362206 0013246 0 ustar 00 Registering your own provider
=============================
Registering your own menu provider allows you to feed your menu with your own
data, accessed by your code. It can for example go through a PHPCR repository
and create the corresponding menu elements.
Create first your Provider class, in the Provider directory of your bundle:
.. code-block:: php
namespace AppBundle\Provider;
use Knp\Menu\FactoryInterface;
use Knp\Menu\Provider\MenuProviderInterface;
class CustomMenuProvider implements MenuProviderInterface
{
/**
* @var FactoryInterface
*/
protected $factory = null;
/**
* @param FactoryInterface $factory the menu factory used to create the menu item
*/
public function __construct(FactoryInterface $factory)
{
$this->factory = $factory;
}
/**
* Retrieves a menu by its name
*
* @param string $name
* @param array $options
* @return \Knp\Menu\ItemInterface
* @throws \InvalidArgumentException if the menu does not exists
*/
public function get($name, array $options = array())
{
if ('demo' == $name) { //several menu could call this provider
$menu = /* construct / get a \Knp\Menu\NodeInterface */;
if ($menu === null) {
throw new \InvalidArgumentException(sprintf('The menu "%s" is not defined.', $name));
}
/*
* Populate your menu here
*/
$menuItem = $this->factory->createFromNode($menu);
return $menuItem;
}
}
/**
* Checks whether a menu exists in this provider
*
* @param string $name
* @param array $options
* @return bool
*/
public function has($name, array $options = array())
{
$menu = /* find the menu called $name */;
return $menu !== null;
}
}
Then, configure the services linked to this new provider.
.. code-block:: yaml
# app/config/services.yml
services:
app.menu_provider:
class: AppBundle\Provider\CustomMenuProvider
arguments:
- @knp_menu.factory
tags:
- { name: knp_menu.provider }
# ...
Finally, to generate the menu, for example inside a twig template type:
.. code-block:: html+jinja
{{ knp_menu_render('demo') }}
The `Symfony CMF MenuBundle`_ provides a complete working example.
.. _`Symfony CMF MenuBundle`: https://github.com/symfony-cmf/MenuBundle
Resources/doc/custom_renderer.rst 0000666 00000003437 13052362206 0013227 0 ustar 00 Registering your own renderer
=============================
Registering your own renderer in the renderer provider is simply a matter
of creating a service tagged with ``knp_menu.renderer``:
.. code-block:: yaml
# app/config/services.yml
services:
app.menu_renderer:
# The class implements Knp\Menu\Renderer\RendererInterface
class: AppBundle\Menu\CustomRenderer
arguments: ["%kernel.charset%"] # set your own dependencies here
tags:
# The alias is what is used to retrieve the menu
- { name: knp_menu.renderer, alias: custom }
# ...
If your renderer extends ``ListRenderer``, you need to provide a ``Matcher`` instance.
The configuration is then the following:
.. code-block:: yaml
# app/config/services.yml
services:
app.menu_renderer:
# The class implements Knp\Menu\Renderer\RendererInterface
class: AppBundle\Menu\CustomRenderer
arguments:
- @knp_menu.matcher
- "%knp_menu.renderer.list.options%"
- "%kernel.charset%"
# add your own dependencies here
tags:
# The alias is what is used to retrieve the menu
- { name: knp_menu.renderer, alias: custom }
# ...
.. note::
The renderer service must be public as it will be retrieved at runtime to
keep it lazy-loaded.
You can now use your renderer to render your menu:
.. code-block:: html+jinja
{{ knp_menu_render('main', {}, 'custom') }}
.. note::
As the renderer is responsible to render some HTML code, the ``knp_menu_render``
function is marked as safe. Take care to handle escaping data in your renderer
to avoid XSS if you use some user input in the menu.
Resources/doc/disabling_providers.rst 0000666 00000001446 13052362206 0014056 0 ustar 00 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.
Resources/doc/events.rst 0000666 00000007776 13052362206 0011345 0 ustar 00 Using events to allow a menu to be extended
===========================================
If you want to let different parts of your system hook into the building of your
menu, a good way is to use an approach based on the Symfony EventDispatcher
component.
Create the menu builder
-----------------------
Your menu builder will create the base menu item and then dispatch an event
to allow other parts of your application to add more stuff to it.
.. code-block:: php
// src/AppBundle/Menu/MainBuilder.php
namespace AppBundle\Menu;
use AppBundle\Event\ConfigureMenuEvent;
use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAware;
class MainBuilder extends ContainerAware
{
public function build(FactoryInterface $factory)
{
$menu = $factory->createItem('root');
$menu->setCurrentUri($this->container->get('request')->getRequestUri());
$menu->addChild('Dashboard', array('route' => '_acp_dashboard'));
$this->container->get('event_dispatcher')->dispatch(
ConfigureMenuEvent::CONFIGURE,
new ConfigureMenuEvent($factory, $menu)
);
return $menu;
}
}
.. note::
This implementation assumes you use the ``BuilderAliasProvider`` (getting
your menu as ``AppBundle:MainBuilder:build``) but you could also define
it as a service and inject the ``event_dispatcher`` service as a dependency.
Create the Event object
-----------------------
The event object allows to pass some data to the listener. In this case,
it will hold the menu being created and the factory.
.. code-block:: php
// src/AppBundle/Event/ConfigureMenuEvent.php
namespace AppBundle\Event;
use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
use Symfony\Component\EventDispatcher\Event;
class ConfigureMenuEvent extends Event
{
const CONFIGURE = 'app.menu_configure';
private $factory;
private $menu;
/**
* @param \Knp\Menu\FactoryInterface $factory
* @param \Knp\Menu\ItemInterface $menu
*/
public function __construct(FactoryInterface $factory, ItemInterface $menu)
{
$this->factory = $factory;
$this->menu = $menu;
}
/**
* @return \Knp\Menu\FactoryInterface
*/
public function getFactory()
{
return $this->factory;
}
/**
* @return \Knp\Menu\ItemInterface
*/
public function getMenu()
{
return $this->menu;
}
}
.. note::
Following the Symfony best practices, the first segment of the event name will
be the alias of the bundle, which allows avoiding conflicts.
That's it. Your builder now provides a hook. Let's see how you can use it!
Create a listener
-----------------
You can register as many listeners as you want for the event. Let's add one.
.. code-block:: php
// src/Acme/AdminBundle/EventListener/ConfigureMenuListener.php
namespace Acme\AdminBundle\EventListener;
use AppBundle\Event\ConfigureMenuEvent;
class ConfigureMenuListener
{
/**
* @param \AppBundle\Event\ConfigureMenuEvent $event
*/
public function onMenuConfigure(ConfigureMenuEvent $event)
{
$menu = $event->getMenu();
$menu->addChild('Matches', array('route' => 'versus_rankedmatch_acp_matches_index'));
$menu->addChild('Participants', array('route' => 'versus_rankedmatch_acp_participants_index'));
}
}
You can now register the listener.
.. code-block:: yaml
# app/config/services.yml
services:
app.admin_configure_menu_listener:
class: Acme\AdminBundle\EventListener\ConfigureMenuListener
tags:
- { name: kernel.event_listener, event: app.menu_configure, method: onMenuConfigure }
You could also create your listener as a subscriber and use the ``kernel.event_subscriber``
tag, which does not have any additional attributes.
Resources/doc/i18n.rst 0000666 00000003502 13052362206 0010577 0 ustar 00 I18n for your Menu Labels
=========================
The KnpMenuBundle translates all menu items by default. Assume you've built a menu
like this::
$menu = $factory->createItem('root');
$menu->addChild('Home', array('route' => 'homepage'));
$menu->addChild('Login', array('route' => 'login'));
The items "Home" and "Login" can now be translated in the message domain:
.. configuration-block::
.. code-block:: yaml
# app/Resources/translations/messages.fr.yml
Home: Accueil
Login: Connexion
.. code-block:: xml
.. code-block:: php
// app/Resources/translations/messages.fr.php
return array(
'Home' => 'Accueil',
'Login' => 'Connexion',
);
Configure the Translation Domain
--------------------------------
You can configure the translation domain that's used in the extras of the menu
item::
// ...
$menu->addChild('Home', array('route' => 'homepage'))
->setExtra('translation_domain', 'AcmeAdminBundle');
Disabling Translation
---------------------
You can disable translation of the menu item by setting ``translation_domain``
to ``false``.
Resources/doc/index.rst 0000666 00000023535 13052362206 0011137 0 ustar 00 Using KnpMenuBundle
===================
Welcome to KnpMenuBundle - creating menus is fun again!
Installation
------------
Step 1: Download the Bundle
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Open a command console, enter your project directory and execute the
following command to download the latest stable version of this bundle:
.. code-block:: bash
$ composer require knplabs/knp-menu-bundle "^2.0"
This command requires you to have Composer installed globally, as explained
in the `installation chapter`_ of the Composer documentation.
Step 2: Enable the Bundle
~~~~~~~~~~~~~~~~~~~~~~~~~
Then, enable the bundle by adding the following line in the ``app/AppKernel.php``
file of your project:
.. code-block:: php
// app/AppKernel.php
// ...
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
// ...
new Knp\Bundle\MenuBundle\KnpMenuBundle(),
);
// ...
}
// ...
}
Step 3: (optional) Configure the bundle
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The bundle comes with a sensible default configuration, which is listed below.
You can define these options if you need to change them:
.. configuration-block::
.. code-block:: yaml
# app/config/config.yml
knp_menu:
# use "twig: false" to disable the Twig extension and the TwigRenderer
twig:
template: KnpMenuBundle::menu.html.twig
# if true, enables the helper for PHP templates
templating: false
# the renderer to use, list is also available by default
default_renderer: twig
.. code-block:: xml
.. code-block:: php
// app/config/config.php
$container->loadFromExtension('knp_menu', array(
// use 'twig' => false to disable the Twig extension and the TwigRenderer
'twig' => array(
'template' => 'KnpMenuBundle::menu.html.twig'
),
// if true, enabled the helper for PHP templates
'templating' => false,
// the renderer to use, list is also available by default
'default_renderer' => 'twig',
));
.. versionadded::2.1.2
The template used to be ``knp_menu.html.twig`` which did not translate menu entries.
Version 2.1.2 adds the template that translates menu entries.
.. note::
Take care to change the default renderer if you disable the Twig support.
Create your first menu!
-----------------------
There are two ways to create a menu: the "easy" way, and the more flexible
method of creating a menu as a service.
Method a) The Easy Way (yay)!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To create a menu, first create a new class in the ``Menu`` directory of one
of your bundles. This class - called ``Builder`` in our example - will have
one method for each menu that you need to build.
An example builder class would look like this:
.. code-block:: php
// src/AppBundle/Menu/Builder.php
namespace AppBundle\Menu;
use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
class Builder implements ContainerAwareInterface
{
use ContainerAwareTrait;
public function mainMenu(FactoryInterface $factory, array $options)
{
$menu = $factory->createItem('root');
$menu->addChild('Home', array('route' => 'homepage'));
// access services from the container!
$em = $this->container->get('doctrine')->getManager();
// findMostRecent and Blog are just imaginary examples
$blog = $em->getRepository('AppBundle:Blog')->findMostRecent();
$menu->addChild('Latest Blog Post', array(
'route' => 'blog_show',
'routeParameters' => array('id' => $blog->getId())
));
// create another menu item
$menu->addChild('About Me', array('route' => 'about'));
// you can also add sub level's to your menu's as follows
$menu['About Me']->addChild('Edit profile', array('route' => 'edit_profile'));
// ... add more children
return $menu;
}
}
With the standard ``knp_menu.html.twig`` template and your current page being
'Home', your menu would render with the following markup:
.. code-block:: html
.. note::
You only need to implement ``ContainerAwareInterface`` if you need the
service container. The more elegant way to handle your dependencies is to
inject them in the constructor. If you want to do that, see method below.
.. note::
The menu builder can be overwritten using the bundle inheritance.
To actually render the menu, just do the following from anywhere in any template:
.. configuration-block::
.. code-block:: html+jinja
{{ knp_menu_render('AppBundle:Builder:mainMenu') }}
.. code-block:: html+php
render('AppBundle:Builder:mainMenu') ?>
With this method, you refer to the menu using a three-part string:
**bundle**:**class**:**method**.
If you needed to create a second menu, you'd simply add another method to
the ``Builder`` class (e.g. ``sidebarMenu``), build and return the new menu,
then render it via ``AppBundle:Builder:sidebarMenu``.
That's it! The menu is *very* configurable. For more details, see the
`KnpMenu documentation`_.
Method b) A menu builder as a service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For information on how to register a menu builder as a service, read
:doc:`Creating Menu Builders as Services `.
Method c) A menu as a service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For information on how to register a service and tag it as a menu, read
:doc:`Creating Menus as Services `.
.. note::
To improve performances, you can :doc:`disable providers you don't need `.
Rendering Menus
---------------
Once you've setup your menu, rendering it easy. If you've used the "easy"
way, then do the following:
.. configuration-block::
.. code-block:: html+jinja
{{ knp_menu_render('AppBundle:Builder:mainMenu') }}
.. code-block:: html+php
render('AppBundle:Builder:mainMenu') ?>
Additionally, you can pass some options to the renderer:
.. configuration-block::
.. code-block:: html+jinja
{{ knp_menu_render('AppBundle:Builder:mainMenu', {'depth': 2, 'currentAsLink': false}) }}
.. code-block:: html+php
render('AppBundle:Builder:mainMenu', array(
'depth' => 2,
'currentAsLink' => false,
)) ?>
For a full list of options, see the "Other rendering options" header on the
`KnpMenu documentation`_.
You can also "get" a menu, which you can use to render later:
.. configuration-block::
.. code-block:: html+jinja
{% set menuItem = knp_menu_get('AppBundle:Builder:mainMenu') %}
{{ knp_menu_render(menuItem) }}
.. code-block:: html+php
get('AppBundle:Builder:mainMenu') ?>
render($menuItem) ?>
If you want to only retrieve a certain branch of the menu, you can do the
following, where 'Contact' is one of the root menu items and has children
beneath it.
.. configuration-block::
.. code-block:: html+jinja
{% set menuItem = knp_menu_get('AppBundle:Builder:mainMenu', ['Contact']) %}
{{ knp_menu_render(['AppBundle:Builder:mainMenu', 'Contact']) }}
.. code-block:: html+php
get('AppBundle:Builder:mainMenu', array('Contact')) ?>
render(array('AppBundle:Builder:mainMenu', 'Contact')) ?>
If you want to pass some options to the builder, you can use the third parameter
of the ``knp_menu_get`` function:
.. configuration-block::
.. code-block:: html+jinja
{% set menuItem = knp_menu_get('AppBundle:Builder:mainMenu', [], {'some_option': 'my_value'}) %}
{{ knp_menu_render(menuItem) }}
.. code-block:: html+php
get('AppBundle:Builder:mainMenu', array(), array(
'some_option' => 'my_value'
)) ?>
render($menuItem) ?>
More Advanced Stuff
-------------------
.. toctree::
:maxdepth: 1
menu_service
menu_builder_service
i18n
events
custom_renderer
custom_provider
disabling_providers
.. _`installation chapter`: https://getcomposer.org/doc/00-intro.md
.. _`KnpMenu documentation`: https://github.com/KnpLabs/KnpMenu/blob/master/doc/01-Basic-Menus.markdown
Resources/doc/menu_builder_service.rst 0000666 00000006767 13052362206 0014232 0 ustar 00 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;
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) }}
Resources/doc/menu_service.rst 0000666 00000010132 13052362206 0012501 0 ustar 00 Creating Menus as Services
==========================
.. note::
Registering a menu as service comes with several limitations:
- it does not allow to use builder options
- it reuses the same instance several times in case you render the same
menu several times, which can have weird side-effects.
It is recommended to register only :doc:`menu builders as services `
instead.
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 object. The advantage of this method is that you can inject the exact
dependencies that your menu 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
*/
public function __construct(FactoryInterface $factory)
{
$this->factory = $factory;
}
public function createMainMenu(RequestStack $requestStack)
{
$menu = $this->factory->createItem('root');
$menu->addChild('Home', array('route' => 'homepage'));
// ... add more children
return $menu;
}
}
Next, register two services: one for your menu builder, and one for the menu
object created by the ``createMainMenu`` method:
.. code-block:: yaml
# app/config/services.yml
services:
app.menu_builder:
class: AppBundle\Menu\MenuBuilder
arguments: ["@knp_menu.factory"]
app.main_menu:
class: Knp\Menu\MenuItem # the service definition requires setting the class
factory: ["@app.menu_builder", createMainMenu]
arguments: ["@request_stack"]
tags:
- { name: knp_menu.menu, 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.
.. note::
If you are using Symfony `2.5` or older version please check the `Using a Factory to Create Services`_
article for correct factories syntax corresponding to your version.
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(RequestStack $requestStack)
{
$menu = $this->factory->createItem('sidebar');
$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.sidebar_menu:
class: Knp\Menu\MenuItem
factory: ["@app.menu_builder", createSidebarMenu]
arguments: ["@request_stack"]
tags:
- { name: knp_menu.menu, alias: sidebar } # Named "sidebar" this time
# ...
It can now be rendered, just like the other menu:
.. code-block:: html+jinja
{{ knp_menu_render('sidebar') }}
.. _`Using a Factory to Create Services`: http://symfony.com/doc/2.5/components/dependency_injection/factories.html
Resources/views/menu.html.twig 0000666 00000000742 13052362206 0012464 0 ustar 00 {% extends 'knp_menu.html.twig' %}
{% block label %}
{%- set translation_domain = item.extra('translation_domain', 'messages') -%}
{%- set label = item.label -%}
{%- if translation_domain is not same as(false) -%}
{%- set label = label|trans(item.extra('translation_params', {}), translation_domain) -%}
{%- endif -%}
{%- if options.allow_safe_labels and item.extra('safe_label', false) %}{{ label|raw }}{% else %}{{ label }}{% endif -%}
{% endblock %}
Templating/Helper/MenuHelper.php 0000666 00000006263 13052362206 0012656 0 ustar 00 helper = $helper;
$this->matcher = $matcher;
$this->menuManipulator = $menuManipulator;
}
/**
* Retrieves an item following a path in the tree.
*
* @param \Knp\Menu\ItemInterface|string $menu
* @param array $path
* @param array $options
*
* @return \Knp\Menu\ItemInterface
*/
public function get($menu, array $path = array(), array $options = array())
{
return $this->helper->get($menu, $path, $options);
}
/**
* Renders a menu with the specified renderer.
*
* @param \Knp\Menu\ItemInterface|string|array $menu
* @param array $options
* @param string $renderer
*
* @return string
*/
public function render($menu, array $options = array(), $renderer = null)
{
return $this->helper->render($menu, $options, $renderer);
}
/**
* Returns an array ready to be used for breadcrumbs.
*
* @param ItemInterface|array|string $menu
* @param string|array|null $subItem
*
* @return array
*/
public function getBreadcrumbsArray($menu, $subItem = null)
{
return $this->helper->getBreadcrumbsArray($menu, $subItem);
}
/**
* A string representation of this menu item
*
* e.g. Top Level 1 > Second Level > This menu
*
* @param ItemInterface $menu
* @param string $separator
*
* @return string
*/
public function getPathAsString(ItemInterface $menu, $separator = ' > ')
{
return $this->menuManipulator->getPathAsString($menu, $separator);
}
/**
* Checks whether an item is current.
*
* @param ItemInterface $item
*
* @return boolean
*/
public function isCurrent(ItemInterface $item)
{
return $this->matcher->isCurrent($item);
}
/**
* Checks whether an item is the ancestor of a current item.
*
* @param ItemInterface $item
* @param integer $depth The max depth to look for the item
*
* @return boolean
*/
public function isAncestor(ItemInterface $item, $depth = null)
{
return $this->matcher->isAncestor($item, $depth);
}
/**
* Returns the current item of a menu.
*
* @param ItemInterface|array|string $menu
*
* @return ItemInterface|null
*/
public function getCurrentItem($menu)
{
return $this->helper->getCurrentItem($menu);
}
/**
* @return string
*/
public function getName()
{
return 'knp_menu';
}
}
Tests/DependencyInjection/Compiler/AddExtensionsPassTest.php 0000666 00000012020 13052362206 0020307 0 ustar 00 getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilder->expects($this->once())
->method('has')
->will($this->returnValue(false));
$containerBuilder->expects($this->never())
->method('findTaggedServiceIds');
$menuPass = new AddExtensionsPass();
$menuPass->process($containerBuilder);
}
public function testProcessWithAlias()
{
$menuFactoryClass = 'Knp\Bundle\MenuBundle\Tests\DependencyInjection\Compiler\MenuFactoryMock';
$definitionMock = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')
->disableOriginalConstructor()
->getMock();
$definitionMock->expects($this->at(0))
->method('getClass')
->will($this->returnValue($menuFactoryClass));
$definitionMock->expects($this->at(1))
->method('addMethodCall')
->with($this->equalTo('addExtension'), $this->equalTo(array(new Reference('id'), 0)));
$definitionMock->expects($this->at(2))
->method('addMethodCall')
->with($this->equalTo('addExtension'), $this->equalTo(array(new Reference('id'), 12)));
$definitionMock->expects($this->at(3))
->method('addMethodCall')
->with($this->equalTo('addExtension'), $this->equalTo(array(new Reference('foo'), -4)));
$parameterBagMock = $this->getMock('Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface');
$parameterBagMock->expects($this->once())
->method('resolveValue')
->with($menuFactoryClass)
->will($this->returnValue($menuFactoryClass));
$containerBuilderMock = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilderMock->expects($this->once())
->method('has')
->will($this->returnValue(true));
$containerBuilderMock->expects($this->once())
->method('findTaggedServiceIds')
->with($this->equalTo('knp_menu.factory_extension'))
->will($this->returnValue(array('id' => array('tag1' => array(), 'tag2' => array('priority' => 12)), 'foo' => array('tag1' => array('priority' => -4)))));
$containerBuilderMock->expects($this->once())
->method('findDefinition')
->with($this->equalTo('knp_menu.factory'))
->will($this->returnValue($definitionMock));
$containerBuilderMock->expects($this->once())
->method('getParameterBag')
->will($this->returnValue($parameterBagMock));
$menuPass = new AddExtensionsPass();
$menuPass->process($containerBuilderMock);
}
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testMissingAddExtension()
{
$definitionMock = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')
->disableOriginalConstructor()
->getMock();
$definitionMock->expects($this->at(0))
->method('getClass')
->will($this->returnValue('SimpleMenuFactory'));
$parameterBagMock = $this->getMock('Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface');
$parameterBagMock->expects($this->once())
->method('resolveValue')
->with('SimpleMenuFactory')
->will($this->returnValue('SimpleMenuFactory'));
$containerBuilderMock = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilderMock->expects($this->once())
->method('has')
->will($this->returnValue(true));
$containerBuilderMock->expects($this->once())
->method('findTaggedServiceIds')
->with($this->equalTo('knp_menu.factory_extension'))
->will($this->returnValue(array('id' => array('tag1' => array(), 'tag2' => array('priority' => 12)), 'foo' => array('tag1' => array('priority' => -4)))));
$containerBuilderMock->expects($this->once())
->method('findDefinition')
->with($this->equalTo('knp_menu.factory'))
->will($this->returnValue($definitionMock));
$containerBuilderMock->expects($this->once())
->method('getParameterBag')
->will($this->returnValue($parameterBagMock));
$menuPass = new AddExtensionsPass();
$menuPass->process($containerBuilderMock);
}
}
class MenuFactoryMock implements FactoryInterface
{
public function createItem($name, array $options = array())
{
}
public function addExtension()
{
}
}
Tests/DependencyInjection/Compiler/AddProvidersPassTest.php 0000666 00000006024 13052362206 0020134 0 ustar 00 getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilder->expects($this->once())
->method('hasDefinition')
->will($this->returnValue(false));
$containerBuilder->expects($this->never())
->method('findTaggedServiceIds');
$providersPass = new AddProvidersPass();
$providersPass->process($containerBuilder);
}
public function testProcessForOneProvider()
{
$containerBuilderMock = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilderMock->expects($this->once())
->method('hasDefinition')
->will($this->returnValue(true));
$containerBuilderMock->expects($this->once())
->method('findTaggedServiceIds')
->with($this->equalTo('knp_menu.provider'))
->will($this->returnValue(array('id' => array('provider_tag1'))));
$containerBuilderMock->expects($this->once())
->method('setAlias')
->with(
$this->equalTo('knp_menu.menu_provider'),
$this->equalTo('id')
);
$providersPass = new AddProvidersPass();
$providersPass->process($containerBuilderMock);
}
public function testProcessForManyProviders()
{
$definitionMock = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')
->disableOriginalConstructor()
->getMock();
$definitionMock->expects($this->once())
->method('replaceArgument')
->with($this->equalTo(0), $this->isType('array'));
$containerBuilderMock = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilderMock->expects($this->once())
->method('hasDefinition')
->will($this->returnValue(true));
$containerBuilderMock->expects($this->once())
->method('findTaggedServiceIds')
->with($this->equalTo('knp_menu.provider'))
->will($this->returnValue(array(
'id' => array('provider_tag1'),
'id2' => array('provider_tag2')
)));
$containerBuilderMock->expects($this->once())
->method('setAlias')
->with(
$this->equalTo('knp_menu.menu_provider'),
$this->equalTo('knp_menu.menu_provider.chain')
);
$containerBuilderMock->expects($this->once())
->method('getDefinition')
->with($this->equalTo('knp_menu.menu_provider.chain'))
->will($this->returnValue($definitionMock));
$providersPass = new AddProvidersPass();
$providersPass->process($containerBuilderMock);
}
}
Tests/DependencyInjection/Compiler/AddRenderersPassTest.php 0000666 00000005161 13052362206 0020111 0 ustar 00 getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilder->expects($this->once())
->method('hasDefinition')
->will($this->returnValue(false));
$containerBuilder->expects($this->never())
->method('findTaggedServiceIds');
$renderersPass = new AddRenderersPass();
$renderersPass->process($containerBuilder);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testProcessWithEmptyAlias()
{
$containerBuilderMock = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilderMock->expects($this->once())
->method('hasDefinition')
->will($this->returnValue(true));
$containerBuilderMock->expects($this->once())
->method('findTaggedServiceIds')
->with($this->equalTo('knp_menu.renderer'))
->will($this->returnValue(array('id' => array('tag1' => array('alias' => '')))));
$renderersPass = new AddRenderersPass();
$renderersPass->process($containerBuilderMock);
}
public function testProcessWithAlias()
{
$definitionMock = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')
->disableOriginalConstructor()
->getMock();
$definitionMock->expects($this->once())
->method('replaceArgument')
->with($this->equalTo(2), $this->equalTo(array('test_alias' => 'id')));
$containerBuilderMock = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilderMock->expects($this->once())
->method('hasDefinition')
->will($this->returnValue(true));
$containerBuilderMock->expects($this->once())
->method('findTaggedServiceIds')
->with($this->equalTo('knp_menu.renderer'))
->will($this->returnValue(array('id' => array('tag1' => array('alias' => 'test_alias')))));
$containerBuilderMock->expects($this->once())
->method('getDefinition')
->with($this->equalTo('knp_menu.renderer_provider'))
->will($this->returnValue($definitionMock));
$renderersPass = new AddRenderersPass();
$renderersPass->process($containerBuilderMock);
}
}
Tests/DependencyInjection/Compiler/AddTemplatePathPassTest.php 0000666 00000005105 13052362206 0020546 0 ustar 00 getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilder->expects($this->any())
->method('hasDefinition')
->will($this->returnValue(false));
$containerBuilder->expects($this->never())
->method('getDefinition');
$templatePathPass = new AddTemplatePathPass();
$templatePathPass->process($containerBuilder);
}
public function testProcess()
{
$definitionMock = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')
->disableOriginalConstructor()
->getMock();
$definitionMock->expects($this->once())
->method('addMethodCall')
->with($this->equalTo('addPath'), $this->isType('array'));
$containerBuilderMock = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilderMock->expects($this->once())
->method('hasDefinition')
->will($this->returnValue(true));
$containerBuilderMock->expects($this->once())
->method('getDefinition')
->with($this->equalTo('twig.loader.filesystem'))
->will($this->returnValue($definitionMock));
$templatePathPass = new AddTemplatePathPass();
$templatePathPass->process($containerBuilderMock);
}
public function testProcessLegacy()
{
$definitionMock = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')
->disableOriginalConstructor()
->getMock();
$definitionMock->expects($this->once())
->method('addMethodCall')
->with($this->equalTo('addPath'), $this->isType('array'));
$containerBuilderMock = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilderMock->expects($this->exactly(2))
->method('hasDefinition')
->will($this->onConsecutiveCalls(false, true));
$containerBuilderMock->expects($this->once())
->method('getDefinition')
->with($this->equalTo('twig.loader'))
->will($this->returnValue($definitionMock));
$templatePathPass = new AddTemplatePathPass();
$templatePathPass->process($containerBuilderMock);
}
}
Tests/DependencyInjection/Compiler/AddVotersPassTest.php 0000666 00000005570 13052362206 0017446 0 ustar 00 getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilder->expects($this->once())
->method('hasDefinition')
->will($this->returnValue(false));
$containerBuilder->expects($this->never())
->method('findTaggedServiceIds');
$menuPass = new AddVotersPass();
$menuPass->process($containerBuilder);
}
public function testProcessWithAlias()
{
$definitionMock = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')
->disableOriginalConstructor()
->getMock();
$definitionMock->expects($this->at(0))
->method('addMethodCall')
->with($this->equalTo('addVoter'), $this->equalTo(array(new Reference('id'))));
$definitionMock->expects($this->at(1))
->method('addMethodCall')
->with($this->equalTo('addVoter'), $this->equalTo(array(new Reference('foo'))));
$definitionMock->expects($this->at(2))
->method('addMethodCall')
->with($this->equalTo('addVoter'), $this->equalTo(array(new Reference('bar'))));
$listenerMock = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')
->disableOriginalConstructor()
->getMock();
$listenerMock->expects($this->once())
->method('addMethodCall')
->with($this->equalTo('addVoter'), $this->equalTo(array(new Reference('foo'))));
$containerBuilderMock = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilderMock->expects($this->once())
->method('hasDefinition')
->will($this->returnValue(true));
$containerBuilderMock->expects($this->once())
->method('findTaggedServiceIds')
->with($this->equalTo('knp_menu.voter'))
->will($this->returnValue(array('id' => array(array()), 'bar' => array(array('priority' => -5, 'request' => false)), 'foo' => array(array('request' => true)))));
$containerBuilderMock->expects($this->at(1))
->method('getDefinition')
->with($this->equalTo('knp_menu.matcher'))
->will($this->returnValue($definitionMock));
$containerBuilderMock->expects($this->at(2))
->method('getDefinition')
->with($this->equalTo('knp_menu.listener.voters'))
->will($this->returnValue($listenerMock));
$menuPass = new AddVotersPass();
$menuPass->process($containerBuilderMock);
}
}
Tests/DependencyInjection/Compiler/MenuBuilderPassTest.php 0000666 00000007620 13052362206 0017764 0 ustar 00 containerBuilder = $this->prophesize('Symfony\Component\DependencyInjection\ContainerBuilder');
$this->definition = $this->prophesize('Symfony\Component\DependencyInjection\Definition');
$this->builderDefinition = $this->prophesize('Symfony\Component\DependencyInjection\Definition');
$this->pass = new MenuBuilderPass();
$this->containerBuilder->getDefinition('knp_menu.menu_provider.builder_service')->willReturn($this->definition);
$this->containerBuilder->getDefinition('id')->willReturn($this->builderDefinition);
$this->builderDefinition->isPublic()->willReturn(true);
$this->builderDefinition->isAbstract()->willReturn(false);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Abstract services cannot be registered as menu builders but "id" is.
*/
public function testFailsWhenServiceIsAbstract()
{
$this->builderDefinition->isAbstract()->willReturn(true);
$this->containerBuilder->findTaggedServiceIds('knp_menu.menu_builder')->willReturn(array('id' => array(array('alias' => 'foo'))));
$this->pass->process($this->containerBuilder->reveal());
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Menu builder services must be public but "id" is a private service.
*/
public function testFailsWhenServiceIsPrivate()
{
$this->builderDefinition->isPublic()->willReturn(false);
$this->containerBuilder->findTaggedServiceIds('knp_menu.menu_builder')->willReturn(array('id' => array(array('alias' => 'foo'))));
$this->pass->process($this->containerBuilder->reveal());
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The alias is not defined in the "knp_menu.menu_builder" tag for the service "id"
*/
public function testFailsWhenAliasIsMissing()
{
$this->containerBuilder->findTaggedServiceIds('knp_menu.menu_builder')->willReturn(array('id' => array(array('alias' => ''))));
$this->pass->process($this->containerBuilder->reveal());
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The method is not defined in the "knp_menu.menu_builder" tag for the service "id"
*/
public function testFailsWhenMethodIsMissing()
{
$this->containerBuilder->findTaggedServiceIds('knp_menu.menu_builder')->willReturn(array('id' => array(array('alias' => 'foo'))));
$this->pass->process($this->containerBuilder->reveal());
}
public function testReplaceArgument()
{
$this->containerBuilder->getDefinition('id1')->willReturn($this->builderDefinition);
$this->containerBuilder->getDefinition('id2')->willReturn($this->builderDefinition);
$taggedServiceIds = array(
'id1' => array(array('alias' => 'foo', 'method' => 'fooMenu'), array('alias' => 'bar', 'method' => 'bar')),
'id2' => array(array('alias' => 'foo', 'method' => 'fooBar'), array('alias' => 'baz', 'method' => 'bar')),
);
$this->containerBuilder->findTaggedServiceIds('knp_menu.menu_builder')->willReturn($taggedServiceIds);
$menuBuilders = array(
'foo' => array('id2', 'fooBar'),
'bar' => array('id1', 'bar'),
'baz' => array('id2', 'bar'),
);
$this->definition->replaceArgument(1, $menuBuilders)->shouldBeCalled();
$this->pass->process($this->containerBuilder->reveal());
}
}
Tests/DependencyInjection/Compiler/MenuPassTest.php 0000666 00000005057 13052362206 0016457 0 ustar 00 getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilder->expects($this->once())
->method('hasDefinition')
->will($this->returnValue(false));
$containerBuilder->expects($this->never())
->method('findTaggedServiceIds');
$menuPass = new MenuPass();
$menuPass->process($containerBuilder);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testProcessWithEmptyAlias()
{
$containerBuilderMock = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilderMock->expects($this->once())
->method('hasDefinition')
->will($this->returnValue(true));
$containerBuilderMock->expects($this->once())
->method('findTaggedServiceIds')
->with($this->equalTo('knp_menu.menu'))
->will($this->returnValue(array('id' => array('tag1' => array('alias' => '')))));
$menuPass = new MenuPass();
$menuPass->process($containerBuilderMock);
}
public function testProcessWithAlias()
{
$definitionMock = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')
->disableOriginalConstructor()
->getMock();
$definitionMock->expects($this->once())
->method('replaceArgument')
->with($this->equalTo(1), $this->equalTo(array('test_alias' => 'id')));
$containerBuilderMock = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
$containerBuilderMock->expects($this->once())
->method('hasDefinition')
->will($this->returnValue(true));
$containerBuilderMock->expects($this->once())
->method('findTaggedServiceIds')
->with($this->equalTo('knp_menu.menu'))
->will($this->returnValue(array('id' => array('tag1' => array('alias' => 'test_alias')))));
$containerBuilderMock->expects($this->once())
->method('getDefinition')
->with($this->equalTo('knp_menu.menu_provider.container_aware'))
->will($this->returnValue($definitionMock));
$menuPass = new MenuPass();
$menuPass->process($containerBuilderMock);
}
}
Tests/DependencyInjection/ConfigurationTest.php 0000666 00000002316 13052362206 0015754 0 ustar 00 loadXML($config);
$previousErrorSetting = libxml_use_internal_errors(true);
$configIsValid = $configDom->schemaValidate(__DIR__.'/../../Resources/config/schema/menu-1.0.xsd');
$errors = array_map(function ($error) {
return sprintf('Line %d: %s', $error->line, trim($error->message));
}, libxml_get_errors());
libxml_use_internal_errors($previousErrorSetting);
$this->assertTrue($configIsValid, implode(PHP_EOL, $errors));
}
public function getConfigs()
{
return array(
array(''),
array(<<
EOC
),
);
}
}
Tests/DependencyInjection/KnpMenuExtensionTest.php 0000666 00000007460 13052362206 0016424 0 ustar 00 load(array(array()), $container);
$this->assertTrue($container->hasDefinition('knp_menu.renderer.list'), 'The list renderer is loaded');
$this->assertTrue($container->hasDefinition('knp_menu.renderer.twig'), 'The twig renderer is loaded');
$this->assertEquals('KnpMenuBundle::menu.html.twig', $container->getParameter('knp_menu.renderer.twig.template'));
$this->assertFalse($container->hasDefinition('knp_menu.templating.helper'), 'The PHP helper is not loaded');
$this->assertTrue($container->getDefinition('knp_menu.menu_provider.builder_alias')->hasTag('knp_menu.provider'), 'The BuilderAliasProvider is enabled');
$this->assertTrue($container->getDefinition('knp_menu.menu_provider.container_aware')->hasTag('knp_menu.provider'), 'The ContainerAwareProvider is enabled');
}
public function testEnableTwig()
{
$container = new ContainerBuilder();
$loader = new KnpMenuExtension();
$loader->load(array(array('twig' => true)), $container);
$this->assertTrue($container->hasDefinition('knp_menu.renderer.twig'));
$this->assertEquals('KnpMenuBundle::menu.html.twig', $container->getParameter('knp_menu.renderer.twig.template'));
}
public function testOverwriteTwigTemplate()
{
$container = new ContainerBuilder();
$loader = new KnpMenuExtension();
$loader->load(array(array('twig' => array('template' => 'foobar'))), $container);
$this->assertTrue($container->hasDefinition('knp_menu.renderer.twig'));
$this->assertEquals('foobar', $container->getParameter('knp_menu.renderer.twig.template'));
}
public function testDisableTwig()
{
$container = new ContainerBuilder();
$loader = new KnpMenuExtension();
$loader->load(array(array('twig' => false)), $container);
$this->assertTrue($container->hasDefinition('knp_menu.renderer.list'));
$this->assertFalse($container->hasDefinition('knp_menu.renderer.twig'));
}
public function testEnsablePhpTemplates()
{
$container = new ContainerBuilder();
$loader = new KnpMenuExtension();
$loader->load(array(array('templating' => true)), $container);
$this->assertTrue($container->hasDefinition('knp_menu.templating.helper'));
}
public function testDisableBuilderAliasProvider()
{
$container = new ContainerBuilder();
$loader = new KnpMenuExtension();
$loader->load(array(array('providers' => array('builder_alias' => false))), $container);
$this->assertFalse($container->getDefinition('knp_menu.menu_provider.builder_alias')->hasTag('knp_menu.provider'), 'The BuilderAliasProvider is disabled');
$this->assertTrue($container->getDefinition('knp_menu.menu_provider.container_aware')->hasTag('knp_menu.provider'), 'The ContainerAwareProvider is enabled');
}
public function testDisableContainerAwareProvider()
{
$container = new ContainerBuilder();
$loader = new KnpMenuExtension();
$loader->load(array(array('providers' => array('container_aware' => false))), $container);
$this->assertTrue($container->getDefinition('knp_menu.menu_provider.builder_alias')->hasTag('knp_menu.provider'), 'The BuilderAliasProvider is enabled');
$this->assertFalse($container->getDefinition('knp_menu.menu_provider.container_aware')->hasTag('knp_menu.provider'), 'The ContainerAwareProvider is disabled');
}
}
Tests/EventListener/VoterInitializerListenerTest.php 0000666 00000003761 13052362206 0017031 0 ustar 00 getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')
->disableOriginalConstructor()
->getMock();
$event->expects($this->once())
->method('getRequestType')
->will($this->returnValue(HttpKernelInterface::SUB_REQUEST));
$voter = $this->getMockBuilder('Knp\Menu\Matcher\Voter\RouteVoter')
->disableOriginalConstructor()
->getMock();
$voter->expects($this->never())
->method('setRequest');
$listener = new VoterInitializerListener();
$listener->addVoter($voter);
$listener->onKernelRequest($event);
}
public function testHandleMasterRequest()
{
$request = new Request();
$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')
->disableOriginalConstructor()
->getMock();
$event->expects($this->once())
->method('getRequestType')
->will($this->returnValue(HttpKernelInterface::MASTER_REQUEST));
$event->expects($this->once())
->method('getRequest')
->will($this->returnValue($request));
$voter = $this->getMockBuilder('Knp\Menu\Matcher\Voter\RouteVoter')
->disableOriginalConstructor()
->getMock();
$voter->expects($this->once())
->method('setRequest')
->with($this->equalTo($request));
$listener = new VoterInitializerListener();
$listener->addVoter($voter);
$listener->addVoter($this->getMock('Knp\Menu\Matcher\Voter\VoterInterface'));
$listener->onKernelRequest($event);
}
}
Tests/Provider/BuilderAliasProviderTest.php 0000666 00000021210 13052362206 0015063 0 ustar 00 getMock('Symfony\Component\HttpKernel\KernelInterface'),
$this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'),
$this->getMock('Knp\Menu\FactoryInterface')
);
$this->assertFalse($provider->has('foo'));
$this->assertFalse($provider->has('foo:bar'));
$this->assertTrue($provider->has('foo:bar:baz'));
}
public function testGetExistentMenu()
{
$item = $this->getMock('Knp\Menu\ItemInterface');
// mock the factory to return a set value when the builder creates the menu
$factory = $this->getMock('Knp\Menu\FactoryInterface');
$factory->expects($this->once())
->method('createItem')
->with('Main menu')
->will($this->returnValue($item));
$provider = new BuilderAliasProvider(
$this->createMockKernelForStub(),
$this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'),
$factory
);
$menu = $provider->get('FooBundle:Builder:mainMenu');
// returns the mocked value returned from mocked factory
$this->assertSame($item, $menu);
}
public function testGetContainerAwareMenu()
{
$item = $this->getMock('Knp\Menu\ItemInterface');
// mock the factory to return a set value when the builder creates the menu
$factory = $this->getMock('Knp\Menu\FactoryInterface');
$factory->expects($this->once())
->method('createItem')
->with('Main menu')
->will($this->returnValue($item));
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
$container->expects($this->once())
->method('get')
->with('test');
$provider = new BuilderAliasProvider(
$this->createMockKernelForStub(),
$container,
$factory
);
$menu = $provider->get('FooBundle:ContainerAwareBuilder:mainMenu');
// returns the mocked value returned from mocked factory
$this->assertSame($item, $menu);
}
/**
* @expectedException InvalidArgumentException
*/
public function testGetInvalidReturnValue()
{
$provider = new BuilderAliasProvider(
$this->createMockKernelForStub(),
$this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'),
$this->getMock('Knp\Menu\FactoryInterface')
);
$menu = $provider->get('FooBundle:Builder:invalidMethod');
}
/**
* @expectedException InvalidArgumentException
*/
public function testGetNonExistentMenu()
{
$provider = new BuilderAliasProvider(
$this->getMock('Symfony\Component\HttpKernel\KernelInterface'),
$this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'),
$this->getMock('Knp\Menu\FactoryInterface')
);
$provider->get('non-existent');
}
/**
* @expectedException InvalidArgumentException
* @expectedExceptionMessage Class "Knp\Bundle\MenuBundle\Tests\Stubs\Menu\Fake" does not exist for menu builder "FooBundle:Fake".
*/
public function testGetNonExistentMenuClass()
{
$provider = new BuilderAliasProvider(
$this->createMockKernelForStub(),
$this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'),
$this->getMock('Knp\Menu\FactoryInterface')
);
$provider->get('FooBundle:Fake:mainMenu');
}
/**
* @expectedException InvalidArgumentException
*/
public function testGetNonExistentMenuMethod()
{
$provider = new BuilderAliasProvider(
$this->createMockKernelForStub(),
$this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'),
$this->getMock('Knp\Menu\FactoryInterface')
);
// bundle will return a null namespace, class won't be found
$provider->get('FooBundle:Builder:fakeMenu');
}
public function testBundleInheritanceParent()
{
$item = $this->getMock('Knp\Menu\ItemInterface');
// mock the factory to return a set value when the builder creates the menu
$factory = $this->getMock('Knp\Menu\FactoryInterface');
$factory->expects($this->once())
->method('createItem')
->with('Main menu')
->will($this->returnValue($item));
$provider = new BuilderAliasProvider(
$this->createTestKernel(),
$this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'),
$factory
);
$menu = $provider->get('FooBundle:Builder:mainMenu');
// returns the mocked value returned from mocked factory
$this->assertSame($item, $menu);
}
public function testBundleInheritanceChild()
{
$item = $this->getMock('Knp\Menu\ItemInterface');
// mock the factory to return a set value when the builder creates the menu
$factory = $this->getMock('Knp\Menu\FactoryInterface');
$factory->expects($this->once())
->method('createItem')
->with('Main menu for the child')
->will($this->returnValue($item));
$provider = new BuilderAliasProvider(
$this->createTestKernel('Knp\Bundle\MenuBundle\Tests\Stubs\Child'),
$this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'),
$factory
);
$menu = $provider->get('FooBundle:Builder:mainMenu');
// returns the mocked value returned from mocked factory
$this->assertSame($item, $menu);
}
/**
* @expectedException InvalidArgumentException
* @expectedExceptionMessage Unable to find menu builder "FooBundle:Fake" in bundles BarBundle, FooBundle.
*/
public function testBundleInheritanceWrongClass()
{
$provider = new BuilderAliasProvider(
$this->createTestKernel(),
$this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'),
$this->getMock('Knp\Menu\FactoryInterface')
);
$provider->get('FooBundle:Fake:mainMenu');
}
/**
* Returns a mocked kernel with a mocked "FooBundle" whose namespace
* points to the Stubs directory.
*/
private function createMockKernelForStub()
{
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
$bundle->expects($this->once())
->method('getNamespace')
->will($this->returnValue('Knp\Bundle\MenuBundle\Tests\Stubs'))
;
$bundle->expects($this->any())
->method('getName')
->will($this->returnValue('FooBundle'))
;
$kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface');
$kernel->expects($this->once())
->method('getBundle')
->with('FooBundle', false)
->will($this->returnValue(array($bundle)))
;
return $kernel;
}
private function createTestKernel($childNamespace = 'Bar', $parentNamespace = 'Knp\Bundle\MenuBundle\Tests\Stubs')
{
$bundleInterface = version_compare(Kernel::VERSION, '2.1-dev', '<')
? 'Knp\Bundle\MenuBundle\Tests\Stubs\ContainerAwareBundleInterface' // Symfony 2.0 misses the extend in the interface
: 'Symfony\Component\HttpKernel\Bundle\BundleInterface';
$bundle = $this->getMock($bundleInterface);
$bundle->expects($this->any())
->method('getNamespace')
->will($this->returnValue($parentNamespace))
;
$bundle->expects($this->any())
->method('getName')
->will($this->returnValue('FooBundle'))
;
$childBundle = $this->getMock($bundleInterface);
$childBundle->expects($this->any())
->method('getNamespace')
->will($this->returnValue($childNamespace))
;
$childBundle->expects($this->any())
->method('getName')
->will($this->returnValue('BarBundle'))
;
$childBundle->expects($this->any())
->method('getParent')
->will($this->returnValue('FooBundle'))
;
$kernel = new TestKernel(array($bundle, $childBundle));
$kernel->boot();
return $kernel;
}
}
Tests/Provider/BuilderServiceProviderTest.php 0000666 00000005022 13052362206 0015435 0 ustar 00 prophesize('Symfony\Component\DependencyInjection\ContainerInterface')->reveal(),
array('first' => array('first', 'method'), 'second' => array('dummy', 'menu'))
);
$this->assertTrue($provider->has('first'));
$this->assertTrue($provider->has('second'));
$this->assertFalse($provider->has('third'));
}
public function testGetExistingMenu()
{
$menu = $this->prophesize('Knp\Menu\ItemInterface');
$container = $this->prophesize('Symfony\Component\DependencyInjection\ContainerInterface');
$builder = $this->prophesize('Knp\Bundle\MenuBundle\Tests\Provider\Builder');
$container->get('menu_builder')->willReturn($builder);
$builder->build(array('test' => 'foo'))->willReturn($menu);
$provider = new BuilderServiceProvider($container->reveal(), array('default' => array('menu_builder', 'build')));
$this->assertSame($menu->reveal(), $provider->get('default', array('test' => 'foo')));
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The menu "non-existent" is not defined.
*/
public function testThrowsExceptionWhenGettingUndefinedMenu()
{
$provider = new BuilderServiceProvider($this->prophesize('Symfony\Component\DependencyInjection\ContainerInterface')->reveal());
$provider->get('non-existent');
}
/**
* @dataProvider provideInvalidMenuDefinitions
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The menu builder definition for the menu "invalid" is invalid. It should be an array (serviceId, method)
*/
public function testThrowsExceptionWhenGettingInvalidMenu($definition)
{
$provider = new BuilderServiceProvider($this->prophesize('Symfony\Component\DependencyInjection\ContainerInterface')->reveal(), array('invalid' => $definition));
$provider->get('invalid');
}
public function provideInvalidMenuDefinitions()
{
return array(
'string' => array('def'),
'missing array elements' => array(array('id')),
'too much array elements' => array(array('id', 'method', 'foo')),
);
}
}
interface Builder
{
public function build(array $options);
}
Tests/Provider/ContainerAwareProviderTest.php 0000666 00000002523 13052362206 0015433 0 ustar 00 getMock('Symfony\Component\DependencyInjection\ContainerInterface'), array('first' => 'first', 'second' => 'dummy'));
$this->assertTrue($provider->has('first'));
$this->assertTrue($provider->has('second'));
$this->assertFalse($provider->has('third'));
}
public function testGetExistentMenu()
{
$menu = $this->getMock('Knp\Menu\ItemInterface');
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
$container->expects($this->once())
->method('get')
->with('menu')
->will($this->returnValue($menu))
;
$provider = new ContainerAwareProvider($container, array('default' => 'menu'));
$this->assertSame($menu, $provider->get('default'));
}
/**
* @expectedException InvalidArgumentException
*/
public function testGetNonExistentMenu()
{
$provider = new ContainerAwareProvider($this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'));
$provider->get('non-existent');
}
}
Tests/Renderer/ContainerAwareProviderTest.php 0000666 00000004015 13052362206 0015405 0 ustar 00 getMock('Symfony\Component\DependencyInjection\ContainerInterface'),
'first',
array('first' => 'first', 'second' => 'dummy')
);
$this->assertTrue($provider->has('first'));
$this->assertTrue($provider->has('second'));
$this->assertFalse($provider->has('third'));
}
public function testGetExistentRenderer()
{
$renderer = $this->getMock('Knp\Menu\Renderer\RendererInterface');
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
$container->expects($this->once())
->method('get')
->with('renderer')
->will($this->returnValue($renderer))
;
$provider = new ContainerAwareProvider($container, 'custom', array('default' => 'renderer', 'custom' => 'other'));
$this->assertSame($renderer, $provider->get('default'));
}
public function testGetDefaultRenderer()
{
$renderer = $this->getMock('Knp\Menu\Renderer\RendererInterface');
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
$container->expects($this->once())
->method('get')
->with('renderer')
->will($this->returnValue($renderer))
;
$provider = new ContainerAwareProvider($container, 'default', array('default' => 'renderer'));
$this->assertSame($renderer, $provider->get());
}
/**
* @expectedException InvalidArgumentException
*/
public function testGetNonExistentRenderer()
{
$provider = new ContainerAwareProvider($this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'), 'default', array());
$provider->get('non-existent');
}
}
Tests/Stubs/Child/Menu/Builder.php 0000666 00000000366 13052362206 0013004 0 ustar 00 createItem('Main menu for the child');
}
}
Tests/Stubs/ContainerAwareBundleInterface.php 0000666 00000000674 13052362206 0015346 0 ustar 00 createItem('Main menu');
}
public function invalidMethod(FactoryInterface $factory)
{
return new \stdClass();
}
}
Tests/Stubs/Menu/ContainerAwareBuilder.php 0000666 00000001203 13052362206 0014573 0 ustar 00 container = $container;
}
public function mainMenu(FactoryInterface $factory)
{
// Check that the container is really set.
$this->container->get('test');
return $factory->createItem('Main menu');
}
}
Tests/Stubs/TestKernel.php 0000666 00000001114 13052362206 0011537 0 ustar 00 mockBundles = $bundles;
parent::__construct('test', false);
}
public function registerBundles()
{
return $this->mockBundles;
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
}
protected function initializeContainer()
{
}
}
Tests/Templating/MenuHelperTest.php 0000666 00000012251 13052362206 0013373 0 ustar 00
*/
class MenuHelperTest extends \PHPUnit_Framework_TestCase
{
public function testGet()
{
$helperMock = $this->getHelperMock();
$helperMock->expects($this->any())
->method('get')
->with($this->equalTo('test'), $this->equalTo(array('pathArray')))
->will($this->returnValue('returned value'));
$helper = new MenuHelper($helperMock, $this->getMatcherMock(), $this->getManipulatorMock());
$this->assertEquals('returned value', $helper->get('test', array('pathArray')));
}
public function testGetMenuWithOptions()
{
$menu = $this->getMock('Knp\Menu\ItemInterface');
$helperMock = $this->getHelperMock();
$helperMock->expects($this->any())
->method('get')
->with('default', array(), array('foo' => 'bar'))
->will($this->returnValue($menu))
;
$helper = new MenuHelper($helperMock, $this->getMatcherMock(), $this->getManipulatorMock());
$this->assertSame($menu, $helper->get('default', array(), array('foo' => 'bar')));
}
public function testRender()
{
$helperMock = $this->getHelperMock();
$helperMock->expects($this->any())
->method('render')
->with($this->equalTo('test'), $this->equalTo(array('options')))
->will($this->returnValue('returned value'));
$helper = new MenuHelper($helperMock, $this->getMatcherMock(), $this->getManipulatorMock());
$this->assertEquals('returned value', $helper->render('test', array('options')));
}
public function testGetName()
{
$helper = new MenuHelper($this->getHelperMock(), $this->getMatcherMock(), $this->getManipulatorMock());
$this->assertEquals('knp_menu', $helper->getName());
}
public function testGetBreadcrumbsArray()
{
$helperMock = $this->getHelperMock(array('getBreadcrumbsArray'));
$helperMock->expects($this->any())
->method('getBreadcrumbsArray')
->with('default')
->will($this->returnValue(array('A', 'B')))
;
$helper = new MenuHelper($helperMock, $this->getMatcherMock(), $this->getManipulatorMock());
$this->assertEquals(array('A', 'B'), $helper->getBreadcrumbsArray('default'));
}
public function testPathAsString()
{
$menu = $this->getMock('Knp\Menu\ItemInterface');
$manipulatorMock = $this->getManipulatorMock(array('getPathAsString'));
$manipulatorMock->expects($this->any())
->method('getPathAsString')
->with($menu)
->will($this->returnValue('A > B'))
;
$helper = new MenuHelper($this->getHelperMock(), $this->getMatcherMock(), $manipulatorMock);
$this->assertEquals('A > B', $helper->getPathAsString($menu));
}
public function testIsCurrent()
{
$current = $this->getMock('Knp\Menu\ItemInterface');
$notCurrent = $this->getMock('Knp\Menu\ItemInterface');
$matcherMock = $this->getMatcherMock();
$matcherMock->expects($this->any())
->method('isCurrent')
->withConsecutive(array($current), array($notCurrent))
->will($this->onConsecutiveCalls(true, false))
;
$helper = new MenuHelper($this->getHelperMock(), $matcherMock, $this->getManipulatorMock());
$this->assertTrue($helper->isCurrent($current));
$this->assertFalse($helper->isCurrent($notCurrent));
}
public function testIsAncestor()
{
$menu = $this->getMock('Knp\Menu\ItemInterface');
$matcherMock = $this->getMatcherMock();
$matcherMock->expects($this->any())
->method('isAncestor')
->with($menu)
->will($this->returnValue(false))
;
$helper = new MenuHelper($this->getHelperMock(), $matcherMock, $this->getManipulatorMock());
$this->assertFalse($helper->isAncestor($menu));
}
public function testGetCurrentItem()
{
$menu = $this->getMock('Knp\Menu\ItemInterface');
$helperMock = $this->getHelperMock(array('getCurrentItem'));
$helperMock->expects($this->any())
->method('getCurrentItem')
->with('default')
->will($this->returnValue($menu))
;
$helper = new MenuHelper($helperMock, $this->getMatcherMock(), $this->getManipulatorMock());
$this->assertEquals($menu, $helper->getCurrentItem('default'));
}
private function getHelperMock(array $methods = array())
{
return $this->getMockBuilder('Knp\Menu\Twig\Helper')
->setMethods($methods)
->disableOriginalConstructor()
->getMock();
}
private function getMatcherMock()
{
return $this->getMock('Knp\Menu\Matcher\MatcherInterface');
}
private function getManipulatorMock(array $methods = array())
{
return $this->getMockBuilder('Knp\Menu\Util\MenuManipulator')
->setMethods($methods)
->getMock();
}
}
composer.json 0000666 00000002013 13052362206 0007265 0 ustar 00 {
"name": "knplabs/knp-menu-bundle",
"description": "This bundle provides an integration of the KnpMenu library",
"keywords": ["menu"],
"type": "symfony-bundle",
"license": "MIT",
"authors": [
{
"name": "Knplabs",
"homepage": "http://knplabs.com"
},
{
"name": "Christophe Coevoet",
"email": "stof@notk.org"
},
{
"name": "Symfony Community",
"homepage": "https://github.com/KnpLabs/KnpMenuBundle/contributors"
}
],
"require": {
"knplabs/knp-menu": "~2.2",
"symfony/framework-bundle": "~2.3|~3.0"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7|~3.0",
"symfony/expression-language": "~2.4|~3.0"
},
"autoload": {
"psr-4": { "Knp\\Bundle\\MenuBundle\\": "" }
},
"extra": {
"branch-alias": {
"dev-master": "2.2.x-dev"
}
}
}
phpunit.xml.dist 0000666 00000001077 13052362206 0007727 0 ustar 00
./Tests/
./
./Resources
./Tests
./vendor