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

Ensure the AbstractNavigationFactory works with zend-mvc v2 #38

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 76 additions & 19 deletions src/Service/AbstractNavigationFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@
namespace Zend\Navigation\Service;

use Interop\Container\ContainerInterface;
use Traversable;
use Zend\Config;
use Zend\Http\Request;
use Zend\Router\RouteMatch;
use Zend\Router\RouteStackInterface as Router;
use Zend\Mvc\Router as MvcRouter;
use Zend\Navigation\Exception;
use Zend\Navigation\Navigation;
use Zend\Router\RouteMatch;
use Zend\Router\RouteStackInterface as Router;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Stdlib\ArrayUtils;

/**
* Abstract navigation factory
Expand Down Expand Up @@ -72,10 +75,10 @@ protected function getPages(ContainerInterface $container)
if (null === $this->pages) {
$configuration = $container->get('config');

if (!isset($configuration['navigation'])) {
if (! isset($configuration['navigation'])) {
throw new Exception\InvalidArgumentException('Could not find navigation configuration key');
}
if (!isset($configuration['navigation'][$this->getName()])) {
if (! isset($configuration['navigation'][$this->getName()])) {
throw new Exception\InvalidArgumentException(sprintf(
'Failed to find a navigation container by the name "%s"',
$this->getName()
Expand All @@ -102,7 +105,7 @@ protected function preparePages(ContainerInterface $container, $pages)
$request = $application->getMvcEvent()->getRequest();

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

Expand All @@ -117,19 +120,18 @@ protected function preparePages(ContainerInterface $container, $pages)
protected function getPagesFromConfig($config = null)
{
if (is_string($config)) {
if (file_exists($config)) {
$config = Config\Factory::fromFile($config);
} else {
if (! file_exists($config)) {
throw new Exception\InvalidArgumentException(sprintf(
'Config was a string but file "%s" does not exist',
$config
));
}
} elseif ($config instanceof Config\Config) {
$config = $config->toArray();
} elseif (!is_array($config)) {
$config = Config\Factory::fromFile($config);
} elseif ($config instanceof Traversable) {
$config = ArrayUtils::iteratorToArray($config);
} elseif (! is_array($config)) {
throw new Exception\InvalidArgumentException(
'Invalid input, expected array, filename, or Zend\Config object'
'Invalid input, expected array, filename, or Traversable object'
);
}

Expand All @@ -138,29 +140,32 @@ protected function getPagesFromConfig($config = null)

/**
* @param array $pages
* @param RouteMatch $routeMatch
* @param Router $router
* @param RouteMatch|MvcRouter\RouteMatch $routeMatch
* @param Router|MvcRouter\RouteStackInterface $router
* @param null|Request $request
* @return array
*/
protected function injectComponents(
array $pages,
RouteMatch $routeMatch = null,
Router $router = null,
$routeMatch = null,
$router = null,
$request = null
) {
$this->validateRouteMatch($routeMatch);
$this->validateRouter($router);

foreach ($pages as &$page) {
$hasUri = isset($page['uri']);
$hasMvc = isset($page['action']) || isset($page['controller']) || isset($page['route']);
if ($hasMvc) {
if (!isset($page['routeMatch']) && $routeMatch) {
if (! isset($page['routeMatch']) && $routeMatch) {
$page['routeMatch'] = $routeMatch;
}
if (!isset($page['router'])) {
if (! isset($page['router'])) {
$page['router'] = $router;
}
} elseif ($hasUri) {
if (!isset($page['request'])) {
if (! isset($page['request'])) {
$page['request'] = $request;
}
}
Expand All @@ -171,4 +176,56 @@ protected function injectComponents(
}
return $pages;
}

/**
* Validate that a route match argument provided to injectComponents is valid.
*
* @param null|RouteMatch|MvcRouter\RouteMatch
* @return void
* @throws Exception\InvalidArgumentException
*/
private function validateRouteMatch($routeMatch)
{
if (null === $routeMatch) {
return;
}

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

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

if (! $router instanceof Router
&& ! $router instanceof MvcRouter\RouteStackInterface
) {
throw new Exception\InvalidArgumentException(sprintf(
'%s or %s expected by %s::injectComponents; received %s',
RouteMatch::class,
MvcRouter\RouteMatch::class,
__CLASS__,
(is_object($router) ? get_class($router) : gettype($router))
));
}
}
}
73 changes: 73 additions & 0 deletions test/Service/AbstractNavigationFactoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php
/**
* @link http://github.com/zendframework/zend-navigation for the canonical source repository
* @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace ZendTest\Navigation\Service;

use PHPUnit_Framework_TestCase as TestCase;
use ReflectionMethod;
use Zend\Mvc\Router as MvcRouter;
use Zend\Navigation\Exception;
use Zend\Router;

/**
* @todo Write tests covering full functionality. Tests were introduced to
* resolve zendframework/zend-navigation#37, and cover one specific
* method to ensure argument validation works correctly.
*/
class AbstractNavigationFactoryTest extends TestCase
{
public function setUp()
{
$this->factory = new TestAsset\TestNavigationFactory();
}

public function testCanInjectComponentsUsingZendRouterClasses()
{
$routeMatch = $this->prophesize(Router\RouteMatch::class)->reveal();
$router = $this->prophesize(Router\RouteStackInterface::class)->reveal();
$args = [[], $routeMatch, $router];

$r = new ReflectionMethod($this->factory, 'injectComponents');
$r->setAccessible(true);
try {
$pages = $r->invokeArgs($this->factory, $args);
} catch (Exception\InvalidArgumentException $e) {
$message = sprintf(
'injectComponents should not raise exception for zend-router classes; received %s',
$e->getMessage()
);
$this->fail($message);
}

$this->assertSame([], $pages);
}

public function testCanInjectComponentsUsingZendMvcRouterClasses()
{
if (! class_exists(MvcRouter\RouteMatch::class)) {
$this->markTestSkipped('Test does not run for zend-mvc v3 releases');
}

$routeMatch = $this->prophesize(MvcRouter\RouteMatch::class)->reveal();
$router = $this->prophesize(MvcRouter\RouteStackInterface::class)->reveal();
$args = [[], $routeMatch, $router];

$r = new ReflectionMethod($this->factory, 'injectComponents');
$r->setAccessible(true);
try {
$pages = $r->invokeArgs($this->factory, $args);
} catch (Exception\InvalidArgumentException $e) {
$message = sprintf(
'injectComponents should not raise exception for zend-mvc router classes; received %s',
$e->getMessage()
);
$this->fail($message);
}

$this->assertSame([], $pages);
}
}
34 changes: 34 additions & 0 deletions test/Service/TestAsset/TestNavigationFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
/**
* @link http://github.com/zendframework/zend-navigation for the canonical source repository
* @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace ZendTest\Navigation\Service\TestAsset;

use Zend\Navigation\Service\AbstractNavigationFactory;

class TestNavigationFactory extends AbstractNavigationFactory
{
/**
* @var string
*/
private $factoryName;

/**
* @param string $factoryName
*/
public function __construct($factoryName = 'test')
{
$this->factoryName = $factoryName;
}

/**
* @return string
*/
protected function getName()
{
return $this->factoryName;
}
}