Skip to content
This repository has been archived by the owner on Jan 30, 2020. It is now read-only.

Zend\Navigation does not work with Zend\Expressive #56

Open
RalfEggert opened this issue Dec 28, 2016 · 36 comments
Open

Zend\Navigation does not work with Zend\Expressive #56

RalfEggert opened this issue Dec 28, 2016 · 36 comments

Comments

@RalfEggert
Copy link
Contributor

I want to use Zend\Navigation in a Zend\Expressive application. First of all, I installed it:

composer require zendframework/zend-navigation

Composer installed it and added the ConfigProvider to my /config/config.php file:

$configManager = new ConfigManager(
    [
        Zend\I18n\ConfigProvider::class,
        Zend\Form\ConfigProvider::class,
        Zend\InputFilter\ConfigProvider::class,
        Zend\Hydrator\ConfigProvider::class,
        Zend\Session\ConfigProvider::class,
        TravelloViewHelper\ConfigProvider::class,
        new PhpFileProvider($pattern),
    ],
    $cachedConfigFile
);

When I try to use the navigation view helper in a template, I get this error:

A plugin by the name "navigation" was not found in the plugin manager Zend\View\HelperPluginManager

So, I added the Zend\Navigation\View\ViewHelperManagerDelegatorFactory to my configuration:

return [
    'dependencies' => [
        'delegators' => [
            Zend\View\HelperPluginManager::class => [
                Zend\Navigation\View\ViewHelperManagerDelegatorFactory::class,
            ],
        ],
    ],
];

No I get this error:

Unable to resolve service "Application" to a factory; are you certain you provided it during configuration?

After some investigation the problem is located here:

https://github.com/zendframework/zend-navigation/blob/master/src/Service/AbstractNavigationFactory.php#L102

The AbstractNavigationFactory seems to have a hard dependency on the MVC application which makes it impossible to use Zend\Navigation with Zend\Expressive currently.

Are there any plans to solve this? What should be done to break up this hard dependency? I guess it would be quite complicated to run Zend\Navigation both with Zend\Mvc and Zend\Expressive, wouldn't it?

@RalfEggert
Copy link
Contributor Author

@froschdesign
Copy link
Member

I also found out, that Zend\Navigation still refers to Zend\Mvc\Router in two places:

Right. At the moment, the navigation component supports the old router of the mvc component and the new router component:

use Zend\Mvc\Router as MvcRouter;
use Zend\Router\RouteMatch;
use Zend\Router\RouteStackInterface;

But I think this is not the problem. Please have a look at Zend\Navigation\Service\AbstractNavigationFactory::preparePages():

$application = $container->get('Application');
$routeMatch  = $application->getMvcEvent()->getRouteMatch();
$router      = $application->getMvcEvent()->getRouter();
$request     = $application->getMvcEvent()->getRequest();

This matches the error message you posted. And this is the problem!

Are there any plans to solve this?

Sure! 😃

I guess it would be quite complicated to run Zend\Navigation both with Zend\Mvc and Zend\Expressive, wouldn't it?

zend-navigation must run without zend-mvc.

@RalfEggert
Copy link
Contributor Author

zend-navigation must run without zend-mvc.

Yep.

Currently Zend\Navigation depends on the Zend\Mvc\Application to access the Zend\Mvc\MvcEvent to access the RouteMatch, Router and Request objects. And its Zend\Navigation\Page\Mvc depends on the Zend\Router. So MVC is quite depply integrated.

To split this up we might need some integration components for Zend\Mvc and Zend\Expressive. Similar to the Zend\Mvc\I18n and packages. Sounds like a lot of work...

@froschdesign
Copy link
Member

froschdesign commented Dec 28, 2016

Currently Zend\Navigation depends on the Zend\Mvc\Application to access the Zend\Mvc\MvcEvent to access the RouteMatch, Router and Request objects.

Right, but only in the current factories!

And its Zend\Navigation\Page\Mvc depends on the Zend\Router. So MVC is quite depply integrated.

Yes and no! 😉
The Zend\Navigation\Page\Mvc depends on zend-router, not zend-mvc!
And zend-router is optional for the entire navigation component.

@tobias-trozowski
Copy link

tobias-trozowski commented Dec 31, 2016

Currently Zend\Navigation depends on the Zend\Mvc\Application to access the Zend\Mvc\MvcEvent to access the RouteMatch, Router and Request objects.

Right, but only in the current factories!

Nope :)
Have a look into Zend\Navigation\Page\Uri::isActive and Zend\Navigation\Page\Mvc::isActive.
The whole "isActive-Strategy" currently depends on a existing RouteMatch or - in case of Page\Uri - the Request object (nope, not the Psr\Http\Message\ServerRequestInterface, it's Zend\Http\Request).
And AFAIK both - RouteMatch and Request - is not available outside the middleware chain.

I really tried to find a better way but for now thats what works for me. At least with the Page\Mvc.

/**
 * @param ContainerInterface $container
 * @param array|\Zend\Config\Config $pages
 * @return null|array
 * @throws \Zend\Navigation\Exception\InvalidArgumentException
 */
protected function preparePages(ContainerInterface $container, $pages)
{
    /** @var RouterInterface $router */
    $router = $container->get(RouterInterface::class);
    // mah... it's ugly, i know
    $request = ServerRequestFactory::fromGlobals();
    $routeMatch = $router->match($request);

    // HTTP request is the only one that may be injected
    if (! $request instanceof Request) {
        $request = null;
    }

    return $this->injectComponents($pages, $routeMatch, $router, $request);
}

@froschdesign
Copy link
Member

Nope :)

Please read carefully, because the content of Ralf's message was different:

Currently Zend\Navigation depends on the Zend\Mvc\Application…

Zend\Mvc is only used in the factories! 😃
Without the current factories you can use the mvc page only with zend-router. No need for the mvc component.

The whole "isActive-Strategy" currently depends on a existing RouteMatch or - in case of Page\Uri - the Request object.

The same here: the mvc component is not needed.

And AFAIK both - RouteMatch and Request - is not available outside the middleware chain.

Right, but that was not the content of Ralf's message.


$routeMatch = $router->match($request);

This creates a Zend\Expressive\Router\RouteResult, but the original injectComponents methods needs an object of Zend\Router\RouteMatch?!

@tobias-trozowski
Copy link

And yep, the match method will create a Zend\Expressive\Router\RouteResult. I had to overwrite the injectComponents too.

Didn't expect that zend-expressive have own implementation for the routing. I supposed zend-expressive uses zend-router.

@weierophinney
Copy link
Member

Didn't expect that zend-expressive have own implementation for the routing. I supposed zend-expressive uses zend-router.

We developed an abstraction around routing, to allow usage of any routing library, and provide three implementations: Aura.Route, FastRoute, and zend-router; FastRoute is the recommended router!

Thanks for opening this issue; clearly, we need to see if we can make it a bit more generic going forward!

@Sohorev
Copy link

Sohorev commented Feb 6, 2017

When you plan to fix the bug? I need to understand whether or not to wait for the decision or to use something else for menu.

@froschdesign
Copy link
Member

@Sohorev

…fix the bug?

This is not a bug, because zend-navigation was never designed and developed to use different types of router.
Now we have to implement this new way.

When? I will look into over the weekend.

@RalfEggert
Copy link
Contributor Author

@froschdesign that will be really great!

@froschdesign
Copy link
Member

@RalfEggert and @weierophinney
I have created a first simple test: froschdesign@02190ac

I wanted an implementation for version 2 of zend-navigation. Therefore, the test includes only new files and no changes in existing files.

(Notice: at the moment there is no support for multiple navigations)

Usage

dependencies.global.php

'dependencies' => [
    'factories'  => [
        Zend\Navigation\Navigation::class => Zend\Navigation\Service\ExpressiveNavigationFactory::class,
    ],
    'delegators' => [
        Zend\View\HelperPluginManager::class => [
            Zend\Navigation\View\ViewHelperManagerDelegatorFactory::class,
        ],
    ],
],

middleware-pipeline.global.php

'dependencies' => [
    'factories' => [
        Zend\Navigation\Middleware\NavigationMiddleware::class => Zend\Navigation\Middleware\NavigationMiddlewareFactory::class,
    ],
],
'middleware_pipeline' => [
    'routing' => [
        'middleware' => [
            ApplicationFactory::ROUTING_MIDDLEWARE,
            Zend\Navigation\Middleware\NavigationMiddleware::class,
            ApplicationFactory::DISPATCH_MIDDLEWARE,
        ],
    ],
],

Add a configuration for the navigation itself:

navigation.global.php

return [
    'navigation' => [
        'default' => [
            [
                'label' => 'Home',
                'route' => 'home',
            ],
            [
                'label'  => 'Add album',
                'route'  => 'album',
                'params' => [
                    'action' => 'add',
                ],
            ],
            [
                'label'  => 'Edit album',
                'route'  => 'album',
                'params' => [
                    'action' => 'edit',
                ],
            ],
        ],
    ],
];

@RalfEggert
Copy link
Contributor Author

This looks great. Having an additional ExpressivePage might make it easy to adopt this. It is really a pain that I cannot use Zend\Navigation properly with Zend\Expressive. This will definitely help.

In the long run we should make Zend\Navigation independent from the MVC router if possible although I understand that it will be a lot of work.

👍 👍 👍

@alextech
Copy link
Contributor

independent from the MVC router

Maybe this move can one time address performance issues that are turning people away from it (or at least I have seen in IRC complain, not sure exactly why, I suspect it deals with redundant router match). isActive recursively comparing whether every page is active feels very redundant. Can this dependency be inversed, where after dispatch event completes if navigation module is present, it is told what the current active page is?

If navigation is told what is active, instead of the other way around, have opportunity to do better tree traversing, instead of brute-force recursive check of all nodes. If Z\Navigation stores its page node references not purely based on navigation hierarchy, but is "indexed" but route property of the pages, that index can be taken advantage of to quickly mark what page is active with $navigation->setActive($routerPath).

@RalfEggert
Copy link
Contributor Author

@froschdesign @weierophinney

Any news? I am really looking forward for this patch to let Zend\Navigation work with Zend\Expressive.

@froschdesign
Copy link
Member

@RalfEggert
Last saturday I added the tests and some fixes for the ExpressivePage class. More tests are on the way.

The support for multiple navigations is still missing.

@Sohorev
Copy link

Sohorev commented Feb 28, 2017

@froschdesign thankyou for you patch
When you plan add it to composer package?

@mano87
Copy link

mano87 commented Mar 6, 2017

@froschdesign
This is great - we also want to use the navigation with zend-expressive! Will this be basically integrated into zend-navigation?

@froschdesign
Copy link
Member

News

Code updates

  • NavigationMiddleware and NavigationMiddlewareFactory can now handle multiple navigation containers
  • ExpressiveNavigationFactory can be used for a single navigation (has no dependencies to zend-servicemanager)
  • ExpressiveNavigationAbstractServiceFactory can be used for a single or for multiple navigations (has dependencies to zend-servicemanager)

(not yet online - sorry!)

Next steps

  • complete all unit tests
  • creating a PR
  • calling for review

When

I hope tomorrow!

@RalfEggert
Copy link
Contributor Author

Nice one! 👍

@RalfEggert
Copy link
Contributor Author

It just comes in time with Zend\Expressive

@froschdesign froschdesign added this to the 2.9.0 milestone Mar 10, 2017
@weierophinney
Copy link
Member

@unnamed666 Please open a new issue with your question, instead of commenting on an unrelated one.

Alternately, use our new forums: https://discourse.zendframework.com.

@av3
Copy link

av3 commented Jun 13, 2017

I wanted to create a new project based on Expressive and had the same errors as Ralf and saw that there is a pull request, which is still open. Could you tell us, when it will be possible to use zend-navigation in Expressive or what I could do to use it with the current version (if possible)? In the documentation of Expressive the navigation isn't mentioned.

@froschdesign
Copy link
Member

froschdesign commented Jun 14, 2017

@av3

In the documentation of Expressive the navigation isn't mentioned.

Right, because this feature is still work in progress.

You can use this branch for testing: https://github.com/froschdesign/zend-navigation/tree/feature/expressive-support

After testing, please come back and give us a feedback. Thanks!

@av3
Copy link

av3 commented Jun 14, 2017

@froschdesign Thank you for your fast reply. I configured the files described. When using a single navigation, the output is working fine and the active menu item is getting his "active" class.

But I wasn't able to use a second navigation, even after adding the abstract_factory to the dependencies. I'm getting the error message

Unable to resolve service "Application" to a factory

Is there something wrong with my config or is the support of multiple containers missing in that branch?

@froschdesign
Copy link
Member

@av3

Is there something wrong with my config…

I see nothing! 😉

…is the support of multiple containers missing in that branch?

No. (ExpressiveNavigationAbstractServiceFactory)
Please compare your config with the example in the related PR.

@av3
Copy link

av3 commented Jun 14, 2017

@froschdesign

Please compare your config with the example

First I used the config for the single container and with the 'default' block in my navigation config. In the second step I extended my dependencies.global.php and added a second block in my navigation config.

I see nothing!

My (complete) dependencies.global.php

return [
    'dependencies' => [
        'abstract_factories' => [
            Zend\Navigation\Service\ExpressiveNavigationAbstractServiceFactory::class,
        ],
        'aliases'            => [
            'Zend\Expressive\Delegate\DefaultDelegate' => Zend\Expressive\Delegate\NotFoundDelegate::class,
        ],
        'delegators'         => [
            Zend\View\HelperPluginManager::class => [
                Zend\Navigation\View\ViewHelperManagerDelegatorFactory::class,
            ],
        ],
        'invokables'         => [
            Zend\Expressive\Helper\ServerUrlHelper::class => Zend\Expressive\Helper\ServerUrlHelper::class,
            Zend\Expressive\Router\RouterInterface::class => Zend\Expressive\Router\ZendRouter::class,
        ],
        'factories'          => [
            'doctrine.entity_manager.orm_default'                     =>
                ContainerInteropDoctrine\EntityManagerFactory::class,
            Zend\Navigation\Navigation::class                         =>
                Zend\Navigation\Service\ExpressiveNavigationFactory::class,
            Zend\Expressive\Application::class                        =>
                Zend\Expressive\Container\ApplicationFactory::class,
            Zend\View\HelperPluginManager::class                      =>
                Zend\Expressive\ZendView\HelperPluginManagerFactory::class,
            Zend\Expressive\Template\TemplateRendererInterface::class =>
                Zend\Expressive\ZendView\ZendViewRendererFactory::class,
            Zend\Expressive\Delegate\NotFoundDelegate::class          =>
                Zend\Expressive\Container\NotFoundDelegateFactory::class,
            Zend\Expressive\Helper\ServerUrlMiddleware::class         =>
                Zend\Expressive\Helper\ServerUrlMiddlewareFactory::class,
            Zend\Expressive\Helper\UrlHelper::class                   =>
                Zend\Expressive\Helper\UrlHelperFactory::class,

            Zend\Stratigility\Middleware\ErrorHandler::class         =>
                Zend\Expressive\Container\ErrorHandlerFactory::class,
            Zend\Expressive\Middleware\ErrorResponseGenerator::class =>
                Zend\Expressive\Container\ErrorResponseGeneratorFactory::class,
            Zend\Expressive\Middleware\NotFoundHandler::class        =>
                Zend\Expressive\Container\NotFoundHandlerFactory::class,
        ],
    ],
];

My complete middleware-pipeline.global.php

return [
    'dependencies'        => [
        'factories' => [
            Zend\Navigation\Middleware\NavigationMiddleware::class =>
                Zend\Navigation\Middleware\NavigationMiddlewareFactory::class,
            Zend\Expressive\Helper\UrlHelperMiddleware::class      =>
                Zend\Expressive\Helper\UrlHelperMiddlewareFactory::class,
        ],
    ],
    'middleware_pipeline' => [
        'always'  => [
            'middleware' => [
                Zend\Expressive\Helper\ServerUrlMiddleware::class,
            ],
            'priority'   => 10000,
        ],
        'routing' => [
            'middleware' => [
                Zend\Expressive\Container\ApplicationFactory::ROUTING_MIDDLEWARE,
                Zend\Navigation\Middleware\NavigationMiddleware::class,
                Zend\Expressive\Helper\UrlHelperMiddleware::class,
                Zend\Expressive\Container\ApplicationFactory::DISPATCH_MIDDLEWARE,
            ],
            'priority'   => 1,
        ],
        'error'   => [
            'middleware' => [
                // Add error middleware here.
            ],
            'error'      => true,
            'priority'   => -10000,
        ],
    ],

My navigation block inside the config of my module:

    'navigation'   => [
        'default' => [
            [
                'label' => 'Startseite',
                'route' => 'home',
            ],
        ],
        'footer' => [
            [
                'label' => 'Impressum',
                'route' => 'imprint',
            ],
        ],
    ],

@froschdesign
Copy link
Member

@av3
Do not register both navigation factories! Only ExpressiveNavigationAbstractServiceFactory.

@av3
Copy link

av3 commented Jun 15, 2017

@froschdesign
If I remove ExpressiveNavigationFactory (factories) and ViewHelperManagerDelegatorFactory (delegators), the error remains. And if I also remove the NavigationMiddlewareFactory (only from factories, the middleware entry remains), I'm getting the following error message:

Too few arguments to function Zend\Navigation\Middleware\NavigationMiddleware::__construct(), 0 passed in /application/vendor/zendframework/zend-expressive/src/MarshalMiddlewareTrait.php on line 145 and exactly 1 expected in /application/vendor/zendframework/zend-navigation/src/Middleware/NavigationMiddleware.php on line 32

@froschdesign
Copy link
Member

@av3

I remove …
ViewHelperManagerDelegatorFactory
NavigationMiddlewareFactory

Why? Don't do this!
For multiple navigations you need the factory ExpressiveNavigationAbstractServiceFactory and not the ExpressiveNavigationFactory - this is the only difference in the config between single and multiple containers.

@av3
Copy link

av3 commented Jun 16, 2017

Sorry, I misunderstood the instructions. But only removing the ExpressiveNavigationFactory and using the ExpressiveNavigationAbstractServiceFactory brings again

Unable to resolve service "Application" to a factory

Now I have the NavigationMiddleware, the ViewHelperManagerDelegatorFactory and also the ExpressiveNavigationAbstractServiceFactory. Could you check my configs again?`

dependencies.global.php

return [
    'dependencies' => [
        'aliases'            => [
            'Zend\Expressive\Delegate\DefaultDelegate' => Zend\Expressive\Delegate\NotFoundDelegate::class,
        ],
        'abstract_factories' => [
            Zend\Navigation\Service\ExpressiveNavigationAbstractServiceFactory::class,
        ],
        'delegators'         => [
            Zend\View\HelperPluginManager::class => [
                Zend\Navigation\View\ViewHelperManagerDelegatorFactory::class,
            ],
        ],
        'invokables'         => [
            Zend\Expressive\Helper\ServerUrlHelper::class => Zend\Expressive\Helper\ServerUrlHelper::class,
        ],
        'factories'          => [
            'doctrine.entity_manager.orm_default'                     =>
                ContainerInteropDoctrine\EntityManagerFactory::class,
            Zend\Expressive\Router\RouterInterface::class             =>
                Zend\Expressive\Router\FastRouteRouterFactory::class,

            Zend\Expressive\Application::class                        =>
                Zend\Expressive\Container\ApplicationFactory::class,
            Zend\View\HelperPluginManager::class                      =>
                Zend\Expressive\ZendView\HelperPluginManagerFactory::class,
            Zend\Expressive\Template\TemplateRendererInterface::class =>
                Zend\Expressive\ZendView\ZendViewRendererFactory::class,
            Zend\Expressive\Delegate\NotFoundDelegate::class          =>
                Zend\Expressive\Container\NotFoundDelegateFactory::class,
            Zend\Expressive\Helper\ServerUrlMiddleware::class         =>
                Zend\Expressive\Helper\ServerUrlMiddlewareFactory::class,
            Zend\Expressive\Helper\UrlHelper::class                   =>
                Zend\Expressive\Helper\UrlHelperFactory::class,
            Zend\Expressive\Helper\UrlHelperMiddleware::class         =>
                Zend\Expressive\Helper\UrlHelperMiddlewareFactory::class,

            Zend\Stratigility\Middleware\ErrorHandler::class         =>
                Zend\Expressive\Container\ErrorHandlerFactory::class,
            Zend\Expressive\Middleware\ErrorResponseGenerator::class =>
                Zend\Expressive\Container\ErrorResponseGeneratorFactory::class,
            Zend\Expressive\Middleware\NotFoundHandler::class        =>
                Zend\Expressive\Container\NotFoundHandlerFactory::class,
        ],
    ],
];

middleware_pipeline.global.php

return [
    'dependencies'        => [
        'factories' => [
            Zend\Navigation\Middleware\NavigationMiddleware::class =>
                Zend\Navigation\Middleware\NavigationMiddlewareFactory::class,
            Zend\Expressive\Helper\UrlHelperMiddleware::class      =>
                Zend\Expressive\Helper\UrlHelperMiddlewareFactory::class,
        ],
    ],
    'middleware_pipeline' => [
        'always'   => [
            'middleware' => [
                Zend\Expressive\Helper\ServerUrlMiddleware::class,
            ],
            'priority'   => 10000,
        ],
        'routing'  => [
            'middleware' => [
                Zend\Expressive\Container\ApplicationFactory::ROUTING_MIDDLEWARE,
                Zend\Navigation\Middleware\NavigationMiddleware::class,
                Zend\Expressive\Helper\UrlHelperMiddleware::class,
                Zend\Expressive\Container\ApplicationFactory::DISPATCH_MIDDLEWARE,
            ],
            'priority'   => 1,
        ],
        'error'    => [
            'middleware' => [
                // Add error middleware here.
            ],
            'error'      => true,
            'priority'   => -10000,
        ],
    ],
];

@mrobinsonuk
Copy link

Firstly, thanks @froschdesign for your work on feature/expressive-support. From navigating (no pun intended) through the code today I have learned that there is much more to this component than I realised.

@av3 I apologise if my comments are not helpful in your circumstances, but I observed the same error message that you described so I thought I would add my experience today in case it was helpful to you.

I was trying to use multiple navigation containers, but after I added the abstract factory ExpressiveNavigationAbstractServiceFactory I also received the error:

Unable to resolve service "Application" to a factory; are you certain you provided it during configuration?

Looking back at the suggested usage it seems pretty obvious to me now, but it took me some time to figure it out.

My mistake was to include Zend\Navigation\ConfigProvider, which added the abstract factory NavigationAbstractServiceFactory. The result was two abstract factories competing for the same navigation configuration key.

Abstract factories appear to be processed in the order they are added. In my case the first to execute was the original NavigationAbstractServiceFactory, which led to the error above. After refactoring my configuration to ensure that ExpressiveNavigationAbstractServiceFactory was registered first I was able to use multiple navigation containers without error. This is not ideal however, and there is no benefit to having an abstract factory registered that is not used.

To work around this it is possible to explicitly map each navigation service to the correct abstract factory, ensuring that NavigationAbstractServiceFactory does not attempt to create the service. e.g.

'factories' => [
    'Zend\\Navigation\\One' =>
        Zend\Navigation\Service\ExpressiveNavigationAbstractServiceFactory::class,
    'Zend\\Navigation\\Two' =>
        Zend\Navigation\Service\ExpressiveNavigationAbstractServiceFactory::class,
    'Zend\\Navigation\\Three' =>
        Zend\Navigation\Service\ExpressiveNavigationAbstractServiceFactory::class,
],

For me, the simplest solution was to not include ConfigProvider, which as far as I can tell does not provide anything that Expressive needs.

This is the only additional configuration I needed to get it working:

'dependencies' => [
    'abstract_factories' => [
        Zend\Navigation\Service\ExpressiveNavigationAbstractServiceFactory::class,
    ],
    'delegators' => [
        Zend\View\HelperPluginManager::class => [
            Zend\Navigation\View
        ],
    ],
    'factories' => [
        Zend\Navigation\Middleware\NavigationMiddleware::class =>
            Zend\Navigation\Middleware\NavigationMiddlewareFactory::class,
    ],
],

I also used the programmatic approach, so adding NavigationMiddleware looked something like this:

$app->pipeRoutingMiddleware();
// ...
$app->pipe(\Zend\Navigation\Middleware\NavigationMiddleware::class);
// ...
$app->pipeDispatchMiddleware();

@froschdesign
Copy link
Member

froschdesign commented Jul 16, 2017

@mrobinsonuk

For me, the simplest solution was to not include ConfigProvider…

Right, because at the moment the ConfigProvider only includes the configuration for zend-mvc-based applications.

/cc @av3

@kaufmajo
Copy link

Is there a plan when milestone 2.9 will be released?

@froschdesign
Copy link
Member

@kaufmajo
Not at the moment, but I think in September it's done.

You can help and test the current status of zend-expressive support. See #61
And of course, feedback is always welcome! 😃

@weierophinney
Copy link
Member

This repository has been closed and moved to laminas/laminas-navigation; a new issue has been opened at laminas/laminas-navigation#2.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

10 participants