Skip to content

Commit

Permalink
Add new 'knp_menu_get_current_item' Twig function (KnpLabs#228)
Browse files Browse the repository at this point in the history
Add knp_menu_get_current_item Twig function
  • Loading branch information
fsevestre authored and dbu committed Aug 3, 2016
1 parent e849f84 commit a74c02b
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.2 (unreleased)

* Added a new function to twig: `knp_menu_get_current_item`

## 2.1.1 (2016-01-08)

* Made compatible with Symfony 3
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "2.1-dev"
"dev-master": "2.2-dev"
}
}
}
18 changes: 18 additions & 0 deletions doc/02-Twig-Integration.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ menu object in the other functions:
{% set item = knp_menu_get('sidebar', ['First section']) %}
{% set breadcrumbs_array = knp_menu_get_breadcrumbs_array('main') %}
{% set current_item = knp_menu_get_current_item('main') %}
```

In some cases, you may want to build the menu differently according to the
Expand Down Expand Up @@ -284,6 +286,22 @@ Twig integration reference
* `knp_menu_get('menuName' [, ['Path', 'To', 'Item'], ['options']])`: retrieve an item of the menu
* `knp_menu_render('menuName' [, ['options'], 'rendererName'])`: render a menu
* `knp_menu_get_breadcrumbs_array('menuName' [, 'subItem'])`: get an array that represent the breadcrumbs of the current page (according to the menu)
* `knp_menu_get_current_item('menuName')`: retrieve the current item (according to the menu)

You can easily generate a breadcrumb of the current page by combining the
`knp_menu_get_breadcrumbs_array` and `knp_menu_get_current_item` functions:

```jinja
<ol class="breadcrumb">
{% for breadcrumb_item in knp_menu_get_breadcrumbs_array(knp_menu_get_current_item('main')) %}
{% if not loop.last %}
<li><a href="{{ breadcrumb_item.uri }}">{{ breadcrumb_item.label }}</a></li>
{% else %}
<li class="active">{{ breadcrumb_item.label }}</li>
{% endif %}
{% endfor %}
</ol>
```

### Filters

Expand Down
2 changes: 1 addition & 1 deletion src/Knp/Menu/Integration/Silex/KnpMenuServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public function register(Application $app)
}

$app['knp_menu.helper'] = $app->share(function () use ($app) {
return new Helper($app['knp_menu.renderer_provider'], $app['knp_menu.menu_provider'], $app['knp_menu.menu_manipulator']);
return new Helper($app['knp_menu.renderer_provider'], $app['knp_menu.menu_provider'], $app['knp_menu.menu_manipulator'], $app['knp_menu.matcher']);
});

if (isset($app['twig'])) {
Expand Down
49 changes: 48 additions & 1 deletion src/Knp/Menu/Twig/Helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Knp\Menu\Twig;

use Knp\Menu\ItemInterface;
use Knp\Menu\Matcher\MatcherInterface;
use Knp\Menu\Util\MenuManipulator;
use Knp\Menu\Renderer\RendererProviderInterface;
use Knp\Menu\Provider\MenuProviderInterface;
Expand All @@ -16,16 +17,20 @@ class Helper
private $rendererProvider;
private $menuProvider;
private $menuManipulator;
private $matcher;

/**
* @param RendererProviderInterface $rendererProvider
* @param MenuProviderInterface|null $menuProvider
* @param MenuManipulator|null $menuManipulator
* @param MatcherInterface|null $matcher
*/
public function __construct(RendererProviderInterface $rendererProvider, MenuProviderInterface $menuProvider = null, MenuManipulator $menuManipulator = null)
public function __construct(RendererProviderInterface $rendererProvider, MenuProviderInterface $menuProvider = null, MenuManipulator $menuManipulator = null, MatcherInterface $matcher = null)
{
$this->rendererProvider = $rendererProvider;
$this->menuProvider = $menuProvider;
$this->menuManipulator = $menuManipulator;
$this->matcher = $matcher;
}

/**
Expand Down Expand Up @@ -120,6 +125,24 @@ public function getBreadcrumbsArray($menu, $subItem = null)
return $this->menuManipulator->getBreadcrumbsArray($menu, $subItem);
}

/**
* Returns the current item of a menu.
*
* @param ItemInterface|array|string $menu
*
* @return ItemInterface|null
*/
public function getCurrentItem($menu)
{
if (null === $this->matcher) {
throw new \BadMethodCallException('The matcher must be set to get the current item of a menu');
}

$menu = $this->castMenu($menu);

return $this->retrieveCurrentItem($menu);
}

/**
* @param ItemInterface|array|string $menu
*
Expand All @@ -142,4 +165,28 @@ private function castMenu($menu)

return $menu;
}

/**
* @param ItemInterface $item
*
* @return ItemInterface|null
*/
private function retrieveCurrentItem(ItemInterface $item)
{
if ($this->matcher->isCurrent($item)) {
return $item;
}

if ($this->matcher->isAncestor($item)) {
foreach ($item->getChildren() as $child) {
$currentItem = $this->retrieveCurrentItem($child);

if (null !== $currentItem) {
return $currentItem;
}
}
}

return null;
}
}
21 changes: 21 additions & 0 deletions src/Knp/Menu/Twig/MenuExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public function getFunctions()
new \Twig_SimpleFunction('knp_menu_get', array($this, 'get')),
new \Twig_SimpleFunction('knp_menu_render', array($this, 'render'), array('is_safe' => array('html'))),
new \Twig_SimpleFunction('knp_menu_get_breadcrumbs_array', array($this, 'getBreadcrumbsArray')),
new \Twig_SimpleFunction('knp_menu_get_current_item', array($this, 'getCurrentItem')),
);
}

Expand Down Expand Up @@ -87,6 +88,26 @@ public function getBreadcrumbsArray($menu, $subItem = null)
return $this->helper->getBreadcrumbsArray($menu, $subItem);
}

/**
* Returns the current item of a menu.
*
* @param ItemInterface|string $menu
*
* @return ItemInterface
*/
public function getCurrentItem($menu)
{
$rootItem = $this->get($menu);

$currentItem = $this->helper->getCurrentItem($rootItem);

if (null === $currentItem) {
$currentItem = $rootItem;
}

return $currentItem;
}

/**
* A string representation of this menu item
*
Expand Down
31 changes: 31 additions & 0 deletions tests/Knp/Menu/Tests/Twig/HelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace Knp\Menu\Tests\Twig;

use Knp\Menu\Matcher\Matcher;
use Knp\Menu\MenuFactory;
use Knp\Menu\MenuItem;
use Knp\Menu\Twig\Helper;

class HelperTest extends \PHPUnit_Framework_TestCase
Expand Down Expand Up @@ -264,4 +267,32 @@ public function testBreadcrumbsArray()

$this->assertEquals(array('A', 'B'), $helper->getBreadcrumbsArray($menu));
}

/**
* @expectedException BadMethodCallException
*/
public function testCurrentItemWithoutMatcher()
{
$helper = new Helper($this->getMock('Knp\Menu\Renderer\RendererProviderInterface'));
$helper->getCurrentItem('default');
}

public function testCurrentItem()
{
$matcher = new Matcher();

$menu = new MenuItem('root', new MenuFactory());
$menu->addChild('c1');
$menu['c1']->addChild('c1_1');
$menu->addChild('c2');
$menu['c2']->addChild('c2_1');
$menu['c2']->addChild('c2_2');
$menu['c2']['c2_2']->addChild('c2_2_1');
$menu['c2']['c2_2']->addChild('c2_2_2')->setCurrent(true);
$menu['c2']['c2_2']->addChild('c2_2_3');

$helper = new Helper($this->getMock('Knp\Menu\Renderer\RendererProviderInterface'), null, null, $matcher);

$this->assertSame('c2_2_2', $helper->getCurrentItem($menu)->getName());
}
}
19 changes: 19 additions & 0 deletions tests/Knp/Menu/Tests/Twig/MenuExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,25 @@ public function testIsAncestor()
$this->assertEquals('not ancestor', $this->getTemplate('{{ menu is knp_menu_ancestor ? "ancestor" : "not ancestor" }}', $helper, $matcher)->render(array('menu' => $menu)));
}

public function testGetCurrentItem()
{
$menu = $this->getMock('Knp\Menu\ItemInterface');
$helper = $this->getHelperMock(array('get', 'getCurrentItem'));
$helper->expects($this->once())
->method('get')
->with('default')
->will($this->returnValue($menu))
;
$matcher = $this->getMatcherMock();
$matcher->expects($this->any())
->method('isCurrent')
->with($menu)
->will($this->returnValue(true))
;

$this->assertEquals('current', $this->getTemplate('{{ knp_menu_get_current_item("default") is knp_menu_current ? "current" : "not current" }}', $helper, $matcher)->render(array()));
}

private function getHelperMock(array $methods)
{
return $this->getMockBuilder('Knp\Menu\Twig\Helper')
Expand Down

0 comments on commit a74c02b

Please sign in to comment.