From 23c74decbd1af4f4a41b76f7145879dc5eb00e41 Mon Sep 17 00:00:00 2001 From: alexmerlin Date: Mon, 20 Jan 2025 11:37:06 +0200 Subject: [PATCH 1/2] Added support for laminas/laminas-servicemanager:4.x Signed-off-by: alexmerlin --- .laminas-ci.json | 6 ++++++ README.md | 6 +++--- composer.json | 15 +++++++------ docs/book/index.md | 2 +- docs/book/v3/overview.md | 2 +- mkdocs.yml | 2 +- psalm-baseline.xml | 5 ----- src/Provider/Factory.php | 6 +++++- src/Provider/ProviderPluginManager.php | 30 ++++++++++++++++++++------ test/Provider/FactoryTest.php | 12 +++++------ 10 files changed, 55 insertions(+), 31 deletions(-) create mode 100644 .laminas-ci.json mode change 100644 => 120000 docs/book/index.md diff --git a/.laminas-ci.json b/.laminas-ci.json new file mode 100644 index 0000000..790cfe4 --- /dev/null +++ b/.laminas-ci.json @@ -0,0 +1,6 @@ +{ + "ignore_php_platform_requirements": { + "8.4": true + }, + "backwardCompatibilityCheck": true +} diff --git a/README.md b/README.md index 8911399..77ba652 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,15 @@ [![Build Static](https://github.com/dotkernel/dot-navigation/actions/workflows/static-analysis.yml/badge.svg?branch=3.0)](https://github.com/dotkernel/dot-navigation/actions/workflows/static-analysis.yml) [![codecov](https://codecov.io/gh/dotkernel/dot-navigation/graph/badge.svg?token=AI9WFYDDX9)](https://codecov.io/gh/dotkernel/dot-navigation) -[![SymfonyInsight](https://insight.symfony.com/projects/68b7c728-4cc9-40ac-a3be-cf17f9b2eaf1/big.svg)](https://insight.symfony.com/projects/68b7c728-4cc9-40ac-a3be-cf17f9b2eaf1) - Allows you to easily define and parse menus inside templates, configuration based approach. ## Installation Run - composer require dotkernel/dot-navigation +```shell +composer require dotkernel/dot-navigation +``` Merge `ConfigProvider` to your application's configuration. diff --git a/composer.json b/composer.json index 46272b2..3197633 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "dotkernel/dot-navigation", "type": "library", - "description": "DotKernel navigation component", + "description": "Dotkernel navigation component", "license": "MIT", "homepage": "https://github.com/dotkernel/dot-navigation", "keywords": [ @@ -13,7 +13,7 @@ ], "authors": [ { - "name": "DotKernel Team", + "name": "Dotkernel Team", "email": "team@dotkernel.com" } ], @@ -24,17 +24,17 @@ } }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", "dotkernel/dot-authorization": "^3.4.1", - "dotkernel/dot-helpers": "^3.5.1", + "dotkernel/dot-helpers": "^3.7.0", "laminas/laminas-escaper": "^2.13.0", - "laminas/laminas-servicemanager": "^3.22.1", + "laminas/laminas-servicemanager": "^4.0", "mezzio/mezzio-template": "^2.9.0", "psr/http-message": "^1.0 || ^2.0", "psr/http-server-middleware": "^1.0.2" }, "require-dev": { - "laminas/laminas-coding-standard": "^2.5.0", + "laminas/laminas-coding-standard": "^3.0.0", "phpunit/phpunit": "^10.4.2", "vimeo/psalm": "^5.16.0" }, @@ -51,7 +51,8 @@ "scripts": { "check": [ "@cs-check", - "@test" + "@test", + "@static-analysis" ], "cs-check": "phpcs", "cs-fix": "phpcbf", diff --git a/docs/book/index.md b/docs/book/index.md deleted file mode 100644 index ae42a26..0000000 --- a/docs/book/index.md +++ /dev/null @@ -1 +0,0 @@ -../../README.md diff --git a/docs/book/index.md b/docs/book/index.md new file mode 120000 index 0000000..fe84005 --- /dev/null +++ b/docs/book/index.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/docs/book/v3/overview.md b/docs/book/v3/overview.md index 510ecd9..159d976 100644 --- a/docs/book/v3/overview.md +++ b/docs/book/v3/overview.md @@ -1,3 +1,3 @@ # Overview -`dot-navigation` is DotKernel's component that allows you to easily define and parse menus inside templates, using a configuration based approach. +`dot-navigation` is Dotkernel's component that allows you to easily define and parse menus inside templates, using a configuration based approach. diff --git a/mkdocs.yml b/mkdocs.yml index 38b44dd..10f8597 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -17,7 +17,7 @@ nav: - "Required Page Options": v3/required-page-options.md - Usage: v3/usage.md site_name: dot-navigation -site_description: "DotKernel's component that allows you to easily define and parse menus inside templates, using a configuration based approach." +site_description: "Dotkernel's component that allows you to easily define and parse menus inside templates, using a configuration based approach." repo_url: "https://github.com/dotkernel/dot-navigation" plugins: - search diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 915d9e0..5b45731 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -10,9 +10,4 @@ RecursiveIterator - - - ProviderPluginManager - - diff --git a/src/Provider/Factory.php b/src/Provider/Factory.php index 7944eed..54e3ad2 100644 --- a/src/Provider/Factory.php +++ b/src/Provider/Factory.php @@ -5,6 +5,7 @@ namespace Dot\Navigation\Provider; use Dot\Navigation\Exception\RuntimeException; +use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; class Factory implements FactoryInterface @@ -18,6 +19,9 @@ public function __construct(ContainerInterface $container, ?ProviderPluginManage $this->providerPluginManager = $providerPluginManager; } + /** + * @throws ContainerExceptionInterface + */ public function create(array $specs): ProviderInterface { $type = $specs['type'] ?? ''; @@ -25,7 +29,7 @@ public function create(array $specs): ProviderInterface throw new RuntimeException('Undefined navigation provider type'); } - return $this->getProviderPluginManager()->get($type, $specs['options'] ?? null); + return $this->getProviderPluginManager()->build($type, $specs['options'] ?? null); } public function getProviderPluginManager(): ProviderPluginManager diff --git a/src/Provider/ProviderPluginManager.php b/src/Provider/ProviderPluginManager.php index 4ea540c..e258bef 100644 --- a/src/Provider/ProviderPluginManager.php +++ b/src/Provider/ProviderPluginManager.php @@ -5,24 +5,42 @@ namespace Dot\Navigation\Provider; use Laminas\ServiceManager\AbstractPluginManager; +use Laminas\ServiceManager\Exception\InvalidServiceException; use Laminas\ServiceManager\Factory\InvokableFactory; +use function gettype; +use function is_object; +use function sprintf; + +/** + * @template InstanceType + * @extends AbstractPluginManager + */ class ProviderPluginManager extends AbstractPluginManager { - /** @var string $instanceOf */ - protected $instanceOf = ProviderInterface::class; + protected string $instanceOf = ProviderInterface::class; - /** @var array */ - protected $factories = [ + protected array $factories = [ ArrayProvider::class => InvokableFactory::class, ]; - /** @var string[] $aliases */ - protected $aliases = [ + protected array $aliases = [ 'arrayprovider' => ArrayProvider::class, 'arrayProvider' => ArrayProvider::class, 'ArrayProvider' => ArrayProvider::class, 'array' => ArrayProvider::class, 'Array' => ArrayProvider::class, ]; + + public function validate(mixed $instance): void + { + if (! $instance instanceof $this->instanceOf) { + throw new InvalidServiceException(sprintf( + '%s can only create instances of %s; %s is invalid', + static::class, + $this->instanceOf, + is_object($instance) ? $instance::class : gettype($instance) + )); + } + } } diff --git a/test/Provider/FactoryTest.php b/test/Provider/FactoryTest.php index 1570f7e..ea4bee7 100644 --- a/test/Provider/FactoryTest.php +++ b/test/Provider/FactoryTest.php @@ -12,10 +12,9 @@ use Laminas\ServiceManager\Exception\ServiceNotFoundException; use PHPUnit\Framework\MockObject\Exception; use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; -use function sprintf; - class FactoryTest extends TestCase { /** @@ -42,6 +41,7 @@ public function testWillCreateFactoryWithProviderPluginManager(): void } /** + * @throws ContainerExceptionInterface * @throws Exception */ public function testFactoryWillNotCreateProviderWithoutProviderType(): void @@ -55,6 +55,7 @@ public function testFactoryWillNotCreateProviderWithoutProviderType(): void } /** + * @throws ContainerExceptionInterface * @throws Exception */ public function testFactoryWillNotCreateProviderWithInvalidProviderType(): void @@ -63,10 +64,7 @@ public function testFactoryWillNotCreateProviderWithInvalidProviderType(): void $this->expectException(ServiceNotFoundException::class); $this->expectExceptionMessage( - sprintf( - 'A plugin by the name "test" was not found in the plugin manager %s', - ProviderPluginManager::class - ) + 'Unable to resolve service "test" to a factory; are you certain you provided it during configuration?' ); $factory = new Factory($container); $factory->create([ @@ -75,6 +73,7 @@ public function testFactoryWillNotCreateProviderWithInvalidProviderType(): void } /** + * @throws ContainerExceptionInterface * @throws Exception */ public function testFactoryWillCreateProviderWithValidProviderTypeAndNoOptions(): void @@ -89,6 +88,7 @@ public function testFactoryWillCreateProviderWithValidProviderTypeAndNoOptions() } /** + * @throws ContainerExceptionInterface * @throws Exception */ public function testFactoryWillCreateProviderWithValidProviderTypeAndOptions(): void From 0e3b8575f7c2f0751bd66396855a3081963c6bc4 Mon Sep 17 00:00:00 2001 From: alexmerlin Date: Mon, 20 Jan 2025 14:42:57 +0200 Subject: [PATCH 2/2] v4 docs Signed-off-by: alexmerlin --- README.md | 6 +-- SECURITY.md | 30 +++++--------- docs/book/v4/components.md | 13 ++++++ docs/book/v4/configuration.md | 7 ++++ docs/book/v4/container-providers.md | 7 ++++ docs/book/v4/installation.md | 5 +++ docs/book/v4/navigation-renderer.md | 11 +++++ docs/book/v4/overview.md | 3 ++ docs/book/v4/required-page-options.md | 7 ++++ docs/book/v4/usage.md | 58 +++++++++++++++++++++++++++ mkdocs.yml | 12 +++++- 11 files changed, 135 insertions(+), 24 deletions(-) create mode 100644 docs/book/v4/components.md create mode 100644 docs/book/v4/configuration.md create mode 100644 docs/book/v4/container-providers.md create mode 100644 docs/book/v4/installation.md create mode 100644 docs/book/v4/navigation-renderer.md create mode 100644 docs/book/v4/overview.md create mode 100644 docs/book/v4/required-page-options.md create mode 100644 docs/book/v4/usage.md diff --git a/README.md b/README.md index 77ba652..195a230 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ # dot-navigation ![OSS Lifecycle](https://img.shields.io/osslifecycle/dotkernel/dot-navigation) -![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-navigation/3.5.1) +![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-navigation/4.0.0) [![GitHub issues](https://img.shields.io/github/issues/dotkernel/dot-navigation)](https://github.com/dotkernel/dot-navigation/issues) [![GitHub forks](https://img.shields.io/github/forks/dotkernel/dot-navigation)](https://github.com/dotkernel/dot-navigation/network) [![GitHub stars](https://img.shields.io/github/stars/dotkernel/dot-navigation)](https://github.com/dotkernel/dot-navigation/stargazers) -[![GitHub license](https://img.shields.io/github/license/dotkernel/dot-navigation)](https://github.com/dotkernel/dot-navigation/blob/3.0/LICENSE.md) +[![GitHub license](https://img.shields.io/github/license/dotkernel/dot-navigation)](https://github.com/dotkernel/dot-navigation/blob/4.0/LICENSE.md) -[![Build Static](https://github.com/dotkernel/dot-navigation/actions/workflows/static-analysis.yml/badge.svg?branch=3.0)](https://github.com/dotkernel/dot-navigation/actions/workflows/static-analysis.yml) +[![Build Static](https://github.com/dotkernel/dot-navigation/actions/workflows/static-analysis.yml/badge.svg?branch=4.0)](https://github.com/dotkernel/dot-navigation/actions/workflows/static-analysis.yml) [![codecov](https://codecov.io/gh/dotkernel/dot-navigation/graph/badge.svg?token=AI9WFYDDX9)](https://codecov.io/gh/dotkernel/dot-navigation) Allows you to easily define and parse menus inside templates, configuration based approach. diff --git a/SECURITY.md b/SECURITY.md index 5cef5a6..843a21e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,17 +2,15 @@ ## Supported Versions - -| Version | Supported | PHP Version | -|---------|--------------------|---------------------------------------------------------------------------------------------------------------| -| 3.x | :white_check_mark: | ![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-navigation/3.4.2)| - +| Version | Supported | PHP Version | +|---------|--------------------|----------------------------------------------------------------------------------------------------------------| +| 4.x | :white_check_mark: | ![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-navigation/4.0.0) | +| <= 3.x | :x: | | ## Reporting Potential Security Issues -If you have encountered a potential security vulnerability in this project, -please report it to us at . We will work with you to -verify the vulnerability and patch it. +If you have encountered a potential security vulnerability in this project, please report it to us at . +We will work with you to verify the vulnerability and patch it. When reporting issues, please provide the following information: @@ -20,20 +18,12 @@ When reporting issues, please provide the following information: - A description indicating how to reproduce the issue - A summary of the security vulnerability and impact -We request that you contact us via the email address above and give the -project contributors a chance to resolve the vulnerability and issue a new -release prior to any public exposure; this helps protect the project's -users, and provides them with a chance to upgrade and/or update in order to -protect their applications. - +We request that you contact us via the email address above and give the project contributors a chance to resolve the vulnerability and issue a new release prior to any public exposure; +this helps protect the project's users, and provides them with a chance to upgrade and/or update in order to protect their applications. ## Policy If we verify a reported security vulnerability, our policy is: -- We will patch the current release branch, as well as the immediate prior minor - release branch. - -- After patching the release branches, we will immediately issue new security - fix releases for each patched release branch. - +- We will patch the current release branch, as well as the immediate prior minor release branch. +- After patching the release branches, we will immediately issue new security fix releases for each patched release branch. diff --git a/docs/book/v4/components.md b/docs/book/v4/components.md new file mode 100644 index 0000000..30b9399 --- /dev/null +++ b/docs/book/v4/components.md @@ -0,0 +1,13 @@ +# Components + +A menu, or navigation container, is a class implementing the \RecursiveIterator interface. It has a hierarchical structure, with nodes called pages(see the `Page` class) that may have children. It is basically a tree + +A Page extends the NavigationContainer class. The NavigationContainer is the top most node which represents the entire menu. The children of this node are Page instances that defines each navigation item. + +A page has a reference to its parent, and can have options and attributes. There are no limitation on what is accepted as options or attributes. + +Options can be any piece of information that describes a page. Some predefined options exists, in order for the navigation module to work seamlessly with other dot modules. + +Attributes are key value pairs that defines the menu item. They are usually inserted as html attributes when parsing the menu, but of course, this is implementation specific. + +A `NavigationService` class, is the service that handles all defined menu container. It can fetch the container from its provider, check if a page is active or not and get the page's generated URI. diff --git a/docs/book/v4/configuration.md b/docs/book/v4/configuration.md new file mode 100644 index 0000000..0b01125 --- /dev/null +++ b/docs/book/v4/configuration.md @@ -0,0 +1,7 @@ +# Configuration + +After installation, register `dot-navigation` in your project by adding the below line to your configuration aggregator (usually: `config/config.php`): + + Dot\Navigation\ConfigProvider::class, + +Locate dot-navigation's distributable config file `vendor/dotkernel/dot-navigation/config/autoload/navigation.global.php.dist` and duplicate it in your project as `config/autoload/navigation.global.php` diff --git a/docs/book/v4/container-providers.md b/docs/book/v4/container-providers.md new file mode 100644 index 0000000..c8b4825 --- /dev/null +++ b/docs/book/v4/container-providers.md @@ -0,0 +1,7 @@ +# Container providers + +Each menu can be created from different sources. The responsibility of creating a menu container from the source falls on a container provider. + +Each provider must implement the interface `ProviderInterface` and be registered in the ProviderPluginManager. + +We offer just one provider for now, `ArrayProvider`, that is able to fetch and create a menu container from a php array that is defined in the configuration file. diff --git a/docs/book/v4/installation.md b/docs/book/v4/installation.md new file mode 100644 index 0000000..b4eb651 --- /dev/null +++ b/docs/book/v4/installation.md @@ -0,0 +1,5 @@ +# Installation + +Install `dotkernel/dot-navigation` by executing the following Composer command: + + composer require dotkernel/dot-navigation diff --git a/docs/book/v4/navigation-renderer.md b/docs/book/v4/navigation-renderer.md new file mode 100644 index 0000000..cb66fac --- /dev/null +++ b/docs/book/v4/navigation-renderer.md @@ -0,0 +1,11 @@ +# NavigationRenderer + +Used to render the navigation container in a displayable format. It can render a simple HTML ul list or use a partial template, to render the menu in a template engine. + +The partial method is usually the more flexible one, custom rules can be defined and checked in the template. + +If you are using twig, there is already a twig extension provided in package dot-twigrenderer, that you can use to easily parse the menus inside your templates + +When using the partial method, the template will receive as parameters the container, the navigation service and any extra parameters set by the developer. + +Navigation containers are referred, when parsed, by their name, as defined in the configuration file. diff --git a/docs/book/v4/overview.md b/docs/book/v4/overview.md new file mode 100644 index 0000000..159d976 --- /dev/null +++ b/docs/book/v4/overview.md @@ -0,0 +1,3 @@ +# Overview + +`dot-navigation` is Dotkernel's component that allows you to easily define and parse menus inside templates, using a configuration based approach. diff --git a/docs/book/v4/required-page-options.md b/docs/book/v4/required-page-options.md new file mode 100644 index 0000000..36dd780 --- /dev/null +++ b/docs/book/v4/required-page-options.md @@ -0,0 +1,7 @@ +# Required page options and attributes + +The following are options that each page should define in the configuration + +* `label` - the text of the menu item +* `route` or `uri` - defines the route or link the menu item will have +* `permission` - can be used optionally, if authorization service is present, in order to omit menu items that are not authorized to visit. diff --git a/docs/book/v4/usage.md b/docs/book/v4/usage.md new file mode 100644 index 0000000..666ce60 --- /dev/null +++ b/docs/book/v4/usage.md @@ -0,0 +1,58 @@ +# Usage + +Below is an example with content of `config/autoload/navigation.global.php`. + +Here we can change or modify the menu structure that will be rendered in the application we are building. + +```php + [ + //enable menu item active if any child is active + 'active_recursion' => true, + + //map a provider name to its config + 'containers' => [ + 'default' => [ + 'type' => 'ArrayProvider', + 'options' => [ + 'items' => [ + [ + 'options' => [ + 'label' => 'Menu #1', + 'route' => [ + 'route_name' => 'home', + 'route_params' => [], + 'query_params' => [], + 'fragment_id' => null, + 'options' => [], + + //the below parameters are not used in route generation + //they are used in finding if a page is active by omitting some parameters from the check + 'ignore_params' => [] + ], + ], + 'attributes' => [ + 'name' => 'Menu #1', + ] + ], + [ + 'options' => [ + 'label' => 'Menu #2', + 'route' => ['route_name' => 'home'], + ], + 'attributes' => [ + 'name' => 'Menu #1', + ] + ] + ], + ], + ], + ], + + //register custom providers here + 'provider_manager' => [], + ], +]; +``` diff --git a/mkdocs.yml b/mkdocs.yml index 10f8597..3edc779 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,11 +2,21 @@ docs_dir: docs/book site_dir: docs/html extra: project: Packages - current_version: v3 + current_version: v4 versions: + - v4 - v3 nav: - Home: index.md + - v4: + - Overview: v4/overview.md + - Configuration: v4/configuration.md + - Installation: v4/installation.md + - Components: v4/components.md + - "Container Providers": v4/container-providers.md + - "Navigation Renderer": v4/navigation-renderer.md + - "Required Page Options": v4/required-page-options.md + - Usage: v4/usage.md - v3: - Overview: v3/overview.md - Configuration: v3/configuration.md