diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dc6ef691..e4d0e5c6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ All notable changes to this project will be documented in this file, in reverse - [#31](https://github.com/zendframework/zend-mvc/pull/31) adds three required arguments to the `Zend\Mvc\Application` constructor: an EventManager instance, a Request instance, and a Response instance. +- [#36](https://github.com/zendframework/zend-mvc/pull/36) adds more than a + dozen service factories, primarily to separate conditional factories into + discrete factories. ### Deprecated @@ -16,12 +19,47 @@ All notable changes to this project will be documented in this file, in reverse ### Removed -- Nothing. +- [#36](https://github.com/zendframework/zend-mvc/pull/36) removes + `Zend\Mvc\Service\ConfigFactory`, as the functionality is now incorporated + into `Zend\ModuleManager\Listener\ServiceListener`. +- [#36](https://github.com/zendframework/zend-mvc/pull/36) removes + the `ServiceLocatorAware` intializer, as zend-servicemanager v3 no longer + defines the interface. +- [#36](https://github.com/zendframework/zend-mvc/pull/36) removes + `Zend\Mvc\Service\ControllerLoaderFactory` and replaces it with + `Zend\Mvc\Service\ControllerManagerFactory`. +- [#36](https://github.com/zendframework/zend-mvc/pull/36) removes + `Zend\Mvc\Service\DiFactory`, `Zend\Mvc\Service\DiAbstractServiceFactory`, + `Zend\Mvc\Service\DiStrictAbstractServiceFactory`, + `Zend\Mvc\Service\DiStrictAbstractServiceFactoryFactory`, + and `Zend\Mvc\Service\DiServiceInitializerFactory`, as zend-servicemanager v3 + removes `Zend\Di` integration. ### Fixed - [#31](https://github.com/zendframework/zend-mvc/pull/31) updates the component to use zend-eventmanager v3. +- [#36](https://github.com/zendframework/zend-mvc/pull/36) updates the component + to use zend-servicemanager v3, and zend-modulemanager v3. This involves: + - Updating all factories implementing either `FactoryInterface` or + `AbstractFactoryInterface` to the new signatures of those interfaces. + - Updating all plugin managers to the updates to `AbstractPluginManager`. + - Updating how plugin manager factories work (they're now passed the container + instance in their constructor arguments, as well as any build options). + - Added a `RouteInvokableFactory`, which can act as either a + `FactoryInterface` or `AbstractFactoryInterface` for loading invokable route + classes, including by fully qualified class name. This is registered as an + abstract factory by default with the `RoutePluginManager`. + - The `DispatchListener` now receives the controller manager instance at + instantiation. + - The `ViewManager` implementations were updated, and most functionality + within separated into discrete factories. (Previously these instances + injected services and aliases into the service manager instance, which is no + longer possible or desirable with the zend-servicemanager v3 changes.) + - `Application::init()` now pulls the configured service manager from the + `Zend\ModuleManager\Listener\ServiceListener` instance before retrieving and + bootstrapping the `Application` instance; this ensure it is fully + configured at that time. ## 2.6.1 - TBD diff --git a/composer.json b/composer.json index d00404ebc..5a85e94d4 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", 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 @@ +
+ 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 @@ +exception->getFile() ?>:exception->getLine() ?>+
exception->getMessage() ?>+
exception->getTraceAsString() ?>+
getFile() ?>:getLine() ?>+
getMessage() ?>+
getTraceAsString() ?>+
exception->getFile() ?>:exception->getLine() ?>+
escapeHtml($this->exception->getMessage()) ?>+
escapeHtml($this->exception->getTraceAsString()) ?>+
getFile() ?>:getLine() ?>+
escapeHtml($e->getMessage()) ?>+
escapeHtml($e->getTraceAsString()) ?>+