Skip to content

Commit

Permalink
Test for zend-expressive support (without changing existing files)
Browse files Browse the repository at this point in the history
  • Loading branch information
froschdesign committed Feb 12, 2017
1 parent 2356160 commit 02190ac
Show file tree
Hide file tree
Showing 4 changed files with 345 additions and 0 deletions.
58 changes: 58 additions & 0 deletions src/Middleware/NavigationMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace Zend\Navigation\Middleware;

use RecursiveIteratorIterator;
use Zend\Navigation\Page\ExpressivePage;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Expressive\Router\RouteResult;
use Zend\Navigation\Navigation;

/**
* Pipeline middleware for injecting a Navigation with a RouteResult.
*/
class NavigationMiddleware
{
/**
* @var Navigation
*/
private $navigation;

/**
* @param Navigation $navigation
*/
public function __construct(Navigation $navigation)
{
$this->navigation = $navigation;
}

/**
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param callable $next
* @return ResponseInterface
*/
public function __invoke(
ServerRequestInterface $request,
ResponseInterface $response,
callable $next
) {
$routeResult = $request->getAttribute(RouteResult::class, false);

if ($routeResult instanceof RouteResult) {
$iterator = new RecursiveIteratorIterator(
$this->navigation,
RecursiveIteratorIterator::SELF_FIRST
);

foreach ($iterator as $page) {
if ($page instanceof ExpressivePage) {
$page->setRouteResult($routeResult);
}
}
}

return $next($request, $response);
}
}
25 changes: 25 additions & 0 deletions src/Middleware/NavigationMiddlewareFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Zend\Navigation\Middleware;

use Interop\Container\ContainerInterface;
use Zend\Navigation\Exception\DomainException;
use Zend\Navigation\Navigation;

class NavigationMiddlewareFactory
{
public function __invoke(ContainerInterface $container)
{
if (! $container->has(Navigation::class)) {
throw new DomainException(
sprintf(
'%s requires a %s service at instantiation; none found',
NavigationMiddleware::class,
Navigation::class
)
);
}

return new NavigationMiddleware($container->get(Navigation::class));
}
}
178 changes: 178 additions & 0 deletions src/Page/ExpressivePage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<?php

namespace Zend\Navigation\Page;

use Zend\Expressive\Router\Exception\RuntimeException as RouterException;
use Zend\Expressive\Router\RouteResult;
use Zend\Expressive\Router\RouterInterface;
use Zend\Navigation\Exception;

/**
* Class ExpressivePage
*/
class ExpressivePage extends AbstractPage
{
/**
* Route name
*
* @var string
*/
private $routeName;

/**
* Route parameters
*
* @var array
*/
private $routeParams = [];

/**
* @var array
*/
private $queryParams = [];

/**
* @var RouteResult
*/
private $routeResult;

/**
* @var RouterInterface
*/
private $router;

/**
* @var string
*/
private $hrefCache;

/**
* @inheritdoc
*/
public function isActive($recursive = false)
{
if (! $this->active && $this->routeName !== null
&& $this->routeResult instanceof RouteResult
) {
$intersectionOfParams = array_intersect_assoc(
$this->routeResult->getMatchedParams(),
$this->routeParams
);

$matchedRouteName = $this->routeResult->getMatchedRouteName();

if ($matchedRouteName === $this->routeName
&& count($intersectionOfParams) === count($this->routeParams)
) {
$this->active = true;

return $this->active;
}
}

return parent::isActive($recursive);
}

/**
* @inheritdoc
*/
public function getHref()
{
// User cache?
if ($this->hrefCache) {
return $this->hrefCache;
}

if ($this->routeName === null) {
return $this->generateUriFromResult(
$this->routeParams,
$this->routeResult
);
}

// Generate the route
$href = $this->router->generateUri(
$this->routeName,
$this->routeParams
);

// Append query parameters if there are any
if (count($this->queryParams) > 0) {
$href .= '?' . http_build_query($this->queryParams);
}

// Append the fragment identifier
if ($this->getFragment() !== null) {
$href .= '#' . $this->getFragment();
}

return $href;
}

/**
* @param string|null $route
*/
public function setRoute($route)
{
if (null !== $route && (! is_string($route) || empty($route))) {
throw new Exception\InvalidArgumentException(
'Invalid argument: $route must be a non-empty string or null'
);
}

$this->routeName = $route;
$this->hrefCache = null;
}

/**
* @param array|null $params
*/
public function setParams(array $params = null)
{
$this->routeParams = empty($params) ? [] : $params;
$this->hrefCache = null;
}

/**
* @param array|null $query
*/
public function setQuery(array $query = null)
{
$this->queryParams = empty($query) ? [] : $query;
$this->hrefCache = null;
}

/**
* @param RouteResult $routeResult
*/
public function setRouteResult(RouteResult $routeResult)
{
$this->routeResult = $routeResult;
}

/**
* @param RouterInterface $router
*/
public function setRouter(RouterInterface $router)
{
$this->router = $router;
}

/**
* @param array $params
* @param RouteResult $result
* @return string
*/
private function generateUriFromResult(array $params, RouteResult $result)
{
if ($result->isFailure()) {
throw new RouterException(
'Attempting to use matched result when routing failed; aborting'
);
}
$name = $result->getMatchedRouteName();
$params = array_merge($result->getMatchedParams(), $params);

return $this->router->generateUri($name, $params);
}
}
84 changes: 84 additions & 0 deletions src/Service/ExpressiveNavigationFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

namespace Zend\Navigation\Service;

use Zend\Navigation\Page\ExpressivePage;
use Interop\Container\ContainerInterface;
use Zend\Expressive\Router\RouterInterface;
use Zend\Navigation\Exception;
use Zend\Navigation\Service\DefaultNavigationFactory as BaseDefaultNavigationFactory;

/**
* Class ExpressiveNavigationFactory
*/
class ExpressiveNavigationFactory extends BaseDefaultNavigationFactory
{
/**
* @inheritdoc
*/
protected function preparePages(ContainerInterface $container, $pages)
{
// Get router
/** @var RouterInterface $router */
$router = $container->get(RouterInterface::class);

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

/**
* @inheritdoc
*/
protected function injectComponents(
array $pages,
$routeMatch = null,
$router = null,
$request = null
) {
$this->validateRouter($router);

foreach ($pages as &$page) {
if (isset($page['route'])) {
// Set Expressive page as page type
$page['type'] = ExpressivePage::class;

// Set router if exists
if ($router !== null && ! isset($page['router'])) {
$page['router'] = $router;
}
}

if (isset($page['pages'])) {
$page['pages'] = $this->injectComponents(
$page['pages'], $routeMatch, $router, $request
);
}
}

return $pages;
}

/**
* Validate that a router argument provided to injectComponents is valid.
*
* @param null|RouterInterface
* @return void
* @throws Exception\InvalidArgumentException
*/
private function validateRouter($router)
{
if (null === $router) {
return;
}

if (! $router instanceof RouterInterface) {
throw new Exception\InvalidArgumentException(
sprintf(
'%s expected by %s::injectComponents; received %s',
RouterInterface::class,
__CLASS__,
(is_object($router) ? get_class($router) : gettype($router))
)
);
}
}
}

0 comments on commit 02190ac

Please sign in to comment.