diff --git a/README.md b/README.md index 58bb08f..904076f 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ rollerworks_navigation: label: ~ # Label of the breadcrumb will be translated with the translator_domain translator_domain: Menus # translator domain for the label route: { name: ~, parameters: { } } # name can not be empty + uri: ~ # Alternatively you can use a URI instead of a route items: [] # Sub-level items, same as this example (unlimited depth nesting) # alternatively you can reference a service for getting the Menu object @@ -124,6 +125,7 @@ rollerworks_navigation: label: ~ # Label of the breadcrumb will be translated with the translator_domain translator_domain: Breadcrumbs # translator domain for the label route: { name: ~, parameters: { } } # name can not be empty + uri: ~ # Alternatively you can use a URI instead of a route # alternatively you can reference a service for getting the Menu object # The service must return a Knp\Menu\ItemInterface instance diff --git a/src/Rollerworks/Bundle/NavigationBundle/DependencyInjection/Configuration.php b/src/Rollerworks/Bundle/NavigationBundle/DependencyInjection/Configuration.php index b9fbe79..57a2e81 100644 --- a/src/Rollerworks/Bundle/NavigationBundle/DependencyInjection/Configuration.php +++ b/src/Rollerworks/Bundle/NavigationBundle/DependencyInjection/Configuration.php @@ -60,10 +60,16 @@ public function getConfigTreeBuilder() ->children() ->scalarNode('parent')->defaultNull()->end() ->scalarNode('label')->defaultNull()->end() + ->arrayNode('options') + ->useAttributeAsKey('name') + ->prototype('variable')->end() + ->end() ->scalarNode('translator_domain')->defaultValue('Breadcrumbs')->end() + ->scalarNode('uri')->defaultNull()->end() ->arrayNode('route') ->children() ->scalarNode('name')->cannotBeEmpty()->end() + ->booleanNode('absolute')->defaultFalse()->end() ->arrayNode('parameters') ->prototype('variable')->end() ->end() @@ -94,17 +100,22 @@ final public function addItemConfig(ArrayNodeDefinition $rootNode) ->children() ->scalarNode('expression')->defaultNull()->end() ->scalarNode('label')->defaultNull()->end() + ->arrayNode('options') + ->useAttributeAsKey('name') + ->prototype('variable')->end() + ->end() ->scalarNode('translator_domain')->defaultValue('Menus')->end() + ->scalarNode('uri')->defaultNull()->end() ->arrayNode('route') ->children() ->scalarNode('name')->cannotBeEmpty()->end() + ->booleanNode('absolute')->defaultFalse()->end() ->arrayNode('parameters') ->useAttributeAsKey('name') ->prototype('variable')->end() ->end() ->end() ->end() - ->arrayNode('service') ->children() ->scalarNode('id')->cannotBeEmpty()->end() @@ -114,7 +125,6 @@ final public function addItemConfig(ArrayNodeDefinition $rootNode) ->end() ->end() ->end() - ->arrayNode('items') ->useAttributeAsKey('name') ->prototype('variable')->end() // use variable as we can't nest to deep @@ -124,6 +134,10 @@ final public function addItemConfig(ArrayNodeDefinition $rootNode) ->ifTrue(function ($v) { return !empty($v['service']) && (!empty($v['expression']) || null !== $v['label']); }) ->thenInvalid('When a "service" or "expression" is set no other configurations should be set for this item.') ->end() + ->validate() + ->ifTrue(function ($v) { return !empty($v['route']) && !empty($v['uri']); }) + ->thenInvalid('An item can only have a route or uri, not both.') + ->end() ->validate() ->ifTrue(function ($v) { return empty($v['service']) && empty($v['expression']) && null === $v['label']; }) ->thenInvalid('Missing a value for either "service" or "label" for this item.') diff --git a/src/Rollerworks/Bundle/NavigationBundle/DependencyInjection/NavigationExtension.php b/src/Rollerworks/Bundle/NavigationBundle/DependencyInjection/NavigationExtension.php index fd1fd22..677ecff 100644 --- a/src/Rollerworks/Bundle/NavigationBundle/DependencyInjection/NavigationExtension.php +++ b/src/Rollerworks/Bundle/NavigationBundle/DependencyInjection/NavigationExtension.php @@ -131,7 +131,7 @@ private function registerBreadcrumbs(array $breadcrumbs, ContainerBuilder $conta * * @return Definition */ - private function createMenuItem($name, array $options = array()) + private function createMenuItem($name, $options = array()) { unset($options['items']); @@ -152,9 +152,16 @@ private function createMenuItem($name, array $options = array()) private function createMenuItemDefinition($name, array $item) { if (isset($item['route']['parameters'])) { - $item['route']['parameters'] = $this->resolveParameters($item['route']['parameters']); + $item['routeParameters'] = $this->resolveParameters($item['route']['parameters']); + $item['routeAbsolute'] = $this->resolveParameters($item['route']['absolute']); + $item['route'] = $this->resolveParameters($item['route']['name']); } + $item['options'] = $this->resolveParameters($item['options']); + $item = array_merge($item['options'], $item); + + unset($item['options']); + if (!empty($item['service'])) { $definition = new Definition('stdClass'); $definition->setFactoryService($item['service']['id']); @@ -234,7 +241,7 @@ private function validateMenuItemConfig(array $configs) * * @param string $value * - * @return Reference + * @return mixed */ private function resolveParameters($value) { diff --git a/tests/Rollerworks/Bundle/NavigationBundle/Tests/DependencyInjection/ConfigurationTest.php b/tests/Rollerworks/Bundle/NavigationBundle/Tests/DependencyInjection/ConfigurationTest.php index 396555a..f5aed44 100644 --- a/tests/Rollerworks/Bundle/NavigationBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/tests/Rollerworks/Bundle/NavigationBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -42,7 +42,9 @@ public function testBreadcrumbsWithDefaulted() 'customers' => array( 'parent' => null, 'label' => null, + 'options' => array(), 'translator_domain' => 'Breadcrumbs', + 'uri' => null, 'expression' => null, ), ), @@ -81,7 +83,9 @@ public function testBreadcrumbAcceptsService() 'customer' => array( 'parent' => null, 'label' => null, + 'options' => array(), 'translator_domain' => 'Breadcrumbs', + 'uri' => null, 'service' => array( 'id' => 'acme_customer.navigation', 'method' => 'getBreadcrumb', @@ -92,7 +96,9 @@ public function testBreadcrumbAcceptsService() 'webhosting' => array( 'parent' => null, 'label' => null, + 'options' => array(), 'translator_domain' => 'Breadcrumbs', + 'uri' => null, 'service' => array( 'id' => 'acme_webhosting.navigation', 'method' => 'getBreadcrumb', diff --git a/tests/Rollerworks/Bundle/NavigationBundle/Tests/DependencyInjection/NavigationExtensionTest.php b/tests/Rollerworks/Bundle/NavigationBundle/Tests/DependencyInjection/NavigationExtensionTest.php index 6152594..cc90636 100644 --- a/tests/Rollerworks/Bundle/NavigationBundle/Tests/DependencyInjection/NavigationExtensionTest.php +++ b/tests/Rollerworks/Bundle/NavigationBundle/Tests/DependencyInjection/NavigationExtensionTest.php @@ -40,16 +40,16 @@ public function testBreadcrumbsAreRegistered() $def->setFactoryService('knp_menu.factory'); $def->setFactoryMethod('createItem'); $def->setArguments(array('root', array())); - $def->addMethodCall('addChild', array('customers', array('label' => 'Customers', 'translator_domain' => 'Breadcrumbs'))); + $def->addMethodCall('addChild', array('customers', array('label' => 'Customers', 'translator_domain' => 'Breadcrumbs', 'uri' => null))); - $this->assertEquals($def, $this->container->findDefinition('rollerworks_navigation.breadcrumbs.customers')); + $this->assertEquals((array) $def, (array) $this->container->findDefinition('rollerworks_navigation.breadcrumbs.customers')); $def = new Definition('Knp\Menu\MenuFactory'); $def->setTags(array('knp_menu.menu' => array(array('alias' => 'webhosting')))); $def->setFactoryService('knp_menu.factory'); $def->setFactoryMethod('createItem'); $def->setArguments(array('root', array())); - $def->addMethodCall('addChild', array('webhosting', array('label' => 'Webhosting', 'translator_domain' => 'Breadcrumbs'))); + $def->addMethodCall('addChild', array('webhosting', array('label' => 'Webhosting', 'translator_domain' => 'Breadcrumbs', 'uri' => null))); $this->assertEquals($def, $this->container->findDefinition('rollerworks_navigation.breadcrumbs.webhosting')); $this->compile(); @@ -86,8 +86,8 @@ public function testBreadcrumbParentsAreResolved() $def->setFactoryService('knp_menu.factory'); $def->setFactoryMethod('createItem'); $def->setArguments(array('root', array())); - $def->addMethodCall('addChild', array('dashboard', array('label' => 'Dashboard', 'translator_domain' => 'Breadcrumbs', 'route' => array('name' => 'site_default', 'parameters' => array())))); - $def->addMethodCall('addChild', array('webhosting', array('label' => 'Webhosting', 'translator_domain' => 'Breadcrumbs', 'route' => array('name' => 'webhosting_home', 'parameters' => array())))); + $def->addMethodCall('addChild', array('dashboard', array('label' => 'Dashboard', 'route' => 'site_default', 'translator_domain' => 'Breadcrumbs', 'uri' => null, 'routeParameters' => array(), 'routeAbsolute' => false))); + $def->addMethodCall('addChild', array('webhosting', array('label' => 'Webhosting', 'route' => 'webhosting_home', 'translator_domain' => 'Breadcrumbs', 'uri' => null, 'routeParameters' => array(), 'routeAbsolute' => false))); $this->assertEquals($def, $this->container->findDefinition('rollerworks_navigation.breadcrumbs.webhosting')); $def = new Definition('Knp\Menu\MenuFactory'); @@ -95,9 +95,9 @@ public function testBreadcrumbParentsAreResolved() $def->setFactoryService('knp_menu.factory'); $def->setFactoryMethod('createItem'); $def->setArguments(array('root', array())); - $def->addMethodCall('addChild', array('dashboard', array('label' => 'Dashboard', 'translator_domain' => 'Breadcrumbs', 'route' => array('name' => 'site_default', 'parameters' => array())))); - $def->addMethodCall('addChild', array('webhosting', array('label' => 'Webhosting', 'translator_domain' => 'Breadcrumbs', 'route' => array('name' => 'webhosting_home', 'parameters' => array())))); - $def->addMethodCall('addChild', array('webhosting_account', array('label' => 'Example.com', 'translator_domain' => null, 'route' => array('name' => 'webhosting_account', 'parameters' => array('id' => 5))))); + $def->addMethodCall('addChild', array('dashboard', array('label' => 'Dashboard', 'translator_domain' => 'Breadcrumbs', 'route' => 'site_default', 'routeParameters' => array(), 'routeAbsolute' => false, 'uri' => null))); + $def->addMethodCall('addChild', array('webhosting', array('label' => 'Webhosting', 'translator_domain' => 'Breadcrumbs', 'route' => 'webhosting_home', 'routeParameters' => array(), 'routeAbsolute' => false, 'uri' => null))); + $def->addMethodCall('addChild', array('webhosting_account', array('label' => 'Example.com', 'translator_domain' => null, 'route' => 'webhosting_account', 'routeParameters' => array('id' => 5), 'routeAbsolute' => false, 'uri' => null))); $this->assertEquals($def, $this->container->findDefinition('rollerworks_navigation.breadcrumbs.webhosting_account')); $this->compile(); @@ -115,6 +115,7 @@ public function testBreadcrumbsAreRegisteredWithExpression() 'parent' => null, 'label' => 'Webhosting', 'translator_domain' => 'Breadcrumbs', + 'uri' => null, 'route' => array( 'name' => 'test', 'parameters' => array('foo' => '@@bar', 'name' => "@service('security_context').getToken().getName()") @@ -133,12 +134,12 @@ public function testBreadcrumbsAreRegisteredWithExpression() 'webhosting', array( 'label' => 'Webhosting', 'translator_domain' => 'Breadcrumbs', - 'route' => array( - 'name' => 'test', - 'parameters' => array( - 'foo' => '@bar', - 'name' => new Expression("service('security_context').getToken().getName()"), - ) + 'uri' => null, + 'route' => 'test', + 'routeAbsolute' => false, + 'routeParameters' => array( + 'foo' => '@bar', + 'name' => new Expression("service('security_context').getToken().getName()"), ), ), )); @@ -191,6 +192,44 @@ public function testDynamicBreadcrumbsAreRegistered() $this->compile(); } + public function testCustomOptionsAreResolved() + { + $this->load(array( + 'breadcrumbs' => array( + 'customers' => array( + 'parent' => null, + 'label' => 'Customers', + 'translator_domain' => 'Breadcrumbs', + 'options' => array('icon' => 'customers') + ), + 'webhosting' => array( + 'parent' => null, + 'label' => 'Webhosting', + 'translator_domain' => 'Breadcrumbs', + ), + ) + )); + + $def = new Definition('Knp\Menu\MenuFactory'); + $def->setTags(array('knp_menu.menu' => array(array('alias' => 'customers')))); + $def->setFactoryService('knp_menu.factory'); + $def->setFactoryMethod('createItem'); + $def->setArguments(array('root', array())); + $def->addMethodCall('addChild', array('customers', array('label' => 'Customers', 'translator_domain' => 'Breadcrumbs', 'uri' => null, 'icon' => 'customers'))); + + $this->assertEquals((array) $def, (array) $this->container->findDefinition('rollerworks_navigation.breadcrumbs.customers')); + + $def = new Definition('Knp\Menu\MenuFactory'); + $def->setTags(array('knp_menu.menu' => array(array('alias' => 'webhosting')))); + $def->setFactoryService('knp_menu.factory'); + $def->setFactoryMethod('createItem'); + $def->setArguments(array('root', array())); + $def->addMethodCall('addChild', array('webhosting', array('label' => 'Webhosting', 'translator_domain' => 'Breadcrumbs', 'uri' => null,))); + $this->assertEquals((array) $def, (array) $this->container->findDefinition('rollerworks_navigation.breadcrumbs.webhosting')); + + $this->compile(); + } + /** * @expectedException \RuntimeException * @expectedExceptionMessage Circular reference detected with parent of breadcrumb "foo", path: "webhosting -> bar -> foo". @@ -276,8 +315,8 @@ public function testMenusAreRegistered() $def->setFactoryService('knp_menu.factory'); $def->setFactoryMethod('createItem'); $def->setArguments(array('root', array('template' => null))); - $def->addMethodCall('addChild', array('customer', array('label' => 'Customers', 'translator_domain' => 'Menus', 'route' => array('name' => 'webhosting_home', 'parameters' => array())))); - $def->addMethodCall('addChild', array('administration', array('label' => 'Administration', 'translator_domain' => 'Menus', 'route' => array('name' => 'administration_home', 'parameters' => array())))); + $def->addMethodCall('addChild', array('customer', array('label' => 'Customers', 'translator_domain' => 'Menus', 'route' => 'webhosting_home', 'routeParameters' => array(), 'routeAbsolute' => false, 'uri' => null))); + $def->addMethodCall('addChild', array('administration', array('label' => 'Administration', 'translator_domain' => 'Menus', 'route' => 'administration_home', 'routeParameters' => array(), 'routeAbsolute' => false, 'uri' => null))); $this->assertEquals($def, $this->container->findDefinition('rollerworks_navigation.menu.main')); @@ -291,19 +330,19 @@ public function testMenusAreRegistered() $rootDef = new Definition('Knp\Menu\MenuFactory'); $rootDef->setFactoryService('knp_menu.factory'); $rootDef->setFactoryMethod('createItem'); - $rootDef->setArguments(array('administration', array('label' => 'Administration', 'route' => array('name' => 'administration_home', 'parameters' => array()), 'translator_domain' => 'Menus'))); - $rootDef->addMethodCall('addChild', array('customer', array('label' => 'Customers', 'route' => array('name' => 'administration_customers', 'parameters' => array()), 'translator_domain' => 'Menus'))); + $rootDef->setArguments(array('administration', array('label' => 'Administration', 'route' => 'administration_home', 'routeParameters' => array(), 'routeAbsolute' => false, 'translator_domain' => 'Menus', 'uri' => null))); + $rootDef->addMethodCall('addChild', array('customer', array('label' => 'Customers', 'route' => 'administration_customers', 'routeParameters' => array(), 'routeAbsolute' => false, 'translator_domain' => 'Menus', 'uri' => null))); $invoiceDef = new Definition('Knp\Menu\MenuFactory'); $invoiceDef->setFactoryService('knp_menu.factory'); $invoiceDef->setFactoryMethod('createItem'); - $invoiceDef->setArguments(array('invoices', array('label' => 'Invoices', 'route' => array('name' => 'administration_invoices', 'parameters' => array()) , 'translator_domain' => 'Menus'))); - $invoiceDef->addMethodCall('addChild', array('invoices_paid', array('label' => 'Paid', 'route' => array('name' => 'administration_invoices', 'parameters' => array('filter' => 'paid')), 'translator_domain' => 'Menus'))); + $invoiceDef->setArguments(array('invoices', array('label' => 'Invoices', 'route' => 'administration_invoices', 'routeParameters' => array(), 'routeAbsolute' => false , 'translator_domain' => 'Menus', 'uri' => null))); + $invoiceDef->addMethodCall('addChild', array('invoices_paid', array('label' => 'Paid', 'route' => 'administration_invoices', 'routeParameters' => array('filter' => 'paid'), 'routeAbsolute' => false, 'translator_domain' => 'Menus', 'uri' => null))); $rootDef->addMethodCall('addChild', array($invoiceDef)); $def->addMethodCall('addChild', array($rootDef)); - $this->assertEquals((array) $def, (array) $this->container->findDefinition('rollerworks_navigation.menu.control_panel')); + $this->assertEquals($def, $this->container->findDefinition('rollerworks_navigation.menu.control_panel')); $this->compile(); } @@ -337,7 +376,7 @@ public function testDynamicMenusAreRegistered() $def->setFactoryService('knp_menu.factory'); $def->setFactoryMethod('createItem'); $def->setArguments(array('root', array('template' => null))); - $def->addMethodCall('addChild', array('customer', array('label' => 'Customers', 'translator_domain' => 'Menus', 'route' => array('name' => 'webhosting_home', 'parameters' => array())))); + $def->addMethodCall('addChild', array('customer', array('label' => 'Customers', 'translator_domain' => 'Menus', 'route' => 'webhosting_home', 'routeParameters' => array(), 'routeAbsolute' => false, 'uri' => null))); $childDef = new Definition('stdClass'); $childDef->setFactoryService('acme_customer.navigation'); @@ -390,12 +429,18 @@ public function testMenusAreRegisteredWithExpression() $def->setFactoryService('knp_menu.factory'); $def->setFactoryMethod('createItem'); $def->setArguments(array('root', array('template' => null))); - $def->addMethodCall('addChild', array('customer', array('label' => 'Customers', 'translator_domain' => 'Menus', 'route' => array('name' => 'webhosting_home', 'parameters' => array())))); - $def->addMethodCall('addChild', array('administration', array('label' => 'Administration', 'translator_domain' => 'Menus', 'route' => array('name' => 'administration_home', 'parameters' => array( + $def->addMethodCall('addChild', array('customer', array('label' => 'Customers', 'translator_domain' => 'Menus', 'route' => 'webhosting_home', 'routeParameters' => array(), 'routeAbsolute' => false, 'uri' => null))); + $def->addMethodCall('addChild', array('administration', array( + 'label' => 'Administration', + 'translator_domain' => 'Menus', + 'route' => 'administration_home', + 'routeParameters' => array( 'foo' => '@bar', 'name' => new Expression("service('security_context').getToken().getName()"), - ) - )))); + ), + 'routeAbsolute' => false, + 'uri' => null + ))); $childDef = new Definition('stdClass'); $childDef->setFactoryService('acme_servers.navigation');