diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a1fff83f..bc3772f3 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -60,10 +60,9 @@ jobs: php: '8.1' symfony: 6.4.* max_deprecations: 0 - - description: 'Symfony 7' + - description: 'Dev deps' php: '8.4' dev: true - symfony: 7.2.* max_deprecations: 0 name: PHP ${{ matrix.php }} tests (${{ matrix.description }}) steps: @@ -78,10 +77,11 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - - run: | - sed -ri 's/"symfony\/(.+)": "(.+)"/"symfony\/\1": "'${{ matrix.symfony }}'"/' composer.json; + - run: composer config --global --no-plugins allow-plugins.symfony/flex true && composer global require symfony/flex if: matrix.symfony - - run: composer config minimum-stability dev && composer config prefer-stable true + - run: echo 'SYMFONY_REQUIRE=${{ matrix.symfony }}' >> "$GITHUB_ENV" + if: matrix.symfony + - run: composer config minimum-stability dev if: matrix.dev - run: composer update --no-interaction --no-progress --ansi ${{ matrix.composer_option }} - run: vendor/bin/phpunit diff --git a/composer.json b/composer.json index 261774ca..64cb6954 100644 --- a/composer.json +++ b/composer.json @@ -23,10 +23,11 @@ "php": "^8.1" }, "conflict": { - "twig/twig": "<1.42.3 || >=2,<2.9" + "symfony/http-foundation": "<5.4", + "twig/twig": "<2.16" }, "require-dev": { - "phpstan/phpstan": "^1.10", + "phpstan/phpstan": "^2.1", "phpunit/phpunit": "^9.6", "psr/container": "^1.0 || ^2.0", "symfony/http-foundation": "^5.4 || ^6.0 || ^7.0", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 020d45df..1f6a573b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,42 +1,8 @@ parameters: ignoreErrors: - - message: "#^Call to an undefined method Symfony\\\\Component\\\\HttpFoundation\\\\RequestStack\\:\\:getMasterRequest\\(\\)\\.$#" - count: 1 - path: src/Knp/Menu/Matcher/Voter/RouteVoter.php - - - - message: "#^Strict comparison using \\=\\=\\= between false and array\\ will always evaluate to false\\.$#" - count: 1 - path: src/Knp/Menu/MenuItem.php - - - - message: "#^Parameter \\#2 \\$path of method Knp\\\\Menu\\\\Twig\\\\Helper\\:\\:get\\(\\) expects array\\, array\\ given\\.$#" + message: '#^Parameter \#2 \$path of method Knp\\Menu\\Twig\\Helper\:\:get\(\) expects array\, array\ given\.$#' + identifier: argument.type count: 1 path: src/Knp/Menu/Twig/Helper.php - - - message: "#^Method Knp\\\\Menu\\\\Util\\\\MenuManipulator\\:\\:getBreadcrumbsArray\\(\\) should return array\\ but returns array\\\\.$#" - count: 1 - path: src/Knp/Menu/Util/MenuManipulator.php - - - - message: "#^Method Knp\\\\Menu\\\\Twig\\\\MenuExtension\\:\\:getBreadcrumbsArray\\(\\) has parameter \\$subItem with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Knp/Menu/Twig/MenuExtension.php - - - - message: "#^PHPDoc tag @param for parameter \\$subItem with type array\\\\|float\\|int\\|Knp\\\\Menu\\\\ItemInterface\\|string\\|null\\>\\|string\\|Traversable\\\\|float\\|int\\|Knp\\\\Menu\\\\ItemInterface\\|string\\|null\\> is not subtype of native type array\\|string\\|null\\.$#" - count: 1 - path: src/Knp/Menu/Twig/MenuExtension.php - - - - message: "#^Method Knp\\\\Menu\\\\Twig\\\\MenuRuntimeExtension\\:\\:getBreadcrumbsArray\\(\\) has parameter \\$subItem with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Knp/Menu/Twig/MenuRuntimeExtension.php - - - - message: "#^PHPDoc tag @param for parameter \\$subItem with type array\\\\|float\\|int\\|Knp\\\\Menu\\\\ItemInterface\\|string\\|null\\>\\|string\\|Traversable\\\\|float\\|int\\|Knp\\\\Menu\\\\ItemInterface\\|string\\|null\\> is not subtype of native type array\\|string\\|null\\.$#" - count: 1 - path: src/Knp/Menu/Twig/MenuRuntimeExtension.php - diff --git a/phpstan.neon b/phpstan.neon index 996ae6cf..0ba884ff 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,6 @@ parameters: level: 8 + treatPhpDocTypesAsCertain: false paths: - src includes: diff --git a/src/Knp/Menu/Iterator/CurrentItemFilterIterator.php b/src/Knp/Menu/Iterator/CurrentItemFilterIterator.php index cf993172..8008c42a 100644 --- a/src/Knp/Menu/Iterator/CurrentItemFilterIterator.php +++ b/src/Knp/Menu/Iterator/CurrentItemFilterIterator.php @@ -2,15 +2,19 @@ namespace Knp\Menu\Iterator; +use Knp\Menu\ItemInterface; use Knp\Menu\Matcher\MatcherInterface; /** * Filter iterator keeping only current items + * + * @template TKey + * @template-extends \FilterIterator> */ class CurrentItemFilterIterator extends \FilterIterator { /** - * @param \Iterator $iterator + * @param \Iterator $iterator */ public function __construct(\Iterator $iterator, private MatcherInterface $matcher) { diff --git a/src/Knp/Menu/Iterator/RecursiveItemIterator.php b/src/Knp/Menu/Iterator/RecursiveItemIterator.php index 5284690f..fe4edfbd 100644 --- a/src/Knp/Menu/Iterator/RecursiveItemIterator.php +++ b/src/Knp/Menu/Iterator/RecursiveItemIterator.php @@ -2,17 +2,21 @@ namespace Knp\Menu\Iterator; +use Knp\Menu\ItemInterface; + /** * Recursive iterator iterating on an item * - * @extends \IteratorIterator> + * @template TKey + * + * @extends \IteratorIterator> * - * @implements \RecursiveIterator> + * @implements \RecursiveIterator */ class RecursiveItemIterator extends \IteratorIterator implements \RecursiveIterator { /** - * @param \Traversable $iterator + * @param \Traversable $iterator */ final public function __construct(\Traversable $iterator) { @@ -25,7 +29,7 @@ public function hasChildren(): bool } /** - * @return RecursiveItemIterator + * @return RecursiveItemIterator */ #[\ReturnTypeWillChange] public function getChildren() diff --git a/src/Knp/Menu/Matcher/Voter/RouteVoter.php b/src/Knp/Menu/Matcher/Voter/RouteVoter.php index 6678e5ad..4b2b43f7 100644 --- a/src/Knp/Menu/Matcher/Voter/RouteVoter.php +++ b/src/Knp/Menu/Matcher/Voter/RouteVoter.php @@ -17,11 +17,7 @@ public function __construct(private RequestStack $requestStack) public function matchItem(ItemInterface $item): ?bool { - if (\method_exists($this->requestStack, 'getMainRequest')) { - $request = $this->requestStack->getMainRequest(); // symfony 5.3+ - } else { - $request = $this->requestStack->getMasterRequest(); - } + $request = $this->requestStack->getMainRequest(); if (null === $request) { return null; diff --git a/src/Knp/Menu/MenuItem.php b/src/Knp/Menu/MenuItem.php index bbd8908f..66db4242 100644 --- a/src/Knp/Menu/MenuItem.php +++ b/src/Knp/Menu/MenuItem.php @@ -148,9 +148,7 @@ public function setName(string $name): ItemInterface $offset = \array_search($oldName, $names); $names[$offset] = $name; - if (false === $children = \array_combine($names, $items)) { - throw new \InvalidArgumentException('Number of elements is not matching.'); - } + $children = \array_combine($names, $items); $parent->setChildren($children); } diff --git a/src/Knp/Menu/Twig/Helper.php b/src/Knp/Menu/Twig/Helper.php index 5ecb9620..957f8c9c 100644 --- a/src/Knp/Menu/Twig/Helper.php +++ b/src/Knp/Menu/Twig/Helper.php @@ -41,10 +41,6 @@ public function get($menu, array $path = [], array $options = []): ItemInterface $menuName = $menu; $menu = $this->menuProvider->get($menuName, $options); - - if (!$menu instanceof ItemInterface) { - throw new \LogicException(\sprintf('The menu "%s" exists, but is not a valid menu item object. Check where you created the menu to be sure it returns an ItemInterface object.', $menuName)); - } } foreach ($path as $child) { @@ -82,7 +78,7 @@ public function render($menu, array $options = [], ?string $renderer = null): st * * Each element in the array will be an array with 3 keys: * - `label` containing the label of the item - * - `url` containing the url of the item (may be `null`) + * - `uri` containing the url of the item (may be `null`) * - `item` containing the original item (may be `null` for the extra items) * * The subItem can be one of the following forms @@ -90,12 +86,12 @@ public function render($menu, array $options = [], ?string $renderer = null): st * * ItemInterface object * * ['subItem' => '@homepage'] * * ['subItem1', 'subItem2'] - * * [['label' => 'subItem1', 'url' => '@homepage'], ['label' => 'subItem2']] + * * [['label' => 'subItem1', 'uri' => '@homepage'], ['label' => 'subItem2']] * * @param mixed $menu * @param mixed $subItem A string or array to append onto the end of the array * - * @phpstan-param string|ItemInterface|array|\Traversable $subItem + * @phpstan-param string|ItemInterface|array|\Traversable $subItem * * @return array> * diff --git a/src/Knp/Menu/Twig/MenuExtension.php b/src/Knp/Menu/Twig/MenuExtension.php index 12a2b663..84e57c51 100644 --- a/src/Knp/Menu/Twig/MenuExtension.php +++ b/src/Knp/Menu/Twig/MenuExtension.php @@ -89,9 +89,8 @@ public function render(array|ItemInterface|string $menu, array $options = [], ?s /** * @param string|ItemInterface|array $menu - * @param string|array|null $subItem * - * @phpstan-param string|ItemInterface|array|\Traversable $subItem + * @phpstan-param string|array $subItem * * @return array> * @phpstan-return list diff --git a/src/Knp/Menu/Twig/MenuRuntimeExtension.php b/src/Knp/Menu/Twig/MenuRuntimeExtension.php index e084a143..5dc4f5fc 100644 --- a/src/Knp/Menu/Twig/MenuRuntimeExtension.php +++ b/src/Knp/Menu/Twig/MenuRuntimeExtension.php @@ -42,9 +42,8 @@ public function render(array|ItemInterface|string $menu, array $options = [], ?s * Returns an array ready to be used for breadcrumbs. * * @param string|ItemInterface|array $menu - * @param string|array|null $subItem * - * @phpstan-param string|ItemInterface|array|\Traversable $subItem + * @phpstan-param string|array $subItem * * @return array> * @phpstan-return list diff --git a/src/Knp/Menu/Util/MenuManipulator.php b/src/Knp/Menu/Util/MenuManipulator.php index 5abb0d22..34d6099c 100644 --- a/src/Knp/Menu/Util/MenuManipulator.php +++ b/src/Knp/Menu/Util/MenuManipulator.php @@ -74,8 +74,8 @@ public function moveToLastPosition(ItemInterface $item): void * Note: when using a child as limit, it will not be included in the returned menu. * the slice is done before this menu. * - * @param mixed $offset name of child, child object, or numeric offset - * @param string|int|ItemInterface $length name of child, child object, or numeric length + * @param mixed $offset name of child, child object, or numeric offset + * @param string|int|ItemInterface|null $length name of child, child object, or numeric length */ public function slice(ItemInterface $item, $offset, $length = null): ItemInterface { @@ -196,7 +196,7 @@ public function toArray(ItemInterface $item, ?int $depth = null): array * * Each element in the array will be an array with 3 keys: * - `label` containing the label of the item - * - `url` containing the url of the item (may be `null`) + * - `uri` containing the url of the item (may be `null`) * - `item` containing the original item (may be `null` for the extra items) * * The subItem can be one of the following forms @@ -206,9 +206,9 @@ public function toArray(ItemInterface $item, ?int $depth = null): array * * ['subItem1', 'subItem2'] * * [['label' => 'subItem1', 'url' => '@homepage'], ['label' => 'subItem2']] * - * @param string|ItemInterface|array|\Traversable $subItem A string or array to append onto the end of the array + * @param string|ItemInterface|array|\Traversable|null $subItem A string or array to append onto the end of the array * - * @phpstan-param string|ItemInterface|array|\Traversable $subItem + * @phpstan-param string|ItemInterface|array|\Traversable|null $subItem * * @return array> * @phpstan-return list