From a46be7d9e9512f3f624e36f840e7993b268639d1 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 30 Sep 2015 08:08:02 -0500 Subject: [PATCH] Refactored to work with zend-servicemanager v3 - All factories implementing `FactoryInterface` and/or `AbstractFactoryInterface` were updated to the new interface signatures. - All plugin managers were updated to the new `AbstractPluginManager` changes. Whenever possible, they were rewritten to remove invokables and instead define factories and/or aliases. - Added the `RouteInvokableFactory`, which acts both as a specialized invokable factory for route implementations (as they use a `::factory()` method for initialization vs a constructor), and an abstract factory for handling FQCN route names. The `RoutePluginManager` composes this abstract factory by default. - `Application::init` was updated to pull the fully configured service manager from the `ServiceListener` after loading modules. - The `DispatchListener` now receives its controller manager instance during instantiation. - Separated router factory into 3: - `ConsoleRouterFactory` will create a console router - `HttpRouterFactory` will create an HTTP router - `RouterFactory` delegates to the above two, based on status of `Console::isConsole()` The above makes it possible to specify the specific router type you want to use via configuration, making testing possible. - Refactored the ViewManager implementations. Previously, the view managers were adding services and aliases to the service manager duing their bootstrap listeners; with the SM now immutable, that does not make sense, and, in fact, leads to errors. In all cases where object creation was occuring, the code was moved to new factories, which the view manager implementations can now pull specifically. Aliases for these were added where appropriate. However, I stopped short of adding factories for general services such as `DefaultRenderingStrategy` as the implementations differ enough that having such a factory mutate based on the selected view manager would require type-hinting to consume the services regardless. - New integration tests for `Application` were written to ensure the SM is in correct state for `bootstrap()` and `run()`, and that the service listener <-> service manager dance is correctly managed. --- composer.json | 4 +- src/Application.php | 26 +- src/Controller/AbstractController.php | 34 +- src/Controller/ControllerManager.php | 119 ++---- src/Controller/Plugin/Forward.php | 5 +- .../Plugin/Service/ForwardFactory.php | 18 +- .../Plugin/Service/IdentityFactory.php | 12 +- src/Controller/PluginManager.php | 111 +++--- src/DispatchListener.php | 35 +- src/Exception/InvalidControllerException.php | 14 - src/Router/Console/SimpleRouteStack.php | 11 +- src/Router/Http/TreeRouteStack.php | 24 +- src/Router/RouteInvokableFactory.php | 83 +++++ src/Router/RoutePluginManager.php | 144 +++++--- src/Router/SimpleRouteStack.php | 3 +- src/Service/AbstractPluginManagerFactory.php | 23 +- src/Service/ApplicationFactory.php | 20 +- src/Service/ConfigFactory.php | 37 -- src/Service/ConsoleAdapterFactory.php | 24 +- .../ConsoleExceptionStrategyFactory.php | 60 +++ .../ConsoleRouteNotFoundStrategyFactory.php | 47 +++ src/Service/ConsoleRouterFactory.php | 38 ++ src/Service/ConsoleViewManagerConfigTrait.php | 39 ++ src/Service/ConsoleViewManagerFactory.php | 12 +- src/Service/ControllerLoaderFactory.php | 48 --- src/Service/ControllerManagerFactory.php | 40 ++ .../ControllerPluginManagerFactory.php | 4 +- .../DiAbstractServiceFactoryFactory.php | 36 -- src/Service/DiFactory.php | 44 --- src/Service/DiServiceInitializerFactory.php | 28 -- .../DiStrictAbstractServiceFactory.php | 142 ------- .../DiStrictAbstractServiceFactoryFactory.php | 37 -- src/Service/DispatchListenerFactory.php | 30 ++ src/Service/EventManagerFactory.php | 14 +- src/Service/FilterManagerFactory.php | 4 +- src/Service/FormAnnotationBuilderFactory.php | 27 +- src/Service/FormElementManagerFactory.php | 17 +- .../HttpDefaultRenderingStrategyFactory.php | 42 +++ src/Service/HttpExceptionStrategyFactory.php | 60 +++ src/Service/HttpMethodListenerFactory.php | 8 +- .../HttpRouteNotFoundStrategyFactory.php | 73 ++++ src/Service/HttpRouterFactory.php | 41 +++ src/Service/HttpViewManagerConfigTrait.php | 37 ++ src/Service/HttpViewManagerFactory.php | 10 +- src/Service/HydratorManagerFactory.php | 4 +- src/Service/InjectTemplateListenerFactory.php | 8 +- src/Service/InputFilterManagerFactory.php | 4 +- src/Service/LogProcessorManagerFactory.php | 4 +- src/Service/LogWriterManagerFactory.php | 4 +- src/Service/ModuleManagerFactory.php | 28 +- src/Service/PaginatorPluginManagerFactory.php | 4 +- src/Service/RequestFactory.php | 10 +- src/Service/ResponseFactory.php | 10 +- src/Service/RoutePluginManagerFactory.php | 4 +- src/Service/RouterConfigTrait.php | 40 ++ src/Service/RouterFactory.php | 46 +-- .../SerializerAdapterPluginManagerFactory.php | 4 +- src/Service/ServiceListenerFactory.php | 227 +++++++----- src/Service/ServiceManagerConfig.php | 121 ++---- .../TranslatorPluginManagerFactory.php | 4 +- src/Service/TranslatorServiceFactory.php | 22 +- src/Service/ValidatorManagerFactory.php | 4 +- src/Service/ViewFactory.php | 35 ++ src/Service/ViewFeedStrategyFactory.php | 14 +- src/Service/ViewHelperManagerFactory.php | 153 +++++--- src/Service/ViewJsonStrategyFactory.php | 12 +- src/Service/ViewManagerFactory.php | 14 +- src/Service/ViewPhpRendererFactory.php | 32 ++ .../ViewPhpRendererStrategyFactory.php | 29 ++ .../ViewPrefixPathStackResolverFactory.php | 12 +- src/Service/ViewResolverFactory.php | 16 +- .../ViewTemplateMapResolverFactory.php | 12 +- src/Service/ViewTemplatePathStackFactory.php | 12 +- src/View/Console/ViewManager.php | 92 +---- src/View/Http/ViewManager.php | 240 ++---------- .../AllowsReturningEarlyFromRoutingTest.php | 34 ++ test/Application/BadControllerTrait.php | 96 +++++ .../ControllerIsDispatchedTest.php | 27 ++ ...hableShouldRaiseDispatchErrorEventTest.php | 38 ++ ...ntrollerShouldTriggerDispatchErrorTest.php | 40 ++ ...veControllerShouldTriggerExceptionTest.php | 40 ++ .../InitializationIntegrationTest.php | 43 +++ ...llerTypeShouldTriggerDispatchErrorTest.php | 41 +++ .../InvalidControllerTypeTrait.php | 96 +++++ test/Application/MissingControllerTrait.php | 83 +++++ test/Application/PathControllerTrait.php | 94 +++++ test/Application/RoutingSuccessTest.php | 36 ++ .../TestAsset/modules/Application/Module.php | 29 ++ .../Application/config/module.config.php | 66 ++++ .../Application/Controller/PathController.php | 27 ++ .../view/application/index/index.phtml | 5 + .../modules/Application/view/error/404.phtml | 107 ++++++ .../Application/view/error/index.phtml | 62 ++++ .../Application/view/layout/layout.phtml | 14 + test/ApplicationTest.php | 348 +++++++----------- test/Controller/AbstractControllerTest.php | 3 +- test/Controller/ActionControllerTest.php | 8 +- test/Controller/ControllerManagerTest.php | 49 +-- test/Controller/IntegrationTest.php | 44 ++- .../Plugin/FilePostRedirectGetTest.php | 2 + test/Controller/Plugin/ForwardTest.php | 131 ++++--- .../Plugin/TestAsset/SamplePluginFactory.php | 6 +- .../SamplePluginWithConstructorFactory.php | 13 +- test/Controller/PluginManagerTest.php | 79 ++-- test/Controller/RestfulControllerTest.php | 5 - .../ControllerLoaderAbstractFactory.php | 19 +- ...catableControllerLoaderAbstractFactory.php | 8 +- test/DispatchListenerTest.php | 105 +++--- test/Router/Http/ChainTest.php | 7 +- test/Router/Http/PartTest.php | 42 ++- test/Router/Http/SegmentTest.php | 95 ++++- .../TranslatorAwareTreeRouteStackTest.php | 4 +- test/Router/RoutePluginManagerTest.php | 91 +---- test/Router/SimpleRouteStackTest.php | 5 +- test/Service/ConsoleAdapterFactoryTest.php | 105 ++++++ .../Service/ConsoleViewManagerFactoryTest.php | 41 +++ test/Service/ControllerLoaderFactoryTest.php | 183 --------- test/Service/ControllerManagerFactoryTest.php | 111 ++++++ test/Service/DiFactoryTest.php | 26 -- .../DiStrictAbstractServiceFactoryTest.php | 64 ---- test/Service/FactoryEnvironmentTrait.php | 29 ++ .../FormAnnotationBuilderFactoryTest.php | 9 +- .../Service/FormElementManagerFactoryTest.php | 34 +- .../Service/HttpMethodListenerFactoryTest.php | 4 +- .../InjectTemplateListenerFactoryTest.php | 4 +- test/Service/RequestFactoryTest.php | 41 +++ test/Service/ResponseFactoryTest.php | 41 +++ test/Service/RouterFactoryTest.php | 46 ++- test/Service/ServiceListenerFactoryTest.php | 36 +- test/Service/ServiceManagerConfigTest.php | 179 ++------- test/Service/TranslatorServiceFactoryTest.php | 87 +++-- test/Service/ViewFeedStrategyFactoryTest.php | 36 ++ test/Service/ViewHelperManagerFactoryTest.php | 159 +++++++- test/Service/ViewJsonStrategyFactoryTest.php | 36 ++ test/Service/ViewManagerFactoryTest.php | 56 +++ ...ViewPrefixPathStackResolverFactoryTest.php | 4 +- test/TestAsset/Locator.php | 18 +- .../Console/CreateViewModelListenerTest.php | 102 +++++ .../Console/DefaultRenderingStrategyTest.php | 10 +- test/View/Console/ViewManagerTest.php | 71 ++-- test/View/DefaultRendereringStrategyTest.php | 28 +- 141 files changed, 3979 insertions(+), 2529 deletions(-) delete mode 100644 src/Exception/InvalidControllerException.php create mode 100644 src/Router/RouteInvokableFactory.php delete mode 100644 src/Service/ConfigFactory.php create mode 100644 src/Service/ConsoleExceptionStrategyFactory.php create mode 100644 src/Service/ConsoleRouteNotFoundStrategyFactory.php create mode 100644 src/Service/ConsoleRouterFactory.php create mode 100644 src/Service/ConsoleViewManagerConfigTrait.php delete mode 100644 src/Service/ControllerLoaderFactory.php create mode 100644 src/Service/ControllerManagerFactory.php delete mode 100644 src/Service/DiAbstractServiceFactoryFactory.php delete mode 100644 src/Service/DiFactory.php delete mode 100644 src/Service/DiServiceInitializerFactory.php delete mode 100644 src/Service/DiStrictAbstractServiceFactory.php delete mode 100644 src/Service/DiStrictAbstractServiceFactoryFactory.php create mode 100644 src/Service/DispatchListenerFactory.php create mode 100644 src/Service/HttpDefaultRenderingStrategyFactory.php create mode 100644 src/Service/HttpExceptionStrategyFactory.php create mode 100644 src/Service/HttpRouteNotFoundStrategyFactory.php create mode 100644 src/Service/HttpRouterFactory.php create mode 100644 src/Service/HttpViewManagerConfigTrait.php create mode 100644 src/Service/RouterConfigTrait.php create mode 100644 src/Service/ViewFactory.php create mode 100644 src/Service/ViewPhpRendererFactory.php create mode 100644 src/Service/ViewPhpRendererStrategyFactory.php create mode 100644 test/Application/AllowsReturningEarlyFromRoutingTest.php create mode 100644 test/Application/BadControllerTrait.php create mode 100644 test/Application/ControllerIsDispatchedTest.php create mode 100644 test/Application/ExceptionsRaisedInDispatchableShouldRaiseDispatchErrorEventTest.php create mode 100644 test/Application/InabilityToRetrieveControllerShouldTriggerDispatchErrorTest.php create mode 100644 test/Application/InabilityToRetrieveControllerShouldTriggerExceptionTest.php create mode 100644 test/Application/InitializationIntegrationTest.php create mode 100644 test/Application/InvalidControllerTypeShouldTriggerDispatchErrorTest.php create mode 100644 test/Application/InvalidControllerTypeTrait.php create mode 100644 test/Application/MissingControllerTrait.php create mode 100644 test/Application/PathControllerTrait.php create mode 100644 test/Application/RoutingSuccessTest.php create mode 100644 test/Application/TestAsset/modules/Application/Module.php create mode 100644 test/Application/TestAsset/modules/Application/config/module.config.php create mode 100644 test/Application/TestAsset/modules/Application/src/Application/Controller/PathController.php create mode 100644 test/Application/TestAsset/modules/Application/view/application/index/index.phtml create mode 100644 test/Application/TestAsset/modules/Application/view/error/404.phtml create mode 100644 test/Application/TestAsset/modules/Application/view/error/index.phtml create mode 100644 test/Application/TestAsset/modules/Application/view/layout/layout.phtml create mode 100644 test/Service/ConsoleAdapterFactoryTest.php create mode 100644 test/Service/ConsoleViewManagerFactoryTest.php delete mode 100644 test/Service/ControllerLoaderFactoryTest.php create mode 100644 test/Service/ControllerManagerFactoryTest.php delete mode 100644 test/Service/DiFactoryTest.php delete mode 100644 test/Service/DiStrictAbstractServiceFactoryTest.php create mode 100644 test/Service/FactoryEnvironmentTrait.php create mode 100644 test/Service/RequestFactoryTest.php create mode 100644 test/Service/ResponseFactoryTest.php create mode 100644 test/Service/ViewFeedStrategyFactoryTest.php create mode 100644 test/Service/ViewJsonStrategyFactoryTest.php create mode 100644 test/Service/ViewManagerFactoryTest.php create mode 100644 test/View/Console/CreateViewModelListenerTest.php diff --git a/composer.json b/composer.json index d00404ebc..04681788b 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "require": { "php": ">=5.5", "zendframework/zend-eventmanager": "dev-develop as 2.7.0", - "zendframework/zend-servicemanager": "~2.5", + "zendframework/zend-servicemanager": "dev-develop as 2.6.0", "zendframework/zend-hydrator": "~1.0", "zendframework/zend-form": "~2.6", "zendframework/zend-stdlib": "~2.7", @@ -39,7 +39,7 @@ "zendframework/zend-uri": "~2.5", "zendframework/zend-validator": "~2.5", "zendframework/zend-version": "~2.5", - "zendframework/zend-view": "dev-develop as 2.6.0", + "zendframework/zend-view": "dev-develop#82c537d8f as 2.6.0", "fabpot/php-cs-fixer": "1.7.*", "phpunit/PHPUnit": "~4.0" }, diff --git a/src/Application.php b/src/Application.php index 2b9068449..360a71aff 100644 --- a/src/Application.php +++ b/src/Application.php @@ -125,7 +125,7 @@ public function __construct( */ public function getConfig() { - return $this->serviceManager->get('Config'); + return $this->serviceManager->get('config'); } /** @@ -140,9 +140,10 @@ public function getConfig() */ public function bootstrap(array $listeners = []) { - $serviceManager = $this->serviceManager; $events = $this->events; + $serviceManager = $this->serviceManager; + // Setup default listeners $listeners = array_unique(array_merge($this->defaultListeners, $listeners)); foreach ($listeners as $listener) { @@ -160,6 +161,7 @@ public function bootstrap(array $listeners = []) // Trigger bootstrap events $events->triggerEvent($event); + return $this; } @@ -252,13 +254,27 @@ public function getEventManager() */ public static function init($configuration = []) { + // Prepare the service manager $smConfig = isset($configuration['service_manager']) ? $configuration['service_manager'] : []; - $serviceManager = new ServiceManager(new Service\ServiceManagerConfig($smConfig)); - $serviceManager->setService('ApplicationConfig', $configuration); + $smConfig = new Service\ServiceManagerConfig($smConfig); + + $serviceManager = new ServiceManager($smConfig->toArray()); + $serviceManager = $serviceManager->withConfig(['services' => [ + 'ApplicationConfig' => $configuration, + ]]); + + // Load modules $serviceManager->get('ModuleManager')->loadModules(); + // Get the configured SM if necessary. + if ($serviceManager->has('ServiceListener')) { + $serviceListener = $serviceManager->get('ServiceListener'); + $serviceManager = $serviceListener->getConfiguredServiceManager(); + } + + // Prepare list of listeners to bootstrap $listenersFromAppConfig = isset($configuration['listeners']) ? $configuration['listeners'] : []; - $config = $serviceManager->get('Config'); + $config = $serviceManager->get('config'); $listenersFromConfigService = isset($config['listeners']) ? $config['listeners'] : []; $listeners = array_unique(array_merge($listenersFromConfigService, $listenersFromAppConfig)); diff --git a/src/Controller/AbstractController.php b/src/Controller/AbstractController.php index 1d5f0d3cc..92e633d92 100644 --- a/src/Controller/AbstractController.php +++ b/src/Controller/AbstractController.php @@ -17,8 +17,7 @@ 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; use Zend\Stdlib\ResponseInterface as Response; @@ -46,8 +45,7 @@ abstract class AbstractController implements Dispatchable, EventManagerAwareInterface, - InjectApplicationEventInterface, - ServiceLocatorAwareInterface + InjectApplicationEventInterface { /** * @var PluginManager @@ -74,11 +72,6 @@ abstract class AbstractController implements */ protected $events; - /** - * @var ServiceLocatorInterface - */ - protected $serviceLocator; - /** * @var null|string|string[] */ @@ -231,27 +224,6 @@ 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 * @@ -260,7 +232,7 @@ public function getServiceLocator() public function getPluginManager() { if (!$this->plugins) { - $this->setPluginManager(new PluginManager()); + $this->setPluginManager(new PluginManager(new ServiceManager())); } $this->plugins->setController($this); diff --git a/src/Controller/ControllerManager.php b/src/Controller/ControllerManager.php index 9749f93af..57cd64184 100644 --- a/src/Controller/ControllerManager.php +++ b/src/Controller/ControllerManager.php @@ -9,13 +9,10 @@ namespace Zend\Mvc\Controller; +use Interop\Container\ContainerInterface; use Zend\EventManager\EventManagerAwareInterface; use Zend\EventManager\SharedEventManagerInterface; -use Zend\Mvc\Exception; use Zend\ServiceManager\AbstractPluginManager; -use Zend\ServiceManager\ConfigInterface; -use Zend\ServiceManager\ServiceLocatorAwareInterface; -use Zend\ServiceManager\ServiceLocatorInterface; use Zend\Stdlib\DispatchableInterface; /** @@ -25,113 +22,77 @@ */ class ControllerManager extends AbstractPluginManager { - /** - * We do not want arbitrary classes instantiated as controllers. - * - * @var bool - */ - protected $autoAddInvokableClass = false; + protected $instanceOf = DispatchableInterface::class; /** * Constructor * - * After invoking parent constructor, add an initializer to inject the - * service manager, event manager, and plugin manager + * Injects an initializer for injecting controllers with an + * event manager and plugin manager. * - * @param null|ConfigInterface $configuration + * @param ContainerInterface $container + * @param array $configuration */ - public function __construct(ConfigInterface $configuration = null) + public function __construct(ContainerInterface $container, array $configuration = []) { - parent::__construct($configuration); - // Pushing to bottom of stack to ensure this is done last - $this->addInitializer([$this, 'injectControllerDependencies'], false); + $this->initializers[] = [$this, 'injectEventManager']; + $this->initializers[] = [$this, 'injectConsole']; + $this->initializers[] = [$this, 'injectPluginManager']; + parent::__construct($container, $configuration); } /** - * Inject required dependencies into the controller. + * Initializer: inject EventManager instance + * + * If we have an event manager composed already, make sure it gets injected + * with the shared event manager. + * + * The AbstractController lazy-instantiates an EM instance, which is why + * the shared EM injection needs to happen; the conditional will always + * pass. * - * @param DispatchableInterface $controller - * @param ServiceLocatorInterface $serviceLocator - * @return void + * @param ContainerInterface $container + * @param DispatchableInterface $controller */ - public function injectControllerDependencies($controller, ServiceLocatorInterface $serviceLocator) + public function injectEventManager(ContainerInterface $container, $controller) { - if (!$controller instanceof DispatchableInterface) { + if (! $controller instanceof EventManagerAwareInterface) { return; } - $parentLocator = $serviceLocator->getServiceLocator(); - - if ($controller instanceof ServiceLocatorAwareInterface) { - $controller->setServiceLocator($parentLocator->get('Zend\ServiceManager\ServiceLocatorInterface')); - } - - if ($controller instanceof EventManagerAwareInterface) { - // If we have an event manager composed already, make sure it gets - // injected with the shared event manager. - // The AbstractController lazy-instantiates an EM instance, which - // is why the shared EM injection needs to happen; the conditional - // will always pass. - $events = $controller->getEventManager(); - if (! $events || ! $events->getSharedManager() instanceof SharedEventManagerInterface) { - $controller->setEventManager($parentLocator->get('EventManager')); - } - } - - if ($controller instanceof AbstractConsoleController) { - $controller->setConsole($parentLocator->get('Console')); - } - - if (method_exists($controller, 'setPluginManager')) { - $controller->setPluginManager($parentLocator->get('ControllerPluginManager')); + $events = $controller->getEventManager(); + if (! $events || ! $events->getSharedManager() instanceof SharedEventManagerInterface) { + $controller->setEventManager($container->get('EventManager')); } } /** - * Validate the plugin - * - * Ensure we have a dispatchable. + * Initializer: inject Console adapter instance * - * @param mixed $plugin - * @return true - * @throws Exception\InvalidControllerException + * @param ContainerInterface $container + * @param DispatchableInterface $controller */ - public function validatePlugin($plugin) + public function injectConsole(ContainerInterface $container, $controller) { - if ($plugin instanceof DispatchableInterface) { - // we're okay + if (! $controller instanceof AbstractConsoleController) { return; } - throw new Exception\InvalidControllerException(sprintf( - 'Controller of type %s is invalid; must implement Zend\Stdlib\DispatchableInterface', - (is_object($plugin) ? get_class($plugin) : gettype($plugin)) - )); + $controller->setConsole($container->get('Console')); } /** - * Override: do not use peering service managers + * Initializer: inject plugin manager * - * @param string|array $name - * @param bool $checkAbstractFactories - * @param bool $usePeeringServiceManagers - * @return bool + * @param ContainerInterface $container + * @param DispatchableInterface $controller */ - public function has($name, $checkAbstractFactories = true, $usePeeringServiceManagers = false) + public function injectPluginManager(ContainerInterface $container, $controller) { - return parent::has($name, $checkAbstractFactories, $usePeeringServiceManagers); - } + if (! method_exists($controller, 'setPluginManager')) { + return; + } - /** - * Override: do not use peering service managers - * - * @param string $name - * @param array $options - * @param bool $usePeeringServiceManagers - * @return mixed - */ - public function get($name, $options = [], $usePeeringServiceManagers = false) - { - return parent::get($name, $options, $usePeeringServiceManagers); + $controller->setPluginManager($container->get('ControllerPluginManager')); } } diff --git a/src/Controller/Plugin/Forward.php b/src/Controller/Plugin/Forward.php index e0824fbf8..d26065ec4 100644 --- a/src/Controller/Plugin/Forward.php +++ b/src/Controller/Plugin/Forward.php @@ -236,7 +236,10 @@ protected function getEvent() $controller = $this->getController(); if (!$controller instanceof InjectApplicationEventInterface) { - throw new Exception\DomainException('Forward plugin requires a controller that implements InjectApplicationEventInterface'); + throw new Exception\DomainException(sprintf( + 'Forward plugin requires a controller that implements InjectApplicationEventInterface; received %s', + (is_object($controller) ? get_class($controller) : var_export($controller, 1)) + )); } $event = $controller->getEvent(); diff --git a/src/Controller/Plugin/Service/ForwardFactory.php b/src/Controller/Plugin/Service/ForwardFactory.php index 1f114ac57..89076fe5c 100644 --- a/src/Controller/Plugin/Service/ForwardFactory.php +++ b/src/Controller/Plugin/Service/ForwardFactory.php @@ -9,9 +9,9 @@ namespace Zend\Mvc\Controller\Plugin\Service; +use Interop\Container\ContainerInterface; use Zend\ServiceManager\Exception\ServiceNotCreatedException; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; use Zend\Mvc\Controller\Plugin\Forward; class ForwardFactory implements FactoryInterface @@ -22,24 +22,16 @@ class ForwardFactory implements FactoryInterface * @return Forward * @throws ServiceNotCreatedException if Controllermanager service is not found in application service locator */ - public function createService(ServiceLocatorInterface $plugins) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - $services = $plugins->getServiceLocator(); - if (!$services instanceof ServiceLocatorInterface) { - throw new ServiceNotCreatedException(sprintf( - '%s requires that the application service manager has been injected; none found', - __CLASS__ - )); - } - - if (!$services->has('ControllerManager')) { + if (! $container->has('ControllerManager')) { throw new ServiceNotCreatedException(sprintf( '%s requires that the application service manager contains a "%s" service; none found', __CLASS__, 'ControllerManager' )); } - $controllers = $services->get('ControllerManager'); + $controllers = $container->get('ControllerManager'); return new Forward($controllers); } diff --git a/src/Controller/Plugin/Service/IdentityFactory.php b/src/Controller/Plugin/Service/IdentityFactory.php index 701b3ddd7..dc3b7acfb 100644 --- a/src/Controller/Plugin/Service/IdentityFactory.php +++ b/src/Controller/Plugin/Service/IdentityFactory.php @@ -9,9 +9,10 @@ namespace Zend\Mvc\Controller\Plugin\Service; +use Interop\Container\ContainerInterface; +use Zend\Authentication\AuthenticationService; use Zend\Mvc\Controller\Plugin\Identity; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; class IdentityFactory implements FactoryInterface { @@ -20,12 +21,11 @@ class IdentityFactory implements FactoryInterface * * @return \Zend\Mvc\Controller\Plugin\Identity */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - $services = $serviceLocator->getServiceLocator(); $helper = new Identity(); - if ($services->has('Zend\Authentication\AuthenticationService')) { - $helper->setAuthenticationService($services->get('Zend\Authentication\AuthenticationService')); + if ($container->has(AuthenticationService::class)) { + $helper->setAuthenticationService($container->get(AuthenticationService::class)); } return $helper; } diff --git a/src/Controller/PluginManager.php b/src/Controller/PluginManager.php index cd7653695..bca5687a8 100644 --- a/src/Controller/PluginManager.php +++ b/src/Controller/PluginManager.php @@ -9,8 +9,8 @@ namespace Zend\Mvc\Controller; -use Zend\Mvc\Exception; use Zend\ServiceManager\AbstractPluginManager; +use Zend\ServiceManager\Factory\InvokableFactory; use Zend\Stdlib\DispatchableInterface; /** @@ -21,42 +21,62 @@ */ class PluginManager extends AbstractPluginManager { - /** - * Default set of plugins factories - * - * @var array - */ - protected $factories = [ - 'forward' => 'Zend\Mvc\Controller\Plugin\Service\ForwardFactory', - 'identity' => 'Zend\Mvc\Controller\Plugin\Service\IdentityFactory', - ]; + protected $instanceOf = Plugin\PluginInterface::class; /** - * Default set of plugins - * - * @var array + * @var string[] Default aliases */ - protected $invokableClasses = [ - 'acceptableviewmodelselector' => 'Zend\Mvc\Controller\Plugin\AcceptableViewModelSelector', - 'filepostredirectget' => 'Zend\Mvc\Controller\Plugin\FilePostRedirectGet', - 'flashmessenger' => 'Zend\Mvc\Controller\Plugin\FlashMessenger', - 'layout' => 'Zend\Mvc\Controller\Plugin\Layout', - 'params' => 'Zend\Mvc\Controller\Plugin\Params', - 'postredirectget' => 'Zend\Mvc\Controller\Plugin\PostRedirectGet', - 'redirect' => 'Zend\Mvc\Controller\Plugin\Redirect', - 'url' => 'Zend\Mvc\Controller\Plugin\Url', - 'createhttpnotfoundmodel' => 'Zend\Mvc\Controller\Plugin\CreateHttpNotFoundModel', - 'createconsolenotfoundmodel' => 'Zend\Mvc\Controller\Plugin\CreateConsoleNotFoundModel', + protected $aliases = [ + 'AcceptableViewModelSelector' => Plugin\AcceptableViewModelSelector::class, + 'acceptableViewModelSelector' => Plugin\AcceptableViewModelSelector::class, + 'acceptableviewmodelselector' => Plugin\AcceptableViewModelSelector::class, + 'FilePostRedirectGet' => Plugin\FilePostRedirectGet::class, + 'filePostRedirectGet' => Plugin\FilePostRedirectGet::class, + 'filepostredirectget' => Plugin\FilePostRedirectGet::class, + 'fileprg' => Plugin\FilePostRedirectGet::class, + 'FlashMessenger' => Plugin\FlashMessenger::class, + 'flashMessenger' => Plugin\FlashMessenger::class, + 'flashmessenger' => Plugin\FlashMessenger::class, + 'Forward' => Plugin\Forward::class, + 'forward' => Plugin\Forward::class, + 'Identity' => Plugin\Identity::class, + 'identity' => Plugin\Identity::class, + 'Layout' => Plugin\Layout::class, + 'layout' => Plugin\Layout::class, + 'Params' => Plugin\Params::class, + 'params' => Plugin\Params::class, + 'PostRedirectGet' => Plugin\PostRedirectGet::class, + 'postRedirectGet' => Plugin\PostRedirectGet::class, + 'postredirectget' => Plugin\PostRedirectGet::class, + 'prg' => Plugin\PostRedirectGet::class, + 'Redirect' => Plugin\Redirect::class, + 'redirect' => Plugin\Redirect::class, + 'Url' => Plugin\Url::class, + 'url' => Plugin\Url::class, + 'CreateHttpNotFoundModel' => Plugin\CreateHttpNotFoundModel::class, + 'createHttpNotFoundModel' => Plugin\CreateHttpNotFoundModel::class, + 'createhttpnotfoundmodel' => Plugin\CreateHttpNotFoundModel::class, + 'CreateConsoleNotFoundModel' => Plugin\CreateConsoleNotFoundModel::class, + 'createConsoleNotFoundModel' => Plugin\CreateConsoleNotFoundModel::class, + 'createconsolenotfoundmodel' => Plugin\CreateConsoleNotFoundModel::class, ]; /** - * Default set of plugin aliases - * - * @var array + * @var string[]|callable[] Default factories */ - protected $aliases = [ - 'prg' => 'postredirectget', - 'fileprg' => 'filepostredirectget', + protected $factories = [ + Plugin\Forward::class => Plugin\Service\ForwardFactory::class, + Plugin\Identity::class => Plugin\Service\IdentityFactory::class, + Plugin\AcceptableViewModelSelector::class => InvokableFactory::class, + Plugin\FilePostRedirectGet::class => InvokableFactory::class, + Plugin\FlashMessenger::class => InvokableFactory::class, + Plugin\Layout::class => InvokableFactory::class, + Plugin\Params::class => InvokableFactory::class, + Plugin\PostRedirectGet::class => InvokableFactory::class, + Plugin\Redirect::class => InvokableFactory::class, + Plugin\Url::class => InvokableFactory::class, + Plugin\CreateHttpNotFoundModel::class => InvokableFactory::class, + Plugin\CreateConsoleNotFoundModel::class => InvokableFactory::class, ]; /** @@ -75,13 +95,11 @@ class PluginManager extends AbstractPluginManager * plugin is lost. * * @param string $name - * @param mixed $options - * @param bool $usePeeringServiceManagers - * @return mixed + * @return DispatchableInterface */ - public function get($name, $options = [], $usePeeringServiceManagers = true) + public function get($name, array $options = null) { - $plugin = parent::get($name, $options, $usePeeringServiceManagers); + $plugin = parent::get($name, $options); $this->injectController($plugin); return $plugin; @@ -132,27 +150,4 @@ public function injectController($plugin) $plugin->setController($controller); } - - /** - * Validate the plugin - * - * Any plugin is considered valid in this context. - * - * @param mixed $plugin - * @return void - * @throws Exception\InvalidPluginException - */ - public function validatePlugin($plugin) - { - if ($plugin instanceof Plugin\PluginInterface) { - // we're okay - return; - } - - throw new Exception\InvalidPluginException(sprintf( - 'Plugin of type %s is invalid; must implement %s\Plugin\PluginInterface', - (is_object($plugin) ? get_class($plugin) : gettype($plugin)), - __NAMESPACE__ - )); - } } diff --git a/src/DispatchListener.php b/src/DispatchListener.php index 4b8671110..e8932400e 100644 --- a/src/DispatchListener.php +++ b/src/DispatchListener.php @@ -12,7 +12,7 @@ use ArrayObject; use Zend\EventManager\AbstractListenerAggregate; use Zend\EventManager\EventManagerInterface; -use Zend\Mvc\Exception\InvalidControllerException; +use Zend\ServiceManager\Exception\InvalidServiceException; use Zend\Stdlib\ArrayUtils; /** @@ -39,6 +39,19 @@ */ class DispatchListener extends AbstractListenerAggregate { + /** + * @var Controller\ControllerManager + */ + private $controllerManager; + + /** + * @param Controller\ControllerManager $controllerManager + */ + public function __construct(Controller\ControllerManager $controllerManager) + { + $this->controllerManager = $controllerManager; + } + /** * Attach listeners to an event manager * @@ -62,20 +75,24 @@ public function attach(EventManagerInterface $events, $priority = 1) */ public function onDispatch(MvcEvent $e) { - $routeMatch = $e->getRouteMatch(); - $controllerName = $routeMatch->getParam('controller', 'not-found'); - $application = $e->getApplication(); - $events = $application->getEventManager(); - $controllerLoader = $application->getServiceManager()->get('ControllerManager'); + $routeMatch = $e->getRouteMatch(); + $controllerName = $routeMatch instanceof Router\RouteMatch + ? $routeMatch->getParam('controller', 'not-found') + : 'not-found'; + $application = $e->getApplication(); + $events = $application->getEventManager(); + $controllerManager = $this->controllerManager; + - if (!$controllerLoader->has($controllerName)) { + // Query abstract controllers, too! + if (! $controllerManager->has($controllerName, true)) { $return = $this->marshalControllerNotFoundEvent($application::ERROR_CONTROLLER_NOT_FOUND, $controllerName, $e, $application); return $this->complete($return, $e); } try { - $controller = $controllerLoader->get($controllerName); - } catch (InvalidControllerException $exception) { + $controller = $controllerManager->get($controllerName); + } catch (InvalidServiceException $exception) { $return = $this->marshalControllerNotFoundEvent($application::ERROR_CONTROLLER_INVALID, $controllerName, $e, $application, $exception); return $this->complete($return, $e); } catch (\Exception $exception) { diff --git a/src/Exception/InvalidControllerException.php b/src/Exception/InvalidControllerException.php deleted file mode 100644 index 166f1fcdb..000000000 --- a/src/Exception/InvalidControllerException.php +++ /dev/null @@ -1,14 +0,0 @@ -routePluginManager; - foreach ([ - 'catchall' => __NAMESPACE__ . '\Catchall', - 'simple' => __NAMESPACE__ . '\Simple', - ] as $name => $class - ) { - $routes->setInvokableClass($name, $class); - }; + $this->routePluginManager = $routes->withConfig(['invokables' => [ + 'catchall' => __NAMESPACE__ . '\Catchall', + 'simple' => __NAMESPACE__ . '\Simple', + ]]); } /** diff --git a/src/Router/Http/TreeRouteStack.php b/src/Router/Http/TreeRouteStack.php index 481f9892f..7581d40d6 100644 --- a/src/Router/Http/TreeRouteStack.php +++ b/src/Router/Http/TreeRouteStack.php @@ -81,7 +81,20 @@ protected function init() $this->prototypes = new ArrayObject; $routes = $this->routePluginManager; - foreach ([ + $this->routePluginManager = $routes->withConfig([ + 'aliases' => [ + 'Chain' => 'chain', + 'Hostname' => 'hostname', + 'Literal' => 'literal', + 'Method' => 'method', + 'Part' => 'part', + 'Query' => 'query', + 'Regex' => 'regex', + 'Scheme' => 'scheme', + 'Segment' => 'segment', + 'Wildcard' => 'wildcard', + ], + 'invokables' => [ 'chain' => __NAMESPACE__ . '\Chain', 'hostname' => __NAMESPACE__ . '\Hostname', 'literal' => __NAMESPACE__ . '\Literal', @@ -92,10 +105,8 @@ protected function init() 'scheme' => __NAMESPACE__ . '\Scheme', 'segment' => __NAMESPACE__ . '\Segment', 'wildcard' => __NAMESPACE__ . '\Wildcard', - ] as $name => $class - ) { - $routes->setInvokableClass($name, $class); - }; + ], + ]); } /** @@ -275,8 +286,7 @@ public function match(Request $request, $pathOffset = null, array $options = []) } foreach ($this->routes as $name => $route) { - if ( - ($match = $route->match($request, $baseUrlLength, $options)) instanceof RouteMatch + if (($match = $route->match($request, $baseUrlLength, $options)) instanceof RouteMatch && ($pathLength === null || $match->getLength() === $pathLength) ) { $match->setMatchedRouteName($name); diff --git a/src/Router/RouteInvokableFactory.php b/src/Router/RouteInvokableFactory.php new file mode 100644 index 000000000..11c477882 --- /dev/null +++ b/src/Router/RouteInvokableFactory.php @@ -0,0 +1,83 @@ +setAlias($invokableClass, $name); - } - return $this; + $config = ArrayUtils::merge(['abstract_factories' => [ + RouteInvokableFactory::class, + ]], $config); + + parent::__construct($container, $config); } /** - * Validate the plugin. + * Pre-process configuration. * - * Checks that the filter loaded is either a valid callback or an instance - * of FilterInterface. + * Checks for invokables, and, if found, maps them to the + * component-specific RouteInvokableFactory; removes the invokables entry + * before passing to the parent. * - * @param mixed $plugin + * @param array $config * @return void - * @throws Exception\RuntimeException if invalid */ - public function validatePlugin($plugin) + protected function configure(array $config) { - if ($plugin instanceof RouteInterface) { - // we're okay - return; + if (isset($config['invokables']) && ! empty($config['invokables'])) { + $aliases = $this->createAliasesForInvokables($config['invokables']); + $factories = $this->createFactoriesForInvokables($config['invokables']); + + if (! empty($aliases)) { + $config['aliases'] = isset($config['aliases']) + ? array_merge($config['aliases'], $aliases) + : $aliases; + } + + $config['factories'] = isset($config['factories']) + ? array_merge($config['factories'], $factories) + : $factories; + + unset($config['invokables']); } - throw new Exception\RuntimeException(sprintf( - 'Plugin of type %s is invalid; must implement %s\RouteInterface', - (is_object($plugin) ? get_class($plugin) : gettype($plugin)), - __NAMESPACE__ - )); + parent::configure($config); } - /** - * Attempt to create an instance via an invokable class. + /** + * Create aliases for invokable classes. * - * Overrides parent implementation by invoking the route factory, - * passing $creationOptions as the argument. + * If an invokable service name does not match the class it maps to, this + * creates an alias to the class (which will later be mapped as an + * invokable factory). * - * @param string $canonicalName - * @param string $requestedName - * @return null|\stdClass - * @throws Exception\RuntimeException If resolved class does not exist, or does not implement RouteInterface + * @param array $invokables + * @return array */ - protected function createFromInvokable($canonicalName, $requestedName) + protected function createAliasesForInvokables(array $invokables) { - $invokable = $this->invokableClasses[$canonicalName]; - if (!class_exists($invokable)) { - throw new Exception\RuntimeException(sprintf( - '%s: failed retrieving "%s%s" via invokable class "%s"; class does not exist', - __METHOD__, - $canonicalName, - ($requestedName ? '(alias: ' . $requestedName . ')' : ''), - $invokable - )); + $aliases = []; + foreach ($invokables as $name => $class) { + if ($name === $class) { + continue; + } + $aliases[$name] = $class; } + return $aliases; + } - if (!static::isSubclassOf($invokable, __NAMESPACE__ . '\RouteInterface')) { - throw new Exception\RuntimeException(sprintf( - '%s: failed retrieving "%s%s" via invokable class "%s"; class does not implement %s\RouteInterface', - __METHOD__, - $canonicalName, - ($requestedName ? '(alias: ' . $requestedName . ')' : ''), - $invokable, - __NAMESPACE__ - )); - } + /** + * Create invokable factories for invokable classes. + * + * If an invokable service name does not match the class it maps to, this + * creates an invokable factory entry for the class name; otherwise, it + * creates an invokable factory for the entry name. + * + * @param array $invokables + * @return array + */ + protected function createFactoriesForInvokables(array $invokables) + { + $factories = []; + foreach ($invokables as $name => $class) { + if ($name === $class) { + $factories[$name] = RouteInvokableFactory::class; + continue; + } - return $invokable::factory($this->creationOptions); + $factories[$class] = RouteInvokableFactory::class; + } + return $factories; } } diff --git a/src/Router/SimpleRouteStack.php b/src/Router/SimpleRouteStack.php index 0bee25b81..a89dbde33 100644 --- a/src/Router/SimpleRouteStack.php +++ b/src/Router/SimpleRouteStack.php @@ -10,6 +10,7 @@ namespace Zend\Mvc\Router; use Traversable; +use Zend\ServiceManager\ServiceManager; use Zend\Stdlib\ArrayUtils; use Zend\Stdlib\RequestInterface as Request; @@ -49,7 +50,7 @@ public function __construct(RoutePluginManager $routePluginManager = null) $this->routes = new PriorityList(); if (null === $routePluginManager) { - $routePluginManager = new RoutePluginManager(); + $routePluginManager = new RoutePluginManager(new ServiceManager()); } $this->routePluginManager = $routePluginManager; diff --git a/src/Service/AbstractPluginManagerFactory.php b/src/Service/AbstractPluginManagerFactory.php index 1463fd5d3..11995a97b 100644 --- a/src/Service/AbstractPluginManagerFactory.php +++ b/src/Service/AbstractPluginManagerFactory.php @@ -9,9 +9,9 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\ServiceManager\AbstractPluginManager; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; abstract class AbstractPluginManagerFactory implements FactoryInterface { @@ -19,24 +19,19 @@ abstract class AbstractPluginManagerFactory implements FactoryInterface /** * Create and return a plugin manager. + * * Classes that extend this should provide a valid class for * the PLUGIN_MANGER_CLASS constant. * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return AbstractPluginManager */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { + $options = $options ?: []; $pluginManagerClass = static::PLUGIN_MANAGER_CLASS; - /* @var $plugins AbstractPluginManager */ - $plugins = new $pluginManagerClass; - $plugins->setServiceLocator($serviceLocator); - $configuration = $serviceLocator->get('Config'); - - if (isset($configuration['di']) && $serviceLocator->has('Di')) { - $plugins->addAbstractFactory($serviceLocator->get('DiAbstractServiceFactory')); - } - - return $plugins; + return new $pluginManagerClass($container, $options); } } diff --git a/src/Service/ApplicationFactory.php b/src/Service/ApplicationFactory.php index 5897aba42..a87edb4c8 100644 --- a/src/Service/ApplicationFactory.php +++ b/src/Service/ApplicationFactory.php @@ -9,9 +9,9 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\Mvc\Application; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; class ApplicationFactory implements FactoryInterface { @@ -21,17 +21,19 @@ class ApplicationFactory implements FactoryInterface * Creates a Zend\Mvc\Application service, passing it the configuration * service and the service manager instance. * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return Application */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { return new Application( - $serviceLocator->get('Config'), - $serviceLocator, - $serviceLocator->get('EventManager'), - $serviceLocator->get('Request'), - $serviceLocator->get('Response') + $container->get('config'), + $container, + $container->get('EventManager'), + $container->get('Request'), + $container->get('Response') ); } } diff --git a/src/Service/ConfigFactory.php b/src/Service/ConfigFactory.php deleted file mode 100644 index a3683994c..000000000 --- a/src/Service/ConfigFactory.php +++ /dev/null @@ -1,37 +0,0 @@ -get('ModuleManager'); - $mm->loadModules(); - $moduleParams = $mm->getEvent()->getParams(); - $config = $moduleParams['configListener']->getMergedConfig(false); - return $config; - } -} diff --git a/src/Service/ConsoleAdapterFactory.php b/src/Service/ConsoleAdapterFactory.php index 0258653d4..bd4ea3ee8 100644 --- a/src/Service/ConsoleAdapterFactory.php +++ b/src/Service/ConsoleAdapterFactory.php @@ -9,11 +9,11 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use stdClass; use Zend\Console\Adapter\AdapterInterface; use Zend\Console\Console; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; class ConsoleAdapterFactory implements FactoryInterface { @@ -35,22 +35,24 @@ class ConsoleAdapterFactory implements FactoryInterface * ) * ) * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return AdapterInterface|stdClass */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { // First, check if we're actually in a Console environment - if (!Console::isConsole()) { + if (! Console::isConsole()) { // SM factory cannot currently return null, so we return dummy object return new stdClass(); } // Read app config and determine Console adapter to use - $config = $serviceLocator->get('Config'); - if (!empty($config['console']) && !empty($config['console']['adapter'])) { + $config = $container->get('config'); + if (! empty($config['console']) && ! empty($config['console']['adapter'])) { // use the adapter supplied in application config - $adapter = $serviceLocator->get($config['console']['adapter']); + $adapter = $container->get($config['console']['adapter']); } else { // try to detect best console adapter $adapter = Console::detectBestAdapter(); @@ -58,15 +60,15 @@ public function createService(ServiceLocatorInterface $serviceLocator) } // check if we have a valid console adapter - if (!$adapter instanceof AdapterInterface) { + if (! $adapter instanceof AdapterInterface) { // SM factory cannot currently return null, so we convert it to dummy object return new stdClass(); } // Optionally, change Console charset - if (!empty($config['console']) && !empty($config['console']['charset'])) { + if (! empty($config['console']) && ! empty($config['console']['charset'])) { // use the charset supplied in application config - $charset = $serviceLocator->get($config['console']['charset']); + $charset = $container->get($config['console']['charset']); $adapter->setCharset($charset); } diff --git a/src/Service/ConsoleExceptionStrategyFactory.php b/src/Service/ConsoleExceptionStrategyFactory.php new file mode 100644 index 000000000..e56ab73dc --- /dev/null +++ b/src/Service/ConsoleExceptionStrategyFactory.php @@ -0,0 +1,60 @@ +getConfig($container); + + $this->injectDisplayExceptions($strategy, $config); + $this->injectExceptionMessage($strategy, $config); + + return $strategy; + } + + /** + * Inject strategy with configured display_exceptions flag. + * + * @param ExceptionStrategy $strategy + * @param array $config + */ + private function injectDisplayExceptions(ExceptionStrategy $strategy, array $config) + { + $flag = array_key_exists('display_exceptions', $config) ? $config['display_exceptions'] : true; + $strategy->setDisplayExceptions($flag); + } + + /** + * Inject strategy with configured exception_message + * + * @param ExceptionStrategy $strategy + * @param array $config + */ + private function injectExceptionMessage(ExceptionStrategy $strategy, array $config) + { + $message = isset($config['exception_message']) ? $config['exception_message'] : ''; + $strategy->setMessage($message); + } +} diff --git a/src/Service/ConsoleRouteNotFoundStrategyFactory.php b/src/Service/ConsoleRouteNotFoundStrategyFactory.php new file mode 100644 index 000000000..43bc723e4 --- /dev/null +++ b/src/Service/ConsoleRouteNotFoundStrategyFactory.php @@ -0,0 +1,47 @@ +getConfig($container); + + $this->injectDisplayNotFoundReason($strategy, $config); + + return $strategy; + } + + /** + * Inject strategy with configured display_not_found_reason flag. + * + * @param RouteNotFoundStrategy $strategy + * @param array $config + */ + private function injectDisplayNotFoundReason(RouteNotFoundStrategy $strategy, array $config) + { + $flag = array_key_exists('display_not_found_reason', $config) ? $config['display_not_found_reason'] : true; + $strategy->setDisplayNotFoundReason($flag); + } +} diff --git a/src/Service/ConsoleRouterFactory.php b/src/Service/ConsoleRouterFactory.php new file mode 100644 index 000000000..2d75e8cc0 --- /dev/null +++ b/src/Service/ConsoleRouterFactory.php @@ -0,0 +1,38 @@ +has('config') ? $container->get('config') : []; + + // Defaults + $class = 'Zend\Mvc\Router\Console\SimpleRouteStack'; + $config = isset($config['console']['router']) ? $config['console']['router'] : []; + + return $this->createRouter($class, $config, $container); + } +} diff --git a/src/Service/ConsoleViewManagerConfigTrait.php b/src/Service/ConsoleViewManagerConfigTrait.php new file mode 100644 index 000000000..21f49dfd2 --- /dev/null +++ b/src/Service/ConsoleViewManagerConfigTrait.php @@ -0,0 +1,39 @@ +has('config') ? $container->get('config') : []; + + if (isset($config['console']['view_manager'])) { + $config = $config['console']['view_manager']; + } elseif (isset($config['view_manager'])) { + $config = $config['view_manager']; + } else { + $config = []; + } + + return (is_array($config) || $config instanceof ArrayAccess) + ? $config + : []; + } +} diff --git a/src/Service/ConsoleViewManagerFactory.php b/src/Service/ConsoleViewManagerFactory.php index e3dfc6653..79cf6f21f 100644 --- a/src/Service/ConsoleViewManagerFactory.php +++ b/src/Service/ConsoleViewManagerFactory.php @@ -9,10 +9,10 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\Console\Console; use Zend\ServiceManager\Exception\ServiceNotCreatedException; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; use Zend\Mvc\View\Console\ViewManager as ConsoleViewManager; class ConsoleViewManagerFactory implements FactoryInterface @@ -20,12 +20,14 @@ class ConsoleViewManagerFactory implements FactoryInterface /** * Create and return the view manager for the console environment * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return ConsoleViewManager */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - if (!Console::isConsole()) { + if (! Console::isConsole()) { throw new ServiceNotCreatedException( 'ConsoleViewManager requires a Console environment; console environment not detected' ); diff --git a/src/Service/ControllerLoaderFactory.php b/src/Service/ControllerLoaderFactory.php deleted file mode 100644 index cf5cda2d0..000000000 --- a/src/Service/ControllerLoaderFactory.php +++ /dev/null @@ -1,48 +0,0 @@ -setServiceLocator($serviceLocator); - $controllerLoader->addPeeringServiceManager($serviceLocator); - - $config = $serviceLocator->get('Config'); - - if (isset($config['di']) && isset($config['di']['allowed_controllers']) && $serviceLocator->has('Di')) { - $controllerLoader->addAbstractFactory($serviceLocator->get('DiStrictAbstractServiceFactory')); - } - - return $controllerLoader; - } -} diff --git a/src/Service/ControllerManagerFactory.php b/src/Service/ControllerManagerFactory.php new file mode 100644 index 000000000..69ad463ac --- /dev/null +++ b/src/Service/ControllerManagerFactory.php @@ -0,0 +1,40 @@ +get('Di'), DiAbstractServiceFactory::USE_SL_BEFORE_DI); - - if ($serviceLocator instanceof ServiceManager) { - /* @var $serviceLocator ServiceManager */ - $serviceLocator->addAbstractFactory($factory, false); - } - - return $factory; - } -} diff --git a/src/Service/DiFactory.php b/src/Service/DiFactory.php deleted file mode 100644 index 9ea5ceaba..000000000 --- a/src/Service/DiFactory.php +++ /dev/null @@ -1,44 +0,0 @@ -get('Config'); - - if (isset($config['di'])) { - $config = new Config($config['di']); - $config->configure($di); - } - - return $di; - } -} diff --git a/src/Service/DiServiceInitializerFactory.php b/src/Service/DiServiceInitializerFactory.php deleted file mode 100644 index 2a2fb1904..000000000 --- a/src/Service/DiServiceInitializerFactory.php +++ /dev/null @@ -1,28 +0,0 @@ -get('Di'), $serviceLocator); - } -} diff --git a/src/Service/DiStrictAbstractServiceFactory.php b/src/Service/DiStrictAbstractServiceFactory.php deleted file mode 100644 index fb367876e..000000000 --- a/src/Service/DiStrictAbstractServiceFactory.php +++ /dev/null @@ -1,142 +0,0 @@ -useServiceLocator = $useServiceLocator; - // since we are using this in a proxy-fashion, localize state - $this->di = $di; - $this->definitions = $this->di->definitions; - $this->instanceManager = $this->di->instanceManager; - } - - /** - * @param array $allowedServiceNames - */ - public function setAllowedServiceNames(array $allowedServiceNames) - { - $this->allowedServiceNames = array_flip(array_values($allowedServiceNames)); - } - - /** - * @return array - */ - public function getAllowedServiceNames() - { - return array_keys($this->allowedServiceNames); - } - - /** - * {@inheritDoc} - * - * Allows creation of services only when in a whitelist - */ - public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $serviceName, $requestedName) - { - if (!isset($this->allowedServiceNames[$requestedName])) { - throw new Exception\InvalidServiceNameException('Service "' . $requestedName . '" is not whitelisted'); - } - - if ($serviceLocator instanceof AbstractPluginManager) { - /* @var $serviceLocator AbstractPluginManager */ - $this->serviceLocator = $serviceLocator->getServiceLocator(); - } else { - $this->serviceLocator = $serviceLocator; - } - - return parent::get($requestedName); - } - - /** - * Overrides Zend\Di to allow the given serviceLocator's services to be reused by Di itself - * - * {@inheritDoc} - * - * @throws Exception\InvalidServiceNameException - */ - public function get($name, array $params = []) - { - if (null === $this->serviceLocator) { - throw new DomainException('No ServiceLocator defined, use `createServiceWithName` instead of `get`'); - } - - if (self::USE_SL_BEFORE_DI === $this->useServiceLocator && $this->serviceLocator->has($name)) { - return $this->serviceLocator->get($name); - } - - try { - return parent::get($name, $params); - } catch (ClassNotFoundException $e) { - if (self::USE_SL_AFTER_DI === $this->useServiceLocator && $this->serviceLocator->has($name)) { - return $this->serviceLocator->get($name); - } - - throw new Exception\ServiceNotFoundException( - sprintf('Service %s was not found in this DI instance', $name), - null, - $e - ); - } - } - - /** - * {@inheritDoc} - * - * Allows creation of services only when in a whitelist - */ - public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) - { - // won't check if the service exists, we are trusting the user's whitelist - return isset($this->allowedServiceNames[$requestedName]); - } -} diff --git a/src/Service/DiStrictAbstractServiceFactoryFactory.php b/src/Service/DiStrictAbstractServiceFactoryFactory.php deleted file mode 100644 index 54dd3335a..000000000 --- a/src/Service/DiStrictAbstractServiceFactoryFactory.php +++ /dev/null @@ -1,37 +0,0 @@ -get('Di'), - DiStrictAbstractServiceFactory::USE_SL_BEFORE_DI - ); - $config = $serviceLocator->get('Config'); - - if (isset($config['di']['allowed_controllers'])) { - $diAbstractFactory->setAllowedServiceNames($config['di']['allowed_controllers']); - } - - return $diAbstractFactory; - } -} diff --git a/src/Service/DispatchListenerFactory.php b/src/Service/DispatchListenerFactory.php new file mode 100644 index 000000000..75c375f7e --- /dev/null +++ b/src/Service/DispatchListenerFactory.php @@ -0,0 +1,30 @@ +get('ControllerManager')); + } +} diff --git a/src/Service/EventManagerFactory.php b/src/Service/EventManagerFactory.php index e23238ddb..0f4352afe 100644 --- a/src/Service/EventManagerFactory.php +++ b/src/Service/EventManagerFactory.php @@ -9,9 +9,9 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\EventManager\EventManager; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; class EventManagerFactory implements FactoryInterface { @@ -21,13 +21,15 @@ class EventManagerFactory implements FactoryInterface * Creates a new EventManager instance, seeding it with a shared instance * of SharedEventManager. * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return EventManager */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - if ($serviceLocator->has('SharedEventManager')) { - return new EventManager($serviceLocator->get('SharedEventManager')); + if ($container->has('SharedEventManager')) { + return new EventManager($container->get('SharedEventManager')); } return new EventManager(); } diff --git a/src/Service/FilterManagerFactory.php b/src/Service/FilterManagerFactory.php index d9a9e1722..b95fabd68 100644 --- a/src/Service/FilterManagerFactory.php +++ b/src/Service/FilterManagerFactory.php @@ -9,7 +9,9 @@ namespace Zend\Mvc\Service; +use Zend\Filter\FilterPluginManager; + class FilterManagerFactory extends AbstractPluginManagerFactory { - const PLUGIN_MANAGER_CLASS = 'Zend\Filter\FilterPluginManager'; + const PLUGIN_MANAGER_CLASS = FilterPluginManager::class; } diff --git a/src/Service/FormAnnotationBuilderFactory.php b/src/Service/FormAnnotationBuilderFactory.php index 873b68a39..60f33bc87 100644 --- a/src/Service/FormAnnotationBuilderFactory.php +++ b/src/Service/FormAnnotationBuilderFactory.php @@ -9,29 +9,34 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\EventManager\ListenerAggregateInterface; use Zend\Form\Annotation\AnnotationBuilder; -use Zend\ServiceManager\Exception\RuntimeException; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Exception\ServiceNotCreatedException; +use Zend\ServiceManager\Factory\FactoryInterface; class FormAnnotationBuilderFactory implements FactoryInterface { /** * Create service * - * @param ServiceLocatorInterface $serviceLocator - * @throws \Zend\ServiceManager\Exception\RuntimeException + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return mixed + * @throws ServiceNotCreatedException for invalid listener configuration. */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { //setup a form factory which can use custom form elements $annotationBuilder = new AnnotationBuilder(); - $formElementManager = $serviceLocator->get('FormElementManager'); + $eventManager = $container->build('EventManager'); + $annotationBuilder->setEventManager($ventManager); + + $formElementManager = $container->get('FormElementManager'); $formElementManager->injectFactory($annotationBuilder); - $config = $serviceLocator->get('Config'); + $config = $container->get('config'); if (isset($config['form_annotation_builder'])) { $config = $config['form_annotation_builder']; @@ -43,11 +48,11 @@ public function createService(ServiceLocatorInterface $serviceLocator) if (isset($config['listeners'])) { foreach ((array) $config['listeners'] as $listenerName) { - $listener = $serviceLocator->get($listenerName); + $listener = $container->get($listenerName); if (!($listener instanceof ListenerAggregateInterface)) { - throw new RuntimeException(sprintf('Invalid event listener (%s) provided', $listenerName)); + throw new ServiceNotCreatedException(sprintf('Invalid event listener (%s) provided', $listenerName)); } - $listener->attach($annotationBuilder->getEventManager()); + $listener->attach($eventManager); } } diff --git a/src/Service/FormElementManagerFactory.php b/src/Service/FormElementManagerFactory.php index e33dd87eb..4f5f33bc2 100644 --- a/src/Service/FormElementManagerFactory.php +++ b/src/Service/FormElementManagerFactory.php @@ -10,23 +10,8 @@ namespace Zend\Mvc\Service; use Zend\Form\FormElementManager; -use Zend\ServiceManager\ServiceLocatorInterface; class FormElementManagerFactory extends AbstractPluginManagerFactory { - const PLUGIN_MANAGER_CLASS = 'Zend\Form\FormElementManager'; - - /** - * Create and return the MVC controller plugin manager - * - * @param ServiceLocatorInterface $serviceLocator - * @return FormElementManager - */ - public function createService(ServiceLocatorInterface $serviceLocator) - { - $plugins = parent::createService($serviceLocator); - $plugins->addPeeringServiceManager($serviceLocator); - $plugins->setRetrieveFromPeeringManagerFirst(true); - return $plugins; - } + const PLUGIN_MANAGER_CLASS = FormElementManager::class; } diff --git a/src/Service/HttpDefaultRenderingStrategyFactory.php b/src/Service/HttpDefaultRenderingStrategyFactory.php new file mode 100644 index 000000000..19a7f5a6d --- /dev/null +++ b/src/Service/HttpDefaultRenderingStrategyFactory.php @@ -0,0 +1,42 @@ +get(View::class)); + $config = $this->getConfig($container); + + $this->injectLayoutTemplate($strategy, $config); + + return $strategy; + } + + private function injectLayoutTemplate(DefaultRenderingStrategy $strategy, array $config) + { + $layout = isset($config['layout']) ? $config['layout'] : 'layout/layout'; + $strategy->setLayoutTemplate($layout); + } +} diff --git a/src/Service/HttpExceptionStrategyFactory.php b/src/Service/HttpExceptionStrategyFactory.php new file mode 100644 index 000000000..51555f436 --- /dev/null +++ b/src/Service/HttpExceptionStrategyFactory.php @@ -0,0 +1,60 @@ +getConfig($container); + + $this->injectDisplayExceptions($strategy, $config); + $this->injectExceptionTemplate($strategy, $config); + + return $strategy; + } + + /** + * Inject strategy with configured display_exceptions flag. + * + * @param ExceptionStrategy $strategy + * @param array $config + */ + private function injectDisplayExceptions(ExceptionStrategy $strategy, array $config) + { + $flag = isset($config['display_exceptions']) ? $config['display_exceptions'] : false; + $strategy->setDisplayExceptions($flag); + } + + /** + * Inject strategy with configured exception_template + * + * @param ExceptionStrategy $strategy + * @param array $config + */ + private function injectExceptionTemplate(ExceptionStrategy $strategy, array $config) + { + $template = isset($config['exception_template']) ? $config['exception_template'] : 'error'; + $strategy->setExceptionTemplate($template); + } +} diff --git a/src/Service/HttpMethodListenerFactory.php b/src/Service/HttpMethodListenerFactory.php index 46ea25eeb..d4c83f3dc 100644 --- a/src/Service/HttpMethodListenerFactory.php +++ b/src/Service/HttpMethodListenerFactory.php @@ -9,9 +9,9 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\Mvc\HttpMethodListener; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; class HttpMethodListenerFactory implements FactoryInterface { @@ -19,9 +19,9 @@ class HttpMethodListenerFactory implements FactoryInterface * {@inheritdoc} * @return HttpMethodListener */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - $config = $serviceLocator->get('config'); + $config = $container->get('config'); if (! isset($config['http_methods_listener'])) { return new HttpMethodListener(); diff --git a/src/Service/HttpRouteNotFoundStrategyFactory.php b/src/Service/HttpRouteNotFoundStrategyFactory.php new file mode 100644 index 000000000..afb5b9d8a --- /dev/null +++ b/src/Service/HttpRouteNotFoundStrategyFactory.php @@ -0,0 +1,73 @@ +getConfig($container); + + $this->injectDisplayExceptions($strategy, $config); + $this->injectDisplayNotFoundReason($strategy, $config); + $this->injectNotFoundTemplate($strategy, $config); + + return $strategy; + } + + /** + * Inject strategy with configured display_exceptions flag. + * + * @param RouteNotFoundStrategy $strategy + * @param array $config + */ + private function injectDisplayExceptions(RouteNotFoundStrategy $strategy, array $config) + { + $flag = isset($config['display_exceptions']) ? $config['display_exceptions'] : false; + $strategy->setDisplayExceptions($flag); + } + + /** + * Inject strategy with configured display_not_found_reason flag. + * + * @param RouteNotFoundStrategy $strategy + * @param array $config + */ + private function injectDisplayNotFoundReason(RouteNotFoundStrategy $strategy, array $config) + { + $flag = isset($config['display_not_found_reason']) ? $config['display_not_found_reason'] : false; + $strategy->setDisplayNotFoundReason($flag); + } + + /** + * Inject strategy with configured not_found_template. + * + * @param RouteNotFoundStrategy $strategy + * @param array $config + */ + private function injectNotFoundTemplate(RouteNotFoundStrategy $strategy, array $config) + { + $template = isset($config['not_found_template']) ? $config['not_found_template'] : '404'; + $strategy->setNotFoundTemplate($template); + } +} diff --git a/src/Service/HttpRouterFactory.php b/src/Service/HttpRouterFactory.php new file mode 100644 index 000000000..c2f288794 --- /dev/null +++ b/src/Service/HttpRouterFactory.php @@ -0,0 +1,41 @@ +has('config') ? $container->get('config') : []; + + // Defaults + $class = 'Zend\Mvc\Router\Http\TreeRouteStack'; + $config = isset($config['router']) ? $config['router'] : []; + + return $this->createRouter($class, $config, $container); + } +} diff --git a/src/Service/HttpViewManagerConfigTrait.php b/src/Service/HttpViewManagerConfigTrait.php new file mode 100644 index 000000000..24239f507 --- /dev/null +++ b/src/Service/HttpViewManagerConfigTrait.php @@ -0,0 +1,37 @@ +has('config') ? $container->get('config') : []; + + if (isset($config['view_manager']) + && (is_array($config['view_manager']) + || $config['view_manager'] instanceof ArrayAccess + ) + ) { + return $config['view_manager']; + } + + return []; + } +} diff --git a/src/Service/HttpViewManagerFactory.php b/src/Service/HttpViewManagerFactory.php index 5c61bad97..8c68e726b 100644 --- a/src/Service/HttpViewManagerFactory.php +++ b/src/Service/HttpViewManagerFactory.php @@ -9,19 +9,21 @@ namespace Zend\Mvc\Service; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Interop\Container\ContainerInterface; use Zend\Mvc\View\Http\ViewManager as HttpViewManager; +use Zend\ServiceManager\Factory\FactoryInterface; class HttpViewManagerFactory implements FactoryInterface { /** * Create and return a view manager for the HTTP environment * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return HttpViewManager */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { return new HttpViewManager(); } diff --git a/src/Service/HydratorManagerFactory.php b/src/Service/HydratorManagerFactory.php index 436a01223..7d889a9e8 100644 --- a/src/Service/HydratorManagerFactory.php +++ b/src/Service/HydratorManagerFactory.php @@ -9,7 +9,9 @@ namespace Zend\Mvc\Service; +use Zend\Hydrator\HydratorPluginManager; + class HydratorManagerFactory extends AbstractPluginManagerFactory { - const PLUGIN_MANAGER_CLASS = 'Zend\Hydrator\HydratorPluginManager'; + const PLUGIN_MANAGER_CLASS = HydratorPluginManager::class; } diff --git a/src/Service/InjectTemplateListenerFactory.php b/src/Service/InjectTemplateListenerFactory.php index e0bac2e1f..ef9ab8bd0 100644 --- a/src/Service/InjectTemplateListenerFactory.php +++ b/src/Service/InjectTemplateListenerFactory.php @@ -9,9 +9,9 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\Mvc\View\Http\InjectTemplateListener; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; class InjectTemplateListenerFactory implements FactoryInterface { @@ -22,10 +22,10 @@ class InjectTemplateListenerFactory implements FactoryInterface * * @return InjectTemplateListener */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { $listener = new InjectTemplateListener(); - $config = $serviceLocator->get('Config'); + $config = $container->get('config'); if (isset($config['view_manager']['controller_map']) && (is_array($config['view_manager']['controller_map'])) diff --git a/src/Service/InputFilterManagerFactory.php b/src/Service/InputFilterManagerFactory.php index 14806f7f8..8878b78de 100644 --- a/src/Service/InputFilterManagerFactory.php +++ b/src/Service/InputFilterManagerFactory.php @@ -9,7 +9,9 @@ namespace Zend\Mvc\Service; +use Zend\InputFilter\InputFilterPluginManager; + class InputFilterManagerFactory extends AbstractPluginManagerFactory { - const PLUGIN_MANAGER_CLASS = 'Zend\InputFilter\InputFilterPluginManager'; + const PLUGIN_MANAGER_CLASS = InputFilterPluginManager::class; } diff --git a/src/Service/LogProcessorManagerFactory.php b/src/Service/LogProcessorManagerFactory.php index fa3f884e8..cab6e2ea6 100644 --- a/src/Service/LogProcessorManagerFactory.php +++ b/src/Service/LogProcessorManagerFactory.php @@ -9,7 +9,9 @@ namespace Zend\Mvc\Service; +use Zend\Log\ProcessorPluginManager as LogProcessorPluginManager; + class LogProcessorManagerFactory extends AbstractPluginManagerFactory { - const PLUGIN_MANAGER_CLASS = 'Zend\Log\ProcessorPluginManager'; + const PLUGIN_MANAGER_CLASS = LogProcessorPluginManager::class; } diff --git a/src/Service/LogWriterManagerFactory.php b/src/Service/LogWriterManagerFactory.php index b858dbe3c..6a984c0ab 100644 --- a/src/Service/LogWriterManagerFactory.php +++ b/src/Service/LogWriterManagerFactory.php @@ -9,7 +9,9 @@ namespace Zend\Mvc\Service; +use Zend\Log\WriterPluginManager as LogWriterPluginManager; + class LogWriterManagerFactory extends AbstractPluginManagerFactory { - const PLUGIN_MANAGER_CLASS = 'Zend\Log\WriterPluginManager'; + const PLUGIN_MANAGER_CLASS = LogWriterPluginManager::class; } diff --git a/src/Service/ModuleManagerFactory.php b/src/Service/ModuleManagerFactory.php index 82a3b6f3e..a295bdd88 100644 --- a/src/Service/ModuleManagerFactory.php +++ b/src/Service/ModuleManagerFactory.php @@ -9,12 +9,12 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\ModuleManager\Listener\DefaultListenerAggregate; use Zend\ModuleManager\Listener\ListenerOptions; use Zend\ModuleManager\ModuleEvent; use Zend\ModuleManager\ModuleManager; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; class ModuleManagerFactory implements FactoryInterface { @@ -29,28 +29,26 @@ class ModuleManagerFactory implements FactoryInterface * the default listener aggregate is attached. The ModuleEvent is also created * and attached to the module manager. * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return ModuleManager */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - if (!$serviceLocator->has('ServiceListener')) { - $serviceLocator->setFactory('ServiceListener', 'Zend\Mvc\Service\ServiceListenerFactory'); - } - - $configuration = $serviceLocator->get('ApplicationConfig'); + $configuration = $container->get('ApplicationConfig'); $listenerOptions = new ListenerOptions($configuration['module_listener_options']); $defaultListeners = new DefaultListenerAggregate($listenerOptions); - $serviceListener = $serviceLocator->get('ServiceListener'); + $serviceListener = $container->get('ServiceListener'); - $serviceListener->addServiceManager( - $serviceLocator, + $serviceListener->setApplicationServiceManager( 'service_manager', 'Zend\ModuleManager\Feature\ServiceProviderInterface', 'getServiceConfig' ); + $serviceListener->addServiceManager( - 'ControllerLoader', + 'ControllerManager', 'controllers', 'Zend\ModuleManager\Feature\ControllerProviderInterface', 'getControllerConfig' @@ -128,12 +126,12 @@ public function createService(ServiceLocatorInterface $serviceLocator) 'getTranslatorPluginConfig' ); - $events = $serviceLocator->get('EventManager'); + $events = $container->get('EventManager'); $defaultListeners->attach($events); $serviceListener->attach($events); $moduleEvent = new ModuleEvent; - $moduleEvent->setParam('ServiceManager', $serviceLocator); + $moduleEvent->setParam('ServiceManager', $container); $moduleManager = new ModuleManager($configuration['modules'], $events); $moduleManager->setEvent($moduleEvent); diff --git a/src/Service/PaginatorPluginManagerFactory.php b/src/Service/PaginatorPluginManagerFactory.php index 182a53a40..547db292d 100644 --- a/src/Service/PaginatorPluginManagerFactory.php +++ b/src/Service/PaginatorPluginManagerFactory.php @@ -9,7 +9,9 @@ namespace Zend\Mvc\Service; +use Zend\Paginator\AdapterPluginManager as PaginatorPluginManager; + class PaginatorPluginManagerFactory extends AbstractPluginManagerFactory { - const PLUGIN_MANAGER_CLASS = 'Zend\Paginator\AdapterPluginManager'; + const PLUGIN_MANAGER_CLASS = PaginatorPluginManager::class; } diff --git a/src/Service/RequestFactory.php b/src/Service/RequestFactory.php index 3c5d4a5c1..88a0a5a4c 100644 --- a/src/Service/RequestFactory.php +++ b/src/Service/RequestFactory.php @@ -9,21 +9,23 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\Console\Console; use Zend\Console\Request as ConsoleRequest; use Zend\Http\PhpEnvironment\Request as HttpRequest; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; class RequestFactory implements FactoryInterface { /** * Create and return a request instance, according to current environment. * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return ConsoleRequest|HttpRequest */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { if (Console::isConsole()) { return new ConsoleRequest(); diff --git a/src/Service/ResponseFactory.php b/src/Service/ResponseFactory.php index 707e6c9dd..9b0b24bad 100644 --- a/src/Service/ResponseFactory.php +++ b/src/Service/ResponseFactory.php @@ -9,21 +9,23 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\Console\Console; use Zend\Console\Response as ConsoleResponse; use Zend\Http\PhpEnvironment\Response as HttpResponse; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; class ResponseFactory implements FactoryInterface { /** * Create and return a response instance, according to current environment. * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return \Zend\Stdlib\Message */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { if (Console::isConsole()) { return new ConsoleResponse(); diff --git a/src/Service/RoutePluginManagerFactory.php b/src/Service/RoutePluginManagerFactory.php index 2f24b8581..1752f6150 100644 --- a/src/Service/RoutePluginManagerFactory.php +++ b/src/Service/RoutePluginManagerFactory.php @@ -9,7 +9,9 @@ namespace Zend\Mvc\Service; +use Zend\Mvc\Router\RoutePluginManager; + class RoutePluginManagerFactory extends AbstractPluginManagerFactory { - const PLUGIN_MANAGER_CLASS = 'Zend\Mvc\Router\RoutePluginManager'; + const PLUGIN_MANAGER_CLASS = RoutePluginManager::class; } diff --git a/src/Service/RouterConfigTrait.php b/src/Service/RouterConfigTrait.php new file mode 100644 index 000000000..fb7b08bdf --- /dev/null +++ b/src/Service/RouterConfigTrait.php @@ -0,0 +1,40 @@ +get('RoutePluginManager'); + $config['route_plugins'] = $routePluginManager; + } + + // Obtain an instance + $factory = sprintf('%s::factory', $class); + return call_user_func($factory, $config); + } +} diff --git a/src/Service/RouterFactory.php b/src/Service/RouterFactory.php index be58c8f7e..100df18de 100644 --- a/src/Service/RouterFactory.php +++ b/src/Service/RouterFactory.php @@ -9,54 +9,32 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\Console\Console; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; class RouterFactory implements FactoryInterface { /** * Create and return the router * - * Retrieves the "router" key of the Config service, and uses it - * to instantiate the router. Uses the TreeRouteStack implementation by - * default. + * Delegates to either the ConsoleRouter or HttpRouter service based + * on the environment type. * - * @param ServiceLocatorInterface $serviceLocator - * @param string|null $cName - * @param string|null $rName + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return \Zend\Mvc\Router\RouteStackInterface */ - public function createService(ServiceLocatorInterface $serviceLocator, $cName = null, $rName = null) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - $config = $serviceLocator->has('Config') ? $serviceLocator->get('Config') : []; - - // Defaults - $routerClass = 'Zend\Mvc\Router\Http\TreeRouteStack'; - $routerConfig = isset($config['router']) ? $config['router'] : []; - // Console environment? - if ($rName === 'ConsoleRouter' // force console router - || ($cName === 'router' && Console::isConsole()) // auto detect console + if ($name === 'ConsoleRouter' // force console router + || (strtolower($name) === 'router' && Console::isConsole()) // auto detect console ) { - // We are in a console, use console router defaults. - $routerClass = 'Zend\Mvc\Router\Console\SimpleRouteStack'; - $routerConfig = isset($config['console']['router']) ? $config['console']['router'] : []; - } - - // Obtain the configured router class, if any - if (isset($routerConfig['router_class']) && class_exists($routerConfig['router_class'])) { - $routerClass = $routerConfig['router_class']; - } - - // Inject the route plugins - if (!isset($routerConfig['route_plugins'])) { - $routePluginManager = $serviceLocator->get('RoutePluginManager'); - $routerConfig['route_plugins'] = $routePluginManager; + return $container->get('ConsoleRouter'); } - // Obtain an instance - $factory = sprintf('%s::factory', $routerClass); - return call_user_func($factory, $routerConfig); + return $container->get('HttpRouter'); } } diff --git a/src/Service/SerializerAdapterPluginManagerFactory.php b/src/Service/SerializerAdapterPluginManagerFactory.php index 11d1653ca..005001d4d 100644 --- a/src/Service/SerializerAdapterPluginManagerFactory.php +++ b/src/Service/SerializerAdapterPluginManagerFactory.php @@ -9,7 +9,9 @@ namespace Zend\Mvc\Service; +use Zend\Serializer\AdapterPluginManager as SerializerAdapterPluginManager; + class SerializerAdapterPluginManagerFactory extends AbstractPluginManagerFactory { - const PLUGIN_MANAGER_CLASS = 'Zend\Serializer\AdapterPluginManager'; + const PLUGIN_MANAGER_CLASS = SerializerAdapterPluginManager::class; } diff --git a/src/Service/ServiceListenerFactory.php b/src/Service/ServiceListenerFactory.php index 299c2b3f0..a5005fea0 100644 --- a/src/Service/ServiceListenerFactory.php +++ b/src/Service/ServiceListenerFactory.php @@ -9,12 +9,13 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\ModuleManager\Listener\ServiceListener; use Zend\ModuleManager\Listener\ServiceListenerInterface; -use Zend\Mvc\Exception\InvalidArgumentException; -use Zend\Mvc\Exception\RuntimeException; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\Mvc\View; +use Zend\ServiceManager\Exception\ServiceNotCreatedException; +use Zend\ServiceManager\Factory\FactoryInterface; +use Zend\ServiceManager\Factory\InvokableFactory; class ServiceListenerFactory implements FactoryInterface { @@ -31,11 +32,11 @@ class ServiceListenerFactory implements FactoryInterface /** * Default mvc-related service configuration -- can be overridden by modules. * + * @todo Re-enable form abstract service factory after zend-form updated to servicemanager v3. * @var array */ protected $defaultServiceConfig = [ 'invokables' => [ - 'DispatchListener' => 'Zend\Mvc\DispatchListener', 'RouteListener' => 'Zend\Mvc\RouteListener', 'SendResponseListener' => 'Zend\Mvc\SendResponseListener', 'ViewJsonRenderer' => 'Zend\View\Renderer\JsonRenderer', @@ -43,21 +44,22 @@ class ServiceListenerFactory implements FactoryInterface ], 'factories' => [ 'Application' => 'Zend\Mvc\Service\ApplicationFactory', - 'Config' => 'Zend\Mvc\Service\ConfigFactory', - 'ControllerLoader' => 'Zend\Mvc\Service\ControllerLoaderFactory', + 'config' => 'Zend\Mvc\Service\ConfigFactory', + 'ControllerManager' => 'Zend\Mvc\Service\ControllerManagerFactory', 'ControllerPluginManager' => 'Zend\Mvc\Service\ControllerPluginManagerFactory', 'ConsoleAdapter' => 'Zend\Mvc\Service\ConsoleAdapterFactory', - 'ConsoleRouter' => 'Zend\Mvc\Service\RouterFactory', + 'ConsoleExceptionStrategy' => ConsoleExceptionStrategyFactory::class, + 'ConsoleRouter' => ConsoleRouterFactory::class, + 'ConsoleRouteNotFoundStrategy' => ConsoleRouteNotFoundStrategyFactory::class, 'ConsoleViewManager' => 'Zend\Mvc\Service\ConsoleViewManagerFactory', - 'DependencyInjector' => 'Zend\Mvc\Service\DiFactory', - 'DiAbstractServiceFactory' => 'Zend\Mvc\Service\DiAbstractServiceFactoryFactory', - 'DiServiceInitializer' => 'Zend\Mvc\Service\DiServiceInitializerFactory', - 'DiStrictAbstractServiceFactory' => 'Zend\Mvc\Service\DiStrictAbstractServiceFactoryFactory', + 'DispatchListener' => 'Zend\Mvc\Service\DispatchListenerFactory', 'FilterManager' => 'Zend\Mvc\Service\FilterManagerFactory', 'FormAnnotationBuilder' => 'Zend\Mvc\Service\FormAnnotationBuilderFactory', 'FormElementManager' => 'Zend\Mvc\Service\FormElementManagerFactory', - 'HttpRouter' => 'Zend\Mvc\Service\RouterFactory', + 'HttpExceptionStrategy' => HttpExceptionStrategyFactory::class, 'HttpMethodListener' => 'Zend\Mvc\Service\HttpMethodListenerFactory', + 'HttpRouteNotFoundStrategy' => HttpRouteNotFoundStrategyFactory::class, + 'HttpRouter' => HttpRouterFactory::class, 'HttpViewManager' => 'Zend\Mvc\Service\HttpViewManagerFactory', 'HydratorManager' => 'Zend\Mvc\Service\HydratorManagerFactory', 'InjectTemplateListener' => 'Zend\Mvc\Service\InjectTemplateListenerFactory', @@ -73,7 +75,9 @@ class ServiceListenerFactory implements FactoryInterface 'SerializerAdapterManager' => 'Zend\Mvc\Service\SerializerAdapterPluginManagerFactory', 'TranslatorPluginManager' => 'Zend\Mvc\Service\TranslatorPluginManagerFactory', 'ValidatorManager' => 'Zend\Mvc\Service\ValidatorManagerFactory', + View\Console\DefaultRenderingStrategy::class => InvokableFactory::class, 'ViewHelperManager' => 'Zend\Mvc\Service\ViewHelperManagerFactory', + View\Http\DefaultRenderingStrategy::class => HttpDefaultRenderingStrategyFactory::class, 'ViewFeedStrategy' => 'Zend\Mvc\Service\ViewFeedStrategyFactory', 'ViewJsonStrategy' => 'Zend\Mvc\Service\ViewJsonStrategyFactory', 'ViewManager' => 'Zend\Mvc\Service\ViewManagerFactory', @@ -81,24 +85,35 @@ class ServiceListenerFactory implements FactoryInterface 'ViewTemplateMapResolver' => 'Zend\Mvc\Service\ViewTemplateMapResolverFactory', 'ViewTemplatePathStack' => 'Zend\Mvc\Service\ViewTemplatePathStackFactory', 'ViewPrefixPathStackResolver' => 'Zend\Mvc\Service\ViewPrefixPathStackResolverFactory', + 'Zend\View\Renderer\PhpRenderer' => ViewPhpRendererFactory::class, + 'Zend\View\Strategy\PhpRendererStrategy' => ViewPhpRendererStrategyFactory::class, + 'Zend\View\View' => ViewFactory::class, ], 'aliases' => [ - 'Configuration' => 'Config', + 'Config' => 'config', + 'Configuration' => 'config', + 'configuration' => 'config', 'Console' => 'ConsoleAdapter', - 'Di' => 'DependencyInjector', - 'Zend\Di\LocatorInterface' => 'DependencyInjector', + 'ConsoleDefaultRenderingStrategy' => View\Console\DefaultRenderingStrategy::class, + 'HttpDefaultRenderingStrategy' => View\Http\DefaultRenderingStrategy::class, + 'View' => 'Zend\View\View', + 'ViewPhpRendererStrategy' => 'Zend\View\Strategy\PhpRendererStrategy', + 'ViewPhpRenderer' => 'Zend\View\Renderer\PhpRenderer', + 'ViewRenderer' => 'Zend\View\Renderer\PhpRenderer', 'Zend\Form\Annotation\FormAnnotationBuilder' => 'FormAnnotationBuilder', 'Zend\Mvc\Controller\PluginManager' => 'ControllerPluginManager', 'Zend\Mvc\View\Http\InjectTemplateListener' => 'InjectTemplateListener', + 'Zend\View\Renderer\RendererInterface' => 'Zend\View\Renderer\PhpRenderer', 'Zend\View\Resolver\TemplateMapResolver' => 'ViewTemplateMapResolver', 'Zend\View\Resolver\TemplatePathStack' => 'ViewTemplatePathStack', 'Zend\View\Resolver\AggregateResolver' => 'ViewResolver', 'Zend\View\Resolver\ResolverInterface' => 'ViewResolver', - 'ControllerManager' => 'ControllerLoader', ], + /* 'abstract_factories' => [ 'Zend\Form\FormAbstractServiceFactory', ], + */ ]; /** @@ -120,83 +135,125 @@ class ServiceListenerFactory implements FactoryInterface * * @param ServiceLocatorInterface $serviceLocator * @return ServiceListener - * @throws InvalidArgumentException For invalid configurations. - * @throws RuntimeException + * @throws ServiceNotCreatedException for invalid ServiceListener service + * @throws ServiceNotCreatedException For invalid configurations. */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $requestedName, array $options = null) { - $configuration = $serviceLocator->get('ApplicationConfig'); + $configuration = $container->get('ApplicationConfig'); - if ($serviceLocator->has('ServiceListenerInterface')) { - $serviceListener = $serviceLocator->get('ServiceListenerInterface'); + $serviceListener = $container->has('ServiceListenerInterface') + ? $container->get('ServiceListenerInterface') + : new ServiceListener($container, $this->defaultServiceConfig); - if (!$serviceListener instanceof ServiceListenerInterface) { - throw new RuntimeException( - 'The service named ServiceListenerInterface must implement ' . - 'Zend\ModuleManager\Listener\ServiceListenerInterface' - ); - } - - $serviceListener->setDefaultServiceConfig($this->defaultServiceConfig); - } else { - $serviceListener = new ServiceListener($serviceLocator, $this->defaultServiceConfig); + if (! $serviceListener instanceof ServiceListenerInterface) { + throw new ServiceNotCreatedException( + 'The service named ServiceListenerInterface must implement ' . + 'Zend\ModuleManager\Listener\ServiceListenerInterface' + ); } if (isset($configuration['service_listener_options'])) { - if (!is_array($configuration['service_listener_options'])) { - throw new InvalidArgumentException(sprintf( - 'The value of service_listener_options must be an array, %s given.', - gettype($configuration['service_listener_options']) - )); - } - - foreach ($configuration['service_listener_options'] as $key => $newServiceManager) { - if (!isset($newServiceManager['service_manager'])) { - throw new InvalidArgumentException(sprintf(self::MISSING_KEY_ERROR, $key, 'service_manager')); - } elseif (!is_string($newServiceManager['service_manager'])) { - throw new InvalidArgumentException(sprintf( - self::VALUE_TYPE_ERROR, - 'service_manager', - gettype($newServiceManager['service_manager']) - )); - } - if (!isset($newServiceManager['config_key'])) { - throw new InvalidArgumentException(sprintf(self::MISSING_KEY_ERROR, $key, 'config_key')); - } elseif (!is_string($newServiceManager['config_key'])) { - throw new InvalidArgumentException(sprintf( - self::VALUE_TYPE_ERROR, - 'config_key', - gettype($newServiceManager['config_key']) - )); - } - if (!isset($newServiceManager['interface'])) { - throw new InvalidArgumentException(sprintf(self::MISSING_KEY_ERROR, $key, 'interface')); - } elseif (!is_string($newServiceManager['interface'])) { - throw new InvalidArgumentException(sprintf( - self::VALUE_TYPE_ERROR, - 'interface', - gettype($newServiceManager['interface']) - )); - } - if (!isset($newServiceManager['method'])) { - throw new InvalidArgumentException(sprintf(self::MISSING_KEY_ERROR, $key, 'method')); - } elseif (!is_string($newServiceManager['method'])) { - throw new InvalidArgumentException(sprintf( - self::VALUE_TYPE_ERROR, - 'method', - gettype($newServiceManager['method']) - )); - } - - $serviceListener->addServiceManager( - $newServiceManager['service_manager'], - $newServiceManager['config_key'], - $newServiceManager['interface'], - $newServiceManager['method'] - ); - } + $this->injectServiceListenerOptions($configuration['service_listener_options'], $serviceListener); } return $serviceListener; } + + /** + * Validate and inject plugin manager options into the service listener. + * + * @param array $options + * @param ServiceListenerInterface $serviceListener + * @throws ServiceListenerInterface for invalid $options types + */ + private function injectServiceListenerOptions($options, ServiceListenerInterface $serviceListener) + { + if (! is_array($options)) { + throw new ServiceNotCreatedException(sprintf( + 'The value of service_listener_options must be an array, %s given.', + (is_object($options) ? get_class($options) : gettype($options)) + )); + } + + foreach ($options as $key => $newServiceManager) { + $this->validatePluginManagerOptions($newServiceManager, $key); + + $serviceListener->addServiceManager( + $newServiceManager['service_manager'], + $newServiceManager['config_key'], + $newServiceManager['interface'], + $newServiceManager['method'] + ); + } + } + + /** + * Validate the structure and types for plugin manager configuration options. + * + * Ensures all required keys are present in the expected types. + * + * @param array $options + * @param string $name Plugin manager service name; used for exception messages + * @throws ServiceNotCreatedException for any missing configuration options. + * @throws ServiceNotCreatedException for configuration options of invalid types. + */ + private function validatePluginManagerOptions($options, $name) + { + if (! is_array($options)) { + throw new ServiceNotCreatedException(sprintf( + 'Plugin manager configuration for "%s" is invalid; must be an array, received "%s"', + $name, + (is_object($options) ? get_class($options) : gettype($options)) + )); + } + + if (! isset($options['service_manager'])) { + throw new ServiceNotCreatedException(sprintf(self::MISSING_KEY_ERROR, $name, 'service_manager')); + } + + if (! is_string($options['service_manager'])) { + throw new ServiceNotCreatedException(sprintf( + self::VALUE_TYPE_ERROR, + 'service_manager', + gettype($options['service_manager']) + )); + } + + if (! isset($options['config_key'])) { + throw new ServiceNotCreatedException(sprintf(self::MISSING_KEY_ERROR, $name, 'config_key')); + } + + if (! is_string($options['config_key'])) { + throw new ServiceNotCreatedException(sprintf( + self::VALUE_TYPE_ERROR, + 'config_key', + gettype($options['config_key']) + )); + } + + if (! isset($options['interface'])) { + throw new ServiceNotCreatedException(sprintf(self::MISSING_KEY_ERROR, $name, 'interface')); + } + + if (! is_string($options['interface'])) { + throw new ServiceNotCreatedException(sprintf( + self::VALUE_TYPE_ERROR, + 'interface', + gettype($options['interface']) + )); + } + + if (! isset($options['method'])) { + throw new ServiceNotCreatedException(sprintf(self::MISSING_KEY_ERROR, $name, 'method')); + } + + if (! is_string($options['method'])) { + throw new ServiceNotCreatedException(sprintf( + self::VALUE_TYPE_ERROR, + 'method', + gettype($options['method']) + )); + } + } } diff --git a/src/Service/ServiceManagerConfig.php b/src/Service/ServiceManagerConfig.php index 304c3b81b..f1c363b80 100644 --- a/src/Service/ServiceManagerConfig.php +++ b/src/Service/ServiceManagerConfig.php @@ -9,81 +9,38 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\EventManager\EventManagerAwareInterface; use Zend\EventManager\EventManagerInterface; use Zend\EventManager\SharedEventManagerInterface; use Zend\ServiceManager\Config; -use Zend\ServiceManager\ServiceLocatorAwareInterface; -use Zend\ServiceManager\ServiceLocatorInterface; use Zend\ServiceManager\ServiceManager; -use Zend\ServiceManager\ServiceManagerAwareInterface; -use Zend\Stdlib\ArrayUtils; class ServiceManagerConfig extends Config { - /** - * Services that can be instantiated without factories - * - * @var array - */ - protected $invokables = [ - 'SharedEventManager' => 'Zend\EventManager\SharedEventManager', - ]; - - /** - * Service factories - * - * @var array - */ - protected $factories = [ - 'EventManager' => 'Zend\Mvc\Service\EventManagerFactory', - 'ModuleManager' => 'Zend\Mvc\Service\ModuleManagerFactory', - ]; - - /** - * Abstract factories - * - * @var array - */ - protected $abstractFactories = []; - - /** - * Aliases - * - * @var array - */ - protected $aliases = [ - 'Zend\EventManager\EventManagerInterface' => 'EventManager', - 'Zend\ServiceManager\ServiceLocatorInterface' => 'ServiceManager', - 'Zend\ServiceManager\ServiceManager' => 'ServiceManager', + protected $config = [ + 'abstract_factories' => [], + 'aliases' => [ + 'Zend\EventManager\EventManagerInterface' => 'EventManager', + 'Zend\ServiceManager\ServiceManager' => 'ServiceManager', + ], + 'delegators' => [], + 'factories' => [ + 'EventManager' => EventManagerFactory::class, + 'ModuleManager' => ModuleManagerFactory::class, + 'ServiceListener' => ServiceListenerFactory::class, + ], + 'lazy_services' => [], + 'initializers' => [], + 'invokables' => [ + 'SharedEventManager' => 'Zend\EventManager\SharedEventManager', + ], + 'services' => [], + 'shared' => [ + 'EventManager' => false, + ], ]; - /** - * Shared services - * - * Services are shared by default; this is primarily to indicate services - * that should NOT be shared - * - * @var array - */ - protected $shared = [ - 'EventManager' => false, - ]; - - /** - * Delegators - * - * @var array - */ - protected $delegators = []; - - /** - * Initializers - * - * @var array - */ - protected $initializers = []; - /** * Constructor * @@ -93,8 +50,8 @@ class ServiceManagerConfig extends Config */ public function __construct(array $configuration = []) { - $this->initializers = [ - 'EventManagerAwareInitializer' => function ($instance, ServiceLocatorInterface $serviceLocator) { + $this->config['initializers'] = array_merge($this->config['initializers'], [ + 'EventManagerAwareInitializer' => function (ContainerInterface $container, $instance) { if (! $instance instanceof EventManagerAwareInterface) { return; } @@ -108,35 +65,11 @@ public function __construct(array $configuration = []) return; } - $instance->setEventManager($serviceLocator->get('EventManager')); - }, - 'ServiceManagerAwareInitializer' => function ($instance, ServiceLocatorInterface $serviceLocator) { - if ($serviceLocator instanceof ServiceManager && $instance instanceof ServiceManagerAwareInterface) { - $instance->setServiceManager($serviceLocator); - } - }, - 'ServiceLocatorAwareInitializer' => function ($instance, ServiceLocatorInterface $serviceLocator) { - if ($instance instanceof ServiceLocatorAwareInterface) { - $instance->setServiceLocator($serviceLocator); - } + $instance->setEventManager($container->get('EventManager')); }, - ]; + ]); - $this->factories['ServiceManager'] = function (ServiceLocatorInterface $serviceLocator) { - return $serviceLocator; - }; - parent::__construct(ArrayUtils::merge( - [ - 'invokables' => $this->invokables, - 'factories' => $this->factories, - 'abstract_factories' => $this->abstractFactories, - 'aliases' => $this->aliases, - 'shared' => $this->shared, - 'delegators' => $this->delegators, - 'initializers' => $this->initializers, - ], - $configuration - )); + parent::__construct($configuration); } } diff --git a/src/Service/TranslatorPluginManagerFactory.php b/src/Service/TranslatorPluginManagerFactory.php index 2dee23cb1..5a88a25b4 100644 --- a/src/Service/TranslatorPluginManagerFactory.php +++ b/src/Service/TranslatorPluginManagerFactory.php @@ -9,7 +9,9 @@ namespace Zend\Mvc\Service; +use Zend\I18n\Translator\LoaderPluginManager as TranslatorLoaderPluginManager; + class TranslatorPluginManagerFactory extends AbstractPluginManagerFactory { - const PLUGIN_MANAGER_CLASS = 'Zend\I18n\Translator\LoaderPluginManager'; + const PLUGIN_MANAGER_CLASS = TranslatorLoaderPluginManager::class; } diff --git a/src/Service/TranslatorServiceFactory.php b/src/Service/TranslatorServiceFactory.php index b48981eb9..f2b444c22 100644 --- a/src/Service/TranslatorServiceFactory.php +++ b/src/Service/TranslatorServiceFactory.php @@ -9,12 +9,12 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Traversable; use Zend\I18n\Translator\Translator; use Zend\Mvc\I18n\DummyTranslator; use Zend\Mvc\I18n\Translator as MvcTranslator; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\FactoryInterface; /** * Overrides the translator factory from the i18n component in order to @@ -23,20 +23,22 @@ class TranslatorServiceFactory implements FactoryInterface { /** - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return MvcTranslator */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { // Assume that if a user has registered a service for the // TranslatorInterface, it must be valid - if ($serviceLocator->has('Zend\I18n\Translator\TranslatorInterface')) { - return new MvcTranslator($serviceLocator->get('Zend\I18n\Translator\TranslatorInterface')); + if ($container->has('Zend\I18n\Translator\TranslatorInterface')) { + return new MvcTranslator($container->get('Zend\I18n\Translator\TranslatorInterface')); } // Load a translator from configuration, if possible - if ($serviceLocator->has('Config')) { - $config = $serviceLocator->get('Config'); + if ($container->has('config')) { + $config = $container->get('config'); // 'translator' => false if (array_key_exists('translator', $config) && $config['translator'] === false) { @@ -49,8 +51,8 @@ public function createService(ServiceLocatorInterface $serviceLocator) || $config['translator'] instanceof Traversable) ) { $i18nTranslator = Translator::factory($config['translator']); - $i18nTranslator->setPluginManager($serviceLocator->get('TranslatorPluginManager')); - $serviceLocator->setService('Zend\I18n\Translator\TranslatorInterface', $i18nTranslator); + $i18nTranslator->setPluginManager($container->get('TranslatorPluginManager')); + // $container->setService('Zend\I18n\Translator\TranslatorInterface', $i18nTranslator); return new MvcTranslator($i18nTranslator); } } diff --git a/src/Service/ValidatorManagerFactory.php b/src/Service/ValidatorManagerFactory.php index a270f8fc3..24691e487 100644 --- a/src/Service/ValidatorManagerFactory.php +++ b/src/Service/ValidatorManagerFactory.php @@ -9,7 +9,9 @@ namespace Zend\Mvc\Service; +use Zend\Validator\ValidatorPluginManager; + class ValidatorManagerFactory extends AbstractPluginManagerFactory { - const PLUGIN_MANAGER_CLASS = 'Zend\Validator\ValidatorPluginManager'; + const PLUGIN_MANAGER_CLASS = ValidatorPluginManager::class; } diff --git a/src/Service/ViewFactory.php b/src/Service/ViewFactory.php new file mode 100644 index 000000000..dd9ce58e6 --- /dev/null +++ b/src/Service/ViewFactory.php @@ -0,0 +1,35 @@ +get('EventManager'); + + $view->setEventManager($events); + $container->get(PhpRendererStrategy::class)->attach($events); + + return $view; + } +} diff --git a/src/Service/ViewFeedStrategyFactory.php b/src/Service/ViewFeedStrategyFactory.php index 2e7c8d20b..b5fc41885 100644 --- a/src/Service/ViewFeedStrategyFactory.php +++ b/src/Service/ViewFeedStrategyFactory.php @@ -9,8 +9,8 @@ namespace Zend\Mvc\Service; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; use Zend\View\Strategy\FeedStrategy; class ViewFeedStrategyFactory implements FactoryInterface @@ -23,13 +23,13 @@ class ViewFeedStrategyFactory implements FactoryInterface * * It then attaches the strategy to the View service, at a priority of 100. * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return FeedStrategy */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - $feedRenderer = $serviceLocator->get('ViewFeedRenderer'); - $feedStrategy = new FeedStrategy($feedRenderer); - return $feedStrategy; + return new FeedStrategy($container->get('ViewFeedRenderer')); } } diff --git a/src/Service/ViewHelperManagerFactory.php b/src/Service/ViewHelperManagerFactory.php index 6f9d3fe0f..3e974eeda 100644 --- a/src/Service/ViewHelperManagerFactory.php +++ b/src/Service/ViewHelperManagerFactory.php @@ -9,63 +9,92 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\Console\Console; -use Zend\Mvc\Exception; use Zend\Mvc\Router\RouteMatch; -use Zend\ServiceManager\ConfigInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Exception\ServiceNotCreatedException; +use Zend\Stdlib\ArrayUtils; use Zend\View\Helper as ViewHelper; -use Zend\View\Helper\HelperInterface as ViewHelperInterface; +use Zend\View\HelperPluginManager; class ViewHelperManagerFactory extends AbstractPluginManagerFactory { - const PLUGIN_MANAGER_CLASS = 'Zend\View\HelperPluginManager'; + const PLUGIN_MANAGER_CLASS = HelperPluginManager::class; /** * An array of helper configuration classes to ensure are on the helper_map stack. * + * These are *not* imported; that way they can be optional dependencies. + * + * @todo Re-enable these once their components have been updated to zend-servicemanager v3 * @var array */ protected $defaultHelperMapClasses = [ + /* 'Zend\Form\View\HelperConfig', 'Zend\I18n\View\HelperConfig', - 'Zend\Navigation\View\HelperConfig' + 'Zend\Navigation\View\HelperConfig', + */ ]; /** * Create and return the view helper manager * - * @param ServiceLocatorInterface $serviceLocator - * @return ViewHelperInterface - * @throws Exception\RuntimeException + * @param ContainerInterface $container + * @return HelperPluginManager + * @throws ServiceNotCreatedException */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $requestedName, array $options = null) { - $plugins = parent::createService($serviceLocator); + $options = $options ?: []; foreach ($this->defaultHelperMapClasses as $configClass) { - if (is_string($configClass) && class_exists($configClass)) { - $config = new $configClass; - - if (!$config instanceof ConfigInterface) { - throw new Exception\RuntimeException(sprintf( - 'Invalid service manager configuration class provided; received "%s", expected class implementing %s', - $configClass, - 'Zend\ServiceManager\ConfigInterface' - )); - } - - $config->configureServiceManager($plugins); + if (! is_string($configClass) || ! class_exists($configClass)) { + continue; + } + + $config = new $configClass(); + + if (! $config instanceof ConfigInterface) { + throw new ServiceNotCreatedException(sprintf( + 'Invalid service manager configuration class provided; received "%s", expected class implementing %s', + $configClass, + ConfigInterface::class + )); } + + $options = ArrayUtils::merge($options, $config->toArray()); } - // Configure URL view helper with router - $plugins->setFactory('url', function () use ($serviceLocator) { + $config = $container->has('config') ? $container->get('config') : []; + + $options['factories'] = isset($options['factories']) ? $options['factories'] : []; + + // Configure URL view helper factory + $options['factories'][ViewHelper\Url::class] = $this->createUrlHelperFactory(); + + // Configure basepath view helper factory + $options['factories'][ViewHelper\BasePath::class] = $this->createBasePathHelperFactory($config); + + // Configure doctype view helper factory + $options['factories'][ViewHelper\Doctype::class] = $this->createDoctypeHelperFactory(); + + return parent::__invoke($container, $requestedName, $options); + } + + /** + * Create a factory for the "url" view helper + * + * @return callable + */ + private function createUrlHelperFactory() + { + return function ($container, $name, array $options = null) { $helper = new ViewHelper\Url; $router = Console::isConsole() ? 'HttpRouter' : 'Router'; - $helper->setRouter($serviceLocator->get($router)); + $helper->setRouter($container->get($router)); - $match = $serviceLocator->get('application') + $match = $container->get('application') ->getMvcEvent() ->getRouteMatch() ; @@ -75,52 +104,62 @@ public function createService(ServiceLocatorInterface $serviceLocator) } return $helper; - }); + }; + } - $plugins->setFactory('basepath', function () use ($serviceLocator) { - $config = $serviceLocator->has('Config') ? $serviceLocator->get('Config') : []; - $basePathHelper = new ViewHelper\BasePath; + /** + * Create a factory for the "basepath" view helper + * + * @param array $config + * @return callable + */ + private function createBasePathHelperFactory($config) + { + return function ($container, $name, array $options = null) { + $config = $container->has('config') ? $container->get('config') : []; + $helper = new ViewHelper\BasePath; if (Console::isConsole() - && isset($config['view_manager']) && isset($config['view_manager']['base_path_console']) ) { - $basePathHelper->setBasePath($config['view_manager']['base_path_console']); - - return $basePathHelper; + $helper->setBasePath($config['view_manager']['base_path_console']); + return $helper; } if (isset($config['view_manager']) && isset($config['view_manager']['base_path'])) { - $basePathHelper->setBasePath($config['view_manager']['base_path']); - - return $basePathHelper; + $helper->setBasePath($config['view_manager']['base_path']); + return $helper; } - $request = $serviceLocator->get('Request'); - + $request = $container->get('Request'); if (is_callable([$request, 'getBasePath'])) { - $basePathHelper->setBasePath($request->getBasePath()); + $helper->setBasePath($request->getBasePath()); } - return $basePathHelper; - }); + return $helper; + }; + } - /** - * Configure doctype view helper with doctype from configuration, if available. - * - * Other view helpers depend on this to decide which spec to generate their tags - * based on. This is why it must be set early instead of later in the layout phtml. - */ - $plugins->setFactory('doctype', function () use ($serviceLocator) { - $config = $serviceLocator->has('Config') ? $serviceLocator->get('Config') : []; + /** + * Configure doctype view helper with doctype from configuration, if available. + * + * Other view helpers depend on this to decide which spec to generate their tags + * based on. + * + * This is why it must be set early instead of later in the layout phtml. + * + * @return callable + */ + private function createDoctypeHelperFactory() + { + return function ($container, $name, array $options = null) { + $config = $container->has('config') ? $container->get('config') : []; $config = isset($config['view_manager']) ? $config['view_manager'] : []; - $doctypeHelper = new ViewHelper\Doctype; + $helper = new ViewHelper\Doctype; if (isset($config['doctype']) && $config['doctype']) { - $doctypeHelper->setDoctype($config['doctype']); + $helper->setDoctype($config['doctype']); } - return $doctypeHelper; - }); - - return $plugins; + return $helper; + }; } } diff --git a/src/Service/ViewJsonStrategyFactory.php b/src/Service/ViewJsonStrategyFactory.php index f0935de5b..92337b299 100644 --- a/src/Service/ViewJsonStrategyFactory.php +++ b/src/Service/ViewJsonStrategyFactory.php @@ -9,8 +9,8 @@ namespace Zend\Mvc\Service; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; use Zend\View\Strategy\JsonStrategy; class ViewJsonStrategyFactory implements FactoryInterface @@ -23,12 +23,14 @@ class ViewJsonStrategyFactory implements FactoryInterface * * It then attaches the strategy to the View service, at a priority of 100. * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return JsonStrategy */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - $jsonRenderer = $serviceLocator->get('ViewJsonRenderer'); + $jsonRenderer = $container->get('ViewJsonRenderer'); $jsonStrategy = new JsonStrategy($jsonRenderer); return $jsonStrategy; } diff --git a/src/Service/ViewManagerFactory.php b/src/Service/ViewManagerFactory.php index 548e530f5..a0a4c7c98 100644 --- a/src/Service/ViewManagerFactory.php +++ b/src/Service/ViewManagerFactory.php @@ -9,26 +9,28 @@ namespace Zend\Mvc\Service; +use Interop\Container\ContainerInterface; use Zend\Console\Console; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; use Zend\Mvc\View\Console\ViewManager as ConsoleViewManager; use Zend\Mvc\View\Http\ViewManager as HttpViewManager; +use Zend\ServiceManager\Factory\FactoryInterface; class ViewManagerFactory implements FactoryInterface { /** * Create and return a view manager based on detected environment * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return ConsoleViewManager|HttpViewManager */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { if (Console::isConsole()) { - return $serviceLocator->get('ConsoleViewManager'); + return $container->get('ConsoleViewManager'); } - return $serviceLocator->get('HttpViewManager'); + return $container->get('HttpViewManager'); } } diff --git a/src/Service/ViewPhpRendererFactory.php b/src/Service/ViewPhpRendererFactory.php new file mode 100644 index 000000000..770704d2c --- /dev/null +++ b/src/Service/ViewPhpRendererFactory.php @@ -0,0 +1,32 @@ +setHelperPluginManager($container->get('ViewHelperManager')); + $renderer->setResolver($container->get('ViewResolver')); + + return $renderer; + } +} diff --git a/src/Service/ViewPhpRendererStrategyFactory.php b/src/Service/ViewPhpRendererStrategyFactory.php new file mode 100644 index 000000000..2d70aaf1d --- /dev/null +++ b/src/Service/ViewPhpRendererStrategyFactory.php @@ -0,0 +1,29 @@ +get(PhpRenderer::class)); + } +} diff --git a/src/Service/ViewPrefixPathStackResolverFactory.php b/src/Service/ViewPrefixPathStackResolverFactory.php index 2c9766a85..8eb85a6a2 100644 --- a/src/Service/ViewPrefixPathStackResolverFactory.php +++ b/src/Service/ViewPrefixPathStackResolverFactory.php @@ -9,8 +9,8 @@ namespace Zend\Mvc\Service; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; use Zend\View\Resolver\PrefixPathStackResolver; class ViewPrefixPathStackResolverFactory implements FactoryInterface @@ -21,12 +21,14 @@ class ViewPrefixPathStackResolverFactory implements FactoryInterface * Creates a Zend\View\Resolver\PrefixPathStackResolver and populates it with the * ['view_manager']['prefix_template_path_stack'] * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return PrefixPathStackResolver */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - $config = $serviceLocator->get('Config'); + $config = $container->get('config'); $prefixes = []; if (isset($config['view_manager']['prefix_template_path_stack'])) { diff --git a/src/Service/ViewResolverFactory.php b/src/Service/ViewResolverFactory.php index e57e6c392..1b242e0f1 100644 --- a/src/Service/ViewResolverFactory.php +++ b/src/Service/ViewResolverFactory.php @@ -9,8 +9,8 @@ namespace Zend\Mvc\Service; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; use Zend\View\Resolver as ViewResolver; class ViewResolverFactory implements FactoryInterface @@ -21,19 +21,21 @@ class ViewResolverFactory implements FactoryInterface * Creates a Zend\View\Resolver\AggregateResolver and attaches the template * map resolver and path stack resolver * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return ViewResolver\AggregateResolver */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { $resolver = new ViewResolver\AggregateResolver(); /* @var $mapResolver \Zend\View\Resolver\ResolverInterface */ - $mapResolver = $serviceLocator->get('ViewTemplateMapResolver'); + $mapResolver = $container->get('ViewTemplateMapResolver'); /* @var $pathResolver \Zend\View\Resolver\ResolverInterface */ - $pathResolver = $serviceLocator->get('ViewTemplatePathStack'); + $pathResolver = $container->get('ViewTemplatePathStack'); /* @var $prefixPathStackResolver \Zend\View\Resolver\ResolverInterface */ - $prefixPathStackResolver = $serviceLocator->get('ViewPrefixPathStackResolver'); + $prefixPathStackResolver = $container->get('ViewPrefixPathStackResolver'); $resolver ->attach($mapResolver) diff --git a/src/Service/ViewTemplateMapResolverFactory.php b/src/Service/ViewTemplateMapResolverFactory.php index 87383740b..64a911daf 100644 --- a/src/Service/ViewTemplateMapResolverFactory.php +++ b/src/Service/ViewTemplateMapResolverFactory.php @@ -9,8 +9,8 @@ namespace Zend\Mvc\Service; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; use Zend\View\Resolver as ViewResolver; class ViewTemplateMapResolverFactory implements FactoryInterface @@ -21,12 +21,14 @@ class ViewTemplateMapResolverFactory implements FactoryInterface * Creates a Zend\View\Resolver\AggregateResolver and populates it with the * ['view_manager']['template_map'] * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return ViewResolver\TemplateMapResolver */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - $config = $serviceLocator->get('Config'); + $config = $container->get('config'); $map = []; if (is_array($config) && isset($config['view_manager'])) { $config = $config['view_manager']; diff --git a/src/Service/ViewTemplatePathStackFactory.php b/src/Service/ViewTemplatePathStackFactory.php index dcf6ddd4b..c4267d7e9 100644 --- a/src/Service/ViewTemplatePathStackFactory.php +++ b/src/Service/ViewTemplatePathStackFactory.php @@ -9,8 +9,8 @@ namespace Zend\Mvc\Service; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; use Zend\View\Resolver as ViewResolver; class ViewTemplatePathStackFactory implements FactoryInterface @@ -22,12 +22,14 @@ class ViewTemplatePathStackFactory implements FactoryInterface * ['view_manager']['template_path_stack'] and sets the default suffix with the * ['view_manager']['default_template_suffix'] * - * @param ServiceLocatorInterface $serviceLocator + * @param ContainerInterface $container + * @param string $name + * @param null|array $options * @return ViewResolver\TemplatePathStack */ - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - $config = $serviceLocator->get('Config'); + $config = $container->get('config'); $templatePathStack = new ViewResolver\TemplatePathStack(); diff --git a/src/View/Console/ViewManager.php b/src/View/Console/ViewManager.php index 97835ff71..bf409ec0c 100644 --- a/src/View/Console/ViewManager.php +++ b/src/View/Console/ViewManager.php @@ -34,13 +34,13 @@ public function onBootstrap($event) $services = $application->getServiceManager(); $events = $application->getEventManager(); $sharedEvents = $events->getSharedManager(); - $this->config = $this->loadConfig($services->get('Config')); + $this->config = $this->loadConfig($services->get('config')); $this->services = $services; $this->event = $event; - $routeNotFoundStrategy = $this->getRouteNotFoundStrategy(); - $exceptionStrategy = $this->getExceptionStrategy(); - $mvcRenderingStrategy = $this->getMvcRenderingStrategy(); + $routeNotFoundStrategy = $services->get('ConsoleRouteNotFoundStrategy'); + $exceptionStrategy = $services->get('ConsoleExceptionStrategy'); + $mvcRenderingStrategy = $services->get('ConsoleDefaultRenderingStrategy'); $createViewModelListener = new CreateViewModelListener(); $injectViewModelListener = new InjectViewModelListener(); $injectParamsListener = new InjectNamedConsoleParamsListener(); @@ -61,90 +61,6 @@ public function onBootstrap($event) $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, [$injectViewModelListener, 'injectViewModel'], -100); } - /** - * Instantiates and configures the default MVC rendering strategy - * - * Overriding to ensure we pick up the MVC rendering strategy for console, - * as well as to ensure that the appropriate aliases are set. - * - * @return DefaultRenderingStrategy - */ - public function getMvcRenderingStrategy() - { - if ($this->mvcRenderingStrategy) { - return $this->mvcRenderingStrategy; - } - - $this->mvcRenderingStrategy = new DefaultRenderingStrategy(); - - $this->services->setService('DefaultRenderingStrategy', $this->mvcRenderingStrategy); - $this->services->setAlias('Zend\Mvc\View\DefaultRenderingStrategy', 'DefaultRenderingStrategy'); - $this->services->setAlias('Zend\Mvc\View\Console\DefaultRenderingStrategy', 'DefaultRenderingStrategy'); - - return $this->mvcRenderingStrategy; - } - - /** - * Instantiates and configures the exception strategy - * - * Overriding to ensure we pick up the exception strategy for console, as - * well as to ensure that the appropriate aliases are set. - * - * @return ExceptionStrategy - */ - public function getExceptionStrategy() - { - if ($this->exceptionStrategy) { - return $this->exceptionStrategy; - } - - $this->exceptionStrategy = new ExceptionStrategy(); - - if (isset($this->config['display_exceptions'])) { - $this->exceptionStrategy->setDisplayExceptions($this->config['display_exceptions']); - } - if (isset($this->config['exception_message'])) { - $this->exceptionStrategy->setMessage($this->config['exception_message']); - } - - $this->services->setService('ExceptionStrategy', $this->exceptionStrategy); - $this->services->setAlias('Zend\Mvc\View\ExceptionStrategy', 'ExceptionStrategy'); - $this->services->setAlias('Zend\Mvc\View\Console\ExceptionStrategy', 'ExceptionStrategy'); - - return $this->exceptionStrategy; - } - - /** - * Instantiates and configures the "route not found", or 404, strategy - * - * Overriding to ensure we pick up the route not found strategy for console, - * as well as to ensure that the appropriate aliases are set. - * - * @return RouteNotFoundStrategy - */ - public function getRouteNotFoundStrategy() - { - if ($this->routeNotFoundStrategy) { - return $this->routeNotFoundStrategy; - } - - $this->routeNotFoundStrategy = new RouteNotFoundStrategy(); - - $displayNotFoundReason = true; - - if (array_key_exists('display_not_found_reason', $this->config)) { - $displayNotFoundReason = $this->config['display_not_found_reason']; - } - $this->routeNotFoundStrategy->setDisplayNotFoundReason($displayNotFoundReason); - - $this->services->setService('RouteNotFoundStrategy', $this->routeNotFoundStrategy); - $this->services->setAlias('Zend\Mvc\View\RouteNotFoundStrategy', 'RouteNotFoundStrategy'); - $this->services->setAlias('Zend\Mvc\View\Console\RouteNotFoundStrategy', 'RouteNotFoundStrategy'); - $this->services->setAlias('404Strategy', 'RouteNotFoundStrategy'); - - return $this->routeNotFoundStrategy; - } - /** * Extract view manager configuration from the application's configuration * diff --git a/src/View/Http/ViewManager.php b/src/View/Http/ViewManager.php index 162cfa3c0..436ba393c 100644 --- a/src/View/Http/ViewManager.php +++ b/src/View/Http/ViewManager.php @@ -17,9 +17,7 @@ use Zend\Mvc\MvcEvent; use Zend\ServiceManager\ServiceManager; use Zend\View\HelperPluginManager as ViewHelperManager; -use Zend\View\Renderer\PhpRenderer as ViewPhpRenderer; use Zend\View\Resolver as ViewResolver; -use Zend\View\Strategy\PhpRendererStrategy; use Zend\View\View; /** @@ -65,13 +63,11 @@ class ViewManager extends AbstractListenerAggregate * Various properties representing strategies and objects instantiated and * configured by the view manager */ - protected $exceptionStrategy; protected $helperManager; protected $mvcRenderingStrategy; protected $renderer; protected $rendererStrategy; protected $resolver; - protected $routeNotFoundStrategy; protected $view; protected $viewModel; /**@-*/ @@ -94,7 +90,7 @@ public function onBootstrap($event) { $application = $event->getApplication(); $services = $application->getServiceManager(); - $config = $services->get('Config'); + $config = $services->get('config'); $events = $application->getEventManager(); $sharedEvents = $events->getSharedManager(); @@ -104,10 +100,13 @@ public function onBootstrap($event) $this->services = $services; $this->event = $event; - $routeNotFoundStrategy = $this->getRouteNotFoundStrategy(); - $exceptionStrategy = $this->getExceptionStrategy(); - $mvcRenderingStrategy = $this->getMvcRenderingStrategy(); - $injectTemplateListener = $this->getInjectTemplateListener(); + $routeNotFoundStrategy = $services->get('HttpRouteNotFoundStrategy'); + $exceptionStrategy = $services->get('HttpExceptionStrategy'); + $mvcRenderingStrategy = $services->get('HttpDefaultRenderingStrategy'); + + $this->injectViewModelIntoPlugin(); + + $injectTemplateListener = $services->get('Zend\Mvc\View\Http\InjectTemplateListener'); $createViewModelListener = new CreateViewModelListener(); $injectViewModelListener = new InjectViewModelListener(); @@ -128,82 +127,7 @@ public function onBootstrap($event) } /** - * Instantiates and configures the renderer's helper manager - * - * @return ViewHelperManager - */ - public function getHelperManager() - { - if ($this->helperManager) { - return $this->helperManager; - } - - return $this->helperManager = $this->services->get('ViewHelperManager'); - } - - /** - * Instantiates and configures the renderer's resolver - * - * @return ViewResolver\ResolverInterface - */ - public function getResolver() - { - if (null === $this->resolver) { - $this->resolver = $this->services->get('ViewResolver'); - } - - return $this->resolver; - } - - /** - * Instantiates and configures the renderer - * - * @return ViewPhpRenderer - */ - public function getRenderer() - { - if ($this->renderer) { - return $this->renderer; - } - - $this->renderer = new ViewPhpRenderer; - $this->renderer->setHelperPluginManager($this->getHelperManager()); - $this->renderer->setResolver($this->getResolver()); - - $model = $this->getViewModel(); - $modelHelper = $this->renderer->plugin('view_model'); - $modelHelper->setRoot($model); - - $this->services->setService('ViewRenderer', $this->renderer); - $this->services->setAlias('Zend\View\Renderer\PhpRenderer', 'ViewRenderer'); - $this->services->setAlias('Zend\View\Renderer\RendererInterface', 'ViewRenderer'); - - return $this->renderer; - } - - /** - * Instantiates and configures the renderer strategy for the view - * - * @return PhpRendererStrategy - */ - public function getRendererStrategy() - { - if ($this->rendererStrategy) { - return $this->rendererStrategy; - } - - $this->rendererStrategy = new PhpRendererStrategy( - $this->getRenderer() - ); - - $this->services->setService('ViewPhpRendererStrategy', $this->rendererStrategy); - $this->services->setAlias('Zend\View\Strategy\PhpRendererStrategy', 'ViewPhpRendererStrategy'); - - return $this->rendererStrategy; - } - - /** - * Instantiates and configures the view + * Retrieves the View instance * * @return View */ @@ -213,128 +137,10 @@ public function getView() return $this->view; } - $this->view = new View(); - $this->view->setEventManager($this->services->get('EventManager')); - $this->getRendererStrategy()->attach($this->view->getEventManager()); - - $this->services->setService('View', $this->view); - $this->services->setAlias('Zend\View\View', 'View'); - + $this->view = $this->services->get(View::class); return $this->view; } - /** - * Retrieves the layout template name from the configuration - * - * @return string - */ - public function getLayoutTemplate() - { - if (isset($this->config['layout'])) { - return $this->config['layout']; - } - - return 'layout/layout'; - } - - /** - * Instantiates and configures the default MVC rendering strategy - * - * @return DefaultRenderingStrategy - */ - public function getMvcRenderingStrategy() - { - if ($this->mvcRenderingStrategy) { - return $this->mvcRenderingStrategy; - } - - $this->mvcRenderingStrategy = new DefaultRenderingStrategy($this->getView()); - $this->mvcRenderingStrategy->setLayoutTemplate($this->getLayoutTemplate()); - - $this->services->setService('DefaultRenderingStrategy', $this->mvcRenderingStrategy); - $this->services->setAlias('Zend\Mvc\View\DefaultRenderingStrategy', 'DefaultRenderingStrategy'); - $this->services->setAlias('Zend\Mvc\View\Http\DefaultRenderingStrategy', 'DefaultRenderingStrategy'); - - return $this->mvcRenderingStrategy; - } - - /** - * Instantiates and configures the exception strategy - * - * @return ExceptionStrategy - */ - public function getExceptionStrategy() - { - if ($this->exceptionStrategy) { - return $this->exceptionStrategy; - } - - $this->exceptionStrategy = new ExceptionStrategy(); - - $displayExceptions = false; - $exceptionTemplate = 'error'; - - if (isset($this->config['display_exceptions'])) { - $displayExceptions = $this->config['display_exceptions']; - } - if (isset($this->config['exception_template'])) { - $exceptionTemplate = $this->config['exception_template']; - } - - $this->exceptionStrategy->setDisplayExceptions($displayExceptions); - $this->exceptionStrategy->setExceptionTemplate($exceptionTemplate); - - $this->services->setService('ExceptionStrategy', $this->exceptionStrategy); - $this->services->setAlias('Zend\Mvc\View\ExceptionStrategy', 'ExceptionStrategy'); - $this->services->setAlias('Zend\Mvc\View\Http\ExceptionStrategy', 'ExceptionStrategy'); - - return $this->exceptionStrategy; - } - - /** - * Instantiates and configures the "route not found", or 404, strategy - * - * @return RouteNotFoundStrategy - */ - public function getRouteNotFoundStrategy() - { - if ($this->routeNotFoundStrategy) { - return $this->routeNotFoundStrategy; - } - - $this->routeNotFoundStrategy = new RouteNotFoundStrategy(); - - $displayExceptions = false; - $displayNotFoundReason = false; - $notFoundTemplate = '404'; - - if (isset($this->config['display_exceptions'])) { - $displayExceptions = $this->config['display_exceptions']; - } - if (isset($this->config['display_not_found_reason'])) { - $displayNotFoundReason = $this->config['display_not_found_reason']; - } - if (isset($this->config['not_found_template'])) { - $notFoundTemplate = $this->config['not_found_template']; - } - - $this->routeNotFoundStrategy->setDisplayExceptions($displayExceptions); - $this->routeNotFoundStrategy->setDisplayNotFoundReason($displayNotFoundReason); - $this->routeNotFoundStrategy->setNotFoundTemplate($notFoundTemplate); - - $this->services->setService('RouteNotFoundStrategy', $this->routeNotFoundStrategy); - $this->services->setAlias('Zend\Mvc\View\RouteNotFoundStrategy', 'RouteNotFoundStrategy'); - $this->services->setAlias('Zend\Mvc\View\Http\RouteNotFoundStrategy', 'RouteNotFoundStrategy'); - $this->services->setAlias('404Strategy', 'RouteNotFoundStrategy'); - - return $this->routeNotFoundStrategy; - } - - public function getInjectTemplateListener() - { - return $this->services->get('Zend\Mvc\View\Http\InjectTemplateListener'); - } - /** * Configures the MvcEvent view model to ensure it has the template injected * @@ -347,7 +153,8 @@ public function getViewModel() } $this->viewModel = $model = $this->event->getViewModel(); - $model->setTemplate($this->getLayoutTemplate()); + $layoutTemplate = $this->services->get('HttpDefaultRenderingStrategy')->getLayoutTemplate(); + $model->setTemplate($layoutTemplate); return $this->viewModel; } @@ -366,19 +173,19 @@ public function getViewModel() */ protected function registerMvcRenderingStrategies(EventManagerInterface $events) { - if (!isset($this->config['mvc_strategies'])) { + if (! isset($this->config['mvc_strategies'])) { return; } $mvcStrategies = $this->config['mvc_strategies']; if (is_string($mvcStrategies)) { $mvcStrategies = [$mvcStrategies]; } - if (!is_array($mvcStrategies) && !$mvcStrategies instanceof Traversable) { + if (! is_array($mvcStrategies) && ! $mvcStrategies instanceof Traversable) { return; } foreach ($mvcStrategies as $mvcStrategy) { - if (!is_string($mvcStrategy)) { + if (! is_string($mvcStrategy)) { continue; } @@ -402,14 +209,14 @@ protected function registerMvcRenderingStrategies(EventManagerInterface $events) */ protected function registerViewStrategies() { - if (!isset($this->config['strategies'])) { + if (! isset($this->config['strategies'])) { return; } $strategies = $this->config['strategies']; if (is_string($strategies)) { $strategies = [$strategies]; } - if (!is_array($strategies) && !$strategies instanceof Traversable) { + if (! is_array($strategies) && ! $strategies instanceof Traversable) { return; } @@ -417,7 +224,7 @@ protected function registerViewStrategies() $events = $view->getEventManager(); foreach ($strategies as $strategy) { - if (!is_string($strategy)) { + if (! is_string($strategy)) { continue; } @@ -427,4 +234,15 @@ protected function registerViewStrategies() } } } + + /** + * Injects the ViewModel view helper with the root view model. + */ + private function injectViewModelIntoPlugin() + { + $model = $this->getViewModel(); + $plugins = $this->services->get('ViewHelperManager'); + $plugin = $plugins->get('viewmodel'); + $plugin->setRoot($model); + } } diff --git a/test/Application/AllowsReturningEarlyFromRoutingTest.php b/test/Application/AllowsReturningEarlyFromRoutingTest.php new file mode 100644 index 000000000..47e731a7a --- /dev/null +++ b/test/Application/AllowsReturningEarlyFromRoutingTest.php @@ -0,0 +1,34 @@ +prepareApplication(); + + $response = new Response(); + + $application->getEventManager()->attach(MvcEvent::EVENT_ROUTE, function ($e) use ($response) { + return $response; + }); + + $result = $application->run(); + $this->assertSame($application, $result); + $this->assertSame($response, $result->getResponse()); + } +} diff --git a/test/Application/BadControllerTrait.php b/test/Application/BadControllerTrait.php new file mode 100644 index 000000000..f85660211 --- /dev/null +++ b/test/Application/BadControllerTrait.php @@ -0,0 +1,96 @@ + [ + 'routes' => [ + 'path' => [ + 'type' => Router\Http\Literal::class, + 'options' => [ + 'route' => '/bad', + 'defaults' => [ + 'controller' => 'bad', + 'action' => 'test', + ], + ], + ], + ], + ], + ]; + + $serviceListener = new ServiceListenerFactory(); + $r = new ReflectionProperty($serviceListener, 'defaultServiceConfig'); + $r->setAccessible(true); + $serviceConfig = $r->getValue($serviceListener); + + $serviceConfig = ArrayUtils::merge( + $serviceConfig, + [ + 'aliases' => [ + 'ControllerLoader' => ControllerManager::class, + 'ControllerManager' => ControllerManager::class, + 'Router' => 'HttpRouter', + ], + 'factories' => [ + ControllerManager::class => function ($services) { + return new ControllerManager($services, ['factories' => [ + 'bad' => function () { + return new BadController(); + }, + ]]); + }, + ], + 'invokables' => [ + 'Request' => 'Zend\Http\PhpEnvironment\Request', + 'Response' => Response::class, + 'ViewManager' => TestAsset\MockViewManager::class, + 'SendResponseListener' => TestAsset\MockSendResponseListener::class, + 'BootstrapListener' => TestAsset\StubBootstrapListener::class, + ], + 'services' => [ + 'config' => $config, + 'ApplicationConfig' => [ + 'modules' => [], + 'module_listener_options' => [ + 'config_cache_enabled' => false, + 'cache_dir' => 'data/cache', + 'module_paths' => [], + ], + ], + ], + ] + ); + $services = new ServiceManager((new ServiceManagerConfig($serviceConfig))->toArray()); + $application = $services->get('Application'); + + $request = $services->get('Request'); + $request->setUri('http://example.local/bad'); + + $application->bootstrap(); + return $application; + } +} diff --git a/test/Application/ControllerIsDispatchedTest.php b/test/Application/ControllerIsDispatchedTest.php new file mode 100644 index 000000000..d780a6fa8 --- /dev/null +++ b/test/Application/ControllerIsDispatchedTest.php @@ -0,0 +1,27 @@ +prepareApplication(); + + $response = $application->run()->getResponse(); + $this->assertContains('PathController', $response->getContent()); + $this->assertContains(MvcEvent::EVENT_DISPATCH, $response->toString()); + } +} diff --git a/test/Application/ExceptionsRaisedInDispatchableShouldRaiseDispatchErrorEventTest.php b/test/Application/ExceptionsRaisedInDispatchableShouldRaiseDispatchErrorEventTest.php new file mode 100644 index 000000000..7defd5347 --- /dev/null +++ b/test/Application/ExceptionsRaisedInDispatchableShouldRaiseDispatchErrorEventTest.php @@ -0,0 +1,38 @@ +prepareApplication(); + + $response = $application->getResponse(); + $events = $application->getEventManager(); + $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($response) { + $exception = $e->getParam('exception'); + $this->assertInstanceOf('Exception', $exception); + $response->setContent($exception->getMessage()); + return $response; + }); + + $application->run(); + $this->assertContains('Raised an exception', $response->getContent()); + } +} diff --git a/test/Application/InabilityToRetrieveControllerShouldTriggerDispatchErrorTest.php b/test/Application/InabilityToRetrieveControllerShouldTriggerDispatchErrorTest.php new file mode 100644 index 000000000..5d1345b65 --- /dev/null +++ b/test/Application/InabilityToRetrieveControllerShouldTriggerDispatchErrorTest.php @@ -0,0 +1,40 @@ +prepareApplication(); + + $response = $application->getResponse(); + $events = $application->getEventManager(); + $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($response) { + $error = $e->getError(); + $controller = $e->getController(); + $response->setContent("Code: " . $error . '; Controller: ' . $controller); + return $response; + }); + + $application->run(); + $this->assertContains(Application::ERROR_CONTROLLER_NOT_FOUND, $response->getContent()); + $this->assertContains('bad', $response->getContent()); + } +} diff --git a/test/Application/InabilityToRetrieveControllerShouldTriggerExceptionTest.php b/test/Application/InabilityToRetrieveControllerShouldTriggerExceptionTest.php new file mode 100644 index 000000000..ed1c07e97 --- /dev/null +++ b/test/Application/InabilityToRetrieveControllerShouldTriggerExceptionTest.php @@ -0,0 +1,40 @@ +prepareApplication(); + + $response = $application->getResponse(); + $events = $application->getEventManager(); + $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($response) { + $error = $e->getError(); + $controller = $e->getController(); + $response->setContent("Code: " . $error . '; Controller: ' . $controller); + return $response; + }); + + $application->run(); + $this->assertContains(Application::ERROR_CONTROLLER_NOT_FOUND, $response->getContent()); + $this->assertContains('bad', $response->getContent()); + } +} diff --git a/test/Application/InitializationIntegrationTest.php b/test/Application/InitializationIntegrationTest.php new file mode 100644 index 000000000..96d75dd76 --- /dev/null +++ b/test/Application/InitializationIntegrationTest.php @@ -0,0 +1,43 @@ + [ + 'Application', + ], + 'module_listener_options' => [ + 'module_paths' => [ + __DIR__ . '/TestAsset/modules', + ], + ], + ]; + + $application = Application::init($appConfig); + + $request = $application->getRequest(); + $request->setUri('http://example.local/path'); + $request->setRequestUri('/path'); + + $application->run(); + $response = $application->getResponse(); + $this->assertContains('Application\\Controller\\PathController', $response->getContent()); + $this->assertContains(MvcEvent::EVENT_DISPATCH, $response->toString()); + } +} diff --git a/test/Application/InvalidControllerTypeShouldTriggerDispatchErrorTest.php b/test/Application/InvalidControllerTypeShouldTriggerDispatchErrorTest.php new file mode 100644 index 000000000..c0d2d5104 --- /dev/null +++ b/test/Application/InvalidControllerTypeShouldTriggerDispatchErrorTest.php @@ -0,0 +1,41 @@ +prepareApplication(); + + $response = $application->getResponse(); + $events = $application->getEventManager(); + $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($response) { + $error = $e->getError(); + $controller = $e->getController(); + $class = $e->getControllerClass(); + $response->setContent("Code: " . $error . '; Controller: ' . $controller . '; Class: ' . $class); + return $response; + }); + + $application->run(); + $this->assertContains(Application::ERROR_CONTROLLER_INVALID, $response->getContent()); + $this->assertContains('bad', $response->getContent()); + } +} diff --git a/test/Application/InvalidControllerTypeTrait.php b/test/Application/InvalidControllerTypeTrait.php new file mode 100644 index 000000000..e45ed2626 --- /dev/null +++ b/test/Application/InvalidControllerTypeTrait.php @@ -0,0 +1,96 @@ + [ + 'routes' => [ + 'path' => [ + 'type' => Router\Http\Literal::class, + 'options' => [ + 'route' => '/bad', + 'defaults' => [ + 'controller' => 'bad', + 'action' => 'test', + ], + ], + ], + ], + ], + ]; + + $serviceListener = new ServiceListenerFactory(); + $r = new ReflectionProperty($serviceListener, 'defaultServiceConfig'); + $r->setAccessible(true); + $serviceConfig = $r->getValue($serviceListener); + + $serviceConfig = ArrayUtils::merge( + $serviceConfig, + [ + 'aliases' => [ + 'ControllerLoader' => ControllerManager::class, + 'ControllerManager' => ControllerManager::class, + 'Router' => 'HttpRouter', + ], + 'factories' => [ + ControllerManager::class => function ($services) { + return new ControllerManager($services, ['factories' => [ + 'bad' => function () { + return new stdClass(); + }, + ]]); + }, + ], + 'invokables' => [ + 'Request' => 'Zend\Http\PhpEnvironment\Request', + 'Response' => Response::class, + 'ViewManager' => TestAsset\MockViewManager::class, + 'SendResponseListener' => TestAsset\MockSendResponseListener::class, + 'BootstrapListener' => TestAsset\StubBootstrapListener::class, + ], + 'services' => [ + 'config' => $config, + 'ApplicationConfig' => [ + 'modules' => [], + 'module_listener_options' => [ + 'config_cache_enabled' => false, + 'cache_dir' => 'data/cache', + 'module_paths' => [], + ], + ], + ], + ] + ); + $services = new ServiceManager((new ServiceManagerConfig($serviceConfig))->toArray()); + $application = $services->get('Application'); + + $request = $services->get('Request'); + $request->setUri('http://example.local/bad'); + + $application->bootstrap(); + return $application; + } +} diff --git a/test/Application/MissingControllerTrait.php b/test/Application/MissingControllerTrait.php new file mode 100644 index 000000000..16ee04c86 --- /dev/null +++ b/test/Application/MissingControllerTrait.php @@ -0,0 +1,83 @@ + [ + 'routes' => [ + 'path' => [ + 'type' => Router\Http\Literal::class, + 'options' => [ + 'route' => '/bad', + 'defaults' => [ + 'controller' => 'bad', + 'action' => 'test', + ], + ], + ], + ], + ], + ]; + + $serviceListener = new ServiceListenerFactory(); + $r = new ReflectionProperty($serviceListener, 'defaultServiceConfig'); + $r->setAccessible(true); + $serviceConfig = $r->getValue($serviceListener); + + $serviceConfig = ArrayUtils::merge( + $serviceConfig, + [ + 'aliases' => [ + 'Router' => 'HttpRouter', + ], + 'invokables' => [ + 'Request' => 'Zend\Http\PhpEnvironment\Request', + 'Response' => Response::class, + 'ViewManager' => TestAsset\MockViewManager::class, + 'SendResponseListener' => TestAsset\MockSendResponseListener::class, + 'BootstrapListener' => TestAsset\StubBootstrapListener::class, + ], + 'services' => [ + 'config' => $config, + 'ApplicationConfig' => [ + 'modules' => [], + 'module_listener_options' => [ + 'config_cache_enabled' => false, + 'cache_dir' => 'data/cache', + 'module_paths' => [], + ], + ], + ], + ] + ); + $services = new ServiceManager((new ServiceManagerConfig($serviceConfig))->toArray()); + $application = $services->get('Application'); + + $request = $services->get('Request'); + $request->setUri('http://example.local/bad'); + + $application->bootstrap(); + return $application; + } +} diff --git a/test/Application/PathControllerTrait.php b/test/Application/PathControllerTrait.php new file mode 100644 index 000000000..18376007d --- /dev/null +++ b/test/Application/PathControllerTrait.php @@ -0,0 +1,94 @@ + [ + 'routes' => [ + 'path' => [ + 'type' => Router\Http\Literal::class, + 'options' => [ + 'route' => '/path', + 'defaults' => [ + 'controller' => 'path', + ], + ], + ], + ], + ], + ]; + + $serviceListener = new ServiceListenerFactory(); + $r = new ReflectionProperty($serviceListener, 'defaultServiceConfig'); + $r->setAccessible(true); + $serviceConfig = $r->getValue($serviceListener); + + $serviceConfig = ArrayUtils::merge( + $serviceConfig, + [ + 'aliases' => [ + 'ControllerLoader' => ControllerManager::class, + 'ControllerManager' => ControllerManager::class, + 'Router' => 'HttpRouter', + ], + 'factories' => [ + ControllerManager::class => function ($services) { + return new ControllerManager($services, ['factories' => [ + 'path' => function () { + return new TestAsset\PathController(); + }, + ]]); + }, + ], + 'invokables' => [ + 'Request' => 'Zend\Http\PhpEnvironment\Request', + 'Response' => Response::class, + 'ViewManager' => TestAsset\MockViewManager::class, + 'SendResponseListener' => TestAsset\MockSendResponseListener::class, + 'BootstrapListener' => TestAsset\StubBootstrapListener::class, + ], + 'services' => [ + 'config' => $config, + 'ApplicationConfig' => [ + 'modules' => [], + 'module_listener_options' => [ + 'config_cache_enabled' => false, + 'cache_dir' => 'data/cache', + 'module_paths' => [], + ], + ], + ], + ] + ); + $services = new ServiceManager((new ServiceManagerConfig($serviceConfig))->toArray()); + $application = $services->get('Application'); + + $request = $services->get('Request'); + $request->setUri('http://example.local/path'); + + $application->bootstrap(); + return $application; + } +} diff --git a/test/Application/RoutingSuccessTest.php b/test/Application/RoutingSuccessTest.php new file mode 100644 index 000000000..5c47b2e8f --- /dev/null +++ b/test/Application/RoutingSuccessTest.php @@ -0,0 +1,36 @@ +prepareApplication(); + + $log = []; + + $application->getEventManager()->attach(MvcEvent::EVENT_ROUTE, function ($e) use (&$log) { + $match = $e->getRouteMatch(); + $this->assertInstanceOf(Router\RouteMatch::class, $match, 'Did not receive expected route match'); + $log['route-match'] = $match; + }, -100); + + $application->run(); + $this->assertArrayHasKey('route-match', $log); + $this->assertInstanceOf(Router\RouteMatch::class, $log['route-match']); + } +} diff --git a/test/Application/TestAsset/modules/Application/Module.php b/test/Application/TestAsset/modules/Application/Module.php new file mode 100644 index 000000000..acff8cf88 --- /dev/null +++ b/test/Application/TestAsset/modules/Application/Module.php @@ -0,0 +1,29 @@ + array( + 'namespaces' => array( + __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__, + ), + ), + ); + } +} diff --git a/test/Application/TestAsset/modules/Application/config/module.config.php b/test/Application/TestAsset/modules/Application/config/module.config.php new file mode 100644 index 000000000..749f51cde --- /dev/null +++ b/test/Application/TestAsset/modules/Application/config/module.config.php @@ -0,0 +1,66 @@ + [ + 'factories' => [ + 'path' => function () { + return new Controller\PathController(); + }, + ], + ], + 'router' => [ + 'routes' => [ + 'path' => [ + 'type' => 'literal', + 'options' => [ + 'route' => '/path', + 'defaults' => [ + 'controller' => 'path', + ], + ], + ], + ], + ], + 'service_manager' => [ + 'factories' => [ + 'Request' => function () { + return new HttpRequest(); + }, + 'Response' => function () { + return new HttpResponse(); + }, + 'Router' => HttpRouterFactory::class, + 'ViewManager' => HttpViewManagerFactory::class, + ], + ], + 'view_manager' => array( + 'display_not_found_reason' => true, + 'display_exceptions' => true, + 'doctype' => 'HTML5', + 'not_found_template' => 'error/404', + 'exception_template' => 'error/index', + 'template_map' => array( + 'layout/layout' => __DIR__ . '/../view/layout/layout.phtml', + 'application/index/index' => __DIR__ . '/../view/application/index/index.phtml', + 'error/404' => __DIR__ . '/../view/error/404.phtml', + 'error/index' => __DIR__ . '/../view/error/index.phtml', + ), + 'template_path_stack' => array( + __DIR__ . '/../view', + ), + ), +]; diff --git a/test/Application/TestAsset/modules/Application/src/Application/Controller/PathController.php b/test/Application/TestAsset/modules/Application/src/Application/Controller/PathController.php new file mode 100644 index 000000000..2e1be4ebd --- /dev/null +++ b/test/Application/TestAsset/modules/Application/src/Application/Controller/PathController.php @@ -0,0 +1,27 @@ +setContent(__METHOD__); + return $response; + } +} diff --git a/test/Application/TestAsset/modules/Application/view/application/index/index.phtml b/test/Application/TestAsset/modules/Application/view/application/index/index.phtml new file mode 100644 index 000000000..ff98a33ff --- /dev/null +++ b/test/Application/TestAsset/modules/Application/view/application/index/index.phtml @@ -0,0 +1,5 @@ +

Home Page

+ +

+ This is the home page. +

diff --git a/test/Application/TestAsset/modules/Application/view/error/404.phtml b/test/Application/TestAsset/modules/Application/view/error/404.phtml new file mode 100644 index 000000000..f53d90ae7 --- /dev/null +++ b/test/Application/TestAsset/modules/Application/view/error/404.phtml @@ -0,0 +1,107 @@ +

A 404 error occurred

+

message ?>

+ +reason) && $this->reason): ?> + +reason) { + case 'error-controller-cannot-dispatch': + $reasonMessage = 'The requested controller was unable to dispatch the request.'; + break; + case 'error-controller-not-found': + $reasonMessage = 'The requested controller could not be mapped to an existing controller class.'; + break; + case 'error-controller-invalid': + $reasonMessage = 'The requested controller was not dispatchable.'; + break; + case 'error-router-no-match': + $reasonMessage = 'The requested URL could not be matched by routing.'; + break; + default: + $reasonMessage = 'We cannot determine at this time why a 404 was generated.'; + break; +} +?> + +

+ + + +controller) && $this->controller): ?> + +
+
Controller:
+
escapeHtml($this->controller) ?> +controller_class) + && $this->controller_class + && $this->controller_class != $this->controller +) { + echo '(' . sprintf('resolves to %s', $this->escapeHtml($this->controller_class)) . ')'; +} +?> +
+
+ + + +display_exceptions) && $this->display_exceptions): ?> + +exception) && $this->exception instanceof Exception): ?> +
+

Additional information:

+

exception); ?>

+
+
File:
+
+
exception->getFile() ?>:exception->getLine() ?>
+
+
Message:
+
+
exception->getMessage() ?>
+
+
Stack trace:
+
+
exception->getTraceAsString() ?>
+
+
+exception->getPrevious(); + if ($e) : +?> +
+

Previous exceptions:

+ + + + + +

No Exception available

+ + + + diff --git a/test/Application/TestAsset/modules/Application/view/error/index.phtml b/test/Application/TestAsset/modules/Application/view/error/index.phtml new file mode 100644 index 000000000..5f013493b --- /dev/null +++ b/test/Application/TestAsset/modules/Application/view/error/index.phtml @@ -0,0 +1,62 @@ +

An error occurred

+

message ?>

+ +display_exceptions) && $this->display_exceptions): ?> + +exception) && $this->exception instanceof Exception): ?> +
+

Additional information:

+

exception); ?>

+
+
File:
+
+
exception->getFile() ?>:exception->getLine() ?>
+
+
Message:
+
+
escapeHtml($this->exception->getMessage()) ?>
+
+
Stack trace:
+
+
escapeHtml($this->exception->getTraceAsString()) ?>
+
+
+exception->getPrevious(); + if ($e) : +?> +
+

Previous exceptions:

+ + + + + +

No Exception available

+ + + + diff --git a/test/Application/TestAsset/modules/Application/view/layout/layout.phtml b/test/Application/TestAsset/modules/Application/view/layout/layout.phtml new file mode 100644 index 000000000..ac6e48032 --- /dev/null +++ b/test/Application/TestAsset/modules/Application/view/layout/layout.phtml @@ -0,0 +1,14 @@ +doctype(); ?> + + + + + headTitle('ZF2 Skeleton Application')->setSeparator(' - ')->setAutoEscape(false) ?> + + + +
+ content; ?> +
+ + diff --git a/test/ApplicationTest.php b/test/ApplicationTest.php index 23add63af..dbb4a7aaa 100644 --- a/test/ApplicationTest.php +++ b/test/ApplicationTest.php @@ -9,15 +9,15 @@ namespace ZendTest\Mvc; -use ArrayObject; use PHPUnit_Framework_TestCase as TestCase; -use ReflectionObject; +use ReflectionMethod; use ReflectionProperty; use stdClass; use Zend\Http\PhpEnvironment\Response; use Zend\ModuleManager\Listener\ConfigListener; use Zend\ModuleManager\ModuleEvent; use Zend\Mvc\Application; +use Zend\Mvc\Controller\ControllerManager; use Zend\Mvc\MvcEvent; use Zend\Mvc\Router; use Zend\Mvc\Service\ServiceManagerConfig; @@ -42,10 +42,14 @@ class ApplicationTest extends TestCase public function setUp() { + $serviceListener = new ServiceListenerFactory(); + $r = new ReflectionProperty($serviceListener, 'defaultServiceConfig'); + $r->setAccessible(true); + $serviceConfig = $r->getValue($serviceListener); + $serviceConfig = ArrayUtils::merge( - $this->readAttribute(new ServiceListenerFactory, 'defaultServiceConfig'), + $serviceConfig, [ - 'allow_override' => true, 'invokables' => [ 'Request' => 'Zend\Http\PhpEnvironment\Request', 'Response' => 'Zend\Http\PhpEnvironment\Response', @@ -57,7 +61,7 @@ public function setUp() 'Router' => 'HttpRouter', ], 'services' => [ - 'Config' => [], + 'config' => [], 'ApplicationConfig' => [ 'modules' => [], 'module_listener_options' => [ @@ -69,10 +73,25 @@ public function setUp() ], ] ); - $this->serviceManager = new ServiceManager(new ServiceManagerConfig($serviceConfig)); + $this->serviceManager = new ServiceManager((new ServiceManagerConfig($serviceConfig))->toArray()); $this->application = $this->serviceManager->get('Application'); } + /** + * Re-inject the application service manager instance + * + * @param Application $application + * @param ServiceManager $services + * @return Application + */ + public function setApplicationServiceManager(Application $application, ServiceManager $services) + { + $r = new ReflectionProperty($application, 'serviceManager'); + $r->setAccessible(true); + $r->setValue($application, $services); + return $application; + } + public function getConfigListener() { $manager = $this->serviceManager->get('ModuleManager'); @@ -125,9 +144,13 @@ public function testServiceManagerIsPopulated() public function testConfigIsPopulated() { - $smConfig = $this->serviceManager->get('Config'); + $smConfig = $this->serviceManager->get('config'); $appConfig = $this->application->getConfig(); - $this->assertEquals($smConfig, $appConfig, sprintf('SM config: %s; App config: %s', var_export($smConfig, 1), var_export($appConfig, 1))); + $this->assertEquals( + $smConfig, + $appConfig, + sprintf('SM config: %s; App config: %s', var_export($smConfig, 1), var_export($appConfig, 1)) + ); } public function testEventsAreEmptyAtFirst() @@ -160,21 +183,24 @@ public function testBootstrapRegistersListeners($listenerServiceName, $event, $m public function bootstrapRegistersListenersProvider() { + // @codingStandardsIgnoreStart + // [ Service Name, Event, Method, isCustom ] return [ - ['RouteListener', MvcEvent::EVENT_ROUTE, 'onRoute'], - ['DispatchListener', MvcEvent::EVENT_DISPATCH, 'onDispatch'], - ['SendResponseListener', MvcEvent::EVENT_FINISH, 'sendResponse'], - ['ViewManager', MvcEvent::EVENT_BOOTSTRAP, 'onBootstrap'], - ['HttpMethodListener', MvcEvent::EVENT_ROUTE, 'onRoute'], - ['BootstrapListener', MvcEvent::EVENT_BOOTSTRAP, 'onBootstrap', true], + 'route' => ['RouteListener' , MvcEvent::EVENT_ROUTE , 'onRoute', false], + 'dispatch' => ['DispatchListener' , MvcEvent::EVENT_DISPATCH , 'onDispatch', false], + 'send_response' => ['SendResponseListener' , MvcEvent::EVENT_FINISH , 'sendResponse', false], + 'view_manager' => ['ViewManager' , MvcEvent::EVENT_BOOTSTRAP , 'onBootstrap', false], + 'http_method' => ['HttpMethodListener' , MvcEvent::EVENT_ROUTE , 'onRoute', false], + 'bootstrap' => ['BootstrapListener' , MvcEvent::EVENT_BOOTSTRAP , 'onBootstrap', true ], ]; + // @codingStandardsIgnoreEnd } public function testBootstrapAlwaysRegistersDefaultListeners() { - $refl = new ReflectionProperty($this->application, 'defaultListeners'); - $refl->setAccessible(true); - $defaultListenersNames = $refl->getValue($this->application); + $r = new ReflectionProperty($this->application, 'defaultListeners'); + $r->setAccessible(true); + $defaultListenersNames = $r->getValue($this->application); $defaultListeners = []; foreach ($defaultListenersNames as $defaultListenerName) { $defaultListeners[] = $this->serviceManager->get($defaultListenerName); @@ -230,13 +256,31 @@ public function setupPathController($addService = true) ], ]); $router->addRoute('path', $route); + $services = $this->serviceManager->withConfig([ + 'aliases' => [ + 'Router' => 'HttpRouter', + ], + 'services' => [ + 'HttpRouter' => $router, + ], + ]); + + $application = $this->setApplicationServiceManager($this->application, $services); if ($addService) { - $controllerLoader = $this->serviceManager->get('ControllerLoader'); - $controllerLoader->setFactory('path', function () { - return new TestAsset\PathController; - }); + $services = $services->withConfig(['factories' => [ + 'ControllerManager' => function ($services) { + return new ControllerManager($services, ['factories' => [ + 'path' => function () { + return new TestAsset\PathController; + }, + ]]); + }, + ]]); + $application = $this->setApplicationServiceManager($application, $services); } - $this->application->bootstrap(); + + $application->bootstrap(); + return $application; } public function setupActionController() @@ -254,11 +298,19 @@ public function setupActionController() ]); $router->addRoute('sample', $route); - $controllerLoader = $this->serviceManager->get('ControllerLoader'); - $controllerLoader->setFactory('sample', function () { - return new Controller\TestAsset\SampleController; - }); - $this->application->bootstrap(); + $services = $this->serviceManager->withConfig(['factories' => [ + 'ControllerManager' => function ($services) { + return new ControllerManager($services, ['factories' => [ + 'sample' => function () { + return new Controller\TestAsset\SampleController(); + }, + ]]); + }, + ]]); + $application = $this->setApplicationServiceManager($this->application, $services); + + $application->bootstrap(); + return $application; } public function setupBadController($addService = true) @@ -276,170 +328,36 @@ public function setupBadController($addService = true) ]); $router->addRoute('bad', $route); + $application = $this->application; if ($addService) { - $controllerLoader = $this->serviceManager->get('ControllerLoader'); - $controllerLoader->setFactory('bad', function () { - return new Controller\TestAsset\BadController; - }); + $services = $this->serviceManager->withConfig(['factories' => [ + 'ControllerManager' => function ($services) { + return new ControllerManager($services, ['factories' => [ + 'bad' => function () { + return new Controller\TestAsset\BadController(); + }, + ]]); + }, + ]]); + $application = $this->setApplicationServiceManager($application, $services); } - $this->application->bootstrap(); - } - - public function testRoutingIsExecutedDuringRun() - { - $this->setupPathController(); - - $log = []; - $this->application->getEventManager()->attach(MvcEvent::EVENT_ROUTE, function ($e) use (&$log) { - $match = $e->getRouteMatch(); - if (!$match) { - return; - } - $log['route-match'] = $match; - }); - - $this->application->run(); - $this->assertArrayHasKey('route-match', $log); - $this->assertInstanceOf(Router\RouteMatch::class, $log['route-match']); - } - - public function testAllowsReturningEarlyFromRouting() - { - $this->setupPathController(); - $response = new Response(); - $this->application->getEventManager()->attach(MvcEvent::EVENT_ROUTE, function ($e) use ($response) { - return $response; - }); - - $result = $this->application->run(); - $this->assertSame($this->application, $result); - $this->assertSame($response, $result->getResponse()); - } - - public function testControllerIsDispatchedDuringRun() - { - $this->setupPathController(); - - $response = $this->application->run()->getResponse(); - $this->assertContains('PathController', $response->getContent()); - $this->assertContains(MvcEvent::EVENT_DISPATCH, $response->toString()); - } - - /** - * @group zen-92 - */ - public function testDispatchingInjectsLocatorInLocatorAwareControllers() - { - $this->setupActionController(); - - $events = $this->application->getEventManager()->getSharedManager(); - $storage = new ArrayObject(); - $events->attach('ZendTest\Mvc\Controller\TestAsset\SampleController', MvcEvent::EVENT_DISPATCH, function ($e) use ($storage) { - $controller = $e->getTarget(); - $storage['locator'] = $controller->getServiceLocator(); - return $e->getResponse(); - }, 100); - - $this->application->run(); - - $this->assertTrue(isset($storage['locator'])); - $this->assertSame($this->serviceManager, $storage['locator']); + $application->bootstrap(); + return $application; } public function testFinishEventIsTriggeredAfterDispatching() { - $this->setupActionController(); - $this->application->getEventManager()->attach(MvcEvent::EVENT_FINISH, function ($e) { + $application = $this->setupActionController(); + $application->getEventManager()->attach(MvcEvent::EVENT_FINISH, function ($e) { return $e->getResponse()->setContent($e->getResponse()->getBody() . 'foobar'); }); - $this->application->run(); - $this->assertContains('foobar', $this->application->getResponse()->getBody(), 'The "finish" event was not triggered ("foobar" not in response)'); - } - - /** - * @group error-handling - */ - public function testExceptionsRaisedInDispatchableShouldRaiseDispatchErrorEvent() - { - $this->setupBadController(); - $response = $this->application->getResponse(); - $events = $this->application->getEventManager(); - $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($response) { - $exception = $e->getParam('exception'); - $response->setContent($exception->getMessage()); - return $response; - }); - - $this->application->run(); - $this->assertContains('Raised an exception', $response->getContent()); - } - - /** - * @group error-handling - */ - public function testInabilityToRetrieveControllerShouldTriggerExceptionError() - { - $this->setupBadController(false); - $controllerLoader = $this->serviceManager->get('ControllerLoader'); - $response = $this->application->getResponse(); - $events = $this->application->getEventManager(); - $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($response) { - $error = $e->getError(); - $controller = $e->getController(); - $response->setContent("Code: " . $error . '; Controller: ' . $controller); - return $response; - }); - - $this->application->run(); - $this->assertContains(Application::ERROR_CONTROLLER_NOT_FOUND, $response->getContent()); - $this->assertContains('bad', $response->getContent()); - } - - /** - * @group error-handling - */ - public function testInabilityToRetrieveControllerShouldTriggerDispatchError() - { - $this->setupBadController(false); - $response = $this->application->getResponse(); - $events = $this->application->getEventManager(); - $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($response) { - $error = $e->getError(); - $controller = $e->getController(); - $response->setContent("Code: " . $error . '; Controller: ' . $controller); - return $response; - }); - - $this->application->run(); - $this->assertContains(Application::ERROR_CONTROLLER_NOT_FOUND, $response->getContent()); - $this->assertContains('bad', $response->getContent()); - } - - /** - * @group error-handling - */ - public function testInvalidControllerTypeShouldTriggerDispatchError() - { - $this->serviceManager->get('ControllerLoader'); - $this->setupBadController(false); - $controllerLoader = $this->serviceManager->get('ControllerLoader'); - $controllerLoader->setFactory('bad', function () { - return new stdClass; - }); - $response = $this->application->getResponse(); - $events = $this->application->getEventManager(); - $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($response) { - $error = $e->getError(); - $controller = $e->getController(); - $class = $e->getControllerClass(); - $response->setContent("Code: " . $error . '; Controller: ' . $controller . '; Class: ' . $class); - return $response; - }); - - $this->application->run(); - $this->assertContains(Application::ERROR_CONTROLLER_INVALID, $response->getContent()); - $this->assertContains('bad', $response->getContent()); + $application->run(); + $this->assertContains( + 'foobar', + $this->application->getResponse()->getBody(), + 'The "finish" event was not triggered ("foobar" not in response)' + ); } /** @@ -447,20 +365,20 @@ public function testInvalidControllerTypeShouldTriggerDispatchError() */ public function testRoutingFailureShouldTriggerDispatchError() { - $this->setupBadController(); - $router = new Router\SimpleRouteStack(); - $event = $this->application->getMvcEvent(); + $application = $this->setupBadController(); + $router = new Router\SimpleRouteStack(); + $event = $application->getMvcEvent(); $event->setRouter($router); - $response = $this->application->getResponse(); - $events = $this->application->getEventManager(); + $response = $application->getResponse(); + $events = $application->getEventManager(); $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($response) { $error = $e->getError(); $response->setContent("Code: " . $error); return $response; }); - $this->application->run(); + $application->run(); $this->assertTrue($event->isError()); $this->assertContains(Application::ERROR_ROUTER_NO_MATCH, $response->getContent()); } @@ -470,15 +388,15 @@ public function testRoutingFailureShouldTriggerDispatchError() */ public function testLocatorExceptionShouldTriggerDispatchError() { - $this->setupPathController(false); - $controllerLoader = $this->serviceManager->get('ControllerLoader'); + $application = $this->setupPathController(false); + $controllerLoader = $application->getServiceManager()->get('ControllerManager'); $response = new Response(); - $this->application->getEventManager()->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($response) { + $application->getEventManager()->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($response) { return $response; }); - $result = $this->application->run(); - $this->assertSame($this->application, $result, get_class($result)); + $result = $application->run(); + $this->assertSame($application, $result, get_class($result)); $this->assertSame($response, $result->getResponse(), get_class($result)); } @@ -487,20 +405,20 @@ public function testLocatorExceptionShouldTriggerDispatchError() */ public function testFailureForRouteToReturnRouteMatchShouldPopulateEventError() { - $this->setupBadController(); - $router = new Router\SimpleRouteStack(); - $event = $this->application->getMvcEvent(); + $application = $this->setupBadController(); + $router = new Router\SimpleRouteStack(); + $event = $application->getMvcEvent(); $event->setRouter($router); - $response = $this->application->getResponse(); - $events = $this->application->getEventManager(); + $response = $application->getResponse(); + $events = $application->getEventManager(); $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($response) { $error = $e->getError(); $response->setContent("Code: " . $error); return $response; }); - $this->application->run(); + $application->run(); $this->assertTrue($event->isError()); $this->assertEquals(Application::ERROR_ROUTER_NO_MATCH, $event->getError()); } @@ -552,30 +470,30 @@ public function testFinishShouldRunEvenIfDispatchEventReturnsResponse() public function testApplicationShouldBeEventTargetAtFinishEvent() { - $this->setupActionController(); + $application = $this->setupActionController(); - $events = $this->application->getEventManager(); - $response = $this->application->getResponse(); + $events = $application->getEventManager(); + $response = $application->getResponse(); $events->attach(MvcEvent::EVENT_FINISH, function ($e) use ($response) { $response->setContent("EventClass: " . get_class($e->getTarget())); return $response; }); - $this->application->run(); + $application->run(); $this->assertContains('Zend\Mvc\Application', $response->getContent()); } public function testOnDispatchErrorEventPassedToTriggersShouldBeTheOriginalOne() { - $this->setupPathController(false); - $controllerLoader = $this->serviceManager->get('ControllerLoader'); + $application = $this->setupPathController(false); + $controllerManager = $application->getServiceManager()->get('ControllerManager'); $model = $this->getMock('Zend\View\Model\ViewModel'); - $this->application->getEventManager()->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($model) { + $application->getEventManager()->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use ($model) { $e->setResult($model); }); - $this->application->run(); - $event = $this->application->getMvcEvent(); + $application->run(); + $event = $application->getMvcEvent(); $this->assertInstanceOf('Zend\View\Model\ViewModel', $event->getResult()); } @@ -631,13 +549,12 @@ public function testReturnsResponseFromListenerWhenDispatchEventShortCircuits() public function testCompleteRequestShouldReturnApplicationInstance() { - $r = new ReflectionObject($this->application); - $method = $r->getMethod('completeRequest'); - $method->setAccessible(true); + $r = new ReflectionMethod($this->application, 'completeRequest'); + $r->setAccessible(true); $this->application->bootstrap(); $event = $this->application->getMvcEvent(); - $result = $method->invoke($this->application, $event); + $result = $r->invoke($this->application, $event); $this->assertSame($this->application, $result); } @@ -724,10 +641,9 @@ public function testEventPropagationStatusIsClearedBetweenEventsDuringRun($event $event->stopPropagation(true); // Intentionally not calling bootstrap; setting mvc event - $r = new ReflectionObject($this->application); - $eventProp = $r->getProperty('event'); - $eventProp->setAccessible(true); - $eventProp->setValue($this->application, $event); + $r = new ReflectionProperty($this->application, 'event'); + $r->setAccessible(true); + $r->setValue($this->application, $event); // Setup listeners that stop propagation, but do nothing else $marker = []; diff --git a/test/Controller/AbstractControllerTest.php b/test/Controller/AbstractControllerTest.php index ec922fcd8..4b18a4eeb 100644 --- a/test/Controller/AbstractControllerTest.php +++ b/test/Controller/AbstractControllerTest.php @@ -99,8 +99,7 @@ public function testSetEventManagerWithDefaultIdentifiersIncludesImplementedInte ->with($this->logicalAnd( $this->contains('Zend\\EventManager\\EventManagerAwareInterface'), $this->contains('Zend\\Stdlib\\DispatchableInterface'), - $this->contains('Zend\\Mvc\\InjectApplicationEventInterface'), - $this->contains('Zend\\ServiceManager\\ServiceLocatorAwareInterface') + $this->contains('Zend\\Mvc\\InjectApplicationEventInterface') )); $this->controller->setEventManager($eventManager); diff --git a/test/Controller/ActionControllerTest.php b/test/Controller/ActionControllerTest.php index a7a336d76..5c51cc77a 100644 --- a/test/Controller/ActionControllerTest.php +++ b/test/Controller/ActionControllerTest.php @@ -18,6 +18,7 @@ use Zend\Mvc\Controller\PluginManager; use Zend\Mvc\MvcEvent; use Zend\Mvc\Router\RouteMatch; +use Zend\ServiceManager\ServiceManager; class ActionControllerTest extends TestCase { @@ -160,11 +161,6 @@ public function testDispatchInjectsEventIntoController() $this->assertSame($this->event, $event); } - public function testControllerIsLocatorAware() - { - $this->assertInstanceOf('Zend\ServiceManager\ServiceLocatorAwareInterface', $this->controller); - } - public function testControllerIsEventAware() { $this->assertInstanceOf('Zend\Mvc\InjectApplicationEventInterface', $this->controller); @@ -190,7 +186,7 @@ public function testPluginManagerComposesController() public function testInjectingPluginManagerSetsControllerWhenPossible() { - $plugins = new PluginManager(); + $plugins = new PluginManager(new ServiceManager()); $this->assertNull($plugins->getController()); $this->controller->setPluginManager($plugins); $this->assertSame($this->controller, $plugins->getController()); diff --git a/test/Controller/ControllerManagerTest.php b/test/Controller/ControllerManagerTest.php index 302cab80f..d9336bdd1 100644 --- a/test/Controller/ControllerManagerTest.php +++ b/test/Controller/ControllerManagerTest.php @@ -21,30 +21,30 @@ class ControllerManagerTest extends TestCase { public function setUp() { - $this->sharedEvents = new SharedEventManager; - $this->events = new EventManager($this->sharedEvents); - + $this->sharedEvents = new SharedEventManager; + $this->events = new EventManager($this->sharedEvents); $this->consoleAdapter = new ConsoleAdapter(); - $this->plugins = new ControllerPluginManager(); - $this->services = new ServiceManager(); - $this->services->setService('Console', $this->consoleAdapter); - $this->services->setService('Zend\ServiceManager\ServiceLocatorInterface', $this->services); - $this->services->setService('EventManager', $this->events); - $this->services->setService('SharedEventManager', $this->sharedEvents); - $this->services->setService('ControllerPluginManager', $this->plugins); + $this->services = new ServiceManager([ + 'factories' => [ + 'ControllerPluginManager' => function ($services) { + return new ControllerPluginManager($services); + }, + ], + 'services' => [ + 'Console' => $this->consoleAdapter, + 'EventManager' => $this->events, + 'SharedEventManager' => $this->sharedEvents, + ], + ]); - $this->controllers = new ControllerManager(); - $this->controllers->setServiceLocator($this->services); - $this->controllers->addPeeringServiceManager($this->services); + $this->controllers = new ControllerManager($this->services); } - public function testInjectControllerDependenciesInjectsExpectedDependencies() + public function testCanInjectEventManager() { $controller = new TestAsset\SampleController(); - $this->controllers->injectControllerDependencies($controller, $this->controllers); - $this->assertSame($this->services, $controller->getServiceLocator()); - $this->assertSame($this->plugins, $controller->getPluginManager()); + $this->controllers->injectEventManager($this->services, $controller); // The default AbstractController implementation lazy instantiates an EM // instance, which means we need to check that that instance gets injected @@ -54,19 +54,26 @@ public function testInjectControllerDependenciesInjectsExpectedDependencies() $this->assertSame($this->sharedEvents, $events->getSharedManager()); } - public function testInjectControllerDependenciesToConsoleController() + public function testCanInjectConsoleAdapter() { $controller = new TestAsset\ConsoleController(); - $this->controllers->injectControllerDependencies($controller, $this->controllers); + $this->controllers->injectConsole($this->services, $controller); $this->assertInstanceOf('Zend\Console\Adapter\AdapterInterface', $controller->getConsole()); } - public function testInjectControllerDependenciesWillNotOverwriteExistingEventManager() + public function testCanInjectPluginManager() + { + $controller = new TestAsset\SampleController(); + $this->controllers->injectPluginManager($this->services, $controller); + $this->assertSame($this->services->get('ControllerPluginManager'), $controller->getPluginManager()); + } + + public function testInjectEventManagerWillNotOverwriteExistingEventManagerIfItAlreadyHasASharedManager() { $events = new EventManager($this->sharedEvents); $controller = new TestAsset\SampleController(); $controller->setEventManager($events); - $this->controllers->injectControllerDependencies($controller, $this->controllers); + $this->controllers->injectEventManager($this->services, $controller); $this->assertSame($events, $controller->getEventManager()); $this->assertSame($this->sharedEvents, $events->getSharedManager()); } diff --git a/test/Controller/IntegrationTest.php b/test/Controller/IntegrationTest.php index 39ecea1dd..4c4bdfe75 100644 --- a/test/Controller/IntegrationTest.php +++ b/test/Controller/IntegrationTest.php @@ -20,27 +20,39 @@ class IntegrationTest extends TestCase { public function setUp() { - $this->plugins = new PluginManager(); - $this->sharedEvents = $sharedEvents = new SharedEventManager(); - $this->services = new ServiceManager(); - $this->services->setService('ControllerPluginManager', $this->plugins); - $this->services->setService('SharedEventManager', $this->sharedEvents); - $this->services->setService('Zend\ServiceManager\ServiceLocatorInterface', $this->services); - $this->services->setFactory('EventManager', function ($services) use ($sharedEvents) { - return new EventManager($sharedEvents); - }); - - $this->controllers = new ControllerManager(); - $this->controllers->setServiceLocator($this->services); + $this->sharedEvents = new SharedEventManager(); + + $this->services = new ServiceManager([ + 'services' => [ + 'SharedEventManager' => $this->sharedEvents, + ], + 'factories' => [ + 'ControllerPluginManager' => function ($services) { + return new PluginManager($services); + }, + 'EventManager' => function () { + return new EventManager($this->sharedEvents); + }, + ], + 'shared' => [ + 'EventManager' => false, + ], + ]); } public function testPluginReceivesCurrentController() { - $this->controllers->setInvokableClass('first', 'ZendTest\Mvc\Controller\TestAsset\SampleController'); - $this->controllers->setInvokableClass('second', 'ZendTest\Mvc\Controller\TestAsset\SampleController'); + $controllers = new ControllerManager($this->services, ['factories' => [ + 'first' => function ($services) { + return new TestAsset\SampleController(); + }, + 'second' => function ($services) { + return new TestAsset\SampleController(); + }, + ]]); - $first = $this->controllers->get('first'); - $second = $this->controllers->get('second'); + $first = $controllers->get('first'); + $second = $controllers->get('second'); $this->assertNotSame($first, $second); $plugin1 = $first->plugin('url'); diff --git a/test/Controller/Plugin/FilePostRedirectGetTest.php b/test/Controller/Plugin/FilePostRedirectGetTest.php index da8677683..8db119140 100644 --- a/test/Controller/Plugin/FilePostRedirectGetTest.php +++ b/test/Controller/Plugin/FilePostRedirectGetTest.php @@ -37,6 +37,8 @@ class FilePostRedirectGetTest extends TestCase public function setUp() { + $this->markTestIncomplete('Re-enable when zend-form has been updated to zend-servicemanager v3'); + $this->form = new Form(); $this->collection = new Collection('links', [ diff --git a/test/Controller/Plugin/ForwardTest.php b/test/Controller/Plugin/ForwardTest.php index 8af5c829a..c4211acac 100644 --- a/test/Controller/Plugin/ForwardTest.php +++ b/test/Controller/Plugin/ForwardTest.php @@ -20,10 +20,10 @@ use Zend\Mvc\Controller\Plugin\Forward as ForwardPlugin; use Zend\Mvc\MvcEvent; use Zend\Mvc\Router\RouteMatch; +use Zend\ServiceManager\ServiceManager; use ZendTest\Mvc\Controller\TestAsset\ForwardController; use ZendTest\Mvc\Controller\TestAsset\SampleController; use ZendTest\Mvc\Controller\TestAsset\UneventfulController; -use ZendTest\Mvc\TestAsset\Locator; class ForwardTest extends TestCase { @@ -62,41 +62,44 @@ public function setUp() $routeMatch->setMatchedRouteName('some-route'); $event->setRouteMatch($routeMatch); - $services = new Locator(); - $plugins = $this->plugins = new PluginManager(); - $plugins->setServiceLocator($services); - - $controllers = $this->controllers = new ControllerManager(); - $controllers->setFactory('forward', function () use ($plugins) { - $controller = new ForwardController(); - $controller->setPluginManager($plugins); - return $controller; - }); - $controllers->setServiceLocator($services); - $controllerLoader = function () use ($controllers) { - return $controllers; - }; - $services->add('ControllerLoader', $controllerLoader); - $services->add('ControllerManager', $controllerLoader); - $services->add('ControllerPluginManager', function () use ($plugins) { - return $plugins; - }); - $services->add('Zend\ServiceManager\ServiceLocatorInterface', function () use ($services) { - return $services; - }); - $services->add('EventManager', function () use ($eventManager) { - return new EventManager($eventManager->getSharedManager()); - }); - $services->add('SharedEventManager', function () use ($eventManager) { - return $eventManager->getSharedManager(); - }); + $this->services = $services = new ServiceManager([ + 'aliases' => [ + 'ControllerLoader' => 'ControllerManager', + ], + 'factories' => [ + 'ControllerManager' => function ($services, $name) { + $plugins = $services->get('ControllerPluginManager'); + return new ControllerManager($services, ['factories' => [ + 'forward' => function ($services) use ($plugins) { + $controller = new ForwardController(); + $controller->setPluginManager($plugins); + return $controller; + }, + ]]); + }, + 'ControllerPluginManager' => function ($services, $name) { + return new PluginManager($services); + }, + 'EventManager' => function ($services, $name) { + return new EventManager($services->get('SharedEventManager')); + }, + 'SharedEventManager' => function ($services, $name) { + return new SharedEventManager(); + }, + ], + 'shared' => [ + 'EventManager' => false, + ], + ]); + + $this->controllers = $services->get('ControllerManager'); + $plugins = $services->get('ControllerPluginManager'); $this->controller = new SampleController(); $this->controller->setEvent($event); - $this->controller->setServiceLocator($services); $this->controller->setPluginManager($plugins); - $this->plugin = $this->controller->plugin('forward'); + $this->plugin = $plugins->get('forward'); } public function testPluginWithoutEventAwareControllerRaisesDomainException() @@ -117,20 +120,66 @@ public function testPluginWithoutControllerLocatorRaisesServiceNotCreatedExcepti public function testDispatchRaisesDomainExceptionIfDiscoveredControllerIsNotDispatchable() { - $locator = $this->controller->getServiceLocator(); - $locator->add('bogus', function () { - return new stdClass; - }); - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); - $this->plugin->dispatch('bogus'); + $controllers = $this->controllers->withConfig(['factories' => [ + 'bogus' => function () { + return new stdClass; + }, + ]]); + $plugin = new ForwardPlugin($controllers); + $plugin->setController($this->controller); + + $this->setExpectedException('Zend\ServiceManager\Exception\InvalidServiceException', 'DispatchableInterface'); + $plugin->dispatch('bogus'); } public function testDispatchRaisesDomainExceptionIfCircular() { + $event = $this->controller->getEvent(); + + $services = new ServiceManager([ + 'aliases' => [ + 'ControllerLoader' => 'ControllerManager', + ], + 'factories' => [ + 'ControllerManager' => function ($services) use ($event) { + $plugins = $services->get('ControllerPluginManager'); + + return new ControllerManager($services, ['factories' => [ + 'forward' => function ($services) use ($plugins) { + $controller = new ForwardController(); + $controller->setPluginManager($plugins); + return $controller; + }, + 'sample' => function ($services) use ($event, $plugins) { + $controller = new SampleController(); + $controller->setEvent($event); + $controller->setPluginManager($plugins); + return $controller; + }, + ]]); + }, + 'ControllerPluginManager' => function ($services) { + return new PluginManager($services); + }, + 'EventManager' => function ($services, $name) { + return new EventManager($services->get('SharedEventManager')); + }, + 'SharedEventManager' => function ($services, $name) { + return new SharedEventManager(); + }, + ], + 'shared' => [ + 'EventManager' => false, + ], + ]); + + $controllers = $services->get('ControllerManager'); + + $forward = new ForwardPlugin($controllers); + $forward->setController($controllers->get('sample')); + $this->setExpectedException('Zend\Mvc\Exception\DomainException', 'Circular forwarding'); - $sampleController = $this->controller; - $this->controllers->setService('sample', $sampleController); - $this->plugin->dispatch('sample', ['action' => 'test-circular']); + $forward->dispatch('sample', ['action' => 'test-circular']); } public function testPluginDispatchsRequestedControllerWhenFound() @@ -145,7 +194,7 @@ public function testPluginDispatchsRequestedControllerWhenFound() */ public function testNonArrayListenerDoesNotRaiseErrorWhenPluginDispatchsRequestedController() { - $services = $this->plugins->getServiceLocator(); + $services = $this->services; $events = $services->get('EventManager'); $sharedEvents = $this->getMock('Zend\EventManager\SharedEventManagerInterface'); // @codingStandardsIgnoreStart diff --git a/test/Controller/Plugin/TestAsset/SamplePluginFactory.php b/test/Controller/Plugin/TestAsset/SamplePluginFactory.php index 99f2bcec7..a410b271a 100644 --- a/test/Controller/Plugin/TestAsset/SamplePluginFactory.php +++ b/test/Controller/Plugin/TestAsset/SamplePluginFactory.php @@ -9,12 +9,12 @@ namespace ZendTest\Mvc\Controller\Plugin\TestAsset; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; class SamplePluginFactory implements FactoryInterface { - public function createService(ServiceLocatorInterface $serviceLocator) + public function __invoke(ContainerInterface $container, $name, array $options = null) { return new SamplePlugin(); } diff --git a/test/Controller/Plugin/TestAsset/SamplePluginWithConstructorFactory.php b/test/Controller/Plugin/TestAsset/SamplePluginWithConstructorFactory.php index b251e669d..4e37df4e0 100644 --- a/test/Controller/Plugin/TestAsset/SamplePluginWithConstructorFactory.php +++ b/test/Controller/Plugin/TestAsset/SamplePluginWithConstructorFactory.php @@ -9,20 +9,15 @@ namespace ZendTest\Mvc\Controller\Plugin\TestAsset; -use Zend\ServiceManager\FactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; class SamplePluginWithConstructorFactory implements FactoryInterface { protected $options; - public function __construct($options) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - $this->options = $options; - } - - public function createService(ServiceLocatorInterface $serviceLocator) - { - return new SamplePluginWithConstructor($this->options); + return new SamplePluginWithConstructor($options); } } diff --git a/test/Controller/PluginManagerTest.php b/test/Controller/PluginManagerTest.php index 0c39a4fc3..582e214d5 100644 --- a/test/Controller/PluginManagerTest.php +++ b/test/Controller/PluginManagerTest.php @@ -10,28 +10,20 @@ namespace ZendTest\Mvc\Controller; use PHPUnit_Framework_TestCase as TestCase; -use ZendTest\Mvc\Controller\TestAsset\SampleController; -use ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePlugin; +use Zend\Authentication\AuthenticationService; use Zend\Mvc\Controller\PluginManager; use Zend\ServiceManager\ServiceManager; +use ZendTest\Mvc\Controller\TestAsset\SampleController; +use ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePlugin; class PluginManagerTest extends TestCase { - public function testPluginManagerThrowsExceptionForMissingPluginInterface() - { - $this->setExpectedException('Zend\Mvc\Exception\InvalidPluginException'); - - $pluginManager = new PluginManager; - $pluginManager->setInvokableClass('samplePlugin', 'stdClass'); - - $plugin = $pluginManager->get('samplePlugin'); - } - public function testPluginManagerInjectsControllerInPlugin() { $controller = new SampleController; - $pluginManager = new PluginManager; - $pluginManager->setInvokableClass('samplePlugin', 'ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePlugin'); + $pluginManager = new PluginManager(new ServiceManager(), [ + 'invokables' => ['samplePlugin' => SamplePlugin::class], + ]); $pluginManager->setController($controller); $plugin = $pluginManager->get('samplePlugin'); @@ -41,8 +33,9 @@ public function testPluginManagerInjectsControllerInPlugin() public function testPluginManagerInjectsControllerForExistingPlugin() { $controller1 = new SampleController; - $pluginManager = new PluginManager; - $pluginManager->setInvokableClass('samplePlugin', 'ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePlugin'); + $pluginManager = new PluginManager(new ServiceManager(), [ + 'invokables' => ['samplePlugin' => SamplePlugin::class], + ]); $pluginManager->setController($controller1); // Plugin manager registers now instance of SamplePlugin @@ -55,53 +48,63 @@ public function testPluginManagerInjectsControllerForExistingPlugin() $this->assertEquals($controller2, $plugin->getController()); } - public function testGetWithConstrutor() + public function testGetWithConstructor() { - $pluginManager = new PluginManager; - $pluginManager->setInvokableClass('samplePlugin', 'ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePluginWithConstructor'); + $pluginManager = new PluginManager(new ServiceManager(), [ + 'invokables' => ['samplePlugin' => Plugin\TestAsset\SamplePluginWithConstructor::class], + ]); $plugin = $pluginManager->get('samplePlugin'); $this->assertEquals($plugin->getBar(), 'baz'); } - public function testGetWithConstrutorAndOptions() + public function testGetWithConstructorAndOptions() { - $pluginManager = new PluginManager; - $pluginManager->setInvokableClass('samplePlugin', 'ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePluginWithConstructor'); - $plugin = $pluginManager->get('samplePlugin', 'foo'); - $this->assertEquals($plugin->getBar(), 'foo'); + $pluginManager = new PluginManager(new ServiceManager(), [ + 'invokables' => ['samplePlugin' => Plugin\TestAsset\SamplePluginWithConstructor::class], + ]); + $plugin = $pluginManager->get('samplePlugin', ['foo']); + $this->assertEquals($plugin->getBar(), ['foo']); } public function testDefinesFactoryForIdentityPlugin() { - $pluginManager = new PluginManager; + $pluginManager = new PluginManager(new ServiceManager()); $this->assertTrue($pluginManager->has('identity')); } public function testIdentityFactoryCanInjectAuthenticationServiceIfInParentServiceManager() { - $services = new ServiceManager(); - $services->setInvokableClass('Zend\Authentication\AuthenticationService', 'Zend\Authentication\AuthenticationService'); - $pluginManager = new PluginManager; - $pluginManager->setServiceLocator($services); + $services = new ServiceManager([ + 'invokables' => [ + AuthenticationService::class => AuthenticationService::class, + ], + ]); + $pluginManager = new PluginManager($services); $identity = $pluginManager->get('identity'); - $expected = $services->get('Zend\Authentication\AuthenticationService'); + $expected = $services->get(AuthenticationService::class); $this->assertSame($expected, $identity->getAuthenticationService()); } public function testCanCreateByFactory() { - $pluginManager = new PluginManager; - $pluginManager->setFactory('samplePlugin', 'ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePluginFactory'); + $pluginManager = new PluginManager(new ServiceManager(), [ + 'factories' => [ + 'samplePlugin' => Plugin\TestAsset\SamplePluginFactory::class, + ] + ]); $plugin = $pluginManager->get('samplePlugin'); - $this->assertInstanceOf('\ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePlugin', $plugin); + $this->assertInstanceOf(SamplePlugin::class, $plugin); } public function testCanCreateByFactoryWithConstrutor() { - $pluginManager = new PluginManager; - $pluginManager->setFactory('samplePlugin', 'ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePluginWithConstructorFactory'); - $plugin = $pluginManager->get('samplePlugin', 'foo'); - $this->assertInstanceOf('\ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePluginWithConstructor', $plugin); - $this->assertEquals($plugin->getBar(), 'foo'); + $pluginManager = new PluginManager(new ServiceManager(), [ + 'factories' => [ + 'samplePlugin' => Plugin\TestAsset\SamplePluginWithConstructorFactory::class, + ], + ]); + $plugin = $pluginManager->get('samplePlugin', ['foo']); + $this->assertInstanceOf(Plugin\TestAsset\SamplePluginWithConstructor::class, $plugin); + $this->assertEquals($plugin->getBar(), ['foo']); } } diff --git a/test/Controller/RestfulControllerTest.php b/test/Controller/RestfulControllerTest.php index f9df8a677..99cc1efb7 100644 --- a/test/Controller/RestfulControllerTest.php +++ b/test/Controller/RestfulControllerTest.php @@ -341,11 +341,6 @@ public function testDispatchInjectsEventIntoController() $this->assertSame($this->event, $event); } - public function testControllerIsLocatorAware() - { - $this->assertInstanceOf('Zend\ServiceManager\ServiceLocatorAwareInterface', $this->controller); - } - public function testControllerIsEventAware() { $this->assertInstanceOf('Zend\Mvc\InjectApplicationEventInterface', $this->controller); diff --git a/test/Controller/TestAsset/ControllerLoaderAbstractFactory.php b/test/Controller/TestAsset/ControllerLoaderAbstractFactory.php index 9dc280d44..9dd3c3a82 100644 --- a/test/Controller/TestAsset/ControllerLoaderAbstractFactory.php +++ b/test/Controller/TestAsset/ControllerLoaderAbstractFactory.php @@ -9,8 +9,8 @@ namespace ZendTest\Mvc\Controller\TestAsset; -use Zend\ServiceManager\AbstractFactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\AbstractFactoryInterface; class ControllerLoaderAbstractFactory implements AbstractFactoryInterface { @@ -18,16 +18,19 @@ class ControllerLoaderAbstractFactory implements AbstractFactoryInterface 'path' => 'ZendTest\Mvc\TestAsset\PathController', ); - public function canCreateServiceWithName(ServiceLocatorInterface $sl, $cName, $rName) + public function canCreateServiceWithName(ContainerInterface $container, $name) { - $classname = $this->classmap[$cName]; + if (! isset($this->classmap[$name])) { + return false; + } + + $classname = $this->classmap[$name]; return class_exists($classname); } - public function createServiceWithName(ServiceLocatorInterface $sl, $cName, $rName) + public function __invoke(ContainerInterface $container, $name, array $options = null) { - $classname = $this->classmap[$cName]; - $controller = new $classname; - return $controller; + $classname = $this->classmap[$name]; + return new $classname; } } diff --git a/test/Controller/TestAsset/UnlocatableControllerLoaderAbstractFactory.php b/test/Controller/TestAsset/UnlocatableControllerLoaderAbstractFactory.php index f31b8da53..5ab69f451 100644 --- a/test/Controller/TestAsset/UnlocatableControllerLoaderAbstractFactory.php +++ b/test/Controller/TestAsset/UnlocatableControllerLoaderAbstractFactory.php @@ -9,17 +9,17 @@ namespace ZendTest\Mvc\Controller\TestAsset; -use Zend\ServiceManager\AbstractFactoryInterface; -use Zend\ServiceManager\ServiceLocatorInterface; +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\AbstractFactoryInterface; class UnlocatableControllerLoaderAbstractFactory implements AbstractFactoryInterface { - public function canCreateServiceWithName(ServiceLocatorInterface $sl, $cName, $rName) + public function canCreateServiceWithName(ContainerInterface $container, $name) { return false; } - public function createServiceWithName(ServiceLocatorInterface $sl, $cName, $rName) + public function __invoke(ContainerInterface $container, $name, array $options = null) { } } diff --git a/test/DispatchListenerTest.php b/test/DispatchListenerTest.php index d7b84d614..1cb9bb6ba 100644 --- a/test/DispatchListenerTest.php +++ b/test/DispatchListenerTest.php @@ -10,57 +10,20 @@ namespace ZendTest\Mvc; use PHPUnit_Framework_TestCase as TestCase; +use Zend\EventManager\EventManager; +use Zend\Http\Request; +use Zend\Http\Response; use Zend\Mvc\Application; +use Zend\Mvc\Controller\ControllerManager; +use Zend\Mvc\DispatchListener; use Zend\Mvc\MvcEvent; -use Zend\Mvc\Router; -use Zend\Mvc\Service\ServiceManagerConfig; -use Zend\Mvc\Service\ServiceListenerFactory; +use Zend\Mvc\Router\RouteMatch; use Zend\ServiceManager\ServiceManager; -use Zend\Stdlib\ArrayUtils; class DispatchListenerTest extends TestCase { - /** - * @var ServiceManager - */ - protected $serviceManager; - - /** - * @var Application - */ - protected $application; - public function setUp() { - $serviceConfig = ArrayUtils::merge( - $this->readAttribute(new ServiceListenerFactory, 'defaultServiceConfig'), - [ - 'allow_override' => true, - 'invokables' => [ - 'Request' => 'Zend\Http\PhpEnvironment\Request', - 'Response' => 'Zend\Http\PhpEnvironment\Response', - 'ViewManager' => 'ZendTest\Mvc\TestAsset\MockViewManager', - 'SendResponseListener' => 'ZendTest\Mvc\TestAsset\MockSendResponseListener', - 'BootstrapListener' => 'ZendTest\Mvc\TestAsset\StubBootstrapListener', - ], - 'aliases' => [ - 'Router' => 'HttpRouter', - ], - 'services' => [ - 'Config' => [], - 'ApplicationConfig' => [ - 'modules' => [], - 'module_listener_options' => [ - 'config_cache_enabled' => false, - 'cache_dir' => 'data/cache', - 'module_paths' => [], - ], - ], - ], - ] - ); - $this->serviceManager = new ServiceManager(new ServiceManagerConfig($serviceConfig)); - $this->application = $this->serviceManager->get('Application'); } public function setupPathController() @@ -79,45 +42,63 @@ public function setupPathController() $this->application->bootstrap(); } + public function createMvcEvent($controllerMatched) + { + $response = new Response(); + $routeMatch = $this->prophesize(RouteMatch::class); + $routeMatch->getParam('controller', 'not-found')->willReturn('path'); + + $eventManager = new EventManager(); + + $application = $this->prophesize(Application::class); + $application->getEventManager()->willReturn($eventManager); + $application->getResponse()->willReturn($response); + + $event = new MvcEvent(); + $event->setRequest(new Request()); + $event->setResponse($response); + $event->setApplication($application->reveal()); + $event->setRouteMatch($routeMatch->reveal()); + + return $event; + } + public function testControllerLoaderComposedOfAbstractFactory() { - $this->setupPathController(); + $controllerManager = new ControllerManager(new ServiceManager(), ['abstract_factories' => [ + Controller\TestAsset\ControllerLoaderAbstractFactory::class, + ]]); + $listener = new DispatchListener($controllerManager); - $controllerLoader = $this->serviceManager->get('ControllerLoader'); - $controllerLoader->addAbstractFactory('ZendTest\Mvc\Controller\TestAsset\ControllerLoaderAbstractFactory'); + $event = $this->createMvcEvent('path'); $log = []; - $this->application->getEventManager()->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use (&$log) { + $event->getApplication()->getEventManager()->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use (&$log) { $log['error'] = $e->getError(); }); - $this->application->run(); - - $event = $this->application->getMvcEvent(); - $dispatchListener = $this->serviceManager->get('DispatchListener'); - $return = $dispatchListener->onDispatch($event); + $return = $listener->onDispatch($event); - $this->assertEmpty($log); - $this->assertInstanceOf('Zend\Http\PhpEnvironment\Response', $return); + $this->assertEmpty($log, var_export($log, 1)); + $this->assertSame($event->getResponse(), $return); $this->assertSame(200, $return->getStatusCode()); } public function testUnlocatableControllerLoaderComposedOfAbstractFactory() { - $this->setupPathController(); + $controllerManager = new ControllerManager(new ServiceManager(), ['abstract_factories' => [ + Controller\TestAsset\UnlocatableControllerLoaderAbstractFactory::class, + ]]); + $listener = new DispatchListener($controllerManager); - $controllerLoader = $this->serviceManager->get('ControllerLoader'); - $controllerLoader->addAbstractFactory('ZendTest\Mvc\Controller\TestAsset\UnlocatableControllerLoaderAbstractFactory'); + $event = $this->createMvcEvent('path'); $log = []; - $this->application->getEventManager()->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use (&$log) { + $event->getApplication()->getEventManager()->attach(MvcEvent::EVENT_DISPATCH_ERROR, function ($e) use (&$log) { $log['error'] = $e->getError(); }); - $this->application->run(); - $event = $this->application->getMvcEvent(); - $dispatchListener = $this->serviceManager->get('DispatchListener'); - $return = $dispatchListener->onDispatch($event); + $return = $listener->onDispatch($event); $this->assertArrayHasKey('error', $log); $this->assertSame('error-controller-not-found', $log['error']); diff --git a/test/Router/Http/ChainTest.php b/test/Router/Http/ChainTest.php index 3d161d358..ce2f5168a 100644 --- a/test/Router/Http/ChainTest.php +++ b/test/Router/Http/ChainTest.php @@ -13,13 +13,14 @@ use Zend\Http\Request as Request; use Zend\Mvc\Router\RoutePluginManager; use Zend\Mvc\Router\Http\Chain; +use Zend\ServiceManager\ServiceManager; use ZendTest\Mvc\Router\FactoryTester; class ChainTest extends TestCase { public static function getRoute() { - $routePlugins = new RoutePluginManager(); + $routePlugins = new RoutePluginManager(new ServiceManager()); return new Chain( [ @@ -51,7 +52,7 @@ public static function getRoute() public static function getRouteWithOptionalParam() { - $routePlugins = new RoutePluginManager(); + $routePlugins = new RoutePluginManager(new ServiceManager()); return new Chain( [ @@ -192,7 +193,7 @@ public function testFactory() ], [ 'routes' => [], - 'route_plugins' => new RoutePluginManager(), + 'route_plugins' => new RoutePluginManager(new ServiceManager()), ] ); } diff --git a/test/Router/Http/PartTest.php b/test/Router/Http/PartTest.php index b4bd0be43..6aeaf7ba7 100644 --- a/test/Router/Http/PartTest.php +++ b/test/Router/Http/PartTest.php @@ -13,18 +13,37 @@ use PHPUnit_Framework_TestCase as TestCase; use Zend\Http\Request as Request; use Zend\Mvc\Router\RoutePluginManager; +use Zend\Mvc\Router\Http\Literal; use Zend\Mvc\Router\Http\Part; +use Zend\Mvc\Router\Http\Segment; +use Zend\Mvc\Router\Http\Wildcard; +use Zend\ServiceManager\ServiceManager; use Zend\Stdlib\Parameters; use Zend\Stdlib\Request as BaseRequest; use ZendTest\Mvc\Router\FactoryTester; class PartTest extends TestCase { - public static function getRoute() + public static function getRoutePlugins() { - $routePlugins = new RoutePluginManager(); - $routePlugins->setInvokableClass('part', 'Zend\Mvc\Router\Http\Part'); + return new RoutePluginManager(new ServiceManager(), [ + 'aliases' => [ + 'Literal' => 'literal', + 'Part' => 'part', + 'Segment' => 'segment', + 'Wildcard' => 'wildcard', + ], + 'invokables' => [ + 'literal' => Literal::class, + 'part' => Part::class, + 'segment' => Segment::class, + 'wildcard' => Wildcard::class, + ], + ]); + } + public static function getRoute() + { return new Part( [ 'type' => 'Zend\Mvc\Router\Http\Literal', @@ -36,7 +55,7 @@ public static function getRoute() ] ], true, - $routePlugins, + self::getRoutePlugins(), [ 'bar' => [ 'type' => 'Zend\Mvc\Router\Http\Literal', @@ -97,9 +116,6 @@ public static function getRoute() public static function getRouteAlternative() { - $routePlugins = new RoutePluginManager(); - $routePlugins->setInvokableClass('part', 'Zend\Mvc\Router\Http\Part'); - return new Part( [ 'type' => 'Zend\Mvc\Router\Http\Segment', @@ -112,7 +128,7 @@ public static function getRouteAlternative() ] ], true, - $routePlugins, + self::getRoutePlugins(), [ 'wildcard' => [ 'type' => 'Zend\Mvc\Router\Http\Wildcard', @@ -315,7 +331,7 @@ public function testBaseRouteMayNotBePartRoute() { $this->setExpectedException('Zend\Mvc\Router\Exception\InvalidArgumentException', 'Base route may not be a part route'); - $route = new Part(self::getRoute(), true, new RoutePluginManager()); + $route = new Part(self::getRoute(), true, new RoutePluginManager(new ServiceManager())); } public function testNoMatchWithoutUriMethod() @@ -345,7 +361,7 @@ public function testFactory() ], [ 'route' => new \Zend\Mvc\Router\Http\Literal('/foo'), - 'route_plugins' => new RoutePluginManager() + 'route_plugins' => self::getRoutePlugins(), ] ); } @@ -378,7 +394,7 @@ public function testFactoryShouldAcceptTraversableChildRoutes() ], ], ], - 'route_plugins' => new RoutePluginManager(), + 'route_plugins' => self::getRoutePlugins(), 'may_terminate' => true, 'child_routes' => $children, ]; @@ -403,7 +419,7 @@ public function testPartRouteMarkedAsMayTerminateCanMatchWhenQueryStringPresent( ], ], ], - 'route_plugins' => new RoutePluginManager(), + 'route_plugins' => self::getRoutePlugins(), 'may_terminate' => true, 'child_routes' => [ 'child' => [ @@ -446,7 +462,7 @@ public function testPartRouteMarkedAsMayTerminateButWithQueryRouteChildWillMatch ], ], ], - 'route_plugins' => new RoutePluginManager(), + 'route_plugins' => self::getRoutePlugins(), 'may_terminate' => true, /* 'child_routes' => array( diff --git a/test/Router/Http/SegmentTest.php b/test/Router/Http/SegmentTest.php index 4c09e8d34..6ccec5419 100644 --- a/test/Router/Http/SegmentTest.php +++ b/test/Router/Http/SegmentTest.php @@ -21,21 +21,6 @@ class SegmentTest extends TestCase { public function routeProvider() { - $translator = new Translator(); - $translator->setLocale('en-US'); - $enLoader = $this->getMock('Zend\I18n\Translator\Loader\FileLoaderInterface'); - $deLoader = $this->getMock('Zend\I18n\Translator\Loader\FileLoaderInterface'); - $domainLoader = $this->getMock('Zend\I18n\Translator\Loader\FileLoaderInterface'); - $enLoader->expects($this->any())->method('load')->willReturn(new TextDomain(['fw' => 'framework'])); - $deLoader->expects($this->any())->method('load')->willReturn(new TextDomain(['fw' => 'baukasten'])); - $domainLoader->expects($this->any())->method('load')->willReturn(new TextDomain(['fw' => 'fw-alternative'])); - $translator->getPluginManager()->setService('test-en', $enLoader); - $translator->getPluginManager()->setService('test-de', $deLoader); - $translator->getPluginManager()->setService('test-domain', $domainLoader); - $translator->addTranslationFile('test-en', null, 'default', 'en-US'); - $translator->addTranslationFile('test-de', null, 'default', 'de-DE'); - $translator->addTranslationFile('test-domain', null, 'alternative', 'en-US'); - return [ 'simple-match' => [ new Segment('/:foo'), @@ -181,6 +166,33 @@ public function routeProvider() null, ['bar' => 'bar', 'baz' => 'baz'] ], + ]; + } + + public function l10nRouteProvider() + { + $this->markTestIncomplete( + 'Translation tests need to be updated once zend-i18n is updated for zend-servicemanager v3' + ); + + // @codingStandardsIgnoreStart + $translator = new Translator(); + $translator->setLocale('en-US'); + $enLoader = $this->getMock('Zend\I18n\Translator\Loader\FileLoaderInterface'); + $deLoader = $this->getMock('Zend\I18n\Translator\Loader\FileLoaderInterface'); + $domainLoader = $this->getMock('Zend\I18n\Translator\Loader\FileLoaderInterface'); + $enLoader->expects($this->any())->method('load')->willReturn(new TextDomain(['fw' => 'framework'])); + $deLoader->expects($this->any())->method('load')->willReturn(new TextDomain(['fw' => 'baukasten'])); + $domainLoader->expects($this->any())->method('load')->willReturn(new TextDomain(['fw' => 'fw-alternative'])); + $translator->getPluginManager()->setService('test-en', $enLoader); + $translator->getPluginManager()->setService('test-de', $deLoader); + $translator->getPluginManager()->setService('test-domain', $domainLoader); + $translator->addTranslationFile('test-en', null, 'default', 'en-US'); + $translator->addTranslationFile('test-de', null, 'default', 'de-DE'); + $translator->addTranslationFile('test-domain', null, 'alternative', 'en-US'); + // @codingStandardsIgnoreEnd + + return [ 'translate-with-default-locale' => [ new Segment('/{fw}', [], []), '/framework', @@ -291,6 +303,59 @@ public function testAssembling(Segment $route, $path, $offset, array $params = n } } + /** + * @dataProvider l10nRouteProvider + * @param Segment $route + * @param string $path + * @param integer $offset + * @param array $params + * @param array $options + */ + public function testMatchingWithL10n(Segment $route, $path, $offset, array $params = null, array $options = []) + { + $request = new Request(); + $request->setUri('http://example.com' . $path); + $match = $route->match($request, $offset, $options); + + if ($params === null) { + $this->assertNull($match); + } else { + $this->assertInstanceOf('Zend\Mvc\Router\Http\RouteMatch', $match); + + if ($offset === null) { + $this->assertEquals(strlen($path), $match->getLength()); + } + + foreach ($params as $key => $value) { + $this->assertEquals($value, $match->getParam($key)); + } + } + } + + /** + * @dataProvider l10nRouteProvider + * @param Segment $route + * @param string $path + * @param integer $offset + * @param array $params + * @param array $options + */ + public function testAssemblingWithL10n(Segment $route, $path, $offset, array $params = null, array $options = []) + { + if ($params === null) { + // Data which will not match are not tested for assembling. + return; + } + + $result = $route->assemble($params, $options); + + if ($offset !== null) { + $this->assertEquals($offset, strpos($path, $result, $offset)); + } else { + $this->assertEquals($path, $result); + } + } + /** * @dataProvider parseExceptionsProvider * @param string $route diff --git a/test/Router/Http/TranslatorAwareTreeRouteStackTest.php b/test/Router/Http/TranslatorAwareTreeRouteStackTest.php index f3b2bae08..c1f98542c 100644 --- a/test/Router/Http/TranslatorAwareTreeRouteStackTest.php +++ b/test/Router/Http/TranslatorAwareTreeRouteStackTest.php @@ -34,6 +34,8 @@ class TranslatorAwareTreeRouteStackTest extends TestCase public function setUp() { + $this->markTestIncomplete('Re-enable once zend-i18n is updated to zend-servicemanager v3'); + $this->testFilesDir = __DIR__ . '/_files'; $this->translator = new Translator(); @@ -142,7 +144,7 @@ public function testAssembleRouteWithParameterLocale() ); $this->assertEquals('/de/hauptseite', $stack->assemble(['locale' => 'de'], ['name' => 'foo/index'])); - $this->assertEquals('/en/homepage', $stack->assemble(['locale' => 'en'], ['name' => 'foo/index'])); + $this->assertEquals('/en/homepage', $stack->assemble(['locale' => 'en'], ['name' => 'foo/index'])); } public function testMatchRouteWithParameterLocale() diff --git a/test/Router/RoutePluginManagerTest.php b/test/Router/RoutePluginManagerTest.php index c763a58b5..d9dff5d95 100644 --- a/test/Router/RoutePluginManagerTest.php +++ b/test/Router/RoutePluginManagerTest.php @@ -9,105 +9,26 @@ namespace ZendTest\Mvc\Router; -use Zend\Di\Di; -use Zend\Mvc\Router\RoutePluginManager; -use Zend\ServiceManager\Di\DiAbstractServiceFactory; use PHPUnit_Framework_TestCase as TestCase; +use Zend\Mvc\Router\RoutePluginManager; +use Zend\ServiceManager\ServiceManager; -/** - * @group Zend_Router - */ class RoutePluginManagerTest extends TestCase { public function testLoadNonExistentRoute() { - $routes = new RoutePluginManager(); + $routes = new RoutePluginManager(new ServiceManager()); $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); $routes->get('foo'); } public function testCanLoadAnyRoute() { - $routes = new RoutePluginManager(); - $routes->setInvokableClass('DummyRoute', 'ZendTest\Mvc\Router\TestAsset\DummyRoute'); + $routes = new RoutePluginManager(new ServiceManager(), ['invokables' => [ + 'DummyRoute' => 'ZendTest\Mvc\Router\TestAsset\DummyRoute', + ]]); $route = $routes->get('DummyRoute'); $this->assertInstanceOf('ZendTest\Mvc\Router\TestAsset\DummyRoute', $route); } - - public function shippedRoutes() - { - return [ - 'hostname' => ['Zend\Mvc\Router\Http\Hostname', ['route' => 'example.com']], - 'literal' => ['Zend\Mvc\Router\Http\Literal', ['route' => '/example']], - 'regex' => ['Zend\Mvc\Router\Http\Regex', ['regex' => '[a-z]+', 'spec' => '%s']], - 'scheme' => ['Zend\Mvc\Router\Http\Scheme', ['scheme' => 'http']], - 'segment' => ['Zend\Mvc\Router\Http\Segment', ['route' => '/:segment']], - 'wildcard' => ['Zend\Mvc\Router\Http\Wildcard', []], - //'query' => array('Zend\Mvc\Router\Http\Query', array()), - 'method' => ['Zend\Mvc\Router\Http\Method', ['verb' => 'GET']], - ]; - } - - /** - * @dataProvider shippedRoutes - */ - public function testDoesNotInvokeDiForShippedRoutes($routeName, $options) - { - // Setup route plugin manager - $routes = new RoutePluginManager(); - foreach ($this->shippedRoutes() as $name => $info) { - $routes->setInvokableClass($name, $info[0]); - } - - // Add DI abstract factory - $di = new Di; - $diAbstractFactory = new DiAbstractServiceFactory($di, DiAbstractServiceFactory::USE_SL_BEFORE_DI); - $routes->addAbstractFactory($diAbstractFactory); - - $this->assertTrue($routes->has($routeName)); - - try { - $route = $routes->get($routeName, $options); - $this->assertInstanceOf($routeName, $route); - } catch (\Exception $e) { - $messages = []; - do { - $messages[] = $e->getMessage() . "\n" . $e->getTraceAsString(); - } while ($e = $e->getPrevious()); - $this->fail(implode("\n\n", $messages)); - } - } - - /** - * @dataProvider shippedRoutes - */ - public function testDoesNotInvokeDiForShippedRoutesUsingShortName($routeName, $options) - { - // Setup route plugin manager - $routes = new RoutePluginManager(); - foreach ($this->shippedRoutes() as $name => $info) { - $routes->setInvokableClass($name, $info[0]); - } - - // Add DI abstract factory - $di = new Di; - $diAbstractFactory = new DiAbstractServiceFactory($di, DiAbstractServiceFactory::USE_SL_BEFORE_DI); - $routes->addAbstractFactory($diAbstractFactory); - - $shortName = substr($routeName, strrpos($routeName, '\\') + 1); - - $this->assertTrue($routes->has($shortName)); - - try { - $route = $routes->get($shortName, $options); - $this->assertInstanceOf($routeName, $route); - } catch (\Exception $e) { - $messages = []; - do { - $messages[] = $e->getMessage() . "\n" . $e->getTraceAsString(); - } while ($e = $e->getPrevious()); - $this->fail(implode("\n\n", $messages)); - } - } } diff --git a/test/Router/SimpleRouteStackTest.php b/test/Router/SimpleRouteStackTest.php index b0e55d4be..f62d8b7d4 100644 --- a/test/Router/SimpleRouteStackTest.php +++ b/test/Router/SimpleRouteStackTest.php @@ -14,12 +14,13 @@ use Zend\Stdlib\Request; use Zend\Mvc\Router\RoutePluginManager; use Zend\Mvc\Router\SimpleRouteStack; +use Zend\ServiceManager\ServiceManager; class SimpleRouteStackTest extends TestCase { public function testSetRoutePluginManager() { - $routes = new RoutePluginManager(); + $routes = new RoutePluginManager(new ServiceManager()); $stack = new SimpleRouteStack(); $stack->setRoutePluginManager($routes); @@ -239,7 +240,7 @@ public function testFactory() 'Zend\Mvc\Router\SimpleRouteStack', [], [ - 'route_plugins' => new RoutePluginManager(), + 'route_plugins' => new RoutePluginManager(new ServiceManager()), 'routes' => [], 'default_params' => [] ] diff --git a/test/Service/ConsoleAdapterFactoryTest.php b/test/Service/ConsoleAdapterFactoryTest.php new file mode 100644 index 000000000..e2cea142a --- /dev/null +++ b/test/Service/ConsoleAdapterFactoryTest.php @@ -0,0 +1,105 @@ +setConsoleEnvironment(true); + } + + public function testFactoryReturnsAnonymousObjectIfNotConsoleEnvironment() + { + $this->setConsoleEnvironment(false); + $factory = new ConsoleAdapterFactory(); + $result = $factory($this->createContainer(), 'ConsoleAdapter'); + $this->assertInstanceOf(stdClass::class, $result); + } + + public function testFactoryCanUseAdapterFromConfiguration() + { + $this->setConsoleEnvironment(true); + $adapter = $this->prophesize(AdapterInterface::class); + + $container = $this->prophesize(ContainerInterface::class); + $container->get('config')->willReturn([ + 'console' => [ + 'adapter' => 'TestAdapter', + ], + ]); + $container->get('TestAdapter')->will(function () use ($adapter) { + return $adapter->reveal(); + }); + + $factory = new ConsoleAdapterFactory(); + $result = $factory($container->reveal(), 'ConsoleAdapter'); + $this->assertSame($adapter->reveal(), $result); + } + + public function testFactoryReturnsAnonymousObjectIfConfiguredAdapterIsInvalid() + { + $this->setConsoleEnvironment(true); + $container = $this->prophesize(ContainerInterface::class); + $container->get('config')->willReturn([ + 'console' => [ + 'adapter' => 'TestAdapter', + ], + ]); + $container->get('TestAdapter')->willReturn([]); + + $factory = new ConsoleAdapterFactory(); + $result = $factory($container->reveal(), 'ConsoleAdapter'); + $this->assertInstanceOf(stdClass::class, $result); + } + + public function testFactoryWillDetectBestAdapterWhenNoneConfigured() + { + $this->setConsoleEnvironment(true); + + $container = $this->prophesize(ContainerInterface::class); + $container->get('config')->willReturn([]); + + $factory = new ConsoleAdapterFactory(); + $result = $factory($container->reveal(), 'ConsoleAdapter'); + $this->assertInstanceOf(AdapterInterface::class, $result); + } + + public function testFactoryWillInjectCharsetIfConfigured() + { + $this->setConsoleEnvironment(true); + + $charset = $this->prophesize(CharsetInterface::class); + + $container = $this->prophesize(ContainerInterface::class); + $container->get('config')->willReturn([ + 'console' => [ + 'charset' => 'CustomCharset', + ], + ]); + $container->get('CustomCharset')->will(function () use ($charset) { + return $charset->reveal(); + }); + + $factory = new ConsoleAdapterFactory(); + $result = $factory($container->reveal(), 'ConsoleAdapter'); + $this->assertInstanceOf(AdapterInterface::class, $result); + $this->assertSame($charset->reveal(), $result->getCharset()); + } +} diff --git a/test/Service/ConsoleViewManagerFactoryTest.php b/test/Service/ConsoleViewManagerFactoryTest.php new file mode 100644 index 000000000..80307f655 --- /dev/null +++ b/test/Service/ConsoleViewManagerFactoryTest.php @@ -0,0 +1,41 @@ +setConsoleEnvironment(true); + } + + public function testRaisesExceptionWhenNotInConsoleEnvironment() + { + $this->setConsoleEnvironment(false); + $factory = new ConsoleViewManagerFactory(); + $this->setExpectedException(ServiceNotCreatedException::class); + $factory($this->createContainer(), 'ConsoleViewManager'); + } + + public function testReturnsConsoleViewManagerWhenInConsoleEnvironment() + { + $this->setConsoleEnvironment(true); + $factory = new ConsoleViewManagerFactory(); + $result = $factory($this->createContainer(), 'ConsoleViewManager'); + $this->assertInstanceOf(ViewManager::class, $result); + } +} diff --git a/test/Service/ControllerLoaderFactoryTest.php b/test/Service/ControllerLoaderFactoryTest.php deleted file mode 100644 index d7ae43002..000000000 --- a/test/Service/ControllerLoaderFactoryTest.php +++ /dev/null @@ -1,183 +0,0 @@ - []]); - $this->services = new ServiceManager(); - $this->services->setService('Zend\ServiceManager\ServiceLocatorInterface', $this->services); - $this->services->setFactory('ControllerLoader', $loaderFactory); - $this->services->setService('Config', $config); - $this->services->setFactory('ControllerPluginManager', new ControllerPluginManagerFactory()); - $this->services->setFactory('Di', new DiFactory()); - $this->services->setFactory('DiStrictAbstractServiceFactory', new DiStrictAbstractServiceFactoryFactory()); - $this->services->setFactory('DiAbstractServiceFactory', new DiAbstractServiceFactoryFactory()); - $this->services->setFactory('DiServiceInitializer', new DiServiceInitializerFactory()); - $this->services->setFactory('EventManager', new EventManagerFactory()); - $this->services->setInvokableClass('SharedEventManager', 'Zend\EventManager\SharedEventManager'); - } - - public function testCannotLoadInvalidDispatchable() - { - $this->loader = $this->services->get('ControllerLoader'); - - // Ensure the class exists and can be autoloaded - $this->assertTrue(class_exists('ZendTest\Mvc\Service\TestAsset\InvalidDispatchableClass')); - - try { - $this->loader->get('ZendTest\Mvc\Service\TestAsset\InvalidDispatchableClass'); - $this->fail('Retrieving the invalid dispatchable should fail'); - } catch (\Exception $e) { - do { - $this->assertNotContains('Should not instantiate this', $e->getMessage()); - } while ($e = $e->getPrevious()); - } - } - - public function testCannotLoadControllerFromPeer() - { - $this->loader = $this->services->get('ControllerLoader'); - $this->services->setService('foo', $this); - - $this->setExpectedException('Zend\ServiceManager\Exception\ExceptionInterface'); - $this->loader->get('foo'); - } - - public function testControllerLoadedCanBeInjectedWithValuesFromPeer() - { - $this->loader = $this->services->get('ControllerLoader'); - $config = [ - 'invokables' => [ - 'ZendTest\Dispatchable' => 'ZendTest\Mvc\Service\TestAsset\Dispatchable', - ], - ]; - $config = new Config($config); - $config->configureServiceManager($this->loader); - - $controller = $this->loader->get('ZendTest\Dispatchable'); - $this->assertInstanceOf('ZendTest\Mvc\Service\TestAsset\Dispatchable', $controller); - $this->assertSame($this->services, $controller->getServiceLocator()); - $this->assertSame($this->services->get('EventManager'), $controller->getEventManager()); - $this->assertSame($this->services->get('ControllerPluginManager'), $controller->getPluginManager()); - } - - public function testWillInstantiateControllersFromDiAbstractFactoryWhenWhitelisted() - { - $config = new ArrayObject([ - 'di' => [ - 'instance' => [ - 'alias' => [ - 'my-controller' => 'stdClass', - ], - ], - 'allowed_controllers' => [ - 'my-controller', - ], - ], - ]); - $this->services->setAllowOverride(true); - $this->services->setService('Config', $config); - $this->loader = $this->services->get('ControllerLoader'); - - $this->assertTrue($this->loader->has('my-controller')); - // invalid controller exception (because we're getting an \stdClass after all) - $this->setExpectedException('Zend\Mvc\Exception\InvalidControllerException'); - $this->loader->get('my-controller'); - } - - public function testWillNotInstantiateControllersFromDiAbstractFactoryWhenNotWhitelisted() - { - $config = new ArrayObject([ - 'di' => [ - 'instance' => [ - 'alias' => [ - 'evil-controller' => 'stdClass', - ], - ], - 'allowed_controllers' => [ - 'my-controller', - ], - ], - ]); - $this->services->setAllowOverride(true); - $this->services->setService('Config', $config); - $this->loader = $this->services->get('ControllerLoader'); - $this->setExpectedException('Zend\ServiceManager\Exception\ServiceNotFoundException'); - $this->loader->get('evil-controller'); - } - - public function testWillFetchDiDependenciesFromControllerLoaderServiceManager() - { - $controllerName = __NAMESPACE__ . '\TestAsset\ControllerWithDependencies'; - // rewriting since controller loader does not have the correct config, but is already fetched - $config = new ArrayObject([ - 'di' => [ - 'instance' => [ - $controllerName => [ - 'parameters' => [ - 'injected' => 'stdClass', - ], - ], - ], - 'allowed_controllers' => [ - $controllerName, - ], - ], - ]); - $this->services->setAllowOverride(true); - $this->services->setService('Config', $config); - $this->loader = $this->services->get('ControllerLoader'); - - $testService = new \stdClass(); - $this->services->setService('stdClass', $testService); - // invalid controller exception (because we're not getting a \Zend\Stdlib\DispatchableInterface after all) - $controller = $this->loader->get($controllerName); - $this->assertSame($testService, $controller->injectedValue); - } - - public function testCallPluginWithControllerPluginManager() - { - $controllerpluginManager = $this->services->get('ControllerPluginManager'); - $controllerpluginManager->setInvokableClass('samplePlugin', 'ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePlugin'); - - $controller = new \ZendTest\Mvc\Controller\TestAsset\SampleController; - $controllerpluginManager->setController($controller); - - $plugin = $controllerpluginManager->get('samplePlugin'); - $this->assertEquals($controller, $plugin->getController()); - } -} diff --git a/test/Service/ControllerManagerFactoryTest.php b/test/Service/ControllerManagerFactoryTest.php new file mode 100644 index 000000000..2253ad7f0 --- /dev/null +++ b/test/Service/ControllerManagerFactoryTest.php @@ -0,0 +1,111 @@ +defaultServiceConfig = [ + 'invokables' => [ + 'SharedEventManager' => SharedEventManager::class, + ], + 'factories' => [ + 'ControllerManager' => $loaderFactory, + 'ControllerPluginManager' => ControllerPluginManagerFactory::class, + 'EventManager' => EventManagerFactory::class, + ], + 'services' => [ + 'config' => [], + ], + ]; + $this->services = new ServiceManager($this->defaultServiceConfig); + } + + public function testCannotLoadInvalidDispatchable() + { + $loader = $this->services->get('ControllerManager'); + + // Ensure the class exists and can be autoloaded + $this->assertTrue(class_exists('ZendTest\Mvc\Service\TestAsset\InvalidDispatchableClass')); + + try { + $loader->get('ZendTest\Mvc\Service\TestAsset\InvalidDispatchableClass'); + $this->fail('Retrieving the invalid dispatchable should fail'); + } catch (\Exception $e) { + do { + $this->assertNotContains('Should not instantiate this', $e->getMessage()); + } while ($e = $e->getPrevious()); + } + } + + public function testCannotLoadControllerFromPeer() + { + $services = new ServiceManager(array_merge_recursive($this->defaultServiceConfig, ['services' => [ + 'foo' => $this, + ]])); + $loader = $services->get('ControllerManager'); + + $this->setExpectedException('Zend\ServiceManager\Exception\ExceptionInterface'); + $loader->get('foo'); + } + + public function testControllerLoadedCanBeInjectedWithValuesFromPeer() + { + $loader = $this->services->get('ControllerManager'); + $loader = $loader->withConfig(['invokables' => [ + 'ZendTest\Dispatchable' => TestAsset\Dispatchable::class, + ]]); + + $controller = $loader->get('ZendTest\Dispatchable'); + $this->assertInstanceOf(TestAsset\Dispatchable::class, $controller); + $this->assertSame($this->services->get('EventManager'), $controller->getEventManager()); + $this->assertSame($this->services->get('ControllerPluginManager'), $controller->getPluginManager()); + } + + public function testCallPluginWithControllerPluginManager() + { + $controllerPluginManager = $this->services->get('ControllerPluginManager'); + $controllerPluginManager = $controllerPluginManager->withConfig([ + 'invokables' => [ + 'samplePlugin' => 'ZendTest\Mvc\Controller\Plugin\TestAsset\SamplePlugin', + ], + ]); + + $controller = new \ZendTest\Mvc\Controller\TestAsset\SampleController; + $controllerPluginManager->setController($controller); + + $services = $this->services->withConfig(['services' => [ + 'ControllerPluginManager' => $controllerPluginManager, + ]]); + + $plugin = $controllerPluginManager->get('samplePlugin'); + $this->assertEquals($controller, $plugin->getController()); + } +} diff --git a/test/Service/DiFactoryTest.php b/test/Service/DiFactoryTest.php deleted file mode 100644 index 88a0b48b8..000000000 --- a/test/Service/DiFactoryTest.php +++ /dev/null @@ -1,26 +0,0 @@ -setService('Config', ['di' => ['']]); - $serviceManager->setFactory('Di', new DiFactory()); - - $di = $serviceManager->get('Di'); - $this->assertInstanceOf('Zend\Di\Di', $di); - } -} diff --git a/test/Service/DiStrictAbstractServiceFactoryTest.php b/test/Service/DiStrictAbstractServiceFactoryTest.php deleted file mode 100644 index 047cce53f..000000000 --- a/test/Service/DiStrictAbstractServiceFactoryTest.php +++ /dev/null @@ -1,64 +0,0 @@ -getMock('Zend\Di\Di')); - $instance->setAllowedServiceNames(['first-service', 'second-service']); - $allowedServices = $instance->getAllowedServiceNames(); - $this->assertCount(2, $allowedServices); - $this->assertContains('first-service', $allowedServices); - $this->assertContains('second-service', $allowedServices); - } - - public function testWillOnlyCreateServiceInWhitelist() - { - $instance = new DiStrictAbstractServiceFactory($this->getMock('Zend\Di\Di')); - $instance->setAllowedServiceNames(['a-whitelisted-service-name']); - $im = $instance->instanceManager(); - $im->addSharedInstance(new \stdClass(), 'a-whitelisted-service-name'); - $locator = $this->getMock('Zend\ServiceManager\ServiceLocatorInterface'); - - $this->assertTrue($instance->canCreateServiceWithName($locator, 'a-whitelisted-service-name', 'a-whitelisted-service-name')); - $this->assertInstanceOf('stdClass', $instance->createServiceWithName($locator, 'a-whitelisted-service-name', 'a-whitelisted-service-name')); - - $this->assertFalse($instance->canCreateServiceWithName($locator, 'not-whitelisted', 'not-whitelisted')); - $this->setExpectedException('Zend\ServiceManager\Exception\InvalidServiceNameException'); - $instance->createServiceWithName($locator, 'not-whitelisted', 'not-whitelisted'); - } - - public function testWillFetchDependenciesFromServiceManagerBeforeDi() - { - $controllerName = __NAMESPACE__ . '\TestAsset\ControllerWithDependencies'; - $config = new Config([ - 'instance' => [ - $controllerName => ['parameters' => ['injected' => 'stdClass']], - ], - ]); - $locator = new ServiceManager(); - $testService = new \stdClass(); - $locator->setService('stdClass', $testService); - - $di = new Di; - $config->configure($di); - $instance = new DiStrictAbstractServiceFactory($di, DiStrictAbstractServiceFactory::USE_SL_BEFORE_DI); - $instance->setAllowedServiceNames([$controllerName]); - $service = $instance->createServiceWithName($locator, $controllerName, $controllerName); - $this->assertSame($testService, $service->injectedValue); - } -} diff --git a/test/Service/FactoryEnvironmentTrait.php b/test/Service/FactoryEnvironmentTrait.php new file mode 100644 index 000000000..0808284cf --- /dev/null +++ b/test/Service/FactoryEnvironmentTrait.php @@ -0,0 +1,29 @@ +setAccessible(true); + $r->setValue((bool) $isConsole); + } + + private function createContainer() + { + return $this->prophesize(ContainerInterface::class)->reveal(); + } +} diff --git a/test/Service/FormAnnotationBuilderFactoryTest.php b/test/Service/FormAnnotationBuilderFactoryTest.php index 9527097c4..eeb3f1e96 100644 --- a/test/Service/FormAnnotationBuilderFactoryTest.php +++ b/test/Service/FormAnnotationBuilderFactoryTest.php @@ -15,13 +15,18 @@ class FormAnnotationBuilderFactoryTest extends TestCase { + public function setUp() + { + $this->markTestIncomplete('Re-enable once zend-form is migrated to zend-servicemanager v3'); + } + public function testCreateService() { $mockElementManager = $this->getMock('Zend\Form\FormElementManager'); $serviceLocator = new ServiceManager(); $serviceLocator->setService('FormElementManager', $mockElementManager); - $serviceLocator->setService('Config', []); + $serviceLocator->setService('config', []); $sut = new FormAnnotationBuilderFactory(); @@ -35,7 +40,7 @@ public function testCreateServiceSetsPreserveDefinedOrder() $serviceLocator = new ServiceManager(); $serviceLocator->setService('FormElementManager', $mockElementManager); $config = ['form_annotation_builder' => ['preserve_defined_order' => true]]; - $serviceLocator->setService('Config', $config); + $serviceLocator->setService('config', $config); $sut = new FormAnnotationBuilderFactory(); diff --git a/test/Service/FormElementManagerFactoryTest.php b/test/Service/FormElementManagerFactoryTest.php index 6577e72bb..bf25c230d 100644 --- a/test/Service/FormElementManagerFactoryTest.php +++ b/test/Service/FormElementManagerFactoryTest.php @@ -9,12 +9,8 @@ namespace ZendTest\Mvc\Service; -use ArrayObject; use PHPUnit_Framework_TestCase as TestCase; use Zend\Mvc\Service\FormElementManagerFactory; -use Zend\Mvc\Service\DiFactory; -use Zend\Mvc\Service\DiAbstractServiceFactoryFactory; -use Zend\Mvc\Service\DiServiceInitializerFactory; use Zend\ServiceManager\Config; use Zend\ServiceManager\ServiceManager; use Zend\Form\FormElementManager; @@ -33,15 +29,17 @@ class FormElementManagerFactoryTest extends TestCase public function setUp() { + $this->markTestIncomplete('Re-enable once zend-form is migrated to zend-servicemanager v3'); + $formElementManagerFactory = new FormElementManagerFactory(); - $config = new ArrayObject(['di' => []]); - $this->services = new ServiceManager(); - $this->services->setService('Zend\ServiceManager\ServiceLocatorInterface', $this->services); - $this->services->setFactory('FormElementManager', $formElementManagerFactory); - $this->services->setService('Config', $config); - $this->services->setFactory('Di', new DiFactory()); - $this->services->setFactory('DiAbstractServiceFactory', new DiAbstractServiceFactoryFactory()); - $this->services->setFactory('DiServiceInitializer', new DiServiceInitializerFactory()); + $this->services = new ServiceManager([ + 'factories' => [ + 'FormElementManager' => $formElementManagerFactory, + ], + 'services' => [ + 'config' => [], + ], + ]); } public function testWillGetFormElementManager() @@ -56,16 +54,4 @@ public function testWillInstantiateFormFromInvokable() $form = $formElementManager->get('form'); $this->assertInstanceof('Zend\Form\Form', $form); } - - public function testWillInstantiateFormFromDiAbstractFactory() - { - //without DiAbstractFactory - $standaloneFormElementManager = new FormElementManager(); - $this->assertFalse($standaloneFormElementManager->has('ZendTest\Mvc\Service\TestAsset\CustomForm')); - //with DiAbstractFactory - $formElementManager = $this->services->get('FormElementManager'); - $this->assertTrue($formElementManager->has('ZendTest\Mvc\Service\TestAsset\CustomForm')); - $form = $formElementManager->get('ZendTest\Mvc\Service\TestAsset\CustomForm'); - $this->assertInstanceof('ZendTest\Mvc\Service\TestAsset\CustomForm', $form); - } } diff --git a/test/Service/HttpMethodListenerFactoryTest.php b/test/Service/HttpMethodListenerFactoryTest.php index 0653f3933..67daf78e5 100644 --- a/test/Service/HttpMethodListenerFactoryTest.php +++ b/test/Service/HttpMethodListenerFactoryTest.php @@ -32,7 +32,7 @@ public function setUp() public function testCreateWithDefaults() { $factory = new HttpMethodListenerFactory(); - $listener = $factory->createService($this->serviceLocator); + $listener = $factory($this->serviceLocator, 'HttpMethodListener'); $this->assertTrue($listener->isEnabled()); $this->assertNotEmpty($listener->getAllowedMethods()); } @@ -50,7 +50,7 @@ public function testCreateWithConfig() ->willReturn($config); $factory = new HttpMethodListenerFactory(); - $listener = $factory->createService($this->serviceLocator); + $listener = $factory($this->serviceLocator, 'HttpMethodListener'); $listenerConfig = $config['http_methods_listener']; diff --git a/test/Service/InjectTemplateListenerFactoryTest.php b/test/Service/InjectTemplateListenerFactoryTest.php index a89fccaab..6b8aa560e 100644 --- a/test/Service/InjectTemplateListenerFactoryTest.php +++ b/test/Service/InjectTemplateListenerFactoryTest.php @@ -62,10 +62,10 @@ private function buildInjectTemplateListenerWithConfig($config) /* @var $serviceLocator \Zend\ServiceManager\ServiceLocatorInterface|\PHPUnit_Framework_MockObject_MockObject */ $serviceLocator = $this->getMock('Zend\ServiceManager\ServiceLocatorInterface'); - $serviceLocator->expects($this->any())->method('get')->with('Config')->will($this->returnValue($config)); + $serviceLocator->expects($this->any())->method('get')->with('config')->will($this->returnValue($config)); $factory = new InjectTemplateListenerFactory(); - $listener = $factory->createService($serviceLocator); + $listener = $factory($serviceLocator, 'InjectTemplateListener'); $this->assertInstanceOf('Zend\Mvc\View\Http\InjectTemplateListener', $listener); diff --git a/test/Service/RequestFactoryTest.php b/test/Service/RequestFactoryTest.php new file mode 100644 index 000000000..1efe7f23c --- /dev/null +++ b/test/Service/RequestFactoryTest.php @@ -0,0 +1,41 @@ +setConsoleEnvironment(true); + } + + public function testFactoryCreatesConsoleRequestInConsoleEnvironment() + { + $this->setConsoleEnvironment(true); + $factory = new RequestFactory(); + $request = $factory($this->createContainer(), 'Request'); + $this->assertInstanceOf(ConsoleRequest::class, $request); + } + + public function testFactoryCreatesHttpRequestInNonConsoleEnvironment() + { + $this->setConsoleEnvironment(false); + $factory = new RequestFactory(); + $request = $factory($this->createContainer(), 'Request'); + $this->assertInstanceOf(HttpRequest::class, $request); + } +} diff --git a/test/Service/ResponseFactoryTest.php b/test/Service/ResponseFactoryTest.php new file mode 100644 index 000000000..f6d5433da --- /dev/null +++ b/test/Service/ResponseFactoryTest.php @@ -0,0 +1,41 @@ +setConsoleEnvironment(true); + } + + public function testFactoryCreatesConsoleResponseInConsoleEnvironment() + { + $this->setConsoleEnvironment(true); + $factory = new ResponseFactory(); + $response = $factory($this->createContainer(), 'Response'); + $this->assertInstanceOf(ConsoleResponse::class, $response); + } + + public function testFactoryCreatesHttpResponseInNonConsoleEnvironment() + { + $this->setConsoleEnvironment(false); + $factory = new ResponseFactory(); + $response = $factory($this->createContainer(), 'Response'); + $this->assertInstanceOf(HttpResponse::class, $response); + } +} diff --git a/test/Service/RouterFactoryTest.php b/test/Service/RouterFactoryTest.php index a782f0ec0..8fe4485db 100644 --- a/test/Service/RouterFactoryTest.php +++ b/test/Service/RouterFactoryTest.php @@ -11,6 +11,8 @@ use PHPUnit_Framework_TestCase as TestCase; use Zend\Mvc\Router\RoutePluginManager; +use Zend\Mvc\Service\ConsoleRouterFactory; +use Zend\Mvc\Service\HttpRouterFactory; use Zend\Mvc\Service\RouterFactory; use Zend\ServiceManager\ServiceManager; @@ -18,37 +20,49 @@ class RouterFactoryTest extends TestCase { public function setUp() { - $this->services = new ServiceManager(); - $this->services->setService('RoutePluginManager', new RoutePluginManager()); + $this->defaultServiceConfig = [ + 'factories' => [ + 'ConsoleRouter' => ConsoleRouterFactory::class, + 'HttpRouter' => HttpRouterFactory::class, + 'RoutePluginManager' => function ($services, $name, array $options = null) { + return new RoutePluginManager($services); + }, + ], + ]; + $this->factory = new RouterFactory(); } public function testFactoryCanCreateRouterBasedOnConfiguredName() { - $this->services->setService('Config', [ - 'router' => [ - 'router_class' => 'ZendTest\Mvc\Service\TestAsset\Router', - ], - 'console' => [ + $services = new ServiceManager(array_merge_recursive($this->defaultServiceConfig, [ + 'services' => [ 'config' => [ 'router' => [ 'router_class' => 'ZendTest\Mvc\Service\TestAsset\Router', ], - ], - ]); + 'console' => [ + 'router' => [ + 'router_class' => 'ZendTest\Mvc\Service\TestAsset\Router', + ], + ], + ]], + ])); - $router = $this->factory->createService($this->services, 'router', 'Router'); + $router = $this->factory->__invoke($services, 'router'); $this->assertInstanceOf('ZendTest\Mvc\Service\TestAsset\Router', $router); } public function testFactoryCanCreateRouterWhenOnlyHttpRouterConfigPresent() { - $this->services->setService('Config', [ - 'router' => [ - 'router_class' => 'ZendTest\Mvc\Service\TestAsset\Router', - ], - ]); + $services = new ServiceManager(array_merge_recursive($this->defaultServiceConfig, [ + 'services' => [ 'config' => [ + 'router' => [ + 'router_class' => 'ZendTest\Mvc\Service\TestAsset\Router', + ], + ]], + ])); - $router = $this->factory->createService($this->services, 'router', 'Router'); + $router = $this->factory->__invoke($services, 'router'); $this->assertInstanceOf('Zend\Mvc\Router\Console\SimpleRouteStack', $router); } } diff --git a/test/Service/ServiceListenerFactoryTest.php b/test/Service/ServiceListenerFactoryTest.php index 8abd44280..c419aad1d 100644 --- a/test/Service/ServiceListenerFactoryTest.php +++ b/test/Service/ServiceListenerFactoryTest.php @@ -24,7 +24,7 @@ public function setUp() } /** - * @expectedException Zend\Mvc\Exception\InvalidArgumentException + * @expectedException Zend\ServiceManager\Exception\ServiceNotCreatedException * @expectedExceptionMessage The value of service_listener_options must be an array, string given. */ public function testInvalidOptionType() @@ -33,11 +33,11 @@ public function testInvalidOptionType() ->method('get') ->will($this->returnValue(['service_listener_options' => 'string'])); - $this->factory->createService($this->sm); + $this->factory->__invoke($this->sm, 'ServiceListener'); } /** - * @expectedException Zend\Mvc\Exception\InvalidArgumentException + * @expectedException Zend\ServiceManager\Exception\ServiceNotCreatedException * @expectedExceptionMessage Invalid service listener options detected, 0 array must contain service_manager key. */ public function testMissingServiceManager() @@ -51,11 +51,11 @@ public function testMissingServiceManager() ->method('get') ->will($this->returnValue($config)); - $this->factory->createService($this->sm); + $this->factory->__invoke($this->sm, 'ServiceListener'); } /** - * @expectedException Zend\Mvc\Exception\InvalidArgumentException + * @expectedException Zend\ServiceManager\Exception\ServiceNotCreatedException * @expectedExceptionMessage Invalid service listener options detected, service_manager must be a string, integer given. */ public function testInvalidTypeServiceManager() @@ -69,11 +69,11 @@ public function testInvalidTypeServiceManager() ->method('get') ->will($this->returnValue($config)); - $this->factory->createService($this->sm); + $this->factory->__invoke($this->sm, 'ServiceListener'); } /** - * @expectedException Zend\Mvc\Exception\InvalidArgumentException + * @expectedException Zend\ServiceManager\Exception\ServiceNotCreatedException * @expectedExceptionMessage Invalid service listener options detected, 0 array must contain config_key key. */ public function testMissingConfigKey() @@ -87,11 +87,11 @@ public function testMissingConfigKey() ->method('get') ->will($this->returnValue($config)); - $this->factory->createService($this->sm); + $this->factory->__invoke($this->sm, 'ServiceListener'); } /** - * @expectedException Zend\Mvc\Exception\InvalidArgumentException + * @expectedException Zend\ServiceManager\Exception\ServiceNotCreatedException * @expectedExceptionMessage Invalid service listener options detected, config_key must be a string, integer given. */ public function testInvalidTypeConfigKey() @@ -105,11 +105,11 @@ public function testInvalidTypeConfigKey() ->method('get') ->will($this->returnValue($config)); - $this->factory->createService($this->sm); + $this->factory->__invoke($this->sm, 'ServiceListener'); } /** - * @expectedException Zend\Mvc\Exception\InvalidArgumentException + * @expectedException Zend\ServiceManager\Exception\ServiceNotCreatedException * @expectedExceptionMessage Invalid service listener options detected, 0 array must contain interface key. */ public function testMissingInterface() @@ -123,11 +123,11 @@ public function testMissingInterface() ->method('get') ->will($this->returnValue($config)); - $this->factory->createService($this->sm); + $this->factory->__invoke($this->sm, 'ServiceListener'); } /** - * @expectedException Zend\Mvc\Exception\InvalidArgumentException + * @expectedException Zend\ServiceManager\Exception\ServiceNotCreatedException * @expectedExceptionMessage Invalid service listener options detected, interface must be a string, integer given. */ public function testInvalidTypeInterface() @@ -141,11 +141,11 @@ public function testInvalidTypeInterface() ->method('get') ->will($this->returnValue($config)); - $this->factory->createService($this->sm); + $this->factory->__invoke($this->sm, 'ServiceListener'); } /** - * @expectedException Zend\Mvc\Exception\InvalidArgumentException + * @expectedException Zend\ServiceManager\Exception\ServiceNotCreatedException * @expectedExceptionMessage Invalid service listener options detected, 0 array must contain method key. */ public function testMissingMethod() @@ -159,11 +159,11 @@ public function testMissingMethod() ->method('get') ->will($this->returnValue($config)); - $this->factory->createService($this->sm); + $this->factory->__invoke($this->sm, 'ServiceListener'); } /** - * @expectedException Zend\Mvc\Exception\InvalidArgumentException + * @expectedException Zend\ServiceManager\Exception\ServiceNotCreatedException * @expectedExceptionMessage Invalid service listener options detected, method must be a string, integer given. */ public function testInvalidTypeMethod() @@ -177,6 +177,6 @@ public function testInvalidTypeMethod() ->method('get') ->will($this->returnValue($config)); - $this->factory->createService($this->sm); + $this->factory->__invoke($this->sm, 'ServiceListener'); } } diff --git a/test/Service/ServiceManagerConfigTest.php b/test/Service/ServiceManagerConfigTest.php index b496ed82a..ef63793a4 100644 --- a/test/Service/ServiceManagerConfigTest.php +++ b/test/Service/ServiceManagerConfigTest.php @@ -10,9 +10,10 @@ namespace ZendTest\Mvc\Service; use PHPUnit_Framework_TestCase as TestCase; +use stdClass; use Zend\EventManager\EventManager; use Zend\Mvc\Service\ServiceManagerConfig; -use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\Factory\InvokableFactory; use Zend\ServiceManager\ServiceManager; /** @@ -35,9 +36,8 @@ class ServiceManagerConfigTest extends TestCase */ protected function setUp() { - $this->config = new ServiceManagerConfig(); - $this->services = new ServiceManager(); - $this->config->configureServiceManager($this->services); + $this->config = new ServiceManagerConfig(); + $this->services = $this->config->configureServiceManager(new ServiceManager()); } /** @@ -48,12 +48,14 @@ public function testEventManagerAwareInterfaceIsNotInjectedIfPresentButSharedMan $events = new EventManager($this->services->get('SharedEventManager')); TestAsset\EventManagerAwareObject::$defaultEvents = $events; - $this->services->setInvokableClass('EventManagerAwareObject', __NAMESPACE__ . '\TestAsset\EventManagerAwareObject'); + $services = $this->services->withConfig(['invokables' => [ + 'EventManagerAwareObject' => TestAsset\EventManagerAwareObject::class, + ]]); - $instance = $this->services->get('EventManagerAwareObject'); - $this->assertInstanceOf(__NAMESPACE__ . '\TestAsset\EventManagerAwareObject', $instance); + $instance = $services->get('EventManagerAwareObject'); + $this->assertInstanceOf(TestAsset\EventManagerAwareObject::class, $instance); $this->assertSame($events, $instance->getEventManager()); - $this->assertSame($this->services->get('SharedEventManager'), $events->getSharedManager()); + $this->assertSame($services->get('SharedEventManager'), $events->getSharedManager()); } /** @@ -63,18 +65,17 @@ public function testCanMergeCustomConfigWithDefaultConfig() { $custom = [ 'invokables' => [ - 'foo' => '\stdClass', + 'foo' => stdClass::class, ], 'factories' => [ 'bar' => function () { - return new \stdClass(); + return new stdClass(); }, ], ]; $config = new ServiceManagerConfig($custom); - $sm = new ServiceManager(); - $config->configureServiceManager($sm); + $sm = $config->configureServiceManager(new ServiceManager()); $this->assertTrue($sm->has('foo')); $this->assertTrue($sm->has('bar')); @@ -88,23 +89,22 @@ public function testCanOverrideDefaultConfigWithCustomConfig() { $custom = [ 'invokables' => [ - 'foo' => '\stdClass', + 'foo' => stdClass::class, ], 'factories' => [ 'ModuleManager' => function () { - return new \stdClass(); + return new stdClass(); }, ], ]; $config = new ServiceManagerConfig($custom); - $sm = new ServiceManager(); - $config->configureServiceManager($sm); + $sm = $config->configureServiceManager(new ServiceManager()); $this->assertTrue($sm->has('foo')); $this->assertTrue($sm->has('ModuleManager')); - $this->assertInstanceOf('stdClass', $sm->get('ModuleManager')); + $this->assertInstanceOf(stdClass::class, $sm->get('ModuleManager')); } /** @@ -113,162 +113,53 @@ public function testCanOverrideDefaultConfigWithCustomConfig() public function testCanAddDelegators() { $config = [ - 'invokables' => [ - 'foo' => '\stdClass', + 'aliases' => [ + 'foo' => stdClass::class, + ], + 'factories' => [ + stdClass::class => InvokableFactory::class, ], 'delegators' => [ - 'foo' => [ - function (ServiceLocatorInterface $serviceLocator, $name, $requestedName, $callback) { + stdClass::class => [ + function ($container, $name, $callback, array $options = null) { $service = $callback(); $service->bar = 'baz'; return $service; }, - ] + ], ], ]; - $config = new ServiceManagerConfig($config); - $sm = new ServiceManager(); - $config->configureServiceManager($sm); - + $sm = new ServiceManager((new ServiceManagerConfig($config))->toArray()); $std = $sm->get('foo'); - $this->assertInstanceOf('stdClass', $std); + $this->assertInstanceOf(stdClass::class, $std); $this->assertEquals('baz', $std->bar); } - /** - * @group 6266 - */ - public function testDefinesServiceManagerService() - { - $this->assertSame($this->services, $this->services->get('ServiceManager')); - } - - /** - * @group 6266 - */ - public function testCanOverrideServiceManager() - { - $serviceManager = new ServiceManager(new ServiceManagerConfig([ - 'factories' => [ - 'ServiceManager' => function () { - return $this; - } - ], - ])); - - $this->assertSame($this, $serviceManager->get('ServiceManager')); - } - - /** - * @group 6266 - */ - public function testServiceManagerInitializerIsUsedForServiceManagerAwareObjects() - { - $instance = $this->getMock('Zend\ServiceManager\ServiceManagerAwareInterface'); - - $instance->expects($this->once())->method('setServiceManager')->with($this->services); - - $this->services->setFactory( - 'service-manager-aware', - function () use ($instance) { - return $instance; - } - ); - - $this->services->get('service-manager-aware'); - } - - /** - * @group 6266 - */ - public function testServiceManagerInitializerCanBeReplaced() - { - $instance = $this->getMock('Zend\ServiceManager\ServiceManagerAwareInterface'); - $initializer = $this->getMock('stdClass', ['__invoke']); - $serviceManager = new ServiceManager(new ServiceManagerConfig([ - 'initializers' => [ - 'ServiceManagerAwareInitializer' => $initializer - ], - 'factories' => [ - 'service-manager-aware' => function () use ($instance) { - return $instance; - }, - ], - ])); - - $initializer->expects($this->once())->method('__invoke')->with($instance, $serviceManager); - $instance->expects($this->never())->method('setServiceManager'); - - $serviceManager->get('service-manager-aware'); - } - - /** - * @group 6266 - */ - public function testServiceLocatorInitializerIsUsedForServiceLocatorAwareObjects() - { - $instance = $this->getMock('Zend\ServiceManager\ServiceLocatorAwareInterface'); - - $instance->expects($this->once())->method('setServiceLocator')->with($this->services); - - $this->services->setFactory( - 'service-locator-aware', - function () use ($instance) { - return $instance; - } - ); - - $this->services->get('service-locator-aware'); - } - - /** - * @group 6266 - */ - public function testServiceLocatorInitializerCanBeReplaced() - { - $instance = $this->getMock('Zend\ServiceManager\ServiceLocatorAwareInterface'); - $initializer = $this->getMock('stdClass', ['__invoke']); - $serviceManager = new ServiceManager(new ServiceManagerConfig([ - 'initializers' => [ - 'ServiceLocatorAwareInitializer' => $initializer - ], - 'factories' => [ - 'service-locator-aware' => function () use ($instance) { - return $instance; - }, - ], - ])); - - $initializer->expects($this->once())->method('__invoke')->with($instance, $serviceManager); - $instance->expects($this->never())->method('setServiceLocator'); - - $serviceManager->get('service-locator-aware'); - } - /** * @group 6266 */ public function testEventManagerInitializerCanBeReplaced() { $instance = $this->getMock('Zend\EventManager\EventManagerAwareInterface'); - $initializer = $this->getMock('stdClass', ['__invoke']); - $serviceManager = new ServiceManager(new ServiceManagerConfig([ + $initializer = $this->getMock(stdClass::class, ['__invoke']); + $config = new ServiceManagerConfig([ 'initializers' => [ - 'EventManagerAwareInitializer' => $initializer + 'EventManagerAwareInitializer' => $initializer, ], 'factories' => [ - 'event-manager-aware' => function () use ($instance) { + 'EventManagerAware' => function () use ($instance) { return $instance; }, ], - ])); + ]); + $serviceManager = $config->configureServiceManager(new ServiceManager()); - $initializer->expects($this->once())->method('__invoke')->with($instance, $serviceManager); + $initializer->expects($this->once())->method('__invoke')->with($serviceManager, $instance); $instance->expects($this->never())->method('getEventManager'); $instance->expects($this->never())->method('setEventManager'); - $serviceManager->get('event-manager-aware'); + $serviceManager->get('EventManagerAware'); } } diff --git a/test/Service/TranslatorServiceFactoryTest.php b/test/Service/TranslatorServiceFactoryTest.php index 8697a9e93..feb2a356b 100644 --- a/test/Service/TranslatorServiceFactoryTest.php +++ b/test/Service/TranslatorServiceFactoryTest.php @@ -10,6 +10,8 @@ namespace ZendTest\Mvc\Service; use PHPUnit_Framework_TestCase as TestCase; +use Zend\I18n\Translator\LoaderPluginManager; +use Zend\I18n\Translator\TranslatorInterface; use Zend\Mvc\Service\RoutePluginManagerFactory; use Zend\Mvc\Service\ServiceManagerConfig; use Zend\Mvc\Service\TranslatorServiceFactory; @@ -19,20 +21,22 @@ class TranslatorServiceFactoryTest extends TestCase { public function setUp() { + $this->markTestIncomplete('Re-enable and refactor once zend-i18n is updated to zend-servicemanager v3'); + $this->factory = new TranslatorServiceFactory(); - $this->services = new ServiceManager(); - $this->services->setService( - 'TranslatorPluginManager', - $this->getMock('Zend\I18n\Translator\LoaderPluginManager') - ); + $this->services = new ServiceManager(['services' => [ + 'TranslatorPluginManager' => $this->getMock(LoaderPluginManager::class), + ]]); } public function testReturnsMvcTranslatorWithTranslatorInterfaceServiceComposedWhenPresent() { $i18nTranslator = $this->getMock('Zend\I18n\Translator\TranslatorInterface'); - $this->services->setService('Zend\I18n\Translator\TranslatorInterface', $i18nTranslator); + $services = $this->services->withConfig(['services' => [ + TranslatorInterface::class => $i18nTranslator, + ]]); - $translator = $this->factory->createService($this->services); + $translator = $this->factory->__invoke($services); $this->assertInstanceOf('Zend\Mvc\I18n\Translator', $translator); $this->assertSame($i18nTranslator, $translator->getTranslator()); } @@ -43,7 +47,7 @@ public function testReturnsMvcTranslatorWithDummyTranslatorComposedWhenExtIntlIs $this->markTestSkipped('This test will only run if ext/intl is not present'); } - $translator = $this->factory->createService($this->services); + $translator = $this->factory->__invoke($this->services); $this->assertInstanceOf('Zend\Mvc\I18n\Translator', $translator); $this->assertInstanceOf('Zend\Mvc\I18n\DummyTranslator', $translator->getTranslator()); } @@ -54,7 +58,7 @@ public function testReturnsMvcTranslatorWithI18nTranslatorComposedWhenNoTranslat $this->markTestSkipped('This test will only run if ext/intl is present'); } - $translator = $this->factory->createService($this->services); + $translator = $this->factory->__invoke($this->services); $this->assertInstanceOf('Zend\Mvc\I18n\Translator', $translator); $this->assertInstanceOf('Zend\I18n\Translator\Translator', $translator->getTranslator()); } @@ -64,15 +68,17 @@ public function testReturnsTranslatorBasedOnConfigurationWhenNoTranslatorInterfa $config = ['translator' => [ 'locale' => 'en_US', ]]; - $this->services->setService('Config', $config); + $services = $this->services->withConfig(['services' => [ + 'config' => $config, + ]]); - $translator = $this->factory->createService($this->services); + $translator = $this->factory->__invoke($services); $this->assertInstanceOf('Zend\Mvc\I18n\Translator', $translator); $this->assertInstanceOf('Zend\I18n\Translator\Translator', $translator->getTranslator()); return [ 'translator' => $translator->getTranslator(), - 'services' => $this->services, + 'services' => $services, ]; } @@ -95,17 +101,14 @@ public function testSetsPluginManagerFromServiceLocatorBasedOnConfiguration() 'module_listener_options' => [], 'modules' => [], ]; - $serviceLocator = new ServiceManager(new ServiceManagerConfig()); - $serviceLocator->setService('ApplicationConfig', $applicationConfig); + $config = new ServiceManagerConfig(); + $config = array_merge_recursive($config->toArray(), ['services' => [ + 'ApplicationConfig' => $applicationConfig, + ]]); + $serviceLocator = new ServiceManager($config); $serviceLocator->get('ModuleManager')->loadModules(); $serviceLocator->get('Application')->bootstrap(); - //enable to re-write Config - $ref = new \ReflectionObject($serviceLocator); - $prop = $ref->getProperty('allowOverride'); - $prop->setAccessible(true); - $prop->setValue($serviceLocator, true); - $config = [ 'di' => [], 'translator' => [ @@ -113,12 +116,14 @@ public function testSetsPluginManagerFromServiceLocatorBasedOnConfiguration() ], ]; - $serviceLocator->setService('Config', $config); + $services = $serviceLocator->withConfig(['services' => [ + 'config' => $config, + ]]); - $translator = $this->factory->createService($serviceLocator); + $translator = $this->factory->__invoke($services); $this->assertEquals( - $serviceLocator->get('TranslatorPluginManager'), + $services->get('TranslatorPluginManager'), $translator->getPluginManager() ); } @@ -134,17 +139,13 @@ public function testReturnsTranslatorBasedOnConfigurationWhenNoTranslatorInterfa 'module_listener_options' => [], 'modules' => [], ]; - $serviceLocator = new ServiceManager(new ServiceManagerConfig()); - $serviceLocator->setService('ApplicationConfig', $applicationConfig); + $config = array_merge_recursive((new ServiceManagerConfig())->toArray(), ['services' => [ + 'ApplicationConfig' => $applicationConfig, + ]]); + $serviceLocator = new ServiceManager($config); $serviceLocator->get('ModuleManager')->loadModules(); $serviceLocator->get('Application')->bootstrap(); - //enable to re-write Config - $ref = new \ReflectionObject($serviceLocator); - $prop = $ref->getProperty('allowOverride'); - $prop->setAccessible(true); - $prop->setValue($serviceLocator, true); - $config = [ 'di' => [], 'translator' => [ @@ -152,14 +153,16 @@ public function testReturnsTranslatorBasedOnConfigurationWhenNoTranslatorInterfa ], ]; - $serviceLocator->setService('Config', $config); + $services = $serviceLocator->withConfig(['services' => [ + 'config' => $config, + ]]); //#5959 //get any plugins with AbstractPluginManagerFactory $routePluginManagerFactory = new RoutePluginManagerFactory; - $routePluginManager = $routePluginManagerFactory->createService($serviceLocator); + $routePluginManager = $routePluginManagerFactory($services, 'RoutePluginManager'); - $translator = $this->factory->createService($serviceLocator); + $translator = $this->factory->__invoke($services); $this->assertInstanceOf('Zend\Mvc\I18n\Translator', $translator); $this->assertInstanceOf('Zend\I18n\Translator\Translator', $translator->getTranslator()); } @@ -169,6 +172,7 @@ public function testReturnsTranslatorBasedOnConfigurationWhenNoTranslatorInterfa */ public function testSetsInstantiatedI18nTranslatorInstanceInServiceManager($dependencies) { + $this->markTestIncomplete('Test disabled for v3; need to determine if needed'); $translator = $dependencies['translator']; $services = $dependencies['services']; $this->assertTrue($services->has('Zend\I18n\Translator\TranslatorInterface')); @@ -180,12 +184,13 @@ public function testPrefersTranslatorInterfaceImplementationOverConfig() $config = ['translator' => [ 'locale' => 'en_US', ]]; - $this->services->setService('Config', $config); - $i18nTranslator = $this->getMock('Zend\I18n\Translator\TranslatorInterface'); - $this->services->setService('Zend\I18n\Translator\TranslatorInterface', $i18nTranslator); + $services = $this->services->withConfig(['services' => [ + 'config' => $config, + 'Zend\I18n\Translator\TranslatorInterface' => $i18nTranslator, + ]]); - $translator = $this->factory->createService($this->services); + $translator = $this->factory->__invoke($services); $this->assertInstanceOf('Zend\Mvc\I18n\Translator', $translator); $this->assertSame($i18nTranslator, $translator->getTranslator()); } @@ -193,8 +198,10 @@ public function testPrefersTranslatorInterfaceImplementationOverConfig() public function testReturnsDummyTranslatorWhenTranslatorConfigIsBooleanFalse() { $config = ['translator' => false]; - $this->services->setService('Config', $config); - $translator = $this->factory->createService($this->services); + $services = $this->services->withConfig(['services' => [ + 'config' => $config, + ]]); + $translator = $this->factory->__invoke($services); $this->assertInstanceOf('Zend\Mvc\I18n\Translator', $translator); $this->assertInstanceOf('Zend\Mvc\I18n\DummyTranslator', $translator->getTranslator()); } diff --git a/test/Service/ViewFeedStrategyFactoryTest.php b/test/Service/ViewFeedStrategyFactoryTest.php new file mode 100644 index 000000000..a3541ce6a --- /dev/null +++ b/test/Service/ViewFeedStrategyFactoryTest.php @@ -0,0 +1,36 @@ +prophesize(FeedRenderer::class); + $container = $this->prophesize(ContainerInterface::class); + $container->get('ViewFeedRenderer')->will(function () use ($renderer) { + return $renderer->reveal(); + }); + return $container->reveal(); + } + + public function testReturnsFeedStrategy() + { + $factory = new ViewFeedStrategyFactory(); + $result = $factory($this->createContainer(), 'ViewFeedStrategy'); + $this->assertInstanceOf(FeedStrategy::class, $result); + } +} diff --git a/test/Service/ViewHelperManagerFactoryTest.php b/test/Service/ViewHelperManagerFactoryTest.php index 955ea2302..c43aed988 100644 --- a/test/Service/ViewHelperManagerFactoryTest.php +++ b/test/Service/ViewHelperManagerFactoryTest.php @@ -9,8 +9,16 @@ namespace ZendTest\Mvc\Service; +use Interop\Container\ContainerInterface; use PHPUnit_Framework_TestCase as TestCase; +use ReflectionProperty; +use Zend\Console\Console; use Zend\Console\Request as ConsoleRequest; +use Zend\Http\PhpEnvironment\Request as HttpRequest; +use Zend\Mvc\Application; +use Zend\Mvc\MvcEvent; +use Zend\Mvc\Router\RouteMatch; +use Zend\Mvc\Router\RouteStackInterface; use Zend\Mvc\Service\ViewHelperManagerFactory; use Zend\ServiceManager\ServiceManager; @@ -41,8 +49,10 @@ public function emptyConfiguration() */ public function testDoctypeFactoryDoesNotRaiseErrorOnMissingConfiguration($config) { - $this->services->setService('Config', $config); - $manager = $this->factory->createService($this->services); + $services = $this->services->withConfig(['services' => [ + 'config' => $config, + ]]); + $manager = $this->factory->__invoke($services, 'ViewHelperManager'); $this->assertInstanceof('Zend\View\HelperPluginManager', $manager); $doctype = $manager->get('doctype'); $this->assertInstanceof('Zend\View\Helper\Doctype', $doctype); @@ -50,10 +60,12 @@ public function testDoctypeFactoryDoesNotRaiseErrorOnMissingConfiguration($confi public function testConsoleRequestsResultInSilentFailure() { - $this->services->setService('Config', []); - $this->services->setService('Request', new ConsoleRequest()); + $services = $this->services->withConfig(['services' => [ + 'config' => [], + 'Request' => new ConsoleRequest(), + ]]); - $manager = $this->factory->createService($this->services); + $manager = $this->factory->__invoke($services, 'ViewHelperManager'); $doctype = $manager->get('doctype'); $this->assertInstanceof('Zend\View\Helper\Doctype', $doctype); @@ -67,18 +79,141 @@ public function testConsoleRequestsResultInSilentFailure() */ public function testConsoleRequestWithBasePathConsole() { - $this->services->setService('Config', - [ + // Force Console context + $r = new ReflectionProperty(Console::class, 'isConsole'); + $r->setAccessible(true); + $r->setValue(true); + + if (! Console::isConsole()) { + $this->markTestSkipped('Cannot force console context; skipping test'); + } + + $services = $this->services->withConfig(['services' => [ + 'config' => [ 'view_manager' => [ - 'base_path_console' => 'http://test.com' - ] - ] + 'base_path_console' => 'http://test.com', + ], + ], + 'Request' => new ConsoleRequest(), + ]]); + + $this->assertTrue($services->has('config'), 'Config service does not appear to be present'); + $config = $services->get('config'); + $this->assertArrayHasKey( + 'view_manager', + $config, + 'Config service is missing view_manager configuration' + ); + $this->assertArrayHasKey( + 'base_path_console', + $config['view_manager'], + 'Config service is missing base_path_console view_manager configuration' ); - $this->services->setService('Request', new ConsoleRequest()); - $manager = $this->factory->createService($this->services); + $manager = $this->factory->__invoke($services, 'ViewHelperManager'); $basePath = $manager->get('basepath'); $this->assertEquals('http://test.com', $basePath()); } + + public function testCreatesCustomUrlHelperFactory() + { + $routeMatch = $this->prophesize(RouteMatch::class); + + $mvcEvent = $this->prophesize(MvcEvent::class); + $mvcEvent->getRouteMatch()->will(function () use ($routeMatch) { + return $routeMatch->reveal(); + }); + + $application = $this->prophesize(Application::class); + $application->getMvcEvent()->will(function () use ($mvcEvent) { + return $mvcEvent->reveal(); + }); + + $router = $this->prophesize(RouteStackInterface::class); + + $container = $this->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(false); + $container->get('Router')->will(function () use ($router) { + return $router->reveal(); + }); + $container->get('HttpRouter')->will(function () use ($router) { + return $router->reveal(); + }); + $container->get('application')->will(function () use ($application) { + return $application->reveal(); + }); + + $factory = $this->factory; + $manager = $factory($container->reveal(), 'ViewHelperManager'); + $helper = $manager->get('url'); + $this->assertAttributeSame($router->reveal(), 'router', $helper); + $this->assertAttributeSame($routeMatch->reveal(), 'routeMatch', $helper); + } + + public function testCustomBasePathHelperFactoryCanUseViewManagerConfig() + { + $container = $this->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(true); + $container->get('config')->willReturn([ + 'view_manager' => [ + 'base_path' => 'https://example.com/test', + ], + ]); + + $factory = $this->factory; + $manager = $factory($container->reveal(), 'ViewHelperManager'); + $helper = $manager->get('basepath'); + $this->assertEquals('https://example.com/test', $helper()); + } + + public function testCustomBasePathHelperFactoryCanUseViewManagerConsoleConfig() + { + $container = $this->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(true); + $container->get('config')->willReturn([ + 'view_manager' => [ + 'base_path_console' => 'https://example.com/test', + ], + ]); + + $factory = $this->factory; + $manager = $factory($container->reveal(), 'ViewHelperManager'); + $helper = $manager->get('basepath'); + $this->assertEquals('https://example.com/test', $helper()); + } + + public function testCustomBasePathHelperFactoryCanUseRequestService() + { + $request = $this->prophesize(HttpRequest::class); + $request->getBasePath()->willReturn('https://example.com/test'); + + $container = $this->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(true); + $container->get('config')->willReturn([]); + $container->get('Request')->will(function () use ($request) { + return $request->reveal(); + }); + + $factory = $this->factory; + $manager = $factory($container->reveal(), 'ViewHelperManager'); + $helper = $manager->get('basepath'); + $this->assertEquals('https://example.com/test', $helper()); + } + + public function testCustomDoctypeHelperFactoryCanUseViewManagerConfig() + { + $container = $this->prophesize(ContainerInterface::class); + $container->has('config')->willReturn(true); + $container->get('config')->willReturn([ + 'view_manager' => [ + 'doctype' => 'CUSTOM', + ], + ]); + + $factory = $this->factory; + $manager = $factory($container->reveal(), 'ViewHelperManager'); + $helper = $manager->get('doctype'); + $this->assertEquals('CUSTOM', $helper->getDoctype()); + } } diff --git a/test/Service/ViewJsonStrategyFactoryTest.php b/test/Service/ViewJsonStrategyFactoryTest.php new file mode 100644 index 000000000..f364589d4 --- /dev/null +++ b/test/Service/ViewJsonStrategyFactoryTest.php @@ -0,0 +1,36 @@ +prophesize(JsonRenderer::class); + $container = $this->prophesize(ContainerInterface::class); + $container->get('ViewJsonRenderer')->will(function () use ($renderer) { + return $renderer->reveal(); + }); + return $container->reveal(); + } + + public function testReturnsJsonStrategy() + { + $factory = new ViewJsonStrategyFactory(); + $result = $factory($this->createContainer(), 'ViewJsonStrategy'); + $this->assertInstanceOf(JsonStrategy::class, $result); + } +} diff --git a/test/Service/ViewManagerFactoryTest.php b/test/Service/ViewManagerFactoryTest.php new file mode 100644 index 000000000..a81bea773 --- /dev/null +++ b/test/Service/ViewManagerFactoryTest.php @@ -0,0 +1,56 @@ +setConsoleEnvironment(true); + } + + private function createContainer() + { + $console = $this->prophesize(ConsoleViewManager::class); + $http = $this->prophesize(HttpViewManager::class); + $container = $this->prophesize(ContainerInterface::class); + $container->get('ConsoleViewManager')->will(function () use ($console) { + return $console->reveal(); + }); + $container->get('HttpViewManager')->will(function () use ($http) { + return $http->reveal(); + }); + return $container->reveal(); + } + + public function testReturnsConsoleViewManagerInConsoleEnvironment() + { + $this->setConsoleEnvironment(true); + $factory = new ViewManagerFactory(); + $result = $factory($this->createContainer(), 'ViewManager'); + $this->assertInstanceOf(ConsoleViewManager::class, $result); + } + + public function testReturnsHttpViewManagerInNonConsoleEnvironment() + { + $this->setConsoleEnvironment(false); + $factory = new ViewManagerFactory(); + $result = $factory($this->createContainer(), 'ViewManager'); + $this->assertInstanceOf(HttpViewManager::class, $result); + } +} diff --git a/test/Service/ViewPrefixPathStackResolverFactoryTest.php b/test/Service/ViewPrefixPathStackResolverFactoryTest.php index eff5c39e3..87a5d251b 100644 --- a/test/Service/ViewPrefixPathStackResolverFactoryTest.php +++ b/test/Service/ViewPrefixPathStackResolverFactoryTest.php @@ -20,7 +20,7 @@ public function testCreateService() $serviceLocator->expects($this->once()) ->method('get') - ->with('Config') + ->with('config') ->will($this->returnValue([ 'view_manager' => [ 'prefix_template_path_stack' => [ @@ -30,7 +30,7 @@ public function testCreateService() ])); $factory = new ViewPrefixPathStackResolverFactory(); - $resolver = $factory->createService($serviceLocator); + $resolver = $factory($serviceLocator, 'ViewPrefixPathStackResolver'); $this->assertInstanceOf('Zend\View\Resolver\PrefixPathStackResolver', $resolver); } diff --git a/test/TestAsset/Locator.php b/test/TestAsset/Locator.php index 1b77624b4..2546ea7d4 100644 --- a/test/TestAsset/Locator.php +++ b/test/TestAsset/Locator.php @@ -10,7 +10,7 @@ namespace ZendTest\Mvc\TestAsset; use Zend\ServiceManager\ServiceLocatorInterface; -use Zend\Di\Exception\ClassNotFoundException; +use Zend\ServiceManager\Exception\ServiceNotFoundException; /** * Dummy locator used to test handling of locator objects by Application @@ -19,14 +19,13 @@ class Locator implements ServiceLocatorInterface { protected $services = array(); - public function get($name, array $params = array()) + public function get($name) { if (!isset($this->services[$name])) { - throw new ClassNotFoundException(); + throw new ServiceNotFoundException(); } - $service = call_user_func_array($this->services[$name], $params); - return $service; + return call_user_func_array($this->services[$name]); } public function has($name) @@ -34,6 +33,15 @@ public function has($name) return (isset($this->services[$name])); } + public function build($name, array $options = null) + { + if (!isset($this->services[$name])) { + throw new ServiceNotFoundException(); + } + + return call_user_func_array($this->services[$name], $options); + } + public function add($name, $callback) { $this->services[$name] = $callback; diff --git a/test/View/Console/CreateViewModelListenerTest.php b/test/View/Console/CreateViewModelListenerTest.php new file mode 100644 index 000000000..61f09087d --- /dev/null +++ b/test/View/Console/CreateViewModelListenerTest.php @@ -0,0 +1,102 @@ +listener = new CreateViewModelListener(); + } + + public function testAttachesListenersAtExpectedPriorities() + { + $events = new EventManager(); + $this->listener->attach($events); + + $this->assertListenerAtPriority( + [$this->listener, 'createViewModelFromString'], + -80, + MvcEvent::EVENT_DISPATCH, + $events, + 'View model from string listener not found' + ); + + $this->assertListenerAtPriority( + [$this->listener, 'createViewModelFromArray'], + -80, + MvcEvent::EVENT_DISPATCH, + $events, + 'View model from array listener not found' + ); + + $this->assertListenerAtPriority( + [$this->listener, 'createViewModelFromNull'], + -80, + MvcEvent::EVENT_DISPATCH, + $events, + 'View model from null listener not found' + ); + } + + public function testCanDetachListenersFromEventManager() + { + $events = new EventManager(); + $this->listener->attach($events); + + $listeners = $this->getArrayOfListenersForEvent(MvcEvent::EVENT_DISPATCH, $events); + $this->assertCount(3, $listeners); + + $this->listener->detach($events); + $listeners = $this->getArrayOfListenersForEvent(MvcEvent::EVENT_DISPATCH, $events); + $this->assertCount(0, $listeners); + } + + public function testCanCreateViewModelFromStringResult() + { + $event = new MvcEvent(); + $event->setResult('content'); + $this->listener->createViewModelFromString($event); + + $result = $event->getResult(); + $this->assertInstanceOf(ConsoleModel::class, $result); + $this->assertSame('content', $result->getVariable(ConsoleModel::RESULT)); + } + + public function testCanCreateViewModelFromArrayResult() + { + $expected = ['foo' => 'bar']; + $event = new MvcEvent(); + $event->setResult($expected); + $this->listener->createViewModelFromArray($event); + + $result = $event->getResult(); + $this->assertInstanceOf(ConsoleModel::class, $result); + $this->assertSame($expected, $result->getVariables()); + } + + public function testCanCreateViewModelFromNullResult() + { + $event = new MvcEvent(); + $this->listener->createViewModelFromNull($event); + + $result = $event->getResult(); + $this->assertInstanceOf(ConsoleModel::class, $result); + } +} diff --git a/test/View/Console/DefaultRenderingStrategyTest.php b/test/View/Console/DefaultRenderingStrategyTest.php index 43020d80a..25eea159c 100644 --- a/test/View/Console/DefaultRenderingStrategyTest.php +++ b/test/View/Console/DefaultRenderingStrategyTest.php @@ -67,8 +67,9 @@ public function testIgnoresNonConsoleModelNotContainingResultKeyWhenObtainingRes ->willReturnArgument(0); //Register console service - $sm = new ServiceManager(); - $sm->setService('console', $console); + $sm = new ServiceManager(['services' => [ + 'console' => $console, + ]]); /* @var \PHPUnit_Framework_MockObject_MockObject|ApplicationInterface $mockApplication */ $mockApplication = $this->getMock(ApplicationInterface::class); @@ -98,8 +99,9 @@ public function testIgnoresNonModel() ->willReturnArgument(0); //Register console service - $sm = new ServiceManager(); - $sm->setService('console', $console); + $sm = new ServiceManager(['services' => [ + 'console' => $console, + ]]); /* @var \PHPUnit_Framework_MockObject_MockObject|ApplicationInterface $mockApplication */ $mockApplication = $this->getMock(ApplicationInterface::class); diff --git a/test/View/Console/ViewManagerTest.php b/test/View/Console/ViewManagerTest.php index 9d1d735fa..4bd7aea5d 100644 --- a/test/View/Console/ViewManagerTest.php +++ b/test/View/Console/ViewManagerTest.php @@ -10,15 +10,19 @@ namespace ZendTest\Mvc\View\Console; use PHPUnit_Framework_TestCase as TestCase; +use ReflectionProperty; +use Zend\Console\Request as ConsoleRequest; use Zend\Console\Response as ConsoleResponse; use Zend\EventManager\EventManager; use Zend\EventManager\SharedEventManager; use Zend\Mvc\Application; use Zend\Mvc\MvcEvent; use Zend\Mvc\Service\ConsoleViewManagerFactory; +use Zend\Mvc\Service\ServiceListenerFactory; use Zend\Mvc\Service\ServiceManagerConfig; +use Zend\Mvc\View\Console\ViewManager; use Zend\ServiceManager\ServiceManager; -use Zend\Console\Request as ConsoleRequest; +use Zend\Stdlib\ArrayUtils; /** * Tests for {@see \Zend\Mvc\View\Console\ViewManager} @@ -44,9 +48,18 @@ class ViewManagerTest extends TestCase public function setUp() { - $this->config = new ServiceManagerConfig(); - $this->services = new ServiceManager(); - $this->factory = new ConsoleViewManagerFactory(); + $this->services = new ServiceManager($this->prepareServiceManagerConfig()); + $this->factory = new ConsoleViewManagerFactory(); + } + + private function prepareServiceManagerConfig() + { + $serviceListener = new ServiceListenerFactory(); + $r = new ReflectionProperty($serviceListener, 'defaultServiceConfig'); + $r->setAccessible(true); + + $config = $r->getValue($serviceListener); + return ArrayUtils::merge((new ServiceManagerConfig())->toArray(), $config); } /** @@ -105,27 +118,29 @@ public function viewManagerConfiguration() * * @group 6866 */ - public function testConsoleKeyWillOverrideDisplayExceptionAndDisplayNotFoundReason($config) + public function testConsoleKeyWillOverrideDisplayExceptionAndExceptionMessage($config) { $eventManager = new EventManager(new SharedEventManager()); $request = new ConsoleRequest(); $response = new ConsoleResponse(); - $this->services->setService('Config', $config); - $this->services->setService('Request', $request); - $this->services->setService('EventManager', $eventManager); - $this->services->setService('Response', $response); + $services = $this->services->withConfig(['services' => [ + 'config' => $config, + 'Request' => $request, + 'EventManager' => $eventManager, + 'Response' => $response, + ]]); - $manager = $this->factory->createService($this->services); + $manager = $this->factory->__invoke($services, 'ConsoleViewRenderer'); - $application = new Application($config, $this->services, $eventManager, $request, $response); + $application = new Application($config, $services, $eventManager, $request, $response); $event = new MvcEvent(); $event->setApplication($application); $manager->onBootstrap($event); - $this->assertFalse($manager->getExceptionStrategy()->displayExceptions()); - $this->assertFalse($manager->getRouteNotFoundStrategy()->displayNotFoundReason()); + $this->assertFalse($services->get('ConsoleExceptionStrategy')->displayExceptions()); + $this->assertFalse($services->get('ConsoleRouteNotFoundStrategy')->displayNotFoundReason()); } /** @@ -137,20 +152,28 @@ public function testConsoleDisplayExceptionIsTrue() $request = new ConsoleRequest(); $response = new ConsoleResponse(); - $this->services->setService('Config', []); - $this->services->setService('Request', $request); - $this->services->setService('EventManager', $eventManager); - $this->services->setService('Response', $response); - - $manager = $this->factory->createService($this->services); - - $application = new Application([], $this->services, $eventManager, $request, $response); + $services = $this->services->withConfig([ + 'services' => [ + 'config' => [], + 'Request' => $request, + 'EventManager' => $eventManager, + 'Response' => $response, + ], + ]); - $event = new MvcEvent(); + $manager = new ViewManager; + $application = new Application([], $services, $eventManager, $request, $response); + $event = new MvcEvent(); $event->setApplication($application); + $manager->onBootstrap($event); - $this->assertTrue($manager->getExceptionStrategy()->displayExceptions()); - $this->assertTrue($manager->getRouteNotFoundStrategy()->displayNotFoundReason()); + $exceptionStrategy = $services->get('ConsoleExceptionStrategy'); + $this->assertInstanceOf('Zend\Mvc\View\Console\ExceptionStrategy', $exceptionStrategy); + $this->assertTrue($exceptionStrategy->displayExceptions()); + + $routeNotFoundStrategy = $services->get('ConsoleRouteNotFoundStrategy'); + $this->assertInstanceOf('Zend\Mvc\View\Console\RouteNotFoundStrategy', $routeNotFoundStrategy); + $this->assertTrue($routeNotFoundStrategy->displayNotFoundReason()); } } diff --git a/test/View/DefaultRendereringStrategyTest.php b/test/View/DefaultRendereringStrategyTest.php index 18715e64d..87f242a78 100644 --- a/test/View/DefaultRendereringStrategyTest.php +++ b/test/View/DefaultRendereringStrategyTest.php @@ -134,15 +134,25 @@ public function testTriggersRenderErrorEventInCaseOfRenderingException() $model->setTemplate('exception'); $this->event->setViewModel($model); - $services = new ServiceManager(); - $services->setService('Request', $this->request); - $services->setService('Response', $this->response); - $services->setInvokableClass('SharedEventManager', 'Zend\EventManager\SharedEventManager'); - $services->setFactory('EventManager', function ($services) { - $sharedEvents = $services->get('SharedEventManager'); - $events = new EventManager($sharedEvents); - return $events; - }, false); + $services = new ServiceManager([ + 'invokables' => [ + 'SharedEventManager' => 'Zend\EventManager\SharedEventManager', + ], + 'factories' => [ + 'EventManager' => function ($services, $name, array $options = null) { + $sharedEvents = $services->get('SharedEventManager'); + $events = new EventManager($sharedEvents); + return $events; + }, + ], + 'services' => [ + 'Request' => $this->request, + 'Response' => $this->response, + ], + 'shared' => [ + 'EventManager' => false, + ], + ]); $application = new Application([], $services, $services->get('EventManager'), $this->request, $this->response); $this->event->setApplication($application);