From dbd5e1e90eaafe96b43e80fcd63ac80137563a1f Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 10:19:12 -0600 Subject: [PATCH 01/15] Ensure console router is selected correctly v2 tests for `Console::isConsole()` to determine if the console router should be created; added code to the `RouterFactory::createService()` implementation to do that and overwrite the `$requestedName` when detected. --- src/Router/Console/SimpleRouteStack.php | 14 ++++++++------ src/Service/RouterFactory.php | 10 ++++++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Router/Console/SimpleRouteStack.php b/src/Router/Console/SimpleRouteStack.php index ae7db35d2..7b7ff4325 100644 --- a/src/Router/Console/SimpleRouteStack.php +++ b/src/Router/Console/SimpleRouteStack.php @@ -42,8 +42,8 @@ protected function init() Simple::class => RouteInvokableFactory::class, // v2 normalized names - 'zendmvcrouterconsoleCatchall' => RouteInvokableFactory::class, - 'zendmvcrouterconsoleSimple' => RouteInvokableFactory::class, + 'zendmvcrouterconsolecatchall' => RouteInvokableFactory::class, + 'zendmvcrouterconsolesimple' => RouteInvokableFactory::class, ], ]))->configureServiceManager($this->routePluginManager); } @@ -79,19 +79,21 @@ protected function routeFromArray($specs) { if ($specs instanceof Traversable) { $specs = ArrayUtils::iteratorToArray($specs); - } elseif (!is_array($specs)) { + } + + if (! is_array($specs)) { throw new Exception\InvalidArgumentException('Route definition must be an array or Traversable object'); } // default to 'simple' console route - if (!isset($specs['type'])) { - $specs['type'] = 'simple'; + if (! isset($specs['type'])) { + $specs['type'] = Simple::class; } // build route object $route = parent::routeFromArray($specs); - if (!$route instanceof RouteInterface) { + if (! $route instanceof RouteInterface) { throw new Exception\RuntimeException('Given route does not implement Console route interface'); } diff --git a/src/Service/RouterFactory.php b/src/Service/RouterFactory.php index 9cd1ee7c2..ac54bd0dd 100644 --- a/src/Service/RouterFactory.php +++ b/src/Service/RouterFactory.php @@ -46,10 +46,16 @@ public function __invoke(ContainerInterface $container, $name, array $options = * For use with zend-servicemanager v2; proxies to __invoke(). * * @param ServiceLocatorInterface $container + * @param null|string $normalizedName + * @param null|string $requestedName * @return RouteStackInterface */ - public function createService(ServiceLocatorInterface $container) + public function createService(ServiceLocatorInterface $container, $normalizedName = null, $requestedName = null) { - return $this($container, RouteStackInterface::class); + if ($normalizedName === 'router' && Console::isConsole()) { + $requestedName = 'ConsoleRouter'; + } + + return $this($container, $requestedName); } } From e740f8988d763ce858dcbf3477f5a862d01b9ff0 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 10:49:34 -0600 Subject: [PATCH 02/15] Re-implement ServiceLocatorAwareInterface in AbstractController We originally removed the ServiceLocatorAwareInterface implementation from AbstractController when we were targeting a 3.0 release, but it needs to be present for a 2.7 release. --- src/Controller/AbstractController.php | 31 ++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Controller/AbstractController.php b/src/Controller/AbstractController.php index 92e633d92..14504abba 100644 --- a/src/Controller/AbstractController.php +++ b/src/Controller/AbstractController.php @@ -17,6 +17,8 @@ use Zend\Http\Request as HttpRequest; use Zend\Mvc\InjectApplicationEventInterface; use Zend\Mvc\MvcEvent; +use Zend\ServiceManager\ServiceLocatorAwareInterface; +use Zend\ServiceManager\ServiceLocatorInterface; use Zend\ServiceManager\ServiceManager; use Zend\Stdlib\DispatchableInterface as Dispatchable; use Zend\Stdlib\RequestInterface as Request; @@ -45,7 +47,8 @@ abstract class AbstractController implements Dispatchable, EventManagerAwareInterface, - InjectApplicationEventInterface + InjectApplicationEventInterface, + ServiceLocatorAwareInterface { /** * @var PluginManager @@ -62,6 +65,11 @@ abstract class AbstractController implements */ protected $response; + /** + * @var ServiceLocatorInterface + */ + protected $serviceLocator; + /** * @var Event */ @@ -224,6 +232,27 @@ public function getEvent() return $this->event; } + /** + * Set serviceManager instance + * + * @param ServiceLocatorInterface $serviceLocator + * @return void + */ + public function setServiceLocator(ServiceLocatorInterface $serviceLocator) + { + $this->serviceLocator = $serviceLocator; + } + + /** + * Retrieve serviceManager instance + * + * @return ServiceLocatorInterface + */ + public function getServiceLocator() + { + return $this->serviceLocator; + } + /** * Get plugin manager * From 46a4cd2e434340e89591a609b7b4f7ea1faddf88 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 11:06:45 -0600 Subject: [PATCH 03/15] Add service locator injection initializer to ControllerManager This functionality was removed when we were targeting a v3 release, but needs to be re-added when targeting v2.7. --- src/Controller/ControllerManager.php | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/Controller/ControllerManager.php b/src/Controller/ControllerManager.php index a159b5807..9ce581b6c 100644 --- a/src/Controller/ControllerManager.php +++ b/src/Controller/ControllerManager.php @@ -16,6 +16,7 @@ use Zend\ServiceManager\AbstractPluginManager; use Zend\ServiceManager\ConfigInterface; use Zend\ServiceManager\Exception\InvalidServiceException; +use Zend\ServiceManager\ServiceLocatorAwareInterface; use Zend\Stdlib\DispatchableInterface; /** @@ -53,6 +54,7 @@ public function __construct($configOrContainerInstance, array $v3config = []) $this->addInitializer([$this, 'injectEventManager']); $this->addInitializer([$this, 'injectConsole']); $this->addInitializer([$this, 'injectPluginManager']); + $this->addInitializer([$this, 'injectServiceLocator']); parent::__construct($configOrContainerInstance, $v3config); } @@ -191,4 +193,38 @@ public function injectPluginManager($first, $second) $controller->setPluginManager($container->get('ControllerPluginManager')); } + + /** + * Initializer: inject service locator + * + * @param ContainerInterface|DispatchableInterface $first Container when + * using zend-servicemanager v3; controller under v2. + * @param DispatchableInterface|ContainerInterface $second Controller when + * using zend-servicemanager v3; container under v2. + */ + public function injectServiceLocator($first, $second) + { + if ($first instanceof ContainerInterface) { + $container = $first; + $controller = $second; + } else { + $container = $second; + $controller = $first; + } + + // For v2, we need to pull the parent service locator + if (! method_exists($container, 'configure')) { + $container = $container->getServiceLocator() ?: $container; + } + + if ($controller instanceof ServiceLocatorAwareInterface) { + trigger_error(sprintf( + 'ServiceLocatorAwareInterface is deprecated and will be removed in version 3.0, along ' + . 'with the ServiceLocatorAwareInitializer. Please update your class %s to remove ' + . 'the implementation, and start injecting your dependencies via factory instead.', + get_class($controller) + ), E_USER_DEPRECATED); + $controller->setServiceLocator($container); + } + } } From 30915376d27e15401358f65962ccafd13cce848a Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 11:07:34 -0600 Subject: [PATCH 04/15] Alias `console` to `ConsoleAdapter` - to allow retrieval with either `Console` or `console` as the service name. --- src/Service/ServiceListenerFactory.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Service/ServiceListenerFactory.php b/src/Service/ServiceListenerFactory.php index 21c4d51c9..af4b52fb0 100644 --- a/src/Service/ServiceListenerFactory.php +++ b/src/Service/ServiceListenerFactory.php @@ -40,6 +40,7 @@ class ServiceListenerFactory implements FactoryInterface 'aliases' => [ 'Configuration' => 'config', 'configuration' => 'config', + 'console' => 'ConsoleAdapter', 'Console' => 'ConsoleAdapter', 'ConsoleDefaultRenderingStrategy' => View\Console\DefaultRenderingStrategy::class, 'ControllerLoader' => 'ControllerManager', From be0db2808afaf3efa296422bdf1140b6984b1857 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 11:19:22 -0600 Subject: [PATCH 05/15] CS fixes per php-cs-fixer --- src/Router/Console/SimpleRouteStack.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Router/Console/SimpleRouteStack.php b/src/Router/Console/SimpleRouteStack.php index 7b7ff4325..45f0a2d11 100644 --- a/src/Router/Console/SimpleRouteStack.php +++ b/src/Router/Console/SimpleRouteStack.php @@ -80,7 +80,7 @@ protected function routeFromArray($specs) if ($specs instanceof Traversable) { $specs = ArrayUtils::iteratorToArray($specs); } - + if (! is_array($specs)) { throw new Exception\InvalidArgumentException('Route definition must be an array or Traversable object'); } From be9c2480651bb26ec480df0c031c86aecbfa340d Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 11:27:55 -0600 Subject: [PATCH 06/15] Ignore deprecation errors Now that controllers re-implement ServiceLocatorAwareInterface, we get deprecation errors. By adding `PHPUnit_Framework_Error_Deprecated::$enabled = false` to the setup on these tests, we can eliminate having those cast to exceptions, and thus prevent them from marking tests as errored or failed. --- ...isedInDispatchableShouldRaiseDispatchErrorEventTest.php | 7 +++++++ test/Controller/IntegrationTest.php | 4 ++++ test/Controller/Plugin/ForwardTest.php | 4 ++++ test/Service/ControllerManagerFactoryTest.php | 4 ++++ 4 files changed, 19 insertions(+) diff --git a/test/Application/ExceptionsRaisedInDispatchableShouldRaiseDispatchErrorEventTest.php b/test/Application/ExceptionsRaisedInDispatchableShouldRaiseDispatchErrorEventTest.php index 7defd5347..a5f7bc291 100644 --- a/test/Application/ExceptionsRaisedInDispatchableShouldRaiseDispatchErrorEventTest.php +++ b/test/Application/ExceptionsRaisedInDispatchableShouldRaiseDispatchErrorEventTest.php @@ -9,6 +9,7 @@ namespace ZendTest\Mvc\Application; +use PHPUnit_Framework_Error_Deprecated; use PHPUnit_Framework_TestCase as TestCase; use Zend\Mvc\MvcEvent; @@ -16,6 +17,12 @@ class ExceptionsRaisedInDispatchableShouldRaiseDispatchErrorEventTest extends Te { use BadControllerTrait; + public function setUp() + { + // Ignore deprecation errors + PHPUnit_Framework_Error_Deprecated::$enabled = false; + } + /** * @group error-handling */ diff --git a/test/Controller/IntegrationTest.php b/test/Controller/IntegrationTest.php index baa045149..d750bcbd8 100644 --- a/test/Controller/IntegrationTest.php +++ b/test/Controller/IntegrationTest.php @@ -9,6 +9,7 @@ namespace ZendTest\Mvc\Controller; +use PHPUnit_Framework_Error_Deprecated; use PHPUnit_Framework_TestCase as TestCase; use Zend\EventManager\EventManager; use Zend\EventManager\SharedEventManager; @@ -21,6 +22,9 @@ class IntegrationTest extends TestCase { public function setUp() { + // Ignore deprecation errors + PHPUnit_Framework_Error_Deprecated::$enabled = false; + $this->sharedEvents = new SharedEventManager(); $this->services = new ServiceManager(); diff --git a/test/Controller/Plugin/ForwardTest.php b/test/Controller/Plugin/ForwardTest.php index 60a5a4610..a24a4f17e 100644 --- a/test/Controller/Plugin/ForwardTest.php +++ b/test/Controller/Plugin/ForwardTest.php @@ -9,6 +9,7 @@ namespace ZendTest\Mvc\Controller\Plugin; +use PHPUnit_Framework_Error_Deprecated; use PHPUnit_Framework_TestCase as TestCase; use ReflectionClass; use stdClass; @@ -51,6 +52,9 @@ class ForwardTest extends TestCase public function setUp() { + // Ignore deprecation errors + PHPUnit_Framework_Error_Deprecated::$enabled = false; + $eventManager = $this->createEventManager(new SharedEventManager()); $mockApplication = $this->getMock('Zend\Mvc\ApplicationInterface'); $mockApplication->expects($this->any())->method('getEventManager')->will($this->returnValue($eventManager)); diff --git a/test/Service/ControllerManagerFactoryTest.php b/test/Service/ControllerManagerFactoryTest.php index 5ffc53c58..6d1a7b461 100644 --- a/test/Service/ControllerManagerFactoryTest.php +++ b/test/Service/ControllerManagerFactoryTest.php @@ -9,6 +9,7 @@ namespace ZendTest\Mvc\Service; +use PHPUnit_Framework_Error_Deprecated; use PHPUnit_Framework_TestCase as TestCase; use Zend\EventManager\SharedEventManager; use Zend\Mvc\Service\ControllerManagerFactory; @@ -34,6 +35,9 @@ class ControllerManagerFactoryTest extends TestCase public function setUp() { + // Ignore deprecation errors + PHPUnit_Framework_Error_Deprecated::$enabled = false; + $loaderFactory = new ControllerManagerFactory(); $this->defaultServiceConfig = [ 'aliases' => [ From 5cb953e2c849f31abd4a64805d75e4cc7511438d Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 11:34:46 -0600 Subject: [PATCH 07/15] Duck-type ServiceLocatorAwareInterface Since zend-servicemanager v3 does not define `ServiceLocatorAwareInterface`, then we cannot extend it and still support that release series. As such, `AbstractController` no longer explicitly implements it, but does so implicitly by defining the methods. The initializers in both `ServiceManagerConfig` and `ControllerManager` were updated to *also* look for the combination: - interface `ServiceLocatorAwareInterface` does not exist AND - method `setServiceLocator()` is present If that combination is present, the same behavior is retained, including the deprecation notices. --- src/Controller/AbstractController.php | 4 +--- src/Controller/ControllerManager.php | 12 ++++++++++++ src/Service/ServiceManagerConfig.php | 12 ++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/Controller/AbstractController.php b/src/Controller/AbstractController.php index 14504abba..c546a4484 100644 --- a/src/Controller/AbstractController.php +++ b/src/Controller/AbstractController.php @@ -17,7 +17,6 @@ use Zend\Http\Request as HttpRequest; use Zend\Mvc\InjectApplicationEventInterface; use Zend\Mvc\MvcEvent; -use Zend\ServiceManager\ServiceLocatorAwareInterface; use Zend\ServiceManager\ServiceLocatorInterface; use Zend\ServiceManager\ServiceManager; use Zend\Stdlib\DispatchableInterface as Dispatchable; @@ -47,8 +46,7 @@ abstract class AbstractController implements Dispatchable, EventManagerAwareInterface, - InjectApplicationEventInterface, - ServiceLocatorAwareInterface + InjectApplicationEventInterface { /** * @var PluginManager diff --git a/src/Controller/ControllerManager.php b/src/Controller/ControllerManager.php index 9ce581b6c..7471ec429 100644 --- a/src/Controller/ControllerManager.php +++ b/src/Controller/ControllerManager.php @@ -217,6 +217,18 @@ public function injectServiceLocator($first, $second) $container = $container->getServiceLocator() ?: $container; } + if (! interface_exists(ServiceLocatorAwareInterface::class) + && method_exists($controller, 'setServiceLocator') + ) { + trigger_error(sprintf( + 'ServiceLocatorAwareInterface is deprecated and will be removed in version 3.0, along ' + . 'with the ServiceLocatorAwareInitializer. Please update your class %s to remove ' + . 'the implementation, and start injecting your dependencies via factory instead.', + get_class($controller) + ), E_USER_DEPRECATED); + $controller->setServiceLocator($container); + } + if ($controller instanceof ServiceLocatorAwareInterface) { trigger_error(sprintf( 'ServiceLocatorAwareInterface is deprecated and will be removed in version 3.0, along ' diff --git a/src/Service/ServiceManagerConfig.php b/src/Service/ServiceManagerConfig.php index ee223200b..b502ac08e 100644 --- a/src/Service/ServiceManagerConfig.php +++ b/src/Service/ServiceManagerConfig.php @@ -141,6 +141,18 @@ public function __construct(array $config = []) ), E_USER_DEPRECATED); $instance->setServiceLocator($container); } + + if (! interface_exists(ServiceLocatorAwareInterface::class) + && method_exists($instance, 'setServiceLocator') + ) { + trigger_error(sprintf( + 'ServiceLocatorAwareInterface is deprecated and will be removed in version 3.0, along ' + . 'with the ServiceLocatorAwareInitializer. Please update your class %s to remove ' + . 'the implementation, and start injecting your dependencies via factory instead.', + get_class($instance) + ), E_USER_DEPRECATED); + $instance->setServiceLocator($container); + } }, ]); From 5a0aca19b6aad66af0f08ec351566b7ed99467be Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 11:39:03 -0600 Subject: [PATCH 08/15] Exclude deprecation notices from more tests After duck-typing the `ServiceLocatorAwareInterface` usage, two more tests showed failures due to deprecation notices; these have now been marked to exclude them. --- test/Application/AllowsReturningEarlyFromRoutingTest.php | 7 +++++++ test/Application/ControllerIsDispatchedTest.php | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/test/Application/AllowsReturningEarlyFromRoutingTest.php b/test/Application/AllowsReturningEarlyFromRoutingTest.php index 47e731a7a..55f363150 100644 --- a/test/Application/AllowsReturningEarlyFromRoutingTest.php +++ b/test/Application/AllowsReturningEarlyFromRoutingTest.php @@ -9,6 +9,7 @@ namespace ZendTest\Mvc\Application; +use PHPUnit_Framework_Error_Deprecated; use PHPUnit_Framework_TestCase as TestCase; use Zend\Http\PhpEnvironment\Response; use Zend\Mvc\MvcEvent; @@ -17,6 +18,12 @@ class AllowsReturningEarlyFromRoutingTest extends TestCase { use PathControllerTrait; + public function setUp() + { + // Ignore deprecation errors + PHPUnit_Framework_Error_Deprecated::$enabled = false; + } + public function testAllowsReturningEarlyFromRouting() { $application = $this->prepareApplication(); diff --git a/test/Application/ControllerIsDispatchedTest.php b/test/Application/ControllerIsDispatchedTest.php index d780a6fa8..5398a3a1b 100644 --- a/test/Application/ControllerIsDispatchedTest.php +++ b/test/Application/ControllerIsDispatchedTest.php @@ -9,6 +9,7 @@ namespace ZendTest\Mvc\Application; +use PHPUnit_Framework_Error_Deprecated; use PHPUnit_Framework_TestCase as TestCase; use Zend\Mvc\MvcEvent; @@ -16,6 +17,12 @@ class ControllerIsDispatchedTest extends TestCase { use PathControllerTrait; + public function setUp() + { + // Ignore deprecation errors + PHPUnit_Framework_Error_Deprecated::$enabled = false; + } + public function testControllerIsDispatchedDuringRun() { $application = $this->prepareApplication(); From b97120ee34027664f2589bb769e1e400d639e176 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 12:09:39 -0600 Subject: [PATCH 09/15] Test that the default service config contains console aliases --- test/Service/ServiceListenerFactoryTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/Service/ServiceListenerFactoryTest.php b/test/Service/ServiceListenerFactoryTest.php index c419aad1d..adc991306 100644 --- a/test/Service/ServiceListenerFactoryTest.php +++ b/test/Service/ServiceListenerFactoryTest.php @@ -10,6 +10,7 @@ namespace ZendTest\Mvc\Service; use PHPUnit_Framework_TestCase as TestCase; +use ReflectionProperty; use Zend\Mvc\Service\ServiceListenerFactory; class ServiceListenerFactoryTest extends TestCase @@ -179,4 +180,15 @@ public function testInvalidTypeMethod() $this->factory->__invoke($this->sm, 'ServiceListener'); } + + public function testDefinesExpectedAliasesForConsole() + { + $r = new ReflectionProperty($this->factory, 'defaultServiceConfig'); + $r->setAccessible(true); + $config = $r->getValue($this->factory); + + $this->assertArrayHasKey('aliases', $config, 'Missing aliases from default service config'); + $this->assertArrayHasKey('console', $config['aliases'], 'Missing "console" alias from default service config'); + $this->assertArrayHasKey('Console', $config['aliases'], 'Missing "Console" alias from default service config'); + } } From eca3efc93d3cfd8af4f961c14f57ad16e8ce3518 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 12:25:38 -0600 Subject: [PATCH 10/15] Test duck-typed ServiceLocatorAwareInterface initializers Adds tests for both `ServiceManagerConfig` and `ControllerManager`, verifying that each can do duck-typed `ServiceLocatorAwareInterface` injection via the initializers they register. --- test/Controller/ControllerManagerTest.php | 15 +++++++++++ test/Service/ServiceManagerConfigTest.php | 16 +++++++++++ .../DuckTypedServiceLocatorAware.php | 27 +++++++++++++++++++ ...DuckTypedServiceLocatorAwareController.php | 22 +++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 test/Service/TestAsset/DuckTypedServiceLocatorAware.php create mode 100644 test/Service/TestAsset/DuckTypedServiceLocatorAwareController.php diff --git a/test/Controller/ControllerManagerTest.php b/test/Controller/ControllerManagerTest.php index dbdf76bc3..ad57ae2ba 100644 --- a/test/Controller/ControllerManagerTest.php +++ b/test/Controller/ControllerManagerTest.php @@ -9,6 +9,7 @@ namespace ZendTest\Mvc\Controller; +use PHPUnit_Framework_Error_Deprecated; use PHPUnit_Framework_TestCase as TestCase; use ReflectionClass; use Zend\EventManager\EventManager; @@ -16,13 +17,18 @@ use Zend\Mvc\Controller\ControllerManager; use Zend\Mvc\Controller\PluginManager as ControllerPluginManager; use Zend\ServiceManager\Config; +use Zend\ServiceManager\Factory\InvokableFactory; use Zend\ServiceManager\ServiceManager; use Zend\Console\Adapter\Virtual as ConsoleAdapter; +use ZendTest\Mvc\Service\TestAsset\DuckTypedServiceLocatorAwareController; class ControllerManagerTest extends TestCase { public function setUp() { + // Disable deprecation notices + PHPUnit_Framework_Error_Deprecated::$enabled = false; + $this->sharedEvents = new SharedEventManager; $this->events = $this->createEventManager($this->sharedEvents); $this->consoleAdapter = new ConsoleAdapter(); @@ -145,4 +151,13 @@ public function testDoNotUsePeeringServiceManagers() $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); $this->controllers->get('EventManager'); } + + public function testServiceLocatorAwareInitializerInjectsDuckTypedImplementations() + { + $this->controllers->setFactory(DuckTypedServiceLocatorAwareController::class, InvokableFactory::class); + + $controller = $this->controllers->get(DuckTypedServiceLocatorAwareController::class); + $this->assertInstanceOf(DuckTypedServiceLocatorAwareController::class, $controller); + $this->assertSame($this->services, $controller->getServiceLocator()); + } } diff --git a/test/Service/ServiceManagerConfigTest.php b/test/Service/ServiceManagerConfigTest.php index 938abed9b..2b9940f53 100644 --- a/test/Service/ServiceManagerConfigTest.php +++ b/test/Service/ServiceManagerConfigTest.php @@ -9,6 +9,7 @@ namespace ZendTest\Mvc\Service; +use PHPUnit_Framework_Error_Deprecated; use PHPUnit_Framework_TestCase as TestCase; use ReflectionClass; use stdClass; @@ -37,6 +38,9 @@ class ServiceManagerConfigTest extends TestCase */ protected function setUp() { + // Disable deprecation notices + PHPUnit_Framework_Error_Deprecated::$enabled = false; + $this->config = new ServiceManagerConfig(); $this->services = new ServiceManager(); $this->config->configureServiceManager($this->services); @@ -212,4 +216,16 @@ public function testEventManagerInitializerCanBeReplaced() $serviceManager->get('EventManagerAware'); } + + public function testServiceLocatorAwareInitializerInjectsDuckTypedImplementations() + { + $serviceManager = new ServiceManager(['factories' => [ + TestAsset\DuckTypedServiceLocatorAware::class => InvokableFactory::class, + ]]); + (new ServiceManagerConfig())->configureServiceManager($serviceManager); + + $instance = $serviceManager->get(TestAsset\DuckTypedServiceLocatorAware::class); + $this->assertInstanceOf(TestAsset\DuckTypedServiceLocatorAware::class, $instance); + $this->assertSame($serviceManager, $instance->getServiceLocator()); + } } diff --git a/test/Service/TestAsset/DuckTypedServiceLocatorAware.php b/test/Service/TestAsset/DuckTypedServiceLocatorAware.php new file mode 100644 index 000000000..480a464d8 --- /dev/null +++ b/test/Service/TestAsset/DuckTypedServiceLocatorAware.php @@ -0,0 +1,27 @@ +container = $container; + } + + public function getServiceLocator() + { + return $this->container; + } +} diff --git a/test/Service/TestAsset/DuckTypedServiceLocatorAwareController.php b/test/Service/TestAsset/DuckTypedServiceLocatorAwareController.php new file mode 100644 index 000000000..1f2da218a --- /dev/null +++ b/test/Service/TestAsset/DuckTypedServiceLocatorAwareController.php @@ -0,0 +1,22 @@ + Date: Mon, 29 Feb 2016 12:43:54 -0600 Subject: [PATCH 11/15] Ensure expected default console routes are present --- test/Router/Console/SimpleRouteStackTest.php | 57 ++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 test/Router/Console/SimpleRouteStackTest.php diff --git a/test/Router/Console/SimpleRouteStackTest.php b/test/Router/Console/SimpleRouteStackTest.php new file mode 100644 index 000000000..dc7749af0 --- /dev/null +++ b/test/Router/Console/SimpleRouteStackTest.php @@ -0,0 +1,57 @@ + []]; + $simpleOpts = ['route' => 'test']; + + $data = [ + 'catchall' => ['catchall', $catchallOpts, Catchall::class], + 'catchAll' => ['catchAll', $catchallOpts, Catchall::class], + 'Catchall' => ['Catchall', $catchallOpts, Catchall::class], + 'CatchAll' => ['CatchAll', $catchallOpts, Catchall::class], + 'simple' => ['simple', $simpleOpts, Simple::class], + 'Simple' => ['Simple', $simpleOpts, Simple::class], + + Catchall::class => [Catchall::class, $catchallOpts, Catchall::class], + Simple::class => [Simple::class, $simpleOpts, Simple::class], + ]; + + // Two additional cases under zend-servicemanager v2: + $r = new ReflectionClass(ServiceManager::class); + if (! $r->hasMethod('configure')) { + $data['zendmvcrouterconsolecatchall'] = ['zendmvcrouterconsolecatchall', $catchallOpts, Catchall::class]; + $data['zendmvcrouterconsolesimple'] = ['zendmvcrouterconsolesimple', $simpleOpts, Simple::class]; + } + + return $data; + } + + /** + * @dataProvider routeTypeProvider + */ + public function testExpectedAliasesAndFactoriesResolve($serviceName, array $options, $expected) + { + $router = new SimpleRouteStack(); + $routes = $router->getRoutePluginManager(); + $this->assertInstanceOf($expected, $routes->get($serviceName, $options)); + } +} From 167bf67f28915367d27411a0c092d16a241b21fd Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 12:48:31 -0600 Subject: [PATCH 12/15] Ensure that ConsoleRouter is returned under console environment --- test/Service/RouterFactoryTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/Service/RouterFactoryTest.php b/test/Service/RouterFactoryTest.php index f5edfd4a2..0679122be 100644 --- a/test/Service/RouterFactoryTest.php +++ b/test/Service/RouterFactoryTest.php @@ -19,6 +19,8 @@ class RouterFactoryTest extends TestCase { + use FactoryEnvironmentTrait; + public function setUp() { $this->defaultServiceConfig = [ @@ -70,4 +72,15 @@ public function testFactoryCanCreateRouterWhenOnlyHttpRouterConfigPresent() $router = $this->factory->__invoke($services, 'router'); $this->assertInstanceOf('Zend\Mvc\Router\Console\SimpleRouteStack', $router); } + + public function testFactoryWillCreateConsoleRouterBasedOnConsoleUsageUnderServiceManagerV2() + { + $this->setConsoleEnvironment(true); + + $services = new ServiceManager(); + (new Config($this->defaultServiceConfig))->configureServiceManager($services); + + $router = $this->factory->createService($services, 'router'); + $this->assertInstanceOf('Zend\Mvc\Router\Console\SimpleRouteStack', $router); + } } From 7792a1e411c4968b79974776d14d7d309197c741 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 12:58:12 -0600 Subject: [PATCH 13/15] Removed invalid test cases The test cases removed are tested implicitly when retrieving aliases; however, they can never be retrieved directly, as they will not resolve to fully qualified class names. (When retrieving by alias, the FQCN is passed as the "requested name", which is why the factory works ever.) --- test/Router/Console/SimpleRouteStackTest.php | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/test/Router/Console/SimpleRouteStackTest.php b/test/Router/Console/SimpleRouteStackTest.php index dc7749af0..f4fe6adeb 100644 --- a/test/Router/Console/SimpleRouteStackTest.php +++ b/test/Router/Console/SimpleRouteStackTest.php @@ -10,7 +10,6 @@ namespace ZendTest\Mvc\Router\Console; use PHPUnit_Framework_TestCase as TestCase; -use ReflectionClass; use Zend\Mvc\Router\Console\Catchall; use Zend\Mvc\Router\Console\Simple; use Zend\Mvc\Router\Console\SimpleRouteStack; @@ -23,7 +22,7 @@ public function routeTypeProvider() $catchallOpts = ['defaults' => []]; $simpleOpts = ['route' => 'test']; - $data = [ + return [ 'catchall' => ['catchall', $catchallOpts, Catchall::class], 'catchAll' => ['catchAll', $catchallOpts, Catchall::class], 'Catchall' => ['Catchall', $catchallOpts, Catchall::class], @@ -34,15 +33,6 @@ public function routeTypeProvider() Catchall::class => [Catchall::class, $catchallOpts, Catchall::class], Simple::class => [Simple::class, $simpleOpts, Simple::class], ]; - - // Two additional cases under zend-servicemanager v2: - $r = new ReflectionClass(ServiceManager::class); - if (! $r->hasMethod('configure')) { - $data['zendmvcrouterconsolecatchall'] = ['zendmvcrouterconsolecatchall', $catchallOpts, Catchall::class]; - $data['zendmvcrouterconsolesimple'] = ['zendmvcrouterconsolesimple', $simpleOpts, Simple::class]; - } - - return $data; } /** From c4d7430ff5bee95d3295e9c2e6cb257e2af8e468 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 13:02:16 -0600 Subject: [PATCH 14/15] CS fixes per php-cs-fixer --- test/Router/Console/SimpleRouteStackTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Router/Console/SimpleRouteStackTest.php b/test/Router/Console/SimpleRouteStackTest.php index f4fe6adeb..afcec169d 100644 --- a/test/Router/Console/SimpleRouteStackTest.php +++ b/test/Router/Console/SimpleRouteStackTest.php @@ -13,7 +13,6 @@ use Zend\Mvc\Router\Console\Catchall; use Zend\Mvc\Router\Console\Simple; use Zend\Mvc\Router\Console\SimpleRouteStack; -use Zend\ServiceManager\ServiceManager; class SimpleRouteStackTest extends TestCase { From 99e42122f223a18de03ec14bca4a189c88d73b62 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 29 Feb 2016 13:33:47 -0600 Subject: [PATCH 15/15] Better ServiceLocatorAwareInterface duck typing Do not check if ServiceLocatorAwareInterface exists, as that will skip the initializer when it does, but the instance does not implement it and *does* fit duck typing rules. --- src/Controller/ControllerManager.php | 8 ++++++-- src/Service/ServiceManagerConfig.php | 2 +- test/Service/ServiceManagerConfigTest.php | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Controller/ControllerManager.php b/src/Controller/ControllerManager.php index 7471ec429..af85c08ae 100644 --- a/src/Controller/ControllerManager.php +++ b/src/Controller/ControllerManager.php @@ -54,8 +54,11 @@ public function __construct($configOrContainerInstance, array $v3config = []) $this->addInitializer([$this, 'injectEventManager']); $this->addInitializer([$this, 'injectConsole']); $this->addInitializer([$this, 'injectPluginManager']); - $this->addInitializer([$this, 'injectServiceLocator']); parent::__construct($configOrContainerInstance, $v3config); + + // Added after parent construction, as v2 abstract plugin managers add + // one during construction. + $this->addInitializer([$this, 'injectServiceLocator']); } /** @@ -204,6 +207,7 @@ public function injectPluginManager($first, $second) */ public function injectServiceLocator($first, $second) { + printf("In %s\n", __METHOD__); if ($first instanceof ContainerInterface) { $container = $first; $controller = $second; @@ -217,7 +221,7 @@ public function injectServiceLocator($first, $second) $container = $container->getServiceLocator() ?: $container; } - if (! interface_exists(ServiceLocatorAwareInterface::class) + if (! $controller instanceof ServiceLocatorAwareInterface && method_exists($controller, 'setServiceLocator') ) { trigger_error(sprintf( diff --git a/src/Service/ServiceManagerConfig.php b/src/Service/ServiceManagerConfig.php index b502ac08e..b20dc6aec 100644 --- a/src/Service/ServiceManagerConfig.php +++ b/src/Service/ServiceManagerConfig.php @@ -142,7 +142,7 @@ public function __construct(array $config = []) $instance->setServiceLocator($container); } - if (! interface_exists(ServiceLocatorAwareInterface::class) + if (! $instance instanceof ServiceLocatorAwareInterface && method_exists($instance, 'setServiceLocator') ) { trigger_error(sprintf( diff --git a/test/Service/ServiceManagerConfigTest.php b/test/Service/ServiceManagerConfigTest.php index 2b9940f53..13ea77059 100644 --- a/test/Service/ServiceManagerConfigTest.php +++ b/test/Service/ServiceManagerConfigTest.php @@ -219,10 +219,10 @@ public function testEventManagerInitializerCanBeReplaced() public function testServiceLocatorAwareInitializerInjectsDuckTypedImplementations() { - $serviceManager = new ServiceManager(['factories' => [ + $serviceManager = new ServiceManager(); + (new ServiceManagerConfig(['factories' => [ TestAsset\DuckTypedServiceLocatorAware::class => InvokableFactory::class, - ]]); - (new ServiceManagerConfig())->configureServiceManager($serviceManager); + ]]))->configureServiceManager($serviceManager); $instance = $serviceManager->get(TestAsset\DuckTypedServiceLocatorAware::class); $this->assertInstanceOf(TestAsset\DuckTypedServiceLocatorAware::class, $instance);