diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 3c90db96..f0eb4b8e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -80,6 +80,12 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} + - run: | + sed -ri '/symfony\/deprecation-contracts/! s/"symfony\/(.+)": "(.+)"/"symfony\/\1": "'${{ matrix.symfony }}'"/' composer.json; + if: matrix.symfony + - run: | + sed -i 's/"symfony\/deprecation-contracts": "^2.4"/"symfony\/deprecation-contracts": "^3.1"/' composer.json + if: matrix.symfony == '6.4.*' - run: composer config --global --no-plugins allow-plugins.symfony/flex true && composer global require symfony/flex if: matrix.symfony - run: echo 'SYMFONY_REQUIRE=${{ matrix.symfony }}' >> "$GITHUB_ENV" diff --git a/composer.json b/composer.json index c955d319..73755b6b 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,8 @@ } ], "require": { - "php": "^8.1" + "php": "^8.1", + "symfony/deprecation-contracts": "^2.4 || ^3.0" }, "conflict": { "symfony/http-foundation": "<5.4", diff --git a/doc/01-Basic-Menus.md b/doc/01-Basic-Menus.md index 7f9a8fc2..472671d9 100644 --- a/doc/01-Basic-Menus.md +++ b/doc/01-Basic-Menus.md @@ -234,7 +234,7 @@ the second argument to the `render()` method: is an ancestor of the current item. * `currentAsLink` (default: `true`): Whether to render the "current" menu item as link or as span. * `currentClass` (default: `current`) -* `ancestorClass` (default: `current_ancestor`) +* `ancestor_class` (default: `current_ancestor`) (alias: ancestorClass, currently deprecated) * `firstClass` (default: `first`) * `lastClass` (default: `last`) * `compressed` (default: `false`) diff --git a/doc/examples/01_apply_active_class_to_whole_tree.md b/doc/examples/01_apply_active_class_to_whole_tree.md index 4fde2c32..2faa802e 100644 --- a/doc/examples/01_apply_active_class_to_whole_tree.md +++ b/doc/examples/01_apply_active_class_to_whole_tree.md @@ -6,12 +6,12 @@ render method of your used renderer: ```php render($item, ['currentClass' => 'active', 'ancestorClass' => 'active']); +$renderer->render($item, ['currentClass' => 'active', 'ancestor_class' => 'active']); ``` or pass it as argument to the constructor of the used renderer: ```php 'active', 'ancestorClass' => 'active']); +$renderer = new Renderer($matcher, ['currentClass' => 'active', 'ancestor_class' => 'active']); ``` diff --git a/src/Knp/Menu/Renderer/ListRenderer.php b/src/Knp/Menu/Renderer/ListRenderer.php index fa8c63e9..92d082f4 100644 --- a/src/Knp/Menu/Renderer/ListRenderer.php +++ b/src/Knp/Menu/Renderer/ListRenderer.php @@ -22,7 +22,7 @@ public function __construct(protected MatcherInterface $matcher, protected array 'matchingDepth' => null, 'currentAsLink' => true, 'currentClass' => 'current', - 'ancestorClass' => 'current_ancestor', + 'ancestor_class' => 'current_ancestor', 'firstClass' => 'first', 'lastClass' => 'last', 'compressed' => false, @@ -39,6 +39,13 @@ public function render(ItemInterface $item, array $options = []): string { $options = \array_merge($this->defaultOptions, $options); + // Avoid duplication of current_ancestor class. Overwrite value in old config to new one + if (isset($options['ancestorClass'])) { + $options['ancestor_class'] = $options['ancestorClass']; + unset($options['ancestorClass']); + trigger_deprecation('knplabs/knp-menu', '3.3', 'Using "%s" option is deprecated, use "%s" instead.', 'ancestorClass', 'ancestor_class'); + } + $html = $this->renderList($item, $item->getChildrenAttributes(), $options); if ($options['clear_matcher']) { @@ -121,7 +128,11 @@ protected function renderItem(ItemInterface $item, array $options): string if ($this->matcher->isCurrent($item)) { $class[] = $options['currentClass']; } elseif ($this->matcher->isAncestor($item, $options['matchingDepth'])) { - $class[] = $options['ancestorClass']; + if (isset($options['ancestorClass'])) { // Deprecated: it will be removed in future (@see: ancestor_class) + trigger_deprecation('knplabs/knp-menu', '3.3', 'Using "%s" option is deprecated, use "%s" instead.', 'ancestorClass', 'ancestor_class'); + $options['ancestor_class'] = $options['ancestorClass']; + } + $class[] = $options['ancestor_class']; } if ($item->actsLikeFirst()) { diff --git a/src/Knp/Menu/Renderer/RendererInterface.php b/src/Knp/Menu/Renderer/RendererInterface.php index 1855c463..70ee352d 100644 --- a/src/Knp/Menu/Renderer/RendererInterface.php +++ b/src/Knp/Menu/Renderer/RendererInterface.php @@ -16,7 +16,7 @@ interface RendererInterface * 1: only direct children * - currentAsLink: whether the current item should be a link * - currentClass: class added to the current item - * - ancestorClass: class added to the ancestors of the current item + * - ancestor_class: class added to the ancestors of the current item (alias: ancestorClass, deprecated in a future) * - firstClass: class added to the first child * - lastClass: class added to the last child * diff --git a/src/Knp/Menu/Renderer/TwigRenderer.php b/src/Knp/Menu/Renderer/TwigRenderer.php index 534c5aa8..ff1f92af 100644 --- a/src/Knp/Menu/Renderer/TwigRenderer.php +++ b/src/Knp/Menu/Renderer/TwigRenderer.php @@ -25,7 +25,7 @@ public function __construct( 'matchingDepth' => null, 'currentAsLink' => true, 'currentClass' => 'current', - 'ancestorClass' => 'current_ancestor', + 'ancestor_class' => 'current_ancestor', 'firstClass' => 'first', 'lastClass' => 'last', 'template' => $template, @@ -41,6 +41,13 @@ public function render(ItemInterface $item, array $options = []): string { $options = \array_merge($this->defaultOptions, $options); + // Avoid duplication of current_ancestor class. Overwrite value in old config to new one + if (isset($options['ancestorClass'])) { + $options['ancestor_class'] = $options['ancestorClass']; + unset($options['ancestorClass']); + trigger_deprecation('knplabs/knp-menu', '3.3', 'Using "%s" option is deprecated, use "%s" instead.', 'ancestorClass', 'ancestor_class'); + } + $html = $this->environment->render($options['template'], ['item' => $item, 'options' => $options, 'matcher' => $this->matcher]); if ($options['clear_matcher']) { diff --git a/src/Knp/Menu/Resources/views/knp_menu.html.twig b/src/Knp/Menu/Resources/views/knp_menu.html.twig index bb20becb..e9f62786 100644 --- a/src/Knp/Menu/Resources/views/knp_menu.html.twig +++ b/src/Knp/Menu/Resources/views/knp_menu.html.twig @@ -55,7 +55,11 @@ {%- if matcher.isCurrent(item) %} {%- set classes = classes|merge([options.currentClass]) %} {%- elseif matcher.isAncestor(item, options.matchingDepth) %} - {%- set classes = classes|merge([options.ancestorClass]) %} + {%- set classes = classes|merge([options.ancestor_class]) %} + {%- if options.ancestorClass is not empty %} + {% deprecated 'knplabs/knp-menu 3.3: Using "ancestorClass" option is deprecated, use "ancestor_class" instead.' %} + {%- set classes = classes|merge([options.ancestorClass]) %} + {%- endif %} {%- endif %} {%- if item.actsLikeFirst %} {%- set classes = classes|merge([options.firstClass]) %} diff --git a/src/Knp/Menu/Twig/MenuExtension.php b/src/Knp/Menu/Twig/MenuExtension.php index 8d72a4a8..d1b528a4 100644 --- a/src/Knp/Menu/Twig/MenuExtension.php +++ b/src/Knp/Menu/Twig/MenuExtension.php @@ -76,6 +76,13 @@ public function getLastModified(): int */ public function get(ItemInterface|string $menu, array $path = [], array $options = []): ItemInterface { + // Avoid duplication of current_ancestor class. Overwrite value in old config to new one + if (isset($options['ancestorClass'])) { + $options['ancestor_class'] = $options['ancestorClass']; + unset($options['ancestorClass']); + trigger_deprecation('knplabs/knp-menu', '3.3', 'Using "%s" option is deprecated, use "%s" instead.', 'ancestorClass', 'ancestor_class'); + } + assert(null !== $this->runtimeExtension); return $this->runtimeExtension->get($menu, $path, $options); @@ -89,6 +96,13 @@ public function get(ItemInterface|string $menu, array $path = [], array $options */ public function render(array|ItemInterface|string $menu, array $options = [], ?string $renderer = null): string { + // Avoid duplication of current_ancestor class. Overwrite value in old config to new one + if (isset($options['ancestorClass'])) { + $options['ancestor_class'] = $options['ancestorClass']; + unset($options['ancestorClass']); + trigger_deprecation('knplabs/knp-menu', '3.3', 'Using "%s" option is deprecated, use "%s" instead.', 'ancestorClass', 'ancestor_class'); + } + assert(null !== $this->runtimeExtension); return $this->runtimeExtension->render($menu, $options, $renderer); diff --git a/src/Knp/Menu/Twig/MenuRuntimeExtension.php b/src/Knp/Menu/Twig/MenuRuntimeExtension.php index a7d7e131..d31c08fb 100644 --- a/src/Knp/Menu/Twig/MenuRuntimeExtension.php +++ b/src/Knp/Menu/Twig/MenuRuntimeExtension.php @@ -42,6 +42,13 @@ public function get(ItemInterface|string $menu, array $path = [], array $options */ public function render(array|ItemInterface|string $menu, array $options = [], ?string $renderer = null): string { + // Avoid duplication of current_ancestor class. Overwrite value in old config to new one + if (isset($options['ancestorClass'])) { + $options['ancestor_class'] = $options['ancestorClass']; + unset($options['ancestorClass']); + trigger_deprecation('knplabs/knp-menu', '3.3', 'Using "%s" option is deprecated, use "%s" instead.', 'ancestorClass', 'ancestor_class'); + } + return $this->helper->render($menu, $options, $renderer); } diff --git a/tests/Knp/Menu/Tests/Renderer/AbstractRendererTest.php b/tests/Knp/Menu/Tests/Renderer/AbstractRendererTest.php index e568c2be..e3d5a124 100644 --- a/tests/Knp/Menu/Tests/Renderer/AbstractRendererTest.php +++ b/tests/Knp/Menu/Tests/Renderer/AbstractRendererTest.php @@ -199,7 +199,7 @@ public function testRenderWithClassAndTitle(): void $this->assertEquals($rendered, $this->renderer->render($this->menu)); } - public function testRenderWithCurrentItem(): void + public function testLegacyRenderWithCurrentItem(): void { $this->ch2->setCurrent(true); $rendered = '
foobar
', $this->getTemplate('{{ knp_menu_render(menu, {"firstClass": "test"}) }}', $helper)->render(['menu' => $menu])); } + /** + * @group legacy + */ + public function testLegacyRenderMenuWithDeprecatedAncestorClass(): void + { + $menu = $this->getMockBuilder(ItemInterface::class)->getMock(); + $helper = $this->getHelperMock(['render']); + $helper->expects($this->once()) + ->method('render') + ->with($menu, ['ancestor_class' => 'test'], null) + ; + + $this->getTemplate('{{ knp_menu_render(menu, {"ancestorClass": "test"}) }}', $helper)->render(['menu' => $menu, 'ancestorClass' => 'test']); + + $this->expectDeprecation(''); + } + public function testRenderMenuWithRenderer(): void { $menu = $this->getMockBuilder(ItemInterface::class)->getMock();