From c36679db44c87ffd8910dea3a211856baf039297 Mon Sep 17 00:00:00 2001 From: Charlotte Dumartin Date: Thu, 25 Jun 2015 01:19:47 +0200 Subject: [PATCH 1/3] Fixed issue #97 : add weight option --- composer.json | 3 +- doc/01-Basic-Menus.markdown | 15 +++++ src/Knp/Menu/Factory/CoreExtension.php | 2 + src/Knp/Menu/ItemInterface.php | 15 +++++ src/Knp/Menu/MenuItem.php | 50 +++++++++++++++++ src/Knp/Menu/Util/MenuManipulator.php | 1 + .../Knp/Menu/Tests/Iterator/IteratorTest.php | 10 +--- .../Menu/Tests/Util/MenuManipulatorTest.php | 55 ++++++++++++++----- 8 files changed, 127 insertions(+), 24 deletions(-) diff --git a/composer.json b/composer.json index 0592935f..1f4854fd 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,8 @@ } ], "require": { - "php": ">=5.3.0" + "php": ">=5.3.0", + "vanderlee/php-stable-sort-functions": "1.0.1" }, "require-dev": { "pimple/pimple": "1.0.*", diff --git a/doc/01-Basic-Menus.markdown b/doc/01-Basic-Menus.markdown index 0604a518..9990f00b 100644 --- a/doc/01-Basic-Menus.markdown +++ b/doc/01-Basic-Menus.markdown @@ -224,6 +224,21 @@ $renderer->render($menu); Using the above controls, you can specify exactly which part of your menu you need to render at any given time. +### Rendering with sorting by weight + +The renderer with the option weight abides by the menu levels. + +The default weight is 0. Positive weight are prioritized over negative (i.e : 1, 0, -1 is the order) + +```php +addChild('Home', array('weight' => -10)); + +// the second way +$menu['Home']->setWeight(-10); +``` + ### Other rendering options Most renderers also support several other options, which can be passed as diff --git a/src/Knp/Menu/Factory/CoreExtension.php b/src/Knp/Menu/Factory/CoreExtension.php index 472bedc9..c9f0a83e 100644 --- a/src/Knp/Menu/Factory/CoreExtension.php +++ b/src/Knp/Menu/Factory/CoreExtension.php @@ -30,6 +30,7 @@ public function buildOptions(array $options) 'current' => null, 'display' => true, 'displayChildren' => true, + 'weight' => 0, ), $options ); @@ -53,6 +54,7 @@ public function buildItem(ItemInterface $item, array $options) ->setCurrent($options['current']) ->setDisplay($options['display']) ->setDisplayChildren($options['displayChildren']) + ->setWeight($options['weight']) ; $this->buildExtras($item, $options); diff --git a/src/Knp/Menu/ItemInterface.php b/src/Knp/Menu/ItemInterface.php index 07a299ca..5452e9b4 100644 --- a/src/Knp/Menu/ItemInterface.php +++ b/src/Knp/Menu/ItemInterface.php @@ -451,4 +451,19 @@ public function actsLikeFirst(); * @return boolean */ public function actsLikeLast(); + + /** + * Define the position of the element in the menu in function level in the tree + * It can be positive or negative + * + * @param int $weight + * + * @return ItemInterface + */ + public function setWeight($weight); + + /** + * @return int + */ + public function getWeight(); } diff --git a/src/Knp/Menu/MenuItem.php b/src/Knp/Menu/MenuItem.php index 71703282..e84a66a8 100644 --- a/src/Knp/Menu/MenuItem.php +++ b/src/Knp/Menu/MenuItem.php @@ -80,6 +80,11 @@ class MenuItem implements ItemInterface */ protected $factory; + /** + * @var int + */ + protected $weight = 0; + /** * Class constructor * @@ -338,6 +343,8 @@ public function addChild($child, array $options = array()) $this->children[$child->getName()] = $child; + $this->setChildren($this->applySortByWeight($this->children)); + return $child; } @@ -593,4 +600,47 @@ public function offsetUnset($name) { $this->removeChild($name); } + + /** + * @param int $weight + * + * @return $this + */ + public function setWeight($weight) + { + $this->weight = $weight; + + return $this; + } + + /** + * @return int + */ + public function getWeight() + { + return $this->weight; + } + + /** + * @param array $children + * + * @return array + * + * @throws \RuntimeException + */ + public function applySortByWeight(array $children) + { + if (!@suasort($children, function(ItemInterface $itemA, ItemInterface $itemB) + { + if ($itemA->getWeight() === $itemB->getWeight()) { + return 0; + } + + return ($itemA->getWeight() > $itemB->getWeight()) ? -1 : 1; + })) { + throw new \RuntimeException('unable to sort those items by weight'); + } + + return $children; + } } diff --git a/src/Knp/Menu/Util/MenuManipulator.php b/src/Knp/Menu/Util/MenuManipulator.php index fcdbe5b9..5abc4b73 100644 --- a/src/Knp/Menu/Util/MenuManipulator.php +++ b/src/Knp/Menu/Util/MenuManipulator.php @@ -185,6 +185,7 @@ public function toArray(ItemInterface $item, $depth = null) 'extras' => $item->getExtras(), 'display' => $item->isDisplayed(), 'displayChildren' => $item->getDisplayChildren(), + 'weight' => $item->getWeight(), 'current' => $item->isCurrent(), ); diff --git a/tests/Knp/Menu/Tests/Iterator/IteratorTest.php b/tests/Knp/Menu/Tests/Iterator/IteratorTest.php index 3539b359..6bbdcf03 100644 --- a/tests/Knp/Menu/Tests/Iterator/IteratorTest.php +++ b/tests/Knp/Menu/Tests/Iterator/IteratorTest.php @@ -19,15 +19,7 @@ public function testIterator() public function testRecursiveIterator() { - // Adding an item which does not provide a RecursiveIterator to be sure it works properly. - $child = $this->getMock('Knp\Menu\ItemInterface'); - $child->expects($this->any()) - ->method('getName') - ->will($this->returnValue('Foo')); - $child->expects($this->any()) - ->method('getIterator') - ->will($this->returnValue(new \EmptyIterator())); - $this->menu->addChild($child); + $this->menu->addChild('Foo'); $names = array(); foreach (new \RecursiveIteratorIterator(new RecursiveItemIterator($this->menu), \RecursiveIteratorIterator::SELF_FIRST) as $value) { diff --git a/tests/Knp/Menu/Tests/Util/MenuManipulatorTest.php b/tests/Knp/Menu/Tests/Util/MenuManipulatorTest.php index 72c48449..3968159c 100644 --- a/tests/Knp/Menu/Tests/Util/MenuManipulatorTest.php +++ b/tests/Knp/Menu/Tests/Util/MenuManipulatorTest.php @@ -186,20 +186,7 @@ public function testCallRecursively() $menu = $factory->createItem('test_menu'); foreach (range(1, 2) as $i) { - $child = $this->getMock('Knp\Menu\ItemInterface'); - $child->expects($this->any()) - ->method('getName') - ->will($this->returnValue('Child '.$i)) - ; - $child->expects($this->once()) - ->method('setDisplay') - ->with(false) - ; - $child->expects($this->once()) - ->method('getChildren') - ->will($this->returnValue(array())) - ; - $menu->addChild($child); + $menu->addChild('Child '.$i, array('display' => false)); } $manipulator = new MenuManipulator(); @@ -236,6 +223,7 @@ public function testToArrayWithChildren() 'display' => true, 'displayChildren' => true, 'current' => null, + 'weight' => 0, 'children' => array( 'jack' => array( 'name' => 'jack', @@ -249,6 +237,7 @@ public function testToArrayWithChildren() 'display' => false, 'displayChildren' => true, 'current' => null, + 'weight' => 0, 'children' => array( 'john' => array( 'name' => 'john', @@ -263,6 +252,7 @@ public function testToArrayWithChildren() 'displayChildren' => true, 'children' => array(), 'current' => true, + 'weight' => 0, ), ), ), @@ -279,6 +269,7 @@ public function testToArrayWithChildren() 'displayChildren' => false, 'children' => array(), 'current' => false, + 'weight' => 0, ), ), ), @@ -309,6 +300,7 @@ public function testToArrayWithLimitedChildren() 'display' => true, 'displayChildren' => true, 'current' => null, + 'weight' => 0, 'children' => array( 'jack' => array( 'name' => 'jack', @@ -322,6 +314,7 @@ public function testToArrayWithLimitedChildren() 'display' => false, 'displayChildren' => true, 'current' => null, + 'weight' => 0, ), 'joe' => array( 'name' => 'joe', @@ -335,6 +328,7 @@ public function testToArrayWithLimitedChildren() 'display' => true, 'displayChildren' => false, 'current' => null, + 'weight' => 0, ), ), ), @@ -363,6 +357,7 @@ public function testToArrayWithoutChildren() 'display' => true, 'displayChildren' => true, 'current' => null, + 'weight' => 0, ), $manipulator->toArray($menu, 0) ); @@ -383,4 +378,36 @@ private function createMenu($name = 'test_menu', $uri = 'homepage', array $attri return $factory->createItem($name, array('attributes' => $attributes, 'uri' => $uri)); } + + public function testWeightOption() + { + // test stable sort with same weight + $menu = new MenuItem('root', new MenuFactory()); + $menu->addChild('c1', array('weight' => 10)); + $menu->addChild('c2', array('weight' => 10)); + $menu->addChild('c3', array('weight' => 10)); + $menu->addChild('c4', array('weight' => 10)); + $menu->addChild('c5', array('weight' => 10)); + + $this->assertEquals(array('c1', 'c2', 'c3', 'c4', 'c5'), array_keys($menu->getChildren())); + + + // test juste one level + $menu = new MenuItem('root', new MenuFactory()); + $c1 = $menu->addChild('c1', array('weight' => 50)); + $menu->addChild('c2', array('weight' => 1)); + $menu->addChild('c3', array('weight' => -10)); + $menu->addChild('c4', array('weight' => 5)); + + $this->assertEquals(array('c1', 'c4', 'c2', 'c3'), array_keys($menu->getChildren())); + + // test with add a second level in the menu + $c1->addChild('c11', array('weight' => -20)); + $c1->addChild('c12', array('weight' => -5)); + $c1->addChild('c13', array('weight' => 20)); + $c1->addChild('c14', array('weight' => 1)); + + $this->assertEquals(array('c1', 'c4', 'c2', 'c3'), array_keys($menu->getChildren())); // must not change + $this->assertEquals(array('c13', 'c14', 'c12', 'c11'), array_keys($c1->getChildren())); + } } From e87e40ee5b01ee230c0cae546bb84fe9fc16f114 Mon Sep 17 00:00:00 2001 From: Charlotte Dumartin Date: Sat, 18 Jul 2015 00:03:07 +0200 Subject: [PATCH 2/3] fix version stable sort functions and checkstyle --- composer.json | 2 +- src/Knp/Menu/MenuItem.php | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 1f4854fd..9cac28ed 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ ], "require": { "php": ">=5.3.0", - "vanderlee/php-stable-sort-functions": "1.0.1" + "vanderlee/php-stable-sort-functions": "~1.0" }, "require-dev": { "pimple/pimple": "1.0.*", diff --git a/src/Knp/Menu/MenuItem.php b/src/Knp/Menu/MenuItem.php index e84a66a8..657fdf07 100644 --- a/src/Knp/Menu/MenuItem.php +++ b/src/Knp/Menu/MenuItem.php @@ -630,13 +630,12 @@ public function getWeight() */ public function applySortByWeight(array $children) { - if (!@suasort($children, function(ItemInterface $itemA, ItemInterface $itemB) - { + if (!@suasort($children, function(ItemInterface $itemA, ItemInterface $itemB) { if ($itemA->getWeight() === $itemB->getWeight()) { return 0; } - return ($itemA->getWeight() > $itemB->getWeight()) ? -1 : 1; + return $itemA->getWeight() > $itemB->getWeight() ? -1 : 1; })) { throw new \RuntimeException('unable to sort those items by weight'); } From 3ddd6f4ac6c7814ce91bf697952cede60ffca2d0 Mon Sep 17 00:00:00 2001 From: Charlotte Dumartin Date: Mon, 27 Jul 2015 21:10:30 +0200 Subject: [PATCH 3/3] remove the ugly @ to display errors in tests --- src/Knp/Menu/MenuItem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Knp/Menu/MenuItem.php b/src/Knp/Menu/MenuItem.php index 657fdf07..07f0cffc 100644 --- a/src/Knp/Menu/MenuItem.php +++ b/src/Knp/Menu/MenuItem.php @@ -630,7 +630,7 @@ public function getWeight() */ public function applySortByWeight(array $children) { - if (!@suasort($children, function(ItemInterface $itemA, ItemInterface $itemB) { + if (!suasort($children, function(ItemInterface $itemA, ItemInterface $itemB) { if ($itemA->getWeight() === $itemB->getWeight()) { return 0; }