<?php
namespace dns\system;
use dns\system\cache\builder\ControllerCacheBuilder;
+use Zend\Mvc\Router\Http\Literal;
+use Zend\Mvc\Router\Http\Regex;
+use Zend\Mvc\Router\SimpleRouteStack;
+use Zend\ServiceManager\ServiceManager;
/**
* @author Jan Altensen (Stricted)
* init RequestHandler
*/
public function __construct ($module = '') {
- $this->pattern = '~/?(?:(?P<controller>[A-Za-z0-9\-]+)(?:/(?P<id>\d+)(?:-(?P<title>[^/]+))?)?)?~x';
- $controllers = ControllerCacheBuilder::getInstance()->getData(array('module' => $module));
-
if (DNS::getSession()->username !== null) {
DNS::getTPL()->assign(array("username" => DNS::getSession()->username));
}
DNS::getTPL()->assign(array("username" => ''));
}
- $className = "";
- if (!empty($_SERVER['QUERY_STRING'])) {
- $this->matches($_SERVER['QUERY_STRING']);
- $this->registerRouteData();
- }
- else {
- $className = '\\dns'.(empty($module) ? '' : '\\'.$module).'\\page\\IndexPage';
- }
+ $router = new SimpleRouteStack();
+
+ $router->addRoute('', Literal::factory([ 'route' => '', 'defaults' => [ 'controller' => 'dns\page\IndexPage' ] ]));
+ $router->addRoute('Index', Literal::factory([ 'route' => 'Index', 'defaults' => [ 'controller' => 'dns\page\IndexPage' ] ]));
+ $router->addRoute('index', Literal::factory([ 'route' => 'index', 'defaults' => [ 'controller' => 'dns\page\IndexPage' ] ]));
+ $router->addRoute('Login', Literal::factory([ 'route' => 'Login', 'defaults' => [ 'controller' => 'dns\page\LoginPage' ] ]));
+ $router->addRoute('Logout', Literal::factory([ 'route' => 'Logout', 'defaults' => [ 'controller' => 'dns\page\LogoutPage' ] ]));
+ $router->addRoute('DomainList', Literal::factory([ 'route' => 'DomainList', 'defaults' => [ 'controller' => 'dns\page\DomainListPage' ] ]));
+ $router->addRoute('DomainAdd', Literal::factory([ 'route' => 'DomainAdd', 'defaults' => [ 'controller' => 'dns\page\DomainAddPage' ] ]));
+ //$router->addRoute('DomainAdd', Regex::factory([ 'regex' => 'DomainEdit/(?P<id>\d+)(/)?', 'defaults' => [ 'controller' => 'dns\page\DomainEditPage' ], 'spec' => '/DomainEdit/%id%' ]));
- if (isset($this->routeData['controller']) && !empty($this->routeData['controller'])) {
- $controller = strtolower($this->routeData['controller']);
- if (isset($controllers[$controller]) && !empty($controllers[$controller])) {
- $className = $controllers[$controller];
+ $match = $router->match(new Request());
+ if ($match !== null) {
+ foreach ($match->getParams() as $key => $value) {
+ $_GET[$key] = $value;
+ $_REQUEST[$key] = $value;
}
- else {
- @header('HTTP/1.0 404 Not Found');
- DNS::getTPL()->assign(array("activeMenuItem" => '', "error" => 'The link you are trying to reach is no longer available or invalid.'));
- DNS::getTPL()->display('error.tpl');
+
+ $className = $match->getParam("controller");
+
+ if (!User::isLoggedIn() && $className != 'dns\page\LoginPage' && $className != 'dns\page\ApiPage') {
+ echo $className;
+ DNS::getTPL()->display('login.tpl');
exit;
}
- }
-
- if (!User::isLoggedIn() && $className != '\dns\page\LoginPage' && $className != '\dns\page\ApiPage') {
- DNS::getTPL()->display('login.tpl');
- exit;
- }
-
- // handle offline mode
- if (defined('OFFLINE') && OFFLINE) {
- $admin = User::isAdmin();
- $available = false;
- if (defined($className . '::AVAILABLE_DURING_OFFLINE_MODE') && constant($className . '::AVAILABLE_DURING_OFFLINE_MODE')) {
- $available = true;
+ if (defined('OFFLINE') && OFFLINE) {
+ $admin = User::isAdmin();
+ $available = false;
+
+ if (defined($className . '::AVAILABLE_DURING_OFFLINE_MODE') && constant($className . '::AVAILABLE_DURING_OFFLINE_MODE')) {
+ $available = true;
+ }
+
+ if (!$admin && !$available) {
+ @header('HTTP/1.1 503 Service Unavailable');
+ DNS::getTPL()->display('offline.tpl');
+ exit;
+ }
}
- if (!$admin && !$available) {
- @header('HTTP/1.1 503 Service Unavailable');
- DNS::getTPL()->display('offline.tpl');
+ try {
+ new $className();
+ }
+ catch (\Exception $e) {
+ if ($e->getCode() == 404) {
+ @header('HTTP/1.0 404 Not Found');
+ }
+ else if ($e->getCode() == 403) {
+ @header('HTTP/1.0 403 Forbidden');
+ }
+
+ // show error page
+ DNS::getTPL()->assign(array("activeMenuItem" => '', "error" => $e->getMessage()));
+ DNS::getTPL()->display('error.tpl');
exit;
}
}
-
- try {
- new $className();
- }
- catch (\Exception $e) {
- if ($e->getCode() == 404) {
- @header('HTTP/1.0 404 Not Found');
- }
- else if ($e->getCode() == 403) {
- @header('HTTP/1.0 403 Forbidden');
- }
-
- /* show error page */
- DNS::getTPL()->assign(array("activeMenuItem" => '', "error" => $e->getMessage()));
+ else {
+ @header('HTTP/1.0 404 Not Found');
+ DNS::getTPL()->assign(array("activeMenuItem" => '', "error" => 'The link you are trying to reach is no longer available or invalid.'));
DNS::getTPL()->display('error.tpl');
exit;
}
}
-
- /**
- * Registers route data within $_GET and $_REQUEST.
- */
- protected function registerRouteData() {
- foreach ($this->routeData as $key => $value) {
- $_GET[$key] = $value;
- $_REQUEST[$key] = $value;
- }
- }
-
- public function matches($requestURL) {
- if (preg_match($this->pattern, $requestURL, $matches)) {
- foreach ($matches as $key => $value) {
- if (!is_numeric($key)) {
- $this->routeData[$key] = $value;
- }
- }
-
- return true;
- }
-
- return false;
- }
}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc;
+
+use Zend\EventManager\EventManagerAwareInterface;
+use Zend\EventManager\EventManagerInterface;
+use Zend\ServiceManager\ServiceManager;
+use Zend\Stdlib\RequestInterface;
+use Zend\Stdlib\ResponseInterface;
+
+/**
+ * Main application class for invoking applications
+ *
+ * Expects the user will provide a configured ServiceManager, configured with
+ * the following services:
+ *
+ * - EventManager
+ * - ModuleManager
+ * - Request
+ * - Response
+ * - RouteListener
+ * - Router
+ * - DispatchListener
+ * - MiddlewareListener
+ * - ViewManager
+ *
+ * The most common workflow is:
+ * <code>
+ * $services = new Zend\ServiceManager\ServiceManager($servicesConfig);
+ * $app = new Application($appConfig, $services);
+ * $app->bootstrap();
+ * $response = $app->run();
+ * $response->send();
+ * </code>
+ *
+ * bootstrap() opts in to the default route, dispatch, and view listeners,
+ * sets up the MvcEvent, and triggers the bootstrap event. This can be omitted
+ * if you wish to setup your own listeners and/or workflow; alternately, you
+ * can simply extend the class to override such behavior.
+ */
+class Application implements
+ ApplicationInterface,
+ EventManagerAwareInterface
+{
+ const ERROR_CONTROLLER_CANNOT_DISPATCH = 'error-controller-cannot-dispatch';
+ const ERROR_CONTROLLER_NOT_FOUND = 'error-controller-not-found';
+ const ERROR_CONTROLLER_INVALID = 'error-controller-invalid';
+ const ERROR_EXCEPTION = 'error-exception';
+ const ERROR_ROUTER_NO_MATCH = 'error-router-no-match';
+ const ERROR_MIDDLEWARE_CANNOT_DISPATCH = 'error-middleware-cannot-dispatch';
+
+ /**
+ * @var array
+ */
+ protected $configuration = null;
+
+ /**
+ * Default application event listeners
+ *
+ * @var array
+ */
+ protected $defaultListeners = [
+ 'RouteListener',
+ 'MiddlewareListener',
+ 'DispatchListener',
+ 'HttpMethodListener',
+ 'ViewManager',
+ 'SendResponseListener',
+ ];
+
+ /**
+ * MVC event token
+ * @var MvcEvent
+ */
+ protected $event;
+
+ /**
+ * @var EventManagerInterface
+ */
+ protected $events;
+
+ /**
+ * @var \Zend\Stdlib\RequestInterface
+ */
+ protected $request;
+
+ /**
+ * @var ResponseInterface
+ */
+ protected $response;
+
+ /**
+ * @var ServiceManager
+ */
+ protected $serviceManager = null;
+
+ /**
+ * Constructor
+ *
+ * @param mixed $configuration
+ * @param ServiceManager $serviceManager
+ * @param null|EventManagerInterface $events
+ * @param null|RequestInterface $request
+ * @param null|ResponseInterface $response
+ */
+ public function __construct(
+ $configuration,
+ ServiceManager $serviceManager,
+ EventManagerInterface $events = null,
+ RequestInterface $request = null,
+ ResponseInterface $response = null
+ ) {
+ $this->configuration = $configuration;
+ $this->serviceManager = $serviceManager;
+ $this->setEventManager($events ?: $serviceManager->get('EventManager'));
+ $this->request = $request ?: $serviceManager->get('Request');
+ $this->response = $response ?: $serviceManager->get('Response');
+ }
+
+ /**
+ * Retrieve the application configuration
+ *
+ * @return array|object
+ */
+ public function getConfig()
+ {
+ return $this->serviceManager->get('config');
+ }
+
+ /**
+ * Bootstrap the application
+ *
+ * Defines and binds the MvcEvent, and passes it the request, response, and
+ * router. Attaches the ViewManager as a listener. Triggers the bootstrap
+ * event.
+ *
+ * @param array $listeners List of listeners to attach.
+ * @return Application
+ */
+ public function bootstrap(array $listeners = [])
+ {
+ $serviceManager = $this->serviceManager;
+ $events = $this->events;
+
+ // Setup default listeners
+ $listeners = array_unique(array_merge($this->defaultListeners, $listeners));
+
+ foreach ($listeners as $listener) {
+ $serviceManager->get($listener)->attach($events);
+ }
+
+ // Setup MVC Event
+ $this->event = $event = new MvcEvent();
+ $event->setName(MvcEvent::EVENT_BOOTSTRAP);
+ $event->setTarget($this);
+ $event->setApplication($this);
+ $event->setRequest($this->request);
+ $event->setResponse($this->response);
+ $event->setRouter($serviceManager->get('Router'));
+
+ // Trigger bootstrap events
+ $events->triggerEvent($event);
+
+ return $this;
+ }
+
+ /**
+ * Retrieve the service manager
+ *
+ * @return ServiceManager
+ */
+ public function getServiceManager()
+ {
+ return $this->serviceManager;
+ }
+
+ /**
+ * Get the request object
+ *
+ * @return \Zend\Stdlib\RequestInterface
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * Get the response object
+ *
+ * @return ResponseInterface
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ /**
+ * Get the MVC event instance
+ *
+ * @return MvcEvent
+ */
+ public function getMvcEvent()
+ {
+ return $this->event;
+ }
+
+ /**
+ * Set the event manager instance
+ *
+ * @param EventManagerInterface $eventManager
+ * @return Application
+ */
+ public function setEventManager(EventManagerInterface $eventManager)
+ {
+ $eventManager->setIdentifiers([
+ __CLASS__,
+ get_class($this),
+ ]);
+ $this->events = $eventManager;
+ return $this;
+ }
+
+ /**
+ * Retrieve the event manager
+ *
+ * Lazy-loads an EventManager instance if none registered.
+ *
+ * @return EventManagerInterface
+ */
+ public function getEventManager()
+ {
+ return $this->events;
+ }
+
+ /**
+ * Static method for quick and easy initialization of the Application.
+ *
+ * If you use this init() method, you cannot specify a service with the
+ * name of 'ApplicationConfig' in your service manager config. This name is
+ * reserved to hold the array from application.config.php.
+ *
+ * The following services can only be overridden from application.config.php:
+ *
+ * - ModuleManager
+ * - SharedEventManager
+ * - EventManager & Zend\EventManager\EventManagerInterface
+ *
+ * All other services are configured after module loading, thus can be
+ * overridden by modules.
+ *
+ * @param array $configuration
+ * @return Application
+ */
+ public static function init($configuration = [])
+ {
+ // Prepare the service manager
+ $smConfig = isset($configuration['service_manager']) ? $configuration['service_manager'] : [];
+ $smConfig = new Service\ServiceManagerConfig($smConfig);
+
+ $serviceManager = new ServiceManager();
+ $smConfig->configureServiceManager($serviceManager);
+ $serviceManager->setService('ApplicationConfig', $configuration);
+
+ // Load modules
+ $serviceManager->get('ModuleManager')->loadModules();
+
+ // Prepare list of listeners to bootstrap
+ $listenersFromAppConfig = isset($configuration['listeners']) ? $configuration['listeners'] : [];
+ $config = $serviceManager->get('config');
+ $listenersFromConfigService = isset($config['listeners']) ? $config['listeners'] : [];
+
+ $listeners = array_unique(array_merge($listenersFromConfigService, $listenersFromAppConfig));
+
+ return $serviceManager->get('Application')->bootstrap($listeners);
+ }
+
+ /**
+ * Run the application
+ *
+ * @triggers route(MvcEvent)
+ * Routes the request, and sets the RouteMatch object in the event.
+ * @triggers dispatch(MvcEvent)
+ * Dispatches a request, using the discovered RouteMatch and
+ * provided request.
+ * @triggers dispatch.error(MvcEvent)
+ * On errors (controller not found, action not supported, etc.),
+ * populates the event with information about the error type,
+ * discovered controller, and controller class (if known).
+ * Typically, a handler should return a populated Response object
+ * that can be returned immediately.
+ * @return self
+ */
+ public function run()
+ {
+ $events = $this->events;
+ $event = $this->event;
+
+ // Define callback used to determine whether or not to short-circuit
+ $shortCircuit = function ($r) use ($event) {
+ if ($r instanceof ResponseInterface) {
+ return true;
+ }
+ if ($event->getError()) {
+ return true;
+ }
+ return false;
+ };
+
+ // Trigger route event
+ $event->setName(MvcEvent::EVENT_ROUTE);
+ $event->stopPropagation(false); // Clear before triggering
+ $result = $events->triggerEventUntil($shortCircuit, $event);
+ if ($result->stopped()) {
+ $response = $result->last();
+ if ($response instanceof ResponseInterface) {
+ $event->setName(MvcEvent::EVENT_FINISH);
+ $event->setTarget($this);
+ $event->setResponse($response);
+ $event->stopPropagation(false); // Clear before triggering
+ $events->triggerEvent($event);
+ $this->response = $response;
+ return $this;
+ }
+ }
+
+ if ($event->getError()) {
+ return $this->completeRequest($event);
+ }
+
+ // Trigger dispatch event
+ $event->setName(MvcEvent::EVENT_DISPATCH);
+ $event->stopPropagation(false); // Clear before triggering
+ $result = $events->triggerEventUntil($shortCircuit, $event);
+
+ // Complete response
+ $response = $result->last();
+ if ($response instanceof ResponseInterface) {
+ $event->setName(MvcEvent::EVENT_FINISH);
+ $event->setTarget($this);
+ $event->setResponse($response);
+ $event->stopPropagation(false); // Clear before triggering
+ $events->triggerEvent($event);
+ $this->response = $response;
+ return $this;
+ }
+
+ $response = $this->response;
+ $event->setResponse($response);
+ $this->completeRequest($event);
+
+ return $this;
+ }
+
+ /**
+ * @deprecated
+ */
+ public function send()
+ {
+ }
+
+ /**
+ * Complete the request
+ *
+ * Triggers "render" and "finish" events, and returns response from
+ * event object.
+ *
+ * @param MvcEvent $event
+ * @return Application
+ */
+ protected function completeRequest(MvcEvent $event)
+ {
+ $events = $this->events;
+ $event->setTarget($this);
+
+ $event->setName(MvcEvent::EVENT_RENDER);
+ $event->stopPropagation(false); // Clear before triggering
+ $events->triggerEvent($event);
+
+ $event->setName(MvcEvent::EVENT_FINISH);
+ $event->stopPropagation(false); // Clear before triggering
+ $events->triggerEvent($event);
+
+ return $this;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc;
+
+use Zend\EventManager\EventsCapableInterface;
+
+interface ApplicationInterface extends EventsCapableInterface
+{
+ /**
+ * Get the locator object
+ *
+ * @return \Zend\ServiceManager\ServiceLocatorInterface
+ */
+ public function getServiceManager();
+
+ /**
+ * Get the request object
+ *
+ * @return \Zend\Stdlib\RequestInterface
+ */
+ public function getRequest();
+
+ /**
+ * Get the response object
+ *
+ * @return \Zend\Stdlib\ResponseInterface
+ */
+ public function getResponse();
+
+ /**
+ * Run the application
+ *
+ * @return self
+ */
+ public function run();
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller;
+
+use Zend\Http\Response as HttpResponse;
+use Zend\Mvc\Exception;
+use Zend\Mvc\MvcEvent;
+use Zend\View\Model\ViewModel;
+
+/**
+ * Basic action controller
+ */
+abstract class AbstractActionController extends AbstractController
+{
+ /**
+ * {@inheritDoc}
+ */
+ protected $eventIdentifier = __CLASS__;
+
+ /**
+ * Default action if none provided
+ *
+ * @return array
+ */
+ public function indexAction()
+ {
+ return new ViewModel([
+ 'content' => 'Placeholder page'
+ ]);
+ }
+
+ /**
+ * Action called if matched action does not exist
+ *
+ * @return array
+ */
+ public function notFoundAction()
+ {
+ $response = $this->response;
+ $event = $this->getEvent();
+ $routeMatch = $event->getRouteMatch();
+ $routeMatch->setParam('action', 'not-found');
+
+ if ($response instanceof HttpResponse) {
+ return $this->createHttpNotFoundModel($response);
+ }
+ return $this->createConsoleNotFoundModel($response);
+ }
+
+ /**
+ * Execute the request
+ *
+ * @param MvcEvent $e
+ * @return mixed
+ * @throws Exception\DomainException
+ */
+ public function onDispatch(MvcEvent $e)
+ {
+ $routeMatch = $e->getRouteMatch();
+ if (!$routeMatch) {
+ /**
+ * @todo Determine requirements for when route match is missing.
+ * Potentially allow pulling directly from request metadata?
+ */
+ throw new Exception\DomainException('Missing route matches; unsure how to retrieve action');
+ }
+
+ $action = $routeMatch->getParam('action', 'not-found');
+ $method = static::getMethodFromAction($action);
+
+ if (!method_exists($this, $method)) {
+ $method = 'notFoundAction';
+ }
+
+ $actionResponse = $this->$method();
+
+ $e->setResult($actionResponse);
+
+ return $actionResponse;
+ }
+
+ /**
+ * @deprecated please use the {@see \Zend\Mvc\Controller\Plugin\CreateHttpNotFoundModel} plugin instead: this
+ * method will be removed in release 2.5 or later.
+ *
+ * {@inheritDoc}
+ */
+ protected function createHttpNotFoundModel(HttpResponse $response)
+ {
+ return $this->__call('createHttpNotFoundModel', [$response]);
+ }
+
+ /**
+ * @deprecated please use the {@see \Zend\Mvc\Controller\Plugin\CreateConsoleNotFoundModel} plugin instead: this
+ * method will be removed in release 2.5 or later.
+ *
+ * {@inheritDoc}
+ */
+ protected function createConsoleNotFoundModel($response)
+ {
+ return $this->__call('createConsoleNotFoundModel', [$response]);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller;
+
+use Zend\Console\Adapter\AdapterInterface as ConsoleAdapter;
+use Zend\Console\Request as ConsoleRequest;
+use Zend\Mvc\Exception\InvalidArgumentException;
+use Zend\Stdlib\RequestInterface;
+use Zend\Stdlib\ResponseInterface;
+
+class AbstractConsoleController extends AbstractActionController
+{
+ /**
+ * @var ConsoleAdapter
+ */
+ protected $console;
+
+ /**
+ * @param ConsoleAdapter $console
+ * @return self
+ */
+ public function setConsole(ConsoleAdapter $console)
+ {
+ $this->console = $console;
+
+ return $this;
+ }
+
+ /**
+ * @return ConsoleAdapter
+ */
+ public function getConsole()
+ {
+ return $this->console;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dispatch(RequestInterface $request, ResponseInterface $response = null)
+ {
+ if (! $request instanceof ConsoleRequest) {
+ throw new InvalidArgumentException(sprintf(
+ '%s can only dispatch requests in a console environment',
+ get_called_class()
+ ));
+ }
+ return parent::dispatch($request, $response);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller;
+
+use Zend\EventManager\EventInterface as Event;
+use Zend\EventManager\EventManager;
+use Zend\EventManager\EventManagerAwareInterface;
+use Zend\EventManager\EventManagerInterface;
+use Zend\Http\PhpEnvironment\Response as HttpResponse;
+use Zend\Http\Request as HttpRequest;
+use Zend\Mvc\InjectApplicationEventInterface;
+use Zend\Mvc\MvcEvent;
+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;
+
+/**
+ * Abstract controller
+ *
+ * Convenience methods for pre-built plugins (@see __call):
+ *
+ * @method \Zend\View\Model\ModelInterface acceptableViewModelSelector(array $matchAgainst = null, bool $returnDefault = true, \Zend\Http\Header\Accept\FieldValuePart\AbstractFieldValuePart $resultReference = null)
+ * @method bool|array|\Zend\Http\Response fileprg(\Zend\Form\FormInterface $form, $redirect = null, $redirectToUrl = false)
+ * @method bool|array|\Zend\Http\Response filePostRedirectGet(\Zend\Form\FormInterface $form, $redirect = null, $redirectToUrl = false)
+ * @method \Zend\Mvc\Controller\Plugin\FlashMessenger flashMessenger()
+ * @method \Zend\Mvc\Controller\Plugin\Forward forward()
+ * @method mixed|null identity()
+ * @method \Zend\Mvc\Controller\Plugin\Layout|\Zend\View\Model\ModelInterface layout(string $template = null)
+ * @method \Zend\Mvc\Controller\Plugin\Params|mixed params(string $param = null, mixed $default = null)
+ * @method \Zend\Http\Response|array prg(string $redirect = null, bool $redirectToUrl = false)
+ * @method \Zend\Http\Response|array postRedirectGet(string $redirect = null, bool $redirectToUrl = false)
+ * @method \Zend\Mvc\Controller\Plugin\Redirect redirect()
+ * @method \Zend\Mvc\Controller\Plugin\Url url()
+ * @method \Zend\View\Model\ConsoleModel createConsoleNotFoundModel()
+ * @method \Zend\View\Model\ViewModel createHttpNotFoundModel(Response $response)
+ */
+abstract class AbstractController implements
+ Dispatchable,
+ EventManagerAwareInterface,
+ InjectApplicationEventInterface
+{
+ /**
+ * @var PluginManager
+ */
+ protected $plugins;
+
+ /**
+ * @var Request
+ */
+ protected $request;
+
+ /**
+ * @var Response
+ */
+ protected $response;
+
+ /**
+ * @var ServiceLocatorInterface
+ */
+ protected $serviceLocator;
+
+ /**
+ * @var Event
+ */
+ protected $event;
+
+ /**
+ * @var EventManagerInterface
+ */
+ protected $events;
+
+ /**
+ * @var null|string|string[]
+ */
+ protected $eventIdentifier;
+
+ /**
+ * Execute the request
+ *
+ * @param MvcEvent $e
+ * @return mixed
+ */
+ abstract public function onDispatch(MvcEvent $e);
+
+ /**
+ * Dispatch a request
+ *
+ * @events dispatch.pre, dispatch.post
+ * @param Request $request
+ * @param null|Response $response
+ * @return Response|mixed
+ */
+ public function dispatch(Request $request, Response $response = null)
+ {
+ $this->request = $request;
+ if (!$response) {
+ $response = new HttpResponse();
+ }
+ $this->response = $response;
+
+ $e = $this->getEvent();
+ $e->setName(MvcEvent::EVENT_DISPATCH);
+ $e->setRequest($request);
+ $e->setResponse($response);
+ $e->setTarget($this);
+
+ $result = $this->getEventManager()->triggerEventUntil(function ($test) {
+ return ($test instanceof Response);
+ }, $e);
+
+ if ($result->stopped()) {
+ return $result->last();
+ }
+
+ return $e->getResult();
+ }
+
+ /**
+ * Get request object
+ *
+ * @return Request
+ */
+ public function getRequest()
+ {
+ if (!$this->request) {
+ $this->request = new HttpRequest();
+ }
+
+ return $this->request;
+ }
+
+ /**
+ * Get response object
+ *
+ * @return Response
+ */
+ public function getResponse()
+ {
+ if (!$this->response) {
+ $this->response = new HttpResponse();
+ }
+
+ return $this->response;
+ }
+
+ /**
+ * Set the event manager instance used by this context
+ *
+ * @param EventManagerInterface $events
+ * @return AbstractController
+ */
+ public function setEventManager(EventManagerInterface $events)
+ {
+ $className = get_class($this);
+
+ $nsPos = strpos($className, '\\') ?: 0;
+ $events->setIdentifiers(array_merge(
+ [
+ __CLASS__,
+ $className,
+ substr($className, 0, $nsPos)
+ ],
+ array_values(class_implements($className)),
+ (array) $this->eventIdentifier
+ ));
+
+ $this->events = $events;
+ $this->attachDefaultListeners();
+
+ return $this;
+ }
+
+ /**
+ * Retrieve the event manager
+ *
+ * Lazy-loads an EventManager instance if none registered.
+ *
+ * @return EventManagerInterface
+ */
+ public function getEventManager()
+ {
+ if (!$this->events) {
+ $this->setEventManager(new EventManager());
+ }
+
+ return $this->events;
+ }
+
+ /**
+ * Set an event to use during dispatch
+ *
+ * By default, will re-cast to MvcEvent if another event type is provided.
+ *
+ * @param Event $e
+ * @return void
+ */
+ public function setEvent(Event $e)
+ {
+ if (!$e instanceof MvcEvent) {
+ $eventParams = $e->getParams();
+ $e = new MvcEvent();
+ $e->setParams($eventParams);
+ unset($eventParams);
+ }
+ $this->event = $e;
+ }
+
+ /**
+ * Get the attached event
+ *
+ * Will create a new MvcEvent if none provided.
+ *
+ * @return MvcEvent
+ */
+ public function getEvent()
+ {
+ if (!$this->event) {
+ $this->setEvent(new MvcEvent());
+ }
+
+ 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()
+ {
+ trigger_error(sprintf(
+ 'You are retrieving the service locator from within the class %s. Please be aware that '
+ . 'ServiceLocatorAwareInterface is deprecated and will be removed in version 3.0, along '
+ . 'with the ServiceLocatorAwareInitializer. You will need to update your class to accept '
+ . 'all dependencies at creation, either via constructor arguments or setters, and use '
+ . 'a factory to perform the injections.',
+ get_class($this)
+ ), E_USER_DEPRECATED);
+
+ return $this->serviceLocator;
+ }
+
+ /**
+ * Get plugin manager
+ *
+ * @return PluginManager
+ */
+ public function getPluginManager()
+ {
+ if (!$this->plugins) {
+ $this->setPluginManager(new PluginManager(new ServiceManager()));
+ }
+
+ $this->plugins->setController($this);
+ return $this->plugins;
+ }
+
+ /**
+ * Set plugin manager
+ *
+ * @param PluginManager $plugins
+ * @return AbstractController
+ */
+ public function setPluginManager(PluginManager $plugins)
+ {
+ $this->plugins = $plugins;
+ $this->plugins->setController($this);
+
+ return $this;
+ }
+
+ /**
+ * Get plugin instance
+ *
+ * @param string $name Name of plugin to return
+ * @param null|array $options Options to pass to plugin constructor (if not already instantiated)
+ * @return mixed
+ */
+ public function plugin($name, array $options = null)
+ {
+ return $this->getPluginManager()->get($name, $options);
+ }
+
+ /**
+ * Method overloading: return/call plugins
+ *
+ * If the plugin is a functor, call it, passing the parameters provided.
+ * Otherwise, return the plugin instance.
+ *
+ * @param string $method
+ * @param array $params
+ * @return mixed
+ */
+ public function __call($method, $params)
+ {
+ $plugin = $this->plugin($method);
+ if (is_callable($plugin)) {
+ return call_user_func_array($plugin, $params);
+ }
+
+ return $plugin;
+ }
+
+ /**
+ * Register the default events for this controller
+ *
+ * @return void
+ */
+ protected function attachDefaultListeners()
+ {
+ $events = $this->getEventManager();
+ $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'onDispatch']);
+ }
+
+ /**
+ * Transform an "action" token into a method name
+ *
+ * @param string $action
+ * @return string
+ */
+ public static function getMethodFromAction($action)
+ {
+ $method = str_replace(['.', '-', '_'], ' ', $action);
+ $method = ucwords($method);
+ $method = str_replace(' ', '', $method);
+ $method = lcfirst($method);
+ $method .= 'Action';
+
+ return $method;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+namespace Zend\Mvc\Controller;
+
+use Zend\Http\Request as HttpRequest;
+use Zend\Json\Json;
+use Zend\Mvc\Exception;
+use Zend\Mvc\MvcEvent;
+use Zend\Stdlib\RequestInterface as Request;
+use Zend\Stdlib\ResponseInterface as Response;
+
+/**
+ * Abstract RESTful controller
+ */
+abstract class AbstractRestfulController extends AbstractController
+{
+ const CONTENT_TYPE_JSON = 'json';
+
+ /**
+ * {@inheritDoc}
+ */
+ protected $eventIdentifier = __CLASS__;
+
+ /**
+ * @var array
+ */
+ protected $contentTypes = [
+ self::CONTENT_TYPE_JSON => [
+ 'application/hal+json',
+ 'application/json'
+ ]
+ ];
+
+ /**
+ * Name of request or query parameter containing identifier
+ *
+ * @var string
+ */
+ protected $identifierName = 'id';
+
+ /**
+ * @var int From Zend\Json\Json
+ */
+ protected $jsonDecodeType = Json::TYPE_ARRAY;
+
+ /**
+ * Map of custom HTTP methods and their handlers
+ *
+ * @var array
+ */
+ protected $customHttpMethodsMap = [];
+
+ /**
+ * Set the route match/query parameter name containing the identifier
+ *
+ * @param string $name
+ * @return self
+ */
+ public function setIdentifierName($name)
+ {
+ $this->identifierName = (string) $name;
+ return $this;
+ }
+
+ /**
+ * Retrieve the route match/query parameter name containing the identifier
+ *
+ * @return string
+ */
+ public function getIdentifierName()
+ {
+ return $this->identifierName;
+ }
+
+ /**
+ * Create a new resource
+ *
+ * @param mixed $data
+ * @return mixed
+ */
+ public function create($data)
+ {
+ $this->response->setStatusCode(405);
+
+ return [
+ 'content' => 'Method Not Allowed'
+ ];
+ }
+
+ /**
+ * Delete an existing resource
+ *
+ * @param mixed $id
+ * @return mixed
+ */
+ public function delete($id)
+ {
+ $this->response->setStatusCode(405);
+
+ return [
+ 'content' => 'Method Not Allowed'
+ ];
+ }
+
+ /**
+ * Delete the entire resource collection
+ *
+ * Not marked as abstract, as that would introduce a BC break
+ * (introduced in 2.1.0); instead, raises an exception if not implemented.
+ *
+ * @return mixed
+ */
+ public function deleteList($data)
+ {
+ $this->response->setStatusCode(405);
+
+ return [
+ 'content' => 'Method Not Allowed'
+ ];
+ }
+
+ /**
+ * Return single resource
+ *
+ * @param mixed $id
+ * @return mixed
+ */
+ public function get($id)
+ {
+ $this->response->setStatusCode(405);
+
+ return [
+ 'content' => 'Method Not Allowed'
+ ];
+ }
+
+ /**
+ * Return list of resources
+ *
+ * @return mixed
+ */
+ public function getList()
+ {
+ $this->response->setStatusCode(405);
+
+ return [
+ 'content' => 'Method Not Allowed'
+ ];
+ }
+
+ /**
+ * Retrieve HEAD metadata for the resource
+ *
+ * Not marked as abstract, as that would introduce a BC break
+ * (introduced in 2.1.0); instead, raises an exception if not implemented.
+ *
+ * @param null|mixed $id
+ * @return mixed
+ */
+ public function head($id = null)
+ {
+ $this->response->setStatusCode(405);
+
+ return [
+ 'content' => 'Method Not Allowed'
+ ];
+ }
+
+ /**
+ * Respond to the OPTIONS method
+ *
+ * Typically, set the Allow header with allowed HTTP methods, and
+ * return the response.
+ *
+ * Not marked as abstract, as that would introduce a BC break
+ * (introduced in 2.1.0); instead, raises an exception if not implemented.
+ *
+ * @return mixed
+ */
+ public function options()
+ {
+ $this->response->setStatusCode(405);
+
+ return [
+ 'content' => 'Method Not Allowed'
+ ];
+ }
+
+ /**
+ * Respond to the PATCH method
+ *
+ * Not marked as abstract, as that would introduce a BC break
+ * (introduced in 2.1.0); instead, raises an exception if not implemented.
+ *
+ * @param $id
+ * @param $data
+ * @return array
+ */
+ public function patch($id, $data)
+ {
+ $this->response->setStatusCode(405);
+
+ return [
+ 'content' => 'Method Not Allowed'
+ ];
+ }
+
+ /**
+ * Replace an entire resource collection
+ *
+ * Not marked as abstract, as that would introduce a BC break
+ * (introduced in 2.1.0); instead, raises an exception if not implemented.
+ *
+ * @param mixed $data
+ * @return mixed
+ */
+ public function replaceList($data)
+ {
+ $this->response->setStatusCode(405);
+
+ return [
+ 'content' => 'Method Not Allowed'
+ ];
+ }
+
+ /**
+ * Modify a resource collection without completely replacing it
+ *
+ * Not marked as abstract, as that would introduce a BC break
+ * (introduced in 2.2.0); instead, raises an exception if not implemented.
+ *
+ * @param mixed $data
+ * @return mixed
+ */
+ public function patchList($data)
+ {
+ $this->response->setStatusCode(405);
+
+ return [
+ 'content' => 'Method Not Allowed'
+ ];
+ }
+
+ /**
+ * Update an existing resource
+ *
+ * @param mixed $id
+ * @param mixed $data
+ * @return mixed
+ */
+ public function update($id, $data)
+ {
+ $this->response->setStatusCode(405);
+
+ return [
+ 'content' => 'Method Not Allowed'
+ ];
+ }
+
+ /**
+ * Basic functionality for when a page is not available
+ *
+ * @return array
+ */
+ public function notFoundAction()
+ {
+ $this->response->setStatusCode(404);
+
+ return [
+ 'content' => 'Page not found'
+ ];
+ }
+
+ /**
+ * Dispatch a request
+ *
+ * If the route match includes an "action" key, then this acts basically like
+ * a standard action controller. Otherwise, it introspects the HTTP method
+ * to determine how to handle the request, and which method to delegate to.
+ *
+ * @events dispatch.pre, dispatch.post
+ * @param Request $request
+ * @param null|Response $response
+ * @return mixed|Response
+ * @throws Exception\InvalidArgumentException
+ */
+ public function dispatch(Request $request, Response $response = null)
+ {
+ if (! $request instanceof HttpRequest) {
+ throw new Exception\InvalidArgumentException(
+ 'Expected an HTTP request');
+ }
+
+ return parent::dispatch($request, $response);
+ }
+
+ /**
+ * Handle the request
+ *
+ * @todo try-catch in "patch" for patchList should be removed in the future
+ * @param MvcEvent $e
+ * @return mixed
+ * @throws Exception\DomainException if no route matches in event or invalid HTTP method
+ */
+ public function onDispatch(MvcEvent $e)
+ {
+ $routeMatch = $e->getRouteMatch();
+ if (! $routeMatch) {
+ /**
+ * @todo Determine requirements for when route match is missing.
+ * Potentially allow pulling directly from request metadata?
+ */
+ throw new Exception\DomainException(
+ 'Missing route matches; unsure how to retrieve action');
+ }
+
+ $request = $e->getRequest();
+
+ // Was an "action" requested?
+ $action = $routeMatch->getParam('action', false);
+ if ($action) {
+ // Handle arbitrary methods, ending in Action
+ $method = static::getMethodFromAction($action);
+ if (! method_exists($this, $method)) {
+ $method = 'notFoundAction';
+ }
+ $return = $this->$method();
+ $e->setResult($return);
+ return $return;
+ }
+
+ // RESTful methods
+ $method = strtolower($request->getMethod());
+ switch ($method) {
+ // Custom HTTP methods (or custom overrides for standard methods)
+ case (isset($this->customHttpMethodsMap[$method])):
+ $callable = $this->customHttpMethodsMap[$method];
+ $action = $method;
+ $return = call_user_func($callable, $e);
+ break;
+ // DELETE
+ case 'delete':
+ $id = $this->getIdentifier($routeMatch, $request);
+ $data = $this->processBodyContent($request);
+
+ if ($id !== false) {
+ $action = 'delete';
+ $return = $this->delete($id);
+ break;
+ }
+
+ $action = 'deleteList';
+ $return = $this->deleteList($data);
+ break;
+ // GET
+ case 'get':
+ $id = $this->getIdentifier($routeMatch, $request);
+ if ($id !== false) {
+ $action = 'get';
+ $return = $this->get($id);
+ break;
+ }
+ $action = 'getList';
+ $return = $this->getList();
+ break;
+ // HEAD
+ case 'head':
+ $id = $this->getIdentifier($routeMatch, $request);
+ if ($id === false) {
+ $id = null;
+ }
+ $action = 'head';
+ $headResult = $this->head($id);
+ $response = ($headResult instanceof Response) ? clone $headResult : $e->getResponse();
+ $response->setContent('');
+ $return = $response;
+ break;
+ // OPTIONS
+ case 'options':
+ $action = 'options';
+ $this->options();
+ $return = $e->getResponse();
+ break;
+ // PATCH
+ case 'patch':
+ $id = $this->getIdentifier($routeMatch, $request);
+ $data = $this->processBodyContent($request);
+
+ if ($id !== false) {
+ $action = 'patch';
+ $return = $this->patch($id, $data);
+ break;
+ }
+
+ // TODO: This try-catch should be removed in the future, but it
+ // will create a BC break for pre-2.2.0 apps that expect a 405
+ // instead of going to patchList
+ try {
+ $action = 'patchList';
+ $return = $this->patchList($data);
+ } catch (Exception\RuntimeException $ex) {
+ $response = $e->getResponse();
+ $response->setStatusCode(405);
+ return $response;
+ }
+ break;
+ // POST
+ case 'post':
+ $action = 'create';
+ $return = $this->processPostData($request);
+ break;
+ // PUT
+ case 'put':
+ $id = $this->getIdentifier($routeMatch, $request);
+ $data = $this->processBodyContent($request);
+
+ if ($id !== false) {
+ $action = 'update';
+ $return = $this->update($id, $data);
+ break;
+ }
+
+ $action = 'replaceList';
+ $return = $this->replaceList($data);
+ break;
+ // All others...
+ default:
+ $response = $e->getResponse();
+ $response->setStatusCode(405);
+ return $response;
+ }
+
+ $routeMatch->setParam('action', $action);
+ $e->setResult($return);
+ return $return;
+ }
+
+ /**
+ * Process post data and call create
+ *
+ * @param Request $request
+ * @return mixed
+ */
+ public function processPostData(Request $request)
+ {
+ if ($this->requestHasContentType($request, self::CONTENT_TYPE_JSON)) {
+ $data = Json::decode($request->getContent(), $this->jsonDecodeType);
+ } else {
+ $data = $request->getPost()->toArray();
+ }
+
+ return $this->create($data);
+ }
+
+ /**
+ * Check if request has certain content type
+ *
+ * @param Request $request
+ * @param string|null $contentType
+ * @return bool
+ */
+ public function requestHasContentType(Request $request, $contentType = '')
+ {
+ /** @var $headerContentType \Zend\Http\Header\ContentType */
+ $headerContentType = $request->getHeaders()->get('content-type');
+ if (!$headerContentType) {
+ return false;
+ }
+
+ $requestedContentType = $headerContentType->getFieldValue();
+ if (strstr($requestedContentType, ';')) {
+ $headerData = explode(';', $requestedContentType);
+ $requestedContentType = array_shift($headerData);
+ }
+ $requestedContentType = trim($requestedContentType);
+ if (array_key_exists($contentType, $this->contentTypes)) {
+ foreach ($this->contentTypes[$contentType] as $contentTypeValue) {
+ if (stripos($contentTypeValue, $requestedContentType) === 0) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Register a handler for a custom HTTP method
+ *
+ * This method allows you to handle arbitrary HTTP method types, mapping
+ * them to callables. Typically, these will be methods of the controller
+ * instance: e.g., array($this, 'foobar'). The typical place to register
+ * these is in your constructor.
+ *
+ * Additionally, as this map is checked prior to testing the standard HTTP
+ * methods, this is a way to override what methods will handle the standard
+ * HTTP methods. However, if you do this, you will have to retrieve the
+ * identifier and any request content manually.
+ *
+ * Callbacks will be passed the current MvcEvent instance.
+ *
+ * To retrieve the identifier, you can use "$id =
+ * $this->getIdentifier($routeMatch, $request)",
+ * passing the appropriate objects.
+ *
+ * To retrieve the body content data, use "$data = $this->processBodyContent($request)";
+ * that method will return a string, array, or, in the case of JSON, an object.
+ *
+ * @param string $method
+ * @param Callable $handler
+ * @return AbstractRestfulController
+ */
+ public function addHttpMethodHandler($method, /* Callable */ $handler)
+ {
+ if (!is_callable($handler)) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ 'Invalid HTTP method handler: must be a callable; received "%s"',
+ (is_object($handler) ? get_class($handler) : gettype($handler))
+ ));
+ }
+ $method = strtolower($method);
+ $this->customHttpMethodsMap[$method] = $handler;
+ return $this;
+ }
+
+ /**
+ * Retrieve the identifier, if any
+ *
+ * Attempts to see if an identifier was passed in either the URI or the
+ * query string, returning it if found. Otherwise, returns a boolean false.
+ *
+ * @param \Zend\Mvc\Router\RouteMatch $routeMatch
+ * @param Request $request
+ * @return false|mixed
+ */
+ protected function getIdentifier($routeMatch, $request)
+ {
+ $identifier = $this->getIdentifierName();
+ $id = $routeMatch->getParam($identifier, false);
+ if ($id !== false) {
+ return $id;
+ }
+
+ $id = $request->getQuery()->get($identifier, false);
+ if ($id !== false) {
+ return $id;
+ }
+
+ return false;
+ }
+
+ /**
+ * Process the raw body content
+ *
+ * If the content-type indicates a JSON payload, the payload is immediately
+ * decoded and the data returned. Otherwise, the data is passed to
+ * parse_str(). If that function returns a single-member array with a empty
+ * value, the method assumes that we have non-urlencoded content and
+ * returns the raw content; otherwise, the array created is returned.
+ *
+ * @param mixed $request
+ * @return object|string|array
+ */
+ protected function processBodyContent($request)
+ {
+ $content = $request->getContent();
+
+ // JSON content? decode and return it.
+ if ($this->requestHasContentType($request, self::CONTENT_TYPE_JSON)) {
+ return Json::decode($content, $this->jsonDecodeType);
+ }
+
+ parse_str($content, $parsedParams);
+
+ // If parse_str fails to decode, or we have a single element with empty value
+ if (!is_array($parsedParams) || empty($parsedParams)
+ || (1 == count($parsedParams) && '' === reset($parsedParams))
+ ) {
+ return $content;
+ }
+
+ return $parsedParams;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+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\Exception\InvalidServiceException;
+use Zend\ServiceManager\ServiceLocatorAwareInterface;
+use Zend\Stdlib\DispatchableInterface;
+
+/**
+ * Manager for loading controllers
+ *
+ * Does not define any controllers by default, but does add a validator.
+ */
+class ControllerManager extends AbstractPluginManager
+{
+ /**
+ * We do not want arbitrary classes instantiated as controllers.
+ *
+ * @var bool
+ */
+ protected $autoAddInvokableClass = false;
+
+ /**
+ * Controllers must be of this type.
+ *
+ * @var string
+ */
+ protected $instanceOf = DispatchableInterface::class;
+
+ /**
+ * Constructor
+ *
+ * Injects an initializer for injecting controllers with an
+ * event manager and plugin manager.
+ *
+ * @param ConfigInterface|ContainerInterface $container
+ * @param array $v3config
+ */
+ public function __construct($configOrContainerInstance, array $v3config = [])
+ {
+ $this->addInitializer([$this, 'injectEventManager']);
+ $this->addInitializer([$this, 'injectConsole']);
+ $this->addInitializer([$this, 'injectPluginManager']);
+ parent::__construct($configOrContainerInstance, $v3config);
+
+ // Added after parent construction, as v2 abstract plugin managers add
+ // one during construction.
+ $this->addInitializer([$this, 'injectServiceLocator']);
+ }
+
+ /**
+ * Validate a plugin (v3)
+ *
+ * {@inheritDoc}
+ */
+ public function validate($plugin)
+ {
+ if (! $plugin instanceof $this->instanceOf) {
+ throw new InvalidServiceException(sprintf(
+ 'Plugin of type "%s" is invalid; must implement %s',
+ (is_object($plugin) ? get_class($plugin) : gettype($plugin)),
+ $this->instanceOf
+ ));
+ }
+ }
+
+ /**
+ * Validate a plugin (v2)
+ *
+ * {@inheritDoc}
+ *
+ * @throws Exception\InvalidControllerException
+ */
+ public function validatePlugin($plugin)
+ {
+ try {
+ $this->validate($plugin);
+ } catch (InvalidServiceException $e) {
+ throw new Exception\InvalidControllerException(
+ $e->getMessage(),
+ $e->getCode(),
+ $e
+ );
+ }
+ }
+
+ /**
+ * 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 ContainerInterface|DispatchableInterface $first Container when
+ * using zend-servicemanager v3; controller under v2.
+ * @param DispatchableInterface|ContainerInterface $second Controller when
+ * using zend-servicemanager v3; container under v2.
+ */
+ public function injectEventManager($first, $second)
+ {
+ if ($first instanceof ContainerInterface) {
+ $container = $first;
+ $controller = $second;
+ } else {
+ $container = $second;
+ $controller = $first;
+ }
+
+ if (! $controller instanceof EventManagerAwareInterface) {
+ return;
+ }
+
+ $events = $controller->getEventManager();
+ if (! $events || ! $events->getSharedManager() instanceof SharedEventManagerInterface) {
+ // For v2, we need to pull the parent service locator
+ if (! method_exists($container, 'configure')) {
+ $container = $container->getServiceLocator() ?: $container;
+ }
+
+ $controller->setEventManager($container->get('EventManager'));
+ }
+ }
+
+ /**
+ * Initializer: inject Console adapter instance
+ *
+ * @param ContainerInterface|DispatchableInterface $first Container when
+ * using zend-servicemanager v3; controller under v2.
+ * @param DispatchableInterface|ContainerInterface $second Controller when
+ * using zend-servicemanager v3; container under v2.
+ */
+ public function injectConsole($first, $second)
+ {
+ if ($first instanceof ContainerInterface) {
+ $container = $first;
+ $controller = $second;
+ } else {
+ $container = $second;
+ $controller = $first;
+ }
+
+ if (! $controller instanceof AbstractConsoleController) {
+ return;
+ }
+
+ // For v2, we need to pull the parent service locator
+ if (! method_exists($container, 'configure')) {
+ $container = $container->getServiceLocator() ?: $container;
+ }
+
+ $controller->setConsole($container->get('Console'));
+ }
+
+ /**
+ * Initializer: inject plugin manager
+ *
+ * @param ContainerInterface|DispatchableInterface $first Container when
+ * using zend-servicemanager v3; controller under v2.
+ * @param DispatchableInterface|ContainerInterface $second Controller when
+ * using zend-servicemanager v3; container under v2.
+ */
+ public function injectPluginManager($first, $second)
+ {
+ if ($first instanceof ContainerInterface) {
+ $container = $first;
+ $controller = $second;
+ } else {
+ $container = $second;
+ $controller = $first;
+ }
+
+ if (! method_exists($controller, 'setPluginManager')) {
+ return;
+ }
+
+ // For v2, we need to pull the parent service locator
+ if (! method_exists($container, 'configure')) {
+ $container = $container->getServiceLocator() ?: $container;
+ }
+
+ $controller->setPluginManager($container->get('ControllerPluginManager'));
+ }
+
+ /**
+ * Initializer: inject service locator
+ *
+ * @param ContainerInterface|DispatchableInterface $first Container when
+ * using zend-servicemanager v3; controller under v2.
+ * @param DispatchableInterface|ContainerInterface $second Controller when
+ * using zend-servicemanager v3; container under v2.
+ */
+ public function injectServiceLocator($first, $second)
+ {
+ if ($first instanceof ContainerInterface) {
+ $container = $first;
+ $controller = $second;
+ } else {
+ $container = $second;
+ $controller = $first;
+ }
+
+ // For v2, we need to pull the parent service locator
+ if (! method_exists($container, 'configure')) {
+ $container = $container->getServiceLocator() ?: $container;
+ }
+
+ // Inject AbstractController extensions that are not ServiceLocatorAware
+ // with the service manager, but do not emit a deprecation notice. We'll
+ // emit it from AbstractController::getServiceLocator() instead.
+ if (! $controller instanceof ServiceLocatorAwareInterface
+ && $controller instanceof AbstractController
+ && method_exists($controller, 'setServiceLocator')
+ ) {
+ // Do not emit deprecation notice in this case
+ $controller->setServiceLocator($container);
+ }
+
+ // If a controller implements ServiceLocatorAwareInterface explicitly, we
+ // inject, but emit a deprecation notice. Since AbstractController no longer
+ // explicitly does this, this will only affect userland controllers.
+ if ($controller instanceof ServiceLocatorAwareInterface) {
+ trigger_error(sprintf(
+ 'ServiceLocatorAwareInterface is deprecated and will be removed in version 3.0, along '
+ . 'with the ServiceLocatorAwareInitializer. Please update your class %s to remove '
+ . 'the implementation, and start injecting your dependencies via factory instead.',
+ get_class($controller)
+ ), E_USER_DEPRECATED);
+ $controller->setServiceLocator($container);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Zend\Stdlib\DispatchableInterface as Dispatchable;
+
+abstract class AbstractPlugin implements PluginInterface
+{
+ /**
+ * @var null|Dispatchable
+ */
+ protected $controller;
+
+ /**
+ * Set the current controller instance
+ *
+ * @param Dispatchable $controller
+ * @return void
+ */
+ public function setController(Dispatchable $controller)
+ {
+ $this->controller = $controller;
+ }
+
+ /**
+ * Get the current controller instance
+ *
+ * @return null|Dispatchable
+ */
+ public function getController()
+ {
+ return $this->controller;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Zend\Http\Header\Accept\FieldValuePart\AbstractFieldValuePart;
+use Zend\Http\Request;
+use Zend\Mvc\InjectApplicationEventInterface;
+use Zend\Mvc\MvcEvent;
+use Zend\Mvc\Exception\DomainException;
+use Zend\Mvc\Exception\InvalidArgumentException;
+use Zend\View\Model\ModelInterface;
+
+/**
+ * Controller Plugin to assist in selecting an appropriate View Model type based on the
+ * User Agent's accept header.
+ */
+class AcceptableViewModelSelector extends AbstractPlugin
+{
+ /**
+ *
+ * @var string the Key to inject the name of a viewmodel with in an Accept Header
+ */
+ const INJECT_VIEWMODEL_NAME = '_internalViewModel';
+
+ /**
+ *
+ * @var \Zend\Mvc\MvcEvent
+ */
+ protected $event;
+
+ /**
+ *
+ * @var \Zend\Http\Request
+ */
+ protected $request;
+
+ /**
+ * Default array to match against.
+ *
+ * @var Array
+ */
+ protected $defaultMatchAgainst;
+
+ /**
+ *
+ * @var string Default ViewModel
+ */
+ protected $defaultViewModelName = 'Zend\View\Model\ViewModel';
+
+ /**
+ * Detects an appropriate viewmodel for request.
+ *
+ * @param array $matchAgainst (optional) The Array to match against
+ * @param bool $returnDefault (optional) If no match is available. Return default instead
+ * @param AbstractFieldValuePart|null $resultReference (optional) The object that was matched
+ * @throws InvalidArgumentException If the supplied and matched View Model could not be found
+ * @return ModelInterface|null
+ */
+ public function __invoke(
+ array $matchAgainst = null,
+ $returnDefault = true,
+ & $resultReference = null
+ ) {
+ return $this->getViewModel($matchAgainst, $returnDefault, $resultReference);
+ }
+
+ /**
+ * Detects an appropriate viewmodel for request.
+ *
+ * @param array $matchAgainst (optional) The Array to match against
+ * @param bool $returnDefault (optional) If no match is available. Return default instead
+ * @param AbstractFieldValuePart|null $resultReference (optional) The object that was matched
+ * @throws InvalidArgumentException If the supplied and matched View Model could not be found
+ * @return ModelInterface|null
+ */
+ public function getViewModel(
+ array $matchAgainst = null,
+ $returnDefault = true,
+ & $resultReference = null
+ ) {
+ $name = $this->getViewModelName($matchAgainst, $returnDefault, $resultReference);
+
+ if (!$name) {
+ return;
+ }
+
+ if (!class_exists($name)) {
+ throw new InvalidArgumentException('The supplied View Model could not be found');
+ }
+
+ return new $name();
+ }
+
+ /**
+ * Detects an appropriate viewmodel name for request.
+ *
+ * @param array $matchAgainst (optional) The Array to match against
+ * @param bool $returnDefault (optional) If no match is available. Return default instead
+ * @param AbstractFieldValuePart|null $resultReference (optional) The object that was matched.
+ * @return ModelInterface|null Returns null if $returnDefault = false and no match could be made
+ */
+ public function getViewModelName(
+ array $matchAgainst = null,
+ $returnDefault = true,
+ & $resultReference = null
+ ) {
+ $res = $this->match($matchAgainst);
+ if ($res) {
+ $resultReference = $res;
+ return $this->extractViewModelName($res);
+ }
+
+ if ($returnDefault) {
+ return $this->defaultViewModelName;
+ }
+ }
+
+ /**
+ * Detects an appropriate viewmodel name for request.
+ *
+ * @param array $matchAgainst (optional) The Array to match against
+ * @return AbstractFieldValuePart|null The object that was matched
+ */
+ public function match(array $matchAgainst = null)
+ {
+ $request = $this->getRequest();
+ $headers = $request->getHeaders();
+
+ if ((!$matchAgainst && !$this->defaultMatchAgainst) || !$headers->has('accept')) {
+ return;
+ }
+
+ if (!$matchAgainst) {
+ $matchAgainst = $this->defaultMatchAgainst;
+ }
+
+ $matchAgainstString = '';
+ foreach ($matchAgainst as $modelName => $modelStrings) {
+ foreach ((array) $modelStrings as $modelString) {
+ $matchAgainstString .= $this->injectViewModelName($modelString, $modelName);
+ }
+ }
+
+ /** @var $accept \Zend\Http\Header\Accept */
+ $accept = $headers->get('Accept');
+ if (($res = $accept->match($matchAgainstString)) === false) {
+ return;
+ }
+
+ return $res;
+ }
+
+ /**
+ * Set the default View Model (name) to return if no match could be made
+ * @param string $defaultViewModelName The default View Model name
+ * @return AcceptableViewModelSelector provides fluent interface
+ */
+ public function setDefaultViewModelName($defaultViewModelName)
+ {
+ $this->defaultViewModelName = (string) $defaultViewModelName;
+ return $this;
+ }
+
+ /**
+ * Set the default View Model (name) to return if no match could be made
+ * @return string
+ */
+ public function getDefaultViewModelName()
+ {
+ return $this->defaultViewModelName;
+ }
+
+ /**
+ * Set the default Accept Types and View Model combinations to match against if none are specified.
+ *
+ * @param array $matchAgainst (optional) The Array to match against
+ * @return AcceptableViewModelSelector provides fluent interface
+ */
+ public function setDefaultMatchAgainst(array $matchAgainst = null)
+ {
+ $this->defaultMatchAgainst = $matchAgainst;
+ return $this;
+ }
+
+ /**
+ * Get the default Accept Types and View Model combinations to match against if none are specified.
+ *
+ * @return array|null
+ */
+ public function getDefaultMatchAgainst()
+ {
+ return $this->defaultMatchAgainst;
+ }
+
+ /**
+ * Inject the viewmodel name into the accept header string
+ *
+ * @param string $modelAcceptString
+ * @param string $modelName
+ * @return string
+ */
+ protected function injectViewModelName($modelAcceptString, $modelName)
+ {
+ $modelName = str_replace('\\', '|', $modelName);
+ return $modelAcceptString . '; ' . self::INJECT_VIEWMODEL_NAME . '="' . $modelName . '", ';
+ }
+
+ /**
+ * Extract the viewmodel name from a match
+ * @param AbstractFieldValuePart $res
+ * @return string
+ */
+ protected function extractViewModelName(AbstractFieldValuePart $res)
+ {
+ $modelName = $res->getMatchedAgainst()->params[self::INJECT_VIEWMODEL_NAME];
+ return str_replace('|', '\\', $modelName);
+ }
+
+ /**
+ * Get the request
+ *
+ * @return Request
+ * @throws DomainException if unable to find request
+ */
+ protected function getRequest()
+ {
+ if ($this->request) {
+ return $this->request;
+ }
+
+ $event = $this->getEvent();
+ $request = $event->getRequest();
+ if (!$request instanceof Request) {
+ throw new DomainException(
+ 'The event used does not contain a valid Request, but must.'
+ );
+ }
+
+ $this->request = $request;
+ return $request;
+ }
+
+ /**
+ * Get the event
+ *
+ * @return MvcEvent
+ * @throws DomainException if unable to find event
+ */
+ protected function getEvent()
+ {
+ if ($this->event) {
+ return $this->event;
+ }
+
+ $controller = $this->getController();
+ if (!$controller instanceof InjectApplicationEventInterface) {
+ throw new DomainException(
+ 'A controller that implements InjectApplicationEventInterface '
+ . 'is required to use ' . __CLASS__
+ );
+ }
+
+ $event = $controller->getEvent();
+ if (!$event instanceof MvcEvent) {
+ $params = $event->getParams();
+ $event = new MvcEvent();
+ $event->setParams($params);
+ }
+ $this->event = $event;
+
+ return $this->event;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Zend\View\Model\ConsoleModel;
+
+class CreateConsoleNotFoundModel extends AbstractPlugin
+{
+ /**
+ * Create a console view model representing a "not found" action
+ *
+ * @return ConsoleModel
+ */
+ public function __invoke()
+ {
+ $viewModel = new ConsoleModel();
+
+ $viewModel->setErrorLevel(1);
+ $viewModel->setResult('Page not found');
+
+ return $viewModel;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Zend\Http\Response;
+use Zend\View\Model\ViewModel;
+
+class CreateHttpNotFoundModel extends AbstractPlugin
+{
+ /**
+ * Create an HTTP view model representing a "not found" page
+ *
+ * @param Response $response
+ *
+ * @return ViewModel
+ */
+ public function __invoke(Response $response)
+ {
+ $response->setStatusCode(404);
+
+ return new ViewModel(['content' => 'Page not found']);
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Zend\Filter\FilterChain;
+use Zend\Form\FormInterface;
+use Zend\Http\Response;
+use Zend\InputFilter\FileInput;
+use Zend\InputFilter\InputFilterInterface;
+use Zend\Mvc\Exception\RuntimeException;
+use Zend\Session\Container;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Validator\ValidatorChain;
+
+/**
+ * Plugin to help facilitate Post/Redirect/Get for file upload forms
+ * (http://en.wikipedia.org/wiki/Post/Redirect/Get)
+ *
+ * Requires that the Form's File inputs contain a 'fileRenameUpload' filter
+ * with the target option set: 'target' => /valid/target/path'.
+ * This is so the files are moved to a new location between requests.
+ * If this filter is not added, the temporary upload files will disappear
+ * between requests.
+ */
+class FilePostRedirectGet extends AbstractPlugin
+{
+ /**
+ * @var Container
+ */
+ protected $sessionContainer;
+
+ /**
+ * @param FormInterface $form
+ * @param string $redirect Route or URL string (default: current route)
+ * @param bool $redirectToUrl Use $redirect as a URL string (default: false)
+ * @return bool|array|Response
+ */
+ public function __invoke(FormInterface $form, $redirect = null, $redirectToUrl = false)
+ {
+ $request = $this->getController()->getRequest();
+ if ($request->isPost()) {
+ return $this->handlePostRequest($form, $redirect, $redirectToUrl);
+ } else {
+ return $this->handleGetRequest($form);
+ }
+ }
+
+ /**
+ * @param FormInterface $form
+ * @param string $redirect Route or URL string (default: current route)
+ * @param bool $redirectToUrl Use $redirect as a URL string (default: false)
+ * @return Response
+ */
+ protected function handlePostRequest(FormInterface $form, $redirect, $redirectToUrl)
+ {
+ $container = $this->getSessionContainer();
+ $request = $this->getController()->getRequest();
+ $postFiles = $request->getFiles()->toArray();
+ $postOther = $request->getPost()->toArray();
+ $post = ArrayUtils::merge($postOther, $postFiles, true);
+
+ // Fill form with the data first, collections may alter the form/filter structure
+ $form->setData($post);
+
+ // Change required flag to false for any previously uploaded files
+ $inputFilter = $form->getInputFilter();
+ $previousFiles = ($container->files) ?: [];
+ $this->traverseInputs(
+ $inputFilter,
+ $previousFiles,
+ function ($input, $value) {
+ if ($input instanceof FileInput) {
+ $input->setRequired(false);
+ }
+ return $value;
+ }
+ );
+
+ // Run the form validations/filters and retrieve any errors
+ $isValid = $form->isValid();
+ $data = $form->getData(FormInterface::VALUES_AS_ARRAY);
+ $errors = (!$isValid) ? $form->getMessages() : null;
+
+ // Merge and replace previous files with new valid files
+ $prevFileData = $this->getEmptyUploadData($inputFilter, $previousFiles);
+ $newFileData = $this->getNonEmptyUploadData($inputFilter, $data);
+ $postFiles = ArrayUtils::merge(
+ $prevFileData ?: [],
+ $newFileData ?: [],
+ true
+ );
+ $post = ArrayUtils::merge($postOther, $postFiles, true);
+
+ // Save form data in session
+ $container->setExpirationHops(1, ['post', 'errors', 'isValid']);
+ $container->post = $post;
+ $container->errors = $errors;
+ $container->isValid = $isValid;
+ $container->files = $postFiles;
+
+ return $this->redirect($redirect, $redirectToUrl);
+ }
+
+ /**
+ * @param FormInterface $form
+ * @return bool|array
+ */
+ protected function handleGetRequest(FormInterface $form)
+ {
+ $container = $this->getSessionContainer();
+ if (null === $container->post) {
+ // No previous post, bail early
+ unset($container->files);
+ return false;
+ }
+
+ // Collect data from session
+ $post = $container->post;
+ $errors = $container->errors;
+ $isValid = $container->isValid;
+ unset($container->post);
+ unset($container->errors);
+ unset($container->isValid);
+
+ // Fill form with the data first, collections may alter the form/filter structure
+ $form->setData($post);
+
+ // Remove File Input validators and filters on previously uploaded files
+ // in case $form->isValid() or $form->bindValues() is run
+ $inputFilter = $form->getInputFilter();
+ $this->traverseInputs(
+ $inputFilter,
+ $post,
+ function ($input, $value) {
+ if ($input instanceof FileInput) {
+ $input->setAutoPrependUploadValidator(false)
+ ->setValidatorChain(new ValidatorChain())
+ ->setFilterChain(new FilterChain);
+ }
+ return $value;
+ }
+ );
+
+ // set previous state
+ $form->isValid(); // re-validate to bind values
+ if (null !== $errors) {
+ $form->setMessages($errors); // overwrite messages
+ }
+ $this->setProtectedFormProperty($form, 'isValid', $isValid); // force previous state
+
+ // Clear previous files from session data if form was valid
+ if ($isValid) {
+ unset($container->files);
+ }
+
+ return $post;
+ }
+
+ /**
+ * @return Container
+ */
+ public function getSessionContainer()
+ {
+ if (!$this->sessionContainer) {
+ $this->sessionContainer = new Container('file_prg_post1');
+ }
+ return $this->sessionContainer;
+ }
+
+ /**
+ * @param Container $container
+ * @return FilePostRedirectGet
+ */
+ public function setSessionContainer(Container $container)
+ {
+ $this->sessionContainer = $container;
+ return $this;
+ }
+
+ /**
+ * @param FormInterface $form
+ * @param string $property
+ * @param mixed $value
+ * @return FilePostRedirectGet
+ */
+ protected function setProtectedFormProperty(FormInterface $form, $property, $value)
+ {
+ $formClass = new \ReflectionClass($form);
+ $property = $formClass->getProperty($property);
+ $property->setAccessible(true);
+ $property->setValue($form, $value);
+ return $this;
+ }
+
+ /**
+ * Traverse the InputFilter and run a callback against each Input and associated value
+ *
+ * @param InputFilterInterface $inputFilter
+ * @param array $values
+ * @param callable $callback
+ * @return array|null
+ */
+ protected function traverseInputs(InputFilterInterface $inputFilter, $values, $callback)
+ {
+ $returnValues = null;
+ foreach ($values as $name => $value) {
+ if (!$inputFilter->has($name)) {
+ continue;
+ }
+
+ $input = $inputFilter->get($name);
+ if ($input instanceof InputFilterInterface && is_array($value)) {
+ $retVal = $this->traverseInputs($input, $value, $callback);
+ if (null !== $retVal) {
+ $returnValues[$name] = $retVal;
+ }
+ continue;
+ }
+
+ $retVal = $callback($input, $value);
+ if (null !== $retVal) {
+ $returnValues[$name] = $retVal;
+ }
+ }
+ return $returnValues;
+ }
+
+ /**
+ * Traverse the InputFilter and only return the data of FileInputs that have an upload
+ *
+ * @param InputFilterInterface $inputFilter
+ * @param array $data
+ * @return array
+ */
+ protected function getNonEmptyUploadData(InputFilterInterface $inputFilter, $data)
+ {
+ return $this->traverseInputs(
+ $inputFilter,
+ $data,
+ function ($input, $value) {
+ $messages = $input->getMessages();
+ if (is_array($value) && $input instanceof FileInput && empty($messages)) {
+ $rawValue = $input->getRawValue();
+ if (
+ (isset($rawValue['error']) && $rawValue['error'] !== UPLOAD_ERR_NO_FILE)
+ || (isset($rawValue[0]['error']) && $rawValue[0]['error'] !== UPLOAD_ERR_NO_FILE)
+ ) {
+ return $value;
+ }
+ }
+ return;
+ }
+ );
+ }
+
+ /**
+ * Traverse the InputFilter and only return the data of FileInputs that are empty
+ *
+ * @param InputFilterInterface $inputFilter
+ * @param array $data
+ * @return array
+ */
+ protected function getEmptyUploadData(InputFilterInterface $inputFilter, $data)
+ {
+ return $this->traverseInputs(
+ $inputFilter,
+ $data,
+ function ($input, $value) {
+ $messages = $input->getMessages();
+ if (is_array($value) && $input instanceof FileInput && empty($messages)) {
+ $rawValue = $input->getRawValue();
+ if ((isset($rawValue['error']) && $rawValue['error'] === UPLOAD_ERR_NO_FILE)
+ || (isset($rawValue[0]['error']) && $rawValue[0]['error'] === UPLOAD_ERR_NO_FILE)
+ ) {
+ return $value;
+ }
+ }
+ return;
+ }
+ );
+ }
+
+ /**
+ * TODO: Good candidate for traits method in PHP 5.4 with PostRedirectGet plugin
+ *
+ * @param string $redirect
+ * @param bool $redirectToUrl
+ * @return Response
+ * @throws \Zend\Mvc\Exception\RuntimeException
+ */
+ protected function redirect($redirect, $redirectToUrl)
+ {
+ $controller = $this->getController();
+ $params = [];
+ $options = [];
+ $reuseMatchedParams = false;
+
+ if (null === $redirect) {
+ $routeMatch = $controller->getEvent()->getRouteMatch();
+
+ $redirect = $routeMatch->getMatchedRouteName();
+ //null indicates to redirect for self.
+ $reuseMatchedParams = true;
+ }
+
+ if (method_exists($controller, 'getPluginManager')) {
+ // get the redirect plugin from the plugin manager
+ $redirector = $controller->getPluginManager()->get('Redirect');
+ } else {
+ /*
+ * If the user wants to redirect to a route, the redirector has to come
+ * from the plugin manager -- otherwise no router will be injected
+ */
+ if ($redirectToUrl === false) {
+ throw new RuntimeException('Could not redirect to a route without a router');
+ }
+
+ $redirector = new Redirect();
+ }
+
+ if ($redirectToUrl === false) {
+ $response = $redirector->toRoute($redirect, $params, $options, $reuseMatchedParams);
+ $response->setStatusCode(303);
+ return $response;
+ }
+
+ $response = $redirector->toUrl($redirect);
+ $response->setStatusCode(303);
+
+ return $response;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use ArrayIterator;
+use Countable;
+use IteratorAggregate;
+use Zend\Session\Container;
+use Zend\Session\ManagerInterface as Manager;
+use Zend\Stdlib\SplQueue;
+
+/**
+ * Flash Messenger - implement session-based messages
+ */
+class FlashMessenger extends AbstractPlugin implements IteratorAggregate, Countable
+{
+ /**
+ * Default messages namespace
+ */
+ const NAMESPACE_DEFAULT = 'default';
+
+ /**
+ * Success messages namespace
+ */
+ const NAMESPACE_SUCCESS = 'success';
+
+ /**
+ * Warning messages namespace
+ */
+ const NAMESPACE_WARNING = 'warning';
+
+ /**
+ * Error messages namespace
+ */
+ const NAMESPACE_ERROR = 'error';
+
+ /**
+ * Info messages namespace
+ */
+ const NAMESPACE_INFO = 'info';
+
+ /**
+ * @var Container
+ */
+ protected $container;
+
+ /**
+ * Messages from previous request
+ * @var array
+ */
+ protected $messages = [];
+
+ /**
+ * @var Manager
+ */
+ protected $session;
+
+ /**
+ * Whether a message has been added during this request
+ *
+ * @var bool
+ */
+ protected $messageAdded = false;
+
+ /**
+ * Instance namespace, default is 'default'
+ *
+ * @var string
+ */
+ protected $namespace = self::NAMESPACE_DEFAULT;
+
+ /**
+ * Set the session manager
+ *
+ * @param Manager $manager
+ * @return FlashMessenger
+ */
+ public function setSessionManager(Manager $manager)
+ {
+ $this->session = $manager;
+
+ return $this;
+ }
+
+ /**
+ * Retrieve the session manager
+ *
+ * If none composed, lazy-loads a SessionManager instance
+ *
+ * @return Manager
+ */
+ public function getSessionManager()
+ {
+ if (!$this->session instanceof Manager) {
+ $this->setSessionManager(Container::getDefaultManager());
+ }
+
+ return $this->session;
+ }
+
+ /**
+ * Get session container for flash messages
+ *
+ * @return Container
+ */
+ public function getContainer()
+ {
+ if ($this->container instanceof Container) {
+ return $this->container;
+ }
+
+ $manager = $this->getSessionManager();
+ $this->container = new Container('FlashMessenger', $manager);
+
+ return $this->container;
+ }
+
+ /**
+ * Change the namespace messages are added to
+ *
+ * Useful for per action controller messaging between requests
+ *
+ * @param string $namespace
+ * @return FlashMessenger Provides a fluent interface
+ */
+ public function setNamespace($namespace = 'default')
+ {
+ $this->namespace = $namespace;
+
+ return $this;
+ }
+
+ /**
+ * Get the message namespace
+ *
+ * @return string
+ */
+ public function getNamespace()
+ {
+ return $this->namespace;
+ }
+
+ /**
+ * Add a message
+ *
+ * @param string $message
+ * @param null|string $namespace
+ * @param null|int $hops
+ * @return FlashMessenger Provides a fluent interface
+ */
+ public function addMessage($message, $namespace = null, $hops = 1)
+ {
+ $container = $this->getContainer();
+
+ if (null === $namespace) {
+ $namespace = $this->getNamespace();
+ }
+
+ if (! $this->messageAdded) {
+ $this->getMessagesFromContainer();
+ $container->setExpirationHops($hops, null);
+ }
+
+ if (! isset($container->{$namespace})
+ || ! $container->{$namespace} instanceof SplQueue
+ ) {
+ $container->{$namespace} = new SplQueue();
+ }
+
+ $container->{$namespace}->push($message);
+
+ $this->messageAdded = true;
+
+ return $this;
+ }
+
+ /**
+ * Add a message with "info" type
+ *
+ * @param string $message
+ * @return FlashMessenger
+ */
+ public function addInfoMessage($message)
+ {
+ $this->addMessage($message, self::NAMESPACE_INFO);
+
+ return $this;
+ }
+
+ /**
+ * Add a message with "success" type
+ *
+ * @param string $message
+ * @return FlashMessenger
+ */
+ public function addSuccessMessage($message)
+ {
+ $this->addMessage($message, self::NAMESPACE_SUCCESS);
+
+ return $this;
+ }
+
+ /**
+ * Add a message with "warning" type
+ *
+ * @param string $message
+ * @return FlashMessenger
+ */
+ public function addWarningMessage($message)
+ {
+ $this->addMessage($message, self::NAMESPACE_WARNING);
+
+ return $this;
+ }
+
+ /**
+ * Add a message with "error" type
+ *
+ * @param string $message
+ * @return FlashMessenger
+ */
+ public function addErrorMessage($message)
+ {
+ $this->addMessage($message, self::NAMESPACE_ERROR);
+
+ return $this;
+ }
+
+ /**
+ * Whether a specific namespace has messages
+ *
+ * @param string $namespace
+ * @return bool
+ */
+ public function hasMessages($namespace = null)
+ {
+ if (null === $namespace) {
+ $namespace = $this->getNamespace();
+ }
+
+ $this->getMessagesFromContainer();
+
+ return isset($this->messages[$namespace]);
+ }
+
+ /**
+ * Whether "info" namespace has messages
+ *
+ * @return bool
+ */
+ public function hasInfoMessages()
+ {
+ return $this->hasMessages(self::NAMESPACE_INFO);
+ }
+
+ /**
+ * Whether "success" namespace has messages
+ *
+ * @return bool
+ */
+ public function hasSuccessMessages()
+ {
+ return $this->hasMessages(self::NAMESPACE_SUCCESS);
+ }
+
+ /**
+ * Whether "warning" namespace has messages
+ *
+ * @return bool
+ */
+ public function hasWarningMessages()
+ {
+ return $this->hasMessages(self::NAMESPACE_WARNING);
+ }
+
+ /**
+ * Whether "error" namespace has messages
+ *
+ * @return bool
+ */
+ public function hasErrorMessages()
+ {
+ return $this->hasMessages(self::NAMESPACE_ERROR);
+ }
+
+ /**
+ * Get messages from a specific namespace
+ *
+ * @param string $namespace
+ * @return array
+ */
+ public function getMessages($namespace = null)
+ {
+ if (null === $namespace) {
+ $namespace = $this->getNamespace();
+ }
+
+ if ($this->hasMessages($namespace)) {
+ return $this->messages[$namespace]->toArray();
+ }
+
+ return [];
+ }
+
+ /**
+ * Get messages from "info" namespace
+ *
+ * @return array
+ */
+ public function getInfoMessages()
+ {
+ return $this->getMessages(self::NAMESPACE_INFO);
+ }
+
+ /**
+ * Get messages from "success" namespace
+ *
+ * @return array
+ */
+ public function getSuccessMessages()
+ {
+ return $this->getMessages(self::NAMESPACE_SUCCESS);
+ }
+
+ /**
+ * Get messages from "warning" namespace
+ *
+ * @return array
+ */
+ public function getWarningMessages()
+ {
+ return $this->getMessages(self::NAMESPACE_WARNING);
+ }
+
+ /**
+ * Get messages from "error" namespace
+ *
+ * @return array
+ */
+ public function getErrorMessages()
+ {
+ return $this->getMessages(self::NAMESPACE_ERROR);
+ }
+
+ /**
+ * Clear all messages from the previous request & current namespace
+ *
+ * @param string $namespace
+ * @return bool True if messages were cleared, false if none existed
+ */
+ public function clearMessages($namespace = null)
+ {
+ if (null === $namespace) {
+ $namespace = $this->getNamespace();
+ }
+
+ if ($this->hasMessages($namespace)) {
+ unset($this->messages[$namespace]);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Clear all messages from specific namespace
+ *
+ * @param string $namespaceToClear
+ * @return bool True if messages were cleared, false if none existed
+ */
+ public function clearMessagesFromNamespace($namespaceToClear)
+ {
+ return $this->clearMessages($namespaceToClear);
+ }
+
+ /**
+ * Clear all messages from the container
+ *
+ * @return bool True if messages were cleared, false if none existed
+ */
+ public function clearMessagesFromContainer()
+ {
+ $this->getMessagesFromContainer();
+ if (empty($this->messages)) {
+ return false;
+ }
+ unset($this->messages);
+ $this->messages = [];
+
+ return true;
+ }
+
+ /**
+ * Check to see if messages have been added to the current
+ * namespace within this request
+ *
+ * @param string $namespace
+ * @return bool
+ */
+ public function hasCurrentMessages($namespace = null)
+ {
+ $container = $this->getContainer();
+ if (null === $namespace) {
+ $namespace = $this->getNamespace();
+ }
+
+ return isset($container->{$namespace});
+ }
+
+ /**
+ * Check to see if messages have been added to "info"
+ * namespace within this request
+ *
+ * @return bool
+ */
+ public function hasCurrentInfoMessages()
+ {
+ return $this->hasCurrentMessages(self::NAMESPACE_INFO);
+ }
+
+ /**
+ * Check to see if messages have been added to "success"
+ * namespace within this request
+ *
+ * @return bool
+ */
+ public function hasCurrentSuccessMessages()
+ {
+ return $this->hasCurrentMessages(self::NAMESPACE_SUCCESS);
+ }
+
+ /**
+ * Check to see if messages have been added to "warning"
+ * namespace within this request
+ *
+ * @return bool
+ */
+ public function hasCurrentWarningMessages()
+ {
+ return $this->hasCurrentMessages(self::NAMESPACE_WARNING);
+ }
+
+ /**
+ * Check to see if messages have been added to "error"
+ * namespace within this request
+ *
+ * @return bool
+ */
+ public function hasCurrentErrorMessages()
+ {
+ return $this->hasCurrentMessages(self::NAMESPACE_ERROR);
+ }
+
+ /**
+ * Get messages that have been added to the current
+ * namespace within this request
+ *
+ * @param string $namespace
+ * @return array
+ */
+ public function getCurrentMessages($namespace = null)
+ {
+ if (null === $namespace) {
+ $namespace = $this->getNamespace();
+ }
+
+ if ($this->hasCurrentMessages($namespace)) {
+ $container = $this->getContainer();
+
+ return $container->{$namespace}->toArray();
+ }
+
+ return [];
+ }
+
+ /**
+ * Get messages that have been added to the "info"
+ * namespace within this request
+ *
+ * @return array
+ */
+ public function getCurrentInfoMessages()
+ {
+ return $this->getCurrentMessages(self::NAMESPACE_INFO);
+ }
+
+ /**
+ * Get messages that have been added to the "success"
+ * namespace within this request
+ *
+ * @return array
+ */
+ public function getCurrentSuccessMessages()
+ {
+ return $this->getCurrentMessages(self::NAMESPACE_SUCCESS);
+ }
+
+ /**
+ * Get messages that have been added to the "warning"
+ * namespace within this request
+ *
+ * @return array
+ */
+ public function getCurrentWarningMessages()
+ {
+ return $this->getCurrentMessages(self::NAMESPACE_WARNING);
+ }
+
+ /**
+ * Get messages that have been added to the "error"
+ * namespace within this request
+ *
+ * @return array
+ */
+ public function getCurrentErrorMessages()
+ {
+ return $this->getCurrentMessages(self::NAMESPACE_ERROR);
+ }
+
+ /**
+ * Get messages that have been added to the current
+ * namespace in specific namespace
+ *
+ * @param string $namespaceToGet
+ * @return array
+ */
+ public function getCurrentMessagesFromNamespace($namespaceToGet)
+ {
+ return $this->getCurrentMessages($namespaceToGet);
+ }
+
+ /**
+ * Clear messages from the current request and current namespace
+ *
+ * @param string $namespace
+ * @return bool True if current messages were cleared, false if none existed.
+ */
+ public function clearCurrentMessages($namespace = null)
+ {
+ if (null === $namespace) {
+ $namespace = $this->getNamespace();
+ }
+
+ if ($this->hasCurrentMessages($namespace)) {
+ $container = $this->getContainer();
+ unset($container->{$namespace});
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Clear messages from the current namespace
+ *
+ * @param string $namespaceToClear
+ * @return bool True if current messages were cleared from the given namespace, false if none existed.
+ */
+ public function clearCurrentMessagesFromNamespace($namespaceToClear)
+ {
+ return $this->clearCurrentMessages($namespaceToClear);
+ }
+
+ /**
+ * Clear messages from the container
+ *
+ * @return bool True if current messages were cleared from the container, false if none existed.
+ */
+ public function clearCurrentMessagesFromContainer()
+ {
+ $container = $this->getContainer();
+
+ $namespaces = [];
+ foreach ($container as $namespace => $messages) {
+ $namespaces[] = $namespace;
+ }
+
+ if (empty($namespaces)) {
+ return false;
+ }
+
+ foreach ($namespaces as $namespace) {
+ unset($container->{$namespace});
+ }
+
+ return true;
+ }
+
+ /**
+ * Complete the IteratorAggregate interface, for iterating
+ *
+ * @return ArrayIterator
+ */
+ public function getIterator()
+ {
+ if ($this->hasMessages()) {
+ return new ArrayIterator($this->getMessages());
+ }
+
+ return new ArrayIterator();
+ }
+
+ /**
+ * Complete the countable interface
+ *
+ * @return int
+ */
+ public function count()
+ {
+ if ($this->hasMessages()) {
+ return count($this->getMessages());
+ }
+
+ return 0;
+ }
+
+ /**
+ * Get messages from a specific namespace
+ *
+ * @param string $namespaceToGet
+ * @return array
+ */
+ public function getMessagesFromNamespace($namespaceToGet)
+ {
+ return $this->getMessages($namespaceToGet);
+ }
+
+ /**
+ * Pull messages from the session container
+ *
+ * Iterates through the session container, removing messages into the local
+ * scope.
+ *
+ * @return void
+ */
+ protected function getMessagesFromContainer()
+ {
+ if (!empty($this->messages) || $this->messageAdded) {
+ return;
+ }
+
+ $container = $this->getContainer();
+
+ $namespaces = [];
+ foreach ($container as $namespace => $messages) {
+ $this->messages[$namespace] = $messages;
+ $namespaces[] = $namespace;
+ }
+
+ foreach ($namespaces as $namespace) {
+ unset($container->{$namespace});
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Zend\EventManager\SharedEventManagerInterface as SharedEvents;
+use Zend\Mvc\Controller\ControllerManager;
+use Zend\Mvc\Exception;
+use Zend\Mvc\InjectApplicationEventInterface;
+use Zend\Mvc\MvcEvent;
+use Zend\Mvc\Router\RouteMatch;
+use Zend\Stdlib\CallbackHandler;
+
+class Forward extends AbstractPlugin
+{
+ /**
+ * @var ControllerManager
+ */
+ protected $controllers;
+
+ /**
+ * @var MvcEvent
+ */
+ protected $event;
+
+ /**
+ * @var int
+ */
+ protected $maxNestedForwards = 10;
+
+ /**
+ * @var int
+ */
+ protected $numNestedForwards = 0;
+
+ /**
+ * @var array[]|null
+ */
+ protected $listenersToDetach = null;
+
+ /**
+ * @param ControllerManager $controllers
+ */
+ public function __construct(ControllerManager $controllers)
+ {
+ $this->controllers = $controllers;
+ }
+
+ /**
+ * Set maximum number of nested forwards allowed
+ *
+ * @param int $maxNestedForwards
+ * @return self
+ */
+ public function setMaxNestedForwards($maxNestedForwards)
+ {
+ $this->maxNestedForwards = (int) $maxNestedForwards;
+
+ return $this;
+ }
+
+ /**
+ * Get information on listeners that need to be detached before dispatching.
+ *
+ * Each entry in the array contains three keys:
+ *
+ * id (identifier for event-emitting component),
+ * event (the hooked event)
+ * and class (the class of listener that should be detached).
+ *
+ * @return array
+ */
+ public function getListenersToDetach()
+ {
+ // If a blacklist has not been explicitly set, return the default:
+ if (null === $this->listenersToDetach) {
+ // We need to detach the InjectViewModelListener to prevent templates
+ // from getting attached to the ViewModel twice when a calling action
+ // returns the output generated by a forwarded action.
+ $this->listenersToDetach = [[
+ 'id' => 'Zend\Stdlib\DispatchableInterface',
+ 'event' => MvcEvent::EVENT_DISPATCH,
+ 'class' => 'Zend\Mvc\View\Http\InjectViewModelListener',
+ ]];
+ }
+ return $this->listenersToDetach;
+ }
+
+ /**
+ * Set information on listeners that need to be detached before dispatching.
+ *
+ * @param array $listeners Listener information; see getListenersToDetach() for details on format.
+ *
+ * @return self
+ */
+ public function setListenersToDetach($listeners)
+ {
+ $this->listenersToDetach = $listeners;
+
+ return $this;
+ }
+
+ /**
+ * Dispatch another controller
+ *
+ * @param string $name Controller name; either a class name or an alias used in the controller manager
+ * @param null|array $params Parameters with which to seed a custom RouteMatch object for the new controller
+ * @return mixed
+ * @throws Exception\DomainException if composed controller does not define InjectApplicationEventInterface
+ * or Locator aware; or if the discovered controller is not dispatchable
+ */
+ public function dispatch($name, array $params = null)
+ {
+ $event = clone($this->getEvent());
+
+ $controller = $this->controllers->get($name);
+ if ($controller instanceof InjectApplicationEventInterface) {
+ $controller->setEvent($event);
+ }
+
+ // Allow passing parameters to seed the RouteMatch with & copy matched route name
+ if ($params !== null) {
+ $routeMatch = new RouteMatch($params);
+ $routeMatch->setMatchedRouteName($event->getRouteMatch()->getMatchedRouteName());
+ $event->setRouteMatch($routeMatch);
+ }
+
+ if ($this->numNestedForwards > $this->maxNestedForwards) {
+ throw new Exception\DomainException("Circular forwarding detected: greater than $this->maxNestedForwards nested forwards");
+ }
+ $this->numNestedForwards++;
+
+ // Detach listeners that may cause problems during dispatch:
+ $sharedEvents = $event->getApplication()->getEventManager()->getSharedManager();
+ $listeners = $this->detachProblemListeners($sharedEvents);
+
+ $return = $controller->dispatch($event->getRequest(), $event->getResponse());
+
+ // If we detached any listeners, reattach them now:
+ $this->reattachProblemListeners($sharedEvents, $listeners);
+
+ $this->numNestedForwards--;
+
+ return $return;
+ }
+
+ /**
+ * Detach problem listeners specified by getListenersToDetach() and return an array of information that will
+ * allow them to be reattached.
+ *
+ * @param SharedEvents $sharedEvents Shared event manager
+ * @return array
+ */
+ protected function detachProblemListeners(SharedEvents $sharedEvents)
+ {
+ // Convert the problem list from two-dimensional array to more convenient id => event => class format:
+ $formattedProblems = [];
+ foreach ($this->getListenersToDetach() as $current) {
+ if (!isset($formattedProblems[$current['id']])) {
+ $formattedProblems[$current['id']] = [];
+ }
+ if (!isset($formattedProblems[$current['id']][$current['event']])) {
+ $formattedProblems[$current['id']][$current['event']] = [];
+ }
+ $formattedProblems[$current['id']][$current['event']][] = $current['class'];
+ }
+
+ // Loop through the class blacklist, detaching problem events and remembering their CallbackHandlers
+ // for future reference:
+ $results = [];
+ foreach ($formattedProblems as $id => $eventArray) {
+ $results[$id] = [];
+ foreach ($eventArray as $eventName => $classArray) {
+ $results[$id][$eventName] = [];
+ $events = $this->getSharedListenersById($id, $eventName, $sharedEvents);
+ foreach ($events as $priority => $currentPriorityEvents) {
+ // v2 fix
+ if (!is_array($currentPriorityEvents)) {
+ $currentPriorityEvents = [$currentPriorityEvents];
+ }
+ // v3
+ foreach ($currentPriorityEvents as $currentEvent) {
+ $currentCallback = $currentEvent;
+
+ // zend-eventmanager v2 compatibility:
+ if ($currentCallback instanceof CallbackHandler) {
+ $currentCallback = $currentEvent->getCallback();
+ $priority = $currentEvent->getMetadatum('priority');
+ }
+
+ // If we have an array, grab the object
+ if (is_array($currentCallback)) {
+ $currentCallback = array_shift($currentCallback);
+ }
+
+ // This routine is only valid for object callbacks
+ if (!is_object($currentCallback)) {
+ continue;
+ }
+
+ foreach ($classArray as $class) {
+ if ($currentCallback instanceof $class) {
+ // Pass $currentEvent; when using zend-eventmanager v2,
+ // this is the CallbackHandler, while in v3 it's
+ // the actual listener.
+ $this->detachSharedListener($id, $currentEvent, $sharedEvents);
+ $results[$id][$eventName][$priority] = $currentEvent;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return $results;
+ }
+
+ /**
+ * Reattach all problem listeners detached by detachProblemListeners(), if any.
+ *
+ * @param SharedEvents $sharedEvents Shared event manager
+ * @param array $listeners Output of detachProblemListeners()
+ * @return void
+ */
+ protected function reattachProblemListeners(SharedEvents $sharedEvents, array $listeners)
+ {
+ foreach ($listeners as $id => $eventArray) {
+ foreach ($eventArray as $eventName => $callbacks) {
+ foreach ($callbacks as $priority => $current) {
+ $callback = $current;
+
+ // zend-eventmanager v2 compatibility:
+ if ($current instanceof CallbackHandler) {
+ $callback = $current->getCallback();
+ $priority = $current->getMetadatum('priority');
+ }
+
+ $sharedEvents->attach($id, $eventName, $callback, $priority);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the event
+ *
+ * @return MvcEvent
+ * @throws Exception\DomainException if unable to find event
+ */
+ protected function getEvent()
+ {
+ if ($this->event) {
+ return $this->event;
+ }
+
+ $controller = $this->getController();
+ if (!$controller instanceof 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();
+ if (!$event instanceof MvcEvent) {
+ $params = [];
+ if ($event) {
+ $params = $event->getParams();
+ }
+ $event = new MvcEvent();
+ $event->setParams($params);
+ }
+ $this->event = $event;
+
+ return $this->event;
+ }
+
+ /**
+ * Retrieve shared listeners for an event by identifier.
+ *
+ * Varies retrieval based on zend-eventmanager version.
+ *
+ * @param string|int $id
+ * @param string $event
+ * @param SharedEvents $sharedEvents
+ * @return array|\Traversable
+ */
+ private function getSharedListenersById($id, $event, SharedEvents $sharedEvents)
+ {
+ if (method_exists($sharedEvents, 'attachAggregate')) {
+ // v2
+ return $sharedEvents->getListeners($id, $event) ?: [];
+ }
+
+ // v3
+ return $sharedEvents->getListeners([$id], $event);
+ }
+
+ /**
+ * Detach a shared listener by identifier.
+ *
+ * Varies detachment based on zend-eventmanager version.
+ *
+ * @param string|int $id
+ * @param callable|CallbackHandler $listener
+ * @param SharedEvents $sharedEvents
+ * @return void
+ */
+ private function detachSharedListener($id, $listener, SharedEvents $sharedEvents)
+ {
+ if (method_exists($sharedEvents, 'attachAggregate')) {
+ // v2
+ $sharedEvents->detach($id, $listener);
+ return;
+ }
+
+ // v3
+ $sharedEvents->detach($listener, $id);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Zend\Authentication\AuthenticationServiceInterface;
+use Zend\Mvc\Exception;
+
+/**
+ * Controller plugin to fetch the authenticated identity.
+ */
+class Identity extends AbstractPlugin
+{
+ /**
+ * @var AuthenticationServiceInterface
+ */
+ protected $authenticationService;
+
+ /**
+ * @return AuthenticationServiceInterface
+ */
+ public function getAuthenticationService()
+ {
+ return $this->authenticationService;
+ }
+
+ /**
+ * @param AuthenticationServiceInterface $authenticationService
+ */
+ public function setAuthenticationService(AuthenticationServiceInterface $authenticationService)
+ {
+ $this->authenticationService = $authenticationService;
+ }
+
+ /**
+ * Retrieve the current identity, if any.
+ *
+ * If none is present, returns null.
+ *
+ * @return mixed|null
+ * @throws Exception\RuntimeException
+ */
+ public function __invoke()
+ {
+ if (!$this->authenticationService instanceof AuthenticationServiceInterface) {
+ throw new Exception\RuntimeException('No AuthenticationServiceInterface instance provided');
+ }
+ if (!$this->authenticationService->hasIdentity()) {
+ return;
+ }
+ return $this->authenticationService->getIdentity();
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Zend\Mvc\Exception;
+use Zend\Mvc\InjectApplicationEventInterface;
+use Zend\Mvc\MvcEvent;
+use Zend\View\Model\ModelInterface as Model;
+
+class Layout extends AbstractPlugin
+{
+ /**
+ * @var MvcEvent
+ */
+ protected $event;
+
+ /**
+ * Set the layout template
+ *
+ * @param string $template
+ * @return Layout
+ */
+ public function setTemplate($template)
+ {
+ $viewModel = $this->getViewModel();
+ $viewModel->setTemplate((string) $template);
+ return $this;
+ }
+
+ /**
+ * Invoke as a functor
+ *
+ * If no arguments are given, grabs the "root" or "layout" view model.
+ * Otherwise, attempts to set the template for that view model.
+ *
+ * @param null|string $template
+ * @return Model|Layout
+ */
+ public function __invoke($template = null)
+ {
+ if (null === $template) {
+ return $this->getViewModel();
+ }
+ return $this->setTemplate($template);
+ }
+
+ /**
+ * Get the event
+ *
+ * @return MvcEvent
+ * @throws Exception\DomainException if unable to find event
+ */
+ protected function getEvent()
+ {
+ if ($this->event) {
+ return $this->event;
+ }
+
+ $controller = $this->getController();
+ if (!$controller instanceof InjectApplicationEventInterface) {
+ throw new Exception\DomainException('Layout plugin requires a controller that implements InjectApplicationEventInterface');
+ }
+
+ $event = $controller->getEvent();
+ if (!$event instanceof MvcEvent) {
+ $params = $event->getParams();
+ $event = new MvcEvent();
+ $event->setParams($params);
+ }
+ $this->event = $event;
+
+ return $this->event;
+ }
+
+ /**
+ * Retrieve the root view model from the event
+ *
+ * @return Model
+ * @throws Exception\DomainException
+ */
+ protected function getViewModel()
+ {
+ $event = $this->getEvent();
+ $viewModel = $event->getViewModel();
+ if (!$viewModel instanceof Model) {
+ throw new Exception\DomainException('Layout plugin requires that event view model is populated');
+ }
+ return $viewModel;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Zend\Mvc\Exception\RuntimeException;
+use Zend\Mvc\InjectApplicationEventInterface;
+
+class Params extends AbstractPlugin
+{
+ /**
+ * Grabs a param from route match by default.
+ *
+ * @param string $param
+ * @param mixed $default
+ * @return mixed
+ */
+ public function __invoke($param = null, $default = null)
+ {
+ if ($param === null) {
+ return $this;
+ }
+ return $this->fromRoute($param, $default);
+ }
+
+ /**
+ * Return all files or a single file.
+ *
+ * @param string $name File name to retrieve, or null to get all.
+ * @param mixed $default Default value to use when the file is missing.
+ * @return array|\ArrayAccess|null
+ */
+ public function fromFiles($name = null, $default = null)
+ {
+ if ($name === null) {
+ return $this->getController()->getRequest()->getFiles($name, $default)->toArray();
+ }
+
+ return $this->getController()->getRequest()->getFiles($name, $default);
+ }
+
+ /**
+ * Return all header parameters or a single header parameter.
+ *
+ * @param string $header Header name to retrieve, or null to get all.
+ * @param mixed $default Default value to use when the requested header is missing.
+ * @return null|\Zend\Http\Header\HeaderInterface
+ */
+ public function fromHeader($header = null, $default = null)
+ {
+ if ($header === null) {
+ return $this->getController()->getRequest()->getHeaders($header, $default)->toArray();
+ }
+
+ return $this->getController()->getRequest()->getHeaders($header, $default);
+ }
+
+ /**
+ * Return all post parameters or a single post parameter.
+ *
+ * @param string $param Parameter name to retrieve, or null to get all.
+ * @param mixed $default Default value to use when the parameter is missing.
+ * @return mixed
+ */
+ public function fromPost($param = null, $default = null)
+ {
+ if ($param === null) {
+ return $this->getController()->getRequest()->getPost($param, $default)->toArray();
+ }
+
+ return $this->getController()->getRequest()->getPost($param, $default);
+ }
+
+ /**
+ * Return all query parameters or a single query parameter.
+ *
+ * @param string $param Parameter name to retrieve, or null to get all.
+ * @param mixed $default Default value to use when the parameter is missing.
+ * @return mixed
+ */
+ public function fromQuery($param = null, $default = null)
+ {
+ if ($param === null) {
+ return $this->getController()->getRequest()->getQuery($param, $default)->toArray();
+ }
+
+ return $this->getController()->getRequest()->getQuery($param, $default);
+ }
+
+ /**
+ * Return all route parameters or a single route parameter.
+ *
+ * @param string $param Parameter name to retrieve, or null to get all.
+ * @param mixed $default Default value to use when the parameter is missing.
+ * @return mixed
+ * @throws RuntimeException
+ */
+ public function fromRoute($param = null, $default = null)
+ {
+ $controller = $this->getController();
+
+ if (!$controller instanceof InjectApplicationEventInterface) {
+ throw new RuntimeException(
+ 'Controllers must implement Zend\Mvc\InjectApplicationEventInterface to use this plugin.'
+ );
+ }
+
+ if ($param === null) {
+ return $controller->getEvent()->getRouteMatch()->getParams();
+ }
+
+ return $controller->getEvent()->getRouteMatch()->getParam($param, $default);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Zend\Stdlib\DispatchableInterface as Dispatchable;
+
+interface PluginInterface
+{
+ /**
+ * Set the current controller instance
+ *
+ * @param Dispatchable $controller
+ * @return void
+ */
+ public function setController(Dispatchable $controller);
+
+ /**
+ * Get the current controller instance
+ *
+ * @return null|Dispatchable
+ */
+ public function getController();
+}
--- /dev/null
+<?php
+
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Zend\Mvc\Exception\RuntimeException;
+use Zend\Session\Container;
+
+/**
+ * Plugin to help facilitate Post/Redirect/Get (http://en.wikipedia.org/wiki/Post/Redirect/Get)
+ */
+class PostRedirectGet extends AbstractPlugin
+{
+ /**
+ * @var Container
+ */
+ protected $sessionContainer;
+
+ /**
+ * Perform PRG logic
+ *
+ * If a null value is present for the $redirect, the current route is
+ * retrieved and use to generate the URL for redirect.
+ *
+ * If the request method is POST, creates a session container set to expire
+ * after 1 hop containing the values of the POST. It then redirects to the
+ * specified URL using a status 303.
+ *
+ * If the request method is GET, checks to see if we have values in the
+ * session container, and, if so, returns them; otherwise, it returns a
+ * boolean false.
+ *
+ * @param null|string $redirect
+ * @param bool $redirectToUrl
+ * @return \Zend\Http\Response|array|\Traversable|false
+ */
+ public function __invoke($redirect = null, $redirectToUrl = false)
+ {
+ $controller = $this->getController();
+ $request = $controller->getRequest();
+ $container = $this->getSessionContainer();
+
+ if ($request->isPost()) {
+ $container->setExpirationHops(1, 'post');
+ $container->post = $request->getPost()->toArray();
+ return $this->redirect($redirect, $redirectToUrl);
+ } else {
+ if (null !== $container->post) {
+ $post = $container->post;
+ unset($container->post);
+ return $post;
+ }
+
+ return false;
+ }
+ }
+
+ /**
+ * @return Container
+ */
+ public function getSessionContainer()
+ {
+ if (!$this->sessionContainer) {
+ $this->sessionContainer = new Container('prg_post1');
+ }
+ return $this->sessionContainer;
+ }
+
+ /**
+ * @param Container $container
+ * @return PostRedirectGet
+ */
+ public function setSessionContainer(Container $container)
+ {
+ $this->sessionContainer = $container;
+ return $this;
+ }
+
+ /**
+ * TODO: Good candidate for traits method in PHP 5.4 with FilePostRedirectGet plugin
+ *
+ * @param string $redirect
+ * @param bool $redirectToUrl
+ * @return \Zend\Http\Response
+ * @throws \Zend\Mvc\Exception\RuntimeException
+ */
+ protected function redirect($redirect, $redirectToUrl)
+ {
+ $controller = $this->getController();
+ $params = [];
+ $options = ['query' => $controller->params()->fromQuery()];
+ $reuseMatchedParams = false;
+
+ if (null === $redirect) {
+ $routeMatch = $controller->getEvent()->getRouteMatch();
+
+ $redirect = $routeMatch->getMatchedRouteName();
+ //null indicates to redirect for self.
+ $reuseMatchedParams = true;
+ }
+
+ if (method_exists($controller, 'getPluginManager')) {
+ // get the redirect plugin from the plugin manager
+ $redirector = $controller->getPluginManager()->get('Redirect');
+ } else {
+ /*
+ * If the user wants to redirect to a route, the redirector has to come
+ * from the plugin manager -- otherwise no router will be injected
+ */
+ if (false === $redirectToUrl) {
+ throw new RuntimeException('Could not redirect to a route without a router');
+ }
+
+ $redirector = new Redirect();
+ }
+
+ if (false === $redirectToUrl) {
+ $response = $redirector->toRoute($redirect, $params, $options, $reuseMatchedParams);
+ $response->setStatusCode(303);
+ return $response;
+ }
+
+ $response = $redirector->toUrl($redirect);
+ $response->setStatusCode(303);
+
+ return $response;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Zend\Http\Response;
+use Zend\Mvc\Exception;
+use Zend\Mvc\InjectApplicationEventInterface;
+use Zend\Mvc\MvcEvent;
+
+/**
+ * @todo allow specifying status code as a default, or as an option to methods
+ */
+class Redirect extends AbstractPlugin
+{
+ protected $event;
+ protected $response;
+
+ /**
+ * Generate redirect response based on given route
+ *
+ * @param string $route RouteInterface name
+ * @param array $params Parameters to use in url generation, if any
+ * @param array $options RouteInterface-specific options to use in url generation, if any
+ * @param bool $reuseMatchedParams Whether to reuse matched parameters
+ * @return Response
+ * @throws Exception\DomainException if composed controller does not implement InjectApplicationEventInterface, or
+ * router cannot be found in controller event
+ */
+ public function toRoute($route = null, $params = [], $options = [], $reuseMatchedParams = false)
+ {
+ $controller = $this->getController();
+ if (!$controller || !method_exists($controller, 'plugin')) {
+ throw new Exception\DomainException('Redirect plugin requires a controller that defines the plugin() method');
+ }
+
+ $urlPlugin = $controller->plugin('url');
+
+ if (is_scalar($options)) {
+ $url = $urlPlugin->fromRoute($route, $params, $options);
+ } else {
+ $url = $urlPlugin->fromRoute($route, $params, $options, $reuseMatchedParams);
+ }
+
+ return $this->toUrl($url);
+ }
+
+ /**
+ * Generate redirect response based on given URL
+ *
+ * @param string $url
+ * @return Response
+ */
+ public function toUrl($url)
+ {
+ $response = $this->getResponse();
+ $response->getHeaders()->addHeaderLine('Location', $url);
+ $response->setStatusCode(302);
+ return $response;
+ }
+
+ /**
+ * Refresh to current route
+ *
+ * @return Response
+ */
+ public function refresh()
+ {
+ return $this->toRoute(null, [], [], true);
+ }
+
+ /**
+ * Get the response
+ *
+ * @return Response
+ * @throws Exception\DomainException if unable to find response
+ */
+ protected function getResponse()
+ {
+ if ($this->response) {
+ return $this->response;
+ }
+
+ $event = $this->getEvent();
+ $response = $event->getResponse();
+ if (!$response instanceof Response) {
+ throw new Exception\DomainException('Redirect plugin requires event compose a response');
+ }
+ $this->response = $response;
+ return $this->response;
+ }
+
+ /**
+ * Get the event
+ *
+ * @return MvcEvent
+ * @throws Exception\DomainException if unable to find event
+ */
+ protected function getEvent()
+ {
+ if ($this->event) {
+ return $this->event;
+ }
+
+ $controller = $this->getController();
+ if (!$controller instanceof InjectApplicationEventInterface) {
+ throw new Exception\DomainException('Redirect plugin requires a controller that implements InjectApplicationEventInterface');
+ }
+
+ $event = $controller->getEvent();
+ if (!$event instanceof MvcEvent) {
+ $params = $event->getParams();
+ $event = new MvcEvent();
+ $event->setParams($params);
+ }
+ $this->event = $event;
+
+ return $this->event;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+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\Mvc\Controller\Plugin\Forward;
+
+class ForwardFactory implements FactoryInterface
+{
+ /**
+ * {@inheritDoc}
+ *
+ * @return Forward
+ * @throws ServiceNotCreatedException if Controllermanager service is not found in application service locator
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ if (! $container->has('ControllerManager')) {
+ throw new ServiceNotCreatedException(sprintf(
+ '%s requires that the application service manager contains a "%s" service; none found',
+ __CLASS__,
+ 'ControllerManager'
+ ));
+ }
+ $controllers = $container->get('ControllerManager');
+
+ return new Forward($controllers);
+ }
+
+ /**
+ * Create and return Forward instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return Forward
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ $parentContainer = $container->getServiceLocator() ?: $container;
+ return $this($parentContainer, Forward::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+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;
+
+class IdentityFactory implements FactoryInterface
+{
+ /**
+ * {@inheritDoc}
+ *
+ * @return Identity
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $helper = new Identity();
+ if ($container->has(AuthenticationService::class)) {
+ $helper->setAuthenticationService($container->get(AuthenticationService::class));
+ }
+ return $helper;
+ }
+
+ /**
+ * Create and return Identity instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return Identity
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ // Retrieve the parent container when under zend-servicemanager v2
+ if (! method_exists($container, 'configure')) {
+ $container = $container->getServiceLocator() ?: $container;
+ }
+
+ return $this($container, Identity::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller\Plugin;
+
+use Traversable;
+use Zend\EventManager\EventInterface;
+use Zend\Mvc\Exception;
+use Zend\Mvc\InjectApplicationEventInterface;
+use Zend\Mvc\ModuleRouteListener;
+use Zend\Mvc\MvcEvent;
+use Zend\Mvc\Router\RouteStackInterface;
+
+class Url extends AbstractPlugin
+{
+ /**
+ * Generates a URL based on a route
+ *
+ * @param string $route RouteInterface name
+ * @param array|Traversable $params Parameters to use in url generation, if any
+ * @param array|bool $options RouteInterface-specific options to use in url generation, if any.
+ * If boolean, and no fourth argument, used as $reuseMatchedParams.
+ * @param bool $reuseMatchedParams Whether to reuse matched parameters
+ *
+ * @throws \Zend\Mvc\Exception\RuntimeException
+ * @throws \Zend\Mvc\Exception\InvalidArgumentException
+ * @throws \Zend\Mvc\Exception\DomainException
+ * @return string
+ */
+ public function fromRoute($route = null, $params = [], $options = [], $reuseMatchedParams = false)
+ {
+ $controller = $this->getController();
+ if (!$controller instanceof InjectApplicationEventInterface) {
+ throw new Exception\DomainException('Url plugin requires a controller that implements InjectApplicationEventInterface');
+ }
+
+ if (!is_array($params)) {
+ if (!$params instanceof Traversable) {
+ throw new Exception\InvalidArgumentException(
+ 'Params is expected to be an array or a Traversable object'
+ );
+ }
+ $params = iterator_to_array($params);
+ }
+
+ $event = $controller->getEvent();
+ $router = null;
+ $matches = null;
+ if ($event instanceof MvcEvent) {
+ $router = $event->getRouter();
+ $matches = $event->getRouteMatch();
+ } elseif ($event instanceof EventInterface) {
+ $router = $event->getParam('router', false);
+ $matches = $event->getParam('route-match', false);
+ }
+ if (!$router instanceof RouteStackInterface) {
+ throw new Exception\DomainException('Url plugin requires that controller event compose a router; none found');
+ }
+
+ if (3 == func_num_args() && is_bool($options)) {
+ $reuseMatchedParams = $options;
+ $options = [];
+ }
+
+ if ($route === null) {
+ if (!$matches) {
+ throw new Exception\RuntimeException('No RouteMatch instance present');
+ }
+
+ $route = $matches->getMatchedRouteName();
+
+ if ($route === null) {
+ throw new Exception\RuntimeException('RouteMatch does not contain a matched route name');
+ }
+ }
+
+ if ($reuseMatchedParams && $matches) {
+ $routeMatchParams = $matches->getParams();
+
+ if (isset($routeMatchParams[ModuleRouteListener::ORIGINAL_CONTROLLER])) {
+ $routeMatchParams['controller'] = $routeMatchParams[ModuleRouteListener::ORIGINAL_CONTROLLER];
+ unset($routeMatchParams[ModuleRouteListener::ORIGINAL_CONTROLLER]);
+ }
+
+ if (isset($routeMatchParams[ModuleRouteListener::MODULE_NAMESPACE])) {
+ unset($routeMatchParams[ModuleRouteListener::MODULE_NAMESPACE]);
+ }
+
+ $params = array_merge($routeMatchParams, $params);
+ }
+
+ $options['name'] = $route;
+ return $router->assemble($params, $options);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Controller;
+
+use Zend\Mvc\Exception;
+use Zend\ServiceManager\AbstractPluginManager;
+use Zend\ServiceManager\Exception\InvalidServiceException;
+use Zend\ServiceManager\Factory\InvokableFactory;
+use Zend\Stdlib\DispatchableInterface;
+
+/**
+ * Plugin manager implementation for controllers
+ *
+ * Registers a number of default plugins, and contains an initializer for
+ * injecting plugins with the current controller.
+ */
+class PluginManager extends AbstractPluginManager
+{
+ /**
+ * Plugins must be of this type.
+ *
+ * @var string
+ */
+ protected $instanceOf = Plugin\PluginInterface::class;
+
+ /**
+ * @var string[] Default aliases
+ */
+ 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,
+ ];
+
+ /**
+ * @var string[]|callable[] Default factories
+ */
+ 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,
+
+ // v2 normalized names
+
+ 'zendmvccontrollerpluginforward' => Plugin\Service\ForwardFactory::class,
+ 'zendmvccontrollerpluginidentity' => Plugin\Service\IdentityFactory::class,
+ 'zendmvccontrollerpluginacceptableviewmodelselector' => InvokableFactory::class,
+ 'zendmvccontrollerpluginfilepostredirectget' => InvokableFactory::class,
+ 'zendmvccontrollerpluginflashmessenger' => InvokableFactory::class,
+ 'zendmvccontrollerpluginlayout' => InvokableFactory::class,
+ 'zendmvccontrollerpluginparams' => InvokableFactory::class,
+ 'zendmvccontrollerpluginpostredirectget' => InvokableFactory::class,
+ 'zendmvccontrollerpluginredirect' => InvokableFactory::class,
+ 'zendmvccontrollerpluginurl' => InvokableFactory::class,
+ 'zendmvccontrollerplugincreatehttpnotfoundmodel' => InvokableFactory::class,
+ 'zendmvccontrollerplugincreateconsolenotfoundmodel' => InvokableFactory::class,
+ ];
+
+ /**
+ * @var DispatchableInterface
+ */
+ protected $controller;
+
+ /**
+ * Retrieve a registered instance
+ *
+ * After the plugin is retrieved from the service locator, inject the
+ * controller in the plugin every time it is requested. This is required
+ * because a controller can use a plugin and another controller can be
+ * dispatched afterwards. If this second controller uses the same plugin
+ * as the first controller, the reference to the controller inside the
+ * plugin is lost.
+ *
+ * @param string $name
+ * @return DispatchableInterface
+ */
+ public function get($name, array $options = null)
+ {
+ $plugin = parent::get($name, $options);
+ $this->injectController($plugin);
+
+ return $plugin;
+ }
+
+ /**
+ * Set controller
+ *
+ * @param DispatchableInterface $controller
+ * @return PluginManager
+ */
+ public function setController(DispatchableInterface $controller)
+ {
+ $this->controller = $controller;
+
+ return $this;
+ }
+
+ /**
+ * Retrieve controller instance
+ *
+ * @return null|DispatchableInterface
+ */
+ public function getController()
+ {
+ return $this->controller;
+ }
+
+ /**
+ * Inject a helper instance with the registered controller
+ *
+ * @param object $plugin
+ * @return void
+ */
+ public function injectController($plugin)
+ {
+ if (!is_object($plugin)) {
+ return;
+ }
+ if (!method_exists($plugin, 'setController')) {
+ return;
+ }
+
+ $controller = $this->getController();
+ if (!$controller instanceof DispatchableInterface) {
+ return;
+ }
+
+ $plugin->setController($controller);
+ }
+
+ /**
+ * Validate a plugin (v3)
+ *
+ * {@inheritDoc}
+ */
+ public function validate($plugin)
+ {
+ if (! $plugin instanceof $this->instanceOf) {
+ throw new InvalidServiceException(sprintf(
+ 'Plugin of type "%s" is invalid; must implement %s',
+ (is_object($plugin) ? get_class($plugin) : gettype($plugin)),
+ $this->instanceOf
+ ));
+ }
+ }
+
+ /**
+ * Validate a plugin (v2)
+ *
+ * {@inheritDoc}
+ *
+ * @throws Exception\InvalidPluginException
+ */
+ public function validatePlugin($plugin)
+ {
+ try {
+ $this->validate($plugin);
+ } catch (InvalidServiceException $e) {
+ throw new Exception\InvalidPluginException(
+ $e->getMessage(),
+ $e->getCode(),
+ $e
+ );
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc;
+
+use ArrayObject;
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+use Zend\ServiceManager\Exception\InvalidServiceException;
+use Zend\Stdlib\ArrayUtils;
+
+/**
+ * Default dispatch listener
+ *
+ * Pulls controllers from the service manager's "ControllerManager" service.
+ *
+ * If the controller cannot be found a "404" result is set up. Otherwise it
+ * will continue to try to load the controller.
+ *
+ * If the controller is not dispatchable it sets up a "404" result. In case
+ * of any other exceptions it trigger the "dispatch.error" event in an attempt
+ * to return a 500 status.
+ *
+ * If the controller subscribes to InjectApplicationEventInterface, it injects
+ * the current MvcEvent into the controller.
+ *
+ * It then calls the controller's "dispatch" method, passing it the request and
+ * response. If an exception occurs, it triggers the "dispatch.error" event,
+ * in an attempt to return a 500 status.
+ *
+ * The return value of dispatching the controller is placed into the result
+ * property of the MvcEvent, and returned.
+ */
+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
+ *
+ * @param EventManagerInterface $events
+ * @param int $priority
+ * @return void
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'onDispatch']);
+ if (function_exists('zend_monitor_custom_event_ex')) {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, [$this, 'reportMonitorEvent']);
+ }
+ }
+
+ /**
+ * Listen to the "dispatch" event
+ *
+ * @param MvcEvent $e
+ * @return mixed
+ */
+ public function onDispatch(MvcEvent $e)
+ {
+ $routeMatch = $e->getRouteMatch();
+ $controllerName = $routeMatch instanceof Router\RouteMatch
+ ? $routeMatch->getParam('controller', 'not-found')
+ : 'not-found';
+ $application = $e->getApplication();
+ $events = $application->getEventManager();
+ $controllerManager = $this->controllerManager;
+
+
+ // Query abstract controllers, too!
+ if (! $controllerManager->has($controllerName)) {
+ $return = $this->marshalControllerNotFoundEvent($application::ERROR_CONTROLLER_NOT_FOUND, $controllerName, $e, $application);
+ return $this->complete($return, $e);
+ }
+
+ try {
+ $controller = $controllerManager->get($controllerName);
+ } catch (Exception\InvalidControllerException $exception) {
+ $return = $this->marshalControllerNotFoundEvent($application::ERROR_CONTROLLER_INVALID, $controllerName, $e, $application, $exception);
+ return $this->complete($return, $e);
+ } catch (InvalidServiceException $exception) {
+ $return = $this->marshalControllerNotFoundEvent($application::ERROR_CONTROLLER_INVALID, $controllerName, $e, $application, $exception);
+ return $this->complete($return, $e);
+ } catch (\Throwable $exception) {
+ $return = $this->marshalBadControllerEvent($controllerName, $e, $application, $exception);
+ return $this->complete($return, $e);
+ } catch (\Exception $exception) { // @TODO clean up once PHP 7 requirement is enforced
+ $return = $this->marshalBadControllerEvent($controllerName, $e, $application, $exception);
+ return $this->complete($return, $e);
+ }
+
+ if ($controller instanceof InjectApplicationEventInterface) {
+ $controller->setEvent($e);
+ }
+
+ $request = $e->getRequest();
+ $response = $application->getResponse();
+ $caughtException = null;
+
+ try {
+ $return = $controller->dispatch($request, $response);
+ } catch (\Throwable $ex) {
+ $caughtException = $ex;
+ } catch (\Exception $ex) { // @TODO clean up once PHP 7 requirement is enforced
+ $caughtException = $ex;
+ }
+
+ if ($caughtException !== null) {
+ $e->setName(MvcEvent::EVENT_DISPATCH_ERROR);
+ $e->setError($application::ERROR_EXCEPTION);
+ $e->setController($controllerName);
+ $e->setControllerClass(get_class($controller));
+ $e->setParam('exception', $caughtException);
+
+ $return = $application->getEventManager()->triggerEvent($e)->last();
+ if (! $return) {
+ $return = $e->getResult();
+ }
+ }
+
+ return $this->complete($return, $e);
+ }
+
+ /**
+ * @param MvcEvent $e
+ */
+ public function reportMonitorEvent(MvcEvent $e)
+ {
+ $error = $e->getError();
+ $exception = $e->getParam('exception');
+ if ($exception instanceof \Exception || $exception instanceof \Throwable) { // @TODO clean up once PHP 7 requirement is enforced
+ zend_monitor_custom_event_ex($error, $exception->getMessage(), 'Zend Framework Exception', ['code' => $exception->getCode(), 'trace' => $exception->getTraceAsString()]);
+ }
+ }
+
+ /**
+ * Complete the dispatch
+ *
+ * @param mixed $return
+ * @param MvcEvent $event
+ * @return mixed
+ */
+ protected function complete($return, MvcEvent $event)
+ {
+ if (!is_object($return)) {
+ if (ArrayUtils::hasStringKeys($return)) {
+ $return = new ArrayObject($return, ArrayObject::ARRAY_AS_PROPS);
+ }
+ }
+ $event->setResult($return);
+ return $return;
+ }
+
+ /**
+ * Marshal a controller not found exception event
+ *
+ * @param string $type
+ * @param string $controllerName
+ * @param MvcEvent $event
+ * @param Application $application
+ * @param \Exception $exception
+ * @return mixed
+ */
+ protected function marshalControllerNotFoundEvent(
+ $type,
+ $controllerName,
+ MvcEvent $event,
+ Application $application,
+ \Exception $exception = null
+ ) {
+ $event->setName(MvcEvent::EVENT_DISPATCH_ERROR);
+ $event->setError($type);
+ $event->setController($controllerName);
+ $event->setControllerClass('invalid controller class or alias: ' . $controllerName);
+ if ($exception !== null) {
+ $event->setParam('exception', $exception);
+ }
+
+ $events = $application->getEventManager();
+ $results = $events->triggerEvent($event);
+ $return = $results->last();
+ if (! $return) {
+ $return = $event->getResult();
+ }
+ return $return;
+ }
+
+ /**
+ * Marshal a controller not found exception event
+ *
+ * @deprecated Use marshalControllerNotFoundEvent() instead
+ * @param string $type
+ * @param string $controllerName
+ * @param MvcEvent $event
+ * @param Application $application
+ * @param \Exception $exception
+ * @return mixed
+ */
+ protected function marshallControllerNotFoundEvent(
+ $type,
+ $controllerName,
+ MvcEvent $event,
+ Application $application,
+ \Exception $exception = null
+ ) {
+ trigger_error(sprintf(
+ '%s is deprecated; please use %s::marshalControllerNotFoundEvent instead',
+ __METHOD__,
+ __CLASS__
+ ), E_USER_DEPRECATED);
+
+ return $this->marshalControllerNotFoundEvent($type, $controllerName, $event, $application, $exception);
+ }
+
+ /**
+ * Marshal a bad controller exception event
+ *
+ * @todo Update $exception typehint to "Throwable" once PHP 7 requirement
+ * is enforced
+ * @param string $controllerName
+ * @param MvcEvent $event
+ * @param Application $application
+ * @param \Exception|\Throwable $exception
+ * @return mixed
+ */
+ protected function marshalBadControllerEvent($controllerName, MvcEvent $event, Application $application, $exception)
+ {
+ $event->setName(MvcEvent::EVENT_DISPATCH_ERROR);
+ $event->setError($application::ERROR_EXCEPTION);
+ $event->setController($controllerName);
+ $event->setParam('exception', $exception);
+
+ $events = $application->getEventManager();
+ $results = $events->triggerEvent($event);
+ $return = $results->last();
+ if (! $return) {
+ return $event->getResult();
+ }
+
+ return $return;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Exception;
+
+class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Exception;
+
+class DomainException extends \DomainException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Exception;
+
+interface ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Exception;
+
+class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Exception;
+
+class InvalidControllerException extends \Exception implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Exception;
+
+class InvalidPluginException extends \Exception implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Exception;
+
+class MissingLocatorException extends RuntimeException
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Exception;
+
+class RuntimeException extends \RuntimeException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc;
+
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+use Zend\Http\Request as HttpRequest;
+use Zend\Http\Response as HttpResponse;
+
+class HttpMethodListener extends AbstractListenerAggregate
+{
+ /**
+ * @var array
+ */
+ protected $allowedMethods = [
+ HttpRequest::METHOD_CONNECT,
+ HttpRequest::METHOD_DELETE,
+ HttpRequest::METHOD_GET,
+ HttpRequest::METHOD_HEAD,
+ HttpRequest::METHOD_OPTIONS,
+ HttpRequest::METHOD_PATCH,
+ HttpRequest::METHOD_POST,
+ HttpRequest::METHOD_PUT,
+ HttpRequest::METHOD_PROPFIND,
+ HttpRequest::METHOD_TRACE,
+ ];
+
+ /**
+ * @var bool
+ */
+ protected $enabled = true;
+
+ /**
+ * @param bool $enabled
+ * @param array $allowedMethods
+ */
+ public function __construct($enabled = true, $allowedMethods = [])
+ {
+ $this->setEnabled($enabled);
+
+ if (! empty($allowedMethods)) {
+ $this->setAllowedMethods($allowedMethods);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ if (! $this->isEnabled()) {
+ return;
+ }
+
+ $this->listeners[] = $events->attach(
+ MvcEvent::EVENT_ROUTE,
+ [$this, 'onRoute'],
+ 10000
+ );
+ }
+
+ /**
+ * @param MvcEvent $e
+ * @return void|HttpResponse
+ */
+ public function onRoute(MvcEvent $e)
+ {
+ $request = $e->getRequest();
+ $response = $e->getResponse();
+
+ if (! $request instanceof HttpRequest || ! $response instanceof HttpResponse) {
+ return;
+ }
+
+ $method = $request->getMethod();
+
+ if (in_array($method, $this->getAllowedMethods())) {
+ return;
+ }
+
+ $response->setStatusCode(405);
+
+ return $response;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAllowedMethods()
+ {
+ return $this->allowedMethods;
+ }
+
+ /**
+ * @param array $allowedMethods
+ */
+ public function setAllowedMethods(array $allowedMethods)
+ {
+ foreach ($allowedMethods as &$value) {
+ $value = strtoupper($value);
+ }
+ $this->allowedMethods = $allowedMethods;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isEnabled()
+ {
+ return $this->enabled;
+ }
+
+ /**
+ * @param bool $enabled
+ */
+ public function setEnabled($enabled)
+ {
+ $this->enabled = (bool) $enabled;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\I18n;
+
+use Zend\I18n\Translator\TranslatorInterface as I18nTranslatorInterface;
+
+class DummyTranslator implements I18nTranslatorInterface
+{
+ public function translate($message, $textDomain = 'default', $locale = null)
+ {
+ return $message;
+ }
+
+ public function translatePlural($singular, $plural, $number, $textDomain = 'default', $locale = null)
+ {
+ return ($number == 1 ? $singular : $plural);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\I18n;
+
+use Zend\I18n\Translator\TranslatorInterface as I18nTranslatorInterface;
+use Zend\Mvc\Exception;
+use Zend\Validator\Translator\TranslatorInterface as ValidatorTranslatorInterface;
+
+class Translator implements
+ I18nTranslatorInterface,
+ ValidatorTranslatorInterface
+{
+ /**
+ * @var I18nTranslatorInterface
+ */
+ protected $translator;
+
+ /**
+ * @param I18nTranslatorInterface $translator
+ */
+ public function __construct(I18nTranslatorInterface $translator)
+ {
+ $this->translator = $translator;
+ }
+
+ /**
+ * Proxy unknown method calls to underlying translator instance
+ *
+ * Note: this method is only implemented to keep backwards compatibility
+ * with pre-2.3.0 code.
+ *
+ * @deprecated
+ * @param string $method
+ * @param array $args
+ * @return mixed
+ */
+ public function __call($method, array $args)
+ {
+ if (!method_exists($this->translator, $method)) {
+ throw new Exception\BadMethodCallException(sprintf(
+ 'Unable to call method "%s"; does not exist in translator',
+ $method
+ ));
+ }
+ return call_user_func_array([$this->translator, $method], $args);
+ }
+
+ /**
+ * @return I18nTranslatorInterface
+ */
+ public function getTranslator()
+ {
+ return $this->translator;
+ }
+
+ /**
+ * Translate a message using the given text domain and locale
+ *
+ * @param string $message
+ * @param string $textDomain
+ * @param string $locale
+ * @return string
+ */
+ public function translate($message, $textDomain = 'default', $locale = null)
+ {
+ return $this->translator->translate($message, $textDomain, $locale);
+ }
+
+ /**
+ * Provide a pluralized translation of the given string using the given text domain and locale
+ *
+ * @param string $singular
+ * @param string $plural
+ * @param string $number
+ * @param string $textDomain
+ * @param string $locale
+ * @return string
+ */
+ public function translatePlural($singular, $plural, $number, $textDomain = 'default', $locale = null)
+ {
+ return $this->translator->translatePlural($singular, $plural, $number, $textDomain, $locale);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc;
+
+use Zend\EventManager\EventInterface as Event;
+
+interface InjectApplicationEventInterface
+{
+ /**
+ * Compose an Event
+ *
+ * @param Event $event
+ * @return void
+ */
+ public function setEvent(Event $event);
+
+ /**
+ * Retrieve the composed event
+ *
+ * @return Event
+ */
+ public function getEvent();
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc;
+
+use Psr\Http\Message\ResponseInterface as PsrResponseInterface;
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+use Zend\Psr7Bridge\Psr7ServerRequest as Psr7Request;
+use Zend\Psr7Bridge\Psr7Response;
+
+class MiddlewareListener extends AbstractListenerAggregate
+{
+ /**
+ * Attach listeners to an event manager
+ *
+ * @param EventManagerInterface $events
+ * @return void
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'onDispatch'], 1);
+ }
+
+ /**
+ * Listen to the "dispatch" event
+ *
+ * @param MvcEvent $event
+ * @return mixed
+ */
+ public function onDispatch(MvcEvent $event)
+ {
+ $routeMatch = $event->getRouteMatch();
+ $middleware = $routeMatch->getParam('middleware', false);
+ if (false === $middleware) {
+ return;
+ }
+
+ $request = $event->getRequest();
+ $application = $event->getApplication();
+ $response = $application->getResponse();
+ $serviceManager = $application->getServiceManager();
+ $middlewareName = is_string($middleware) ? $middleware : get_class($middleware);
+
+ if (is_string($middleware) && $serviceManager->has($middleware)) {
+ $middleware = $serviceManager->get($middleware);
+ }
+ if (! is_callable($middleware)) {
+ $return = $this->marshalMiddlewareNotCallable($application::ERROR_MIDDLEWARE_CANNOT_DISPATCH, $middlewareName, $event, $application);
+ $event->setResult($return);
+ return $return;
+ }
+
+ $caughtException = null;
+ try {
+ $return = $middleware(Psr7Request::fromZend($request), Psr7Response::fromZend($response));
+ } catch (\Throwable $ex) {
+ $caughtException = $ex;
+ } catch (\Exception $ex) { // @TODO clean up once PHP 7 requirement is enforced
+ $caughtException = $ex;
+ }
+
+ if ($caughtException !== null) {
+ $event->setName(MvcEvent::EVENT_DISPATCH_ERROR);
+ $event->setError($application::ERROR_EXCEPTION);
+ $event->setController($middlewareName);
+ $event->setControllerClass(get_class($middleware));
+ $event->setParam('exception', $caughtException);
+
+ $events = $application->getEventManager();
+ $results = $events->triggerEvent($event);
+ $return = $results->last();
+ if (! $return) {
+ $return = $event->getResult();
+ }
+ }
+
+ if (! $return instanceof PsrResponseInterface) {
+ $event->setResult($return);
+ return $return;
+ }
+ $response = Psr7Response::toZend($return);
+ $event->setResult($response);
+ return $response;
+ }
+
+ /**
+ * Marshal a middleware not callable exception event
+ *
+ * @param string $type
+ * @param string $middlewareName
+ * @param MvcEvent $event
+ * @param Application $application
+ * @param \Exception $exception
+ * @return mixed
+ */
+ protected function marshalMiddlewareNotCallable(
+ $type,
+ $middlewareName,
+ MvcEvent $event,
+ Application $application,
+ \Exception $exception = null
+ ) {
+ $event->setName(MvcEvent::EVENT_DISPATCH_ERROR);
+ $event->setError($type);
+ $event->setController($middlewareName);
+ $event->setControllerClass('Middleware not callable: ' . $middlewareName);
+ if ($exception !== null) {
+ $event->setParam('exception', $exception);
+ }
+
+ $events = $application->getEventManager();
+ $results = $events->triggerEvent($event);
+ $return = $results->last();
+ if (! $return) {
+ $return = $event->getResult();
+ }
+ return $return;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc;
+
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+
+class ModuleRouteListener extends AbstractListenerAggregate
+{
+ const MODULE_NAMESPACE = '__NAMESPACE__';
+ const ORIGINAL_CONTROLLER = '__CONTROLLER__';
+
+ /**
+ * Attach to an event manager
+ *
+ * @param EventManagerInterface $events
+ * @param int $priority
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_ROUTE, [$this, 'onRoute'], $priority);
+ }
+
+ /**
+ * Listen to the "route" event and determine if the module namespace should
+ * be prepended to the controller name.
+ *
+ * If the route match contains a parameter key matching the MODULE_NAMESPACE
+ * constant, that value will be prepended, with a namespace separator, to
+ * the matched controller parameter.
+ *
+ * @param MvcEvent $e
+ * @return null
+ */
+ public function onRoute(MvcEvent $e)
+ {
+ $matches = $e->getRouteMatch();
+ if (!$matches instanceof Router\RouteMatch) {
+ // Can't do anything without a route match
+ return;
+ }
+
+ $module = $matches->getParam(self::MODULE_NAMESPACE, false);
+ if (!$module) {
+ // No module namespace found; nothing to do
+ return;
+ }
+
+ $controller = $matches->getParam('controller', false);
+ if (!$controller) {
+ // no controller matched, nothing to do
+ return;
+ }
+
+ // Ensure the module namespace has not already been applied
+ if (0 === strpos($controller, $module)) {
+ return;
+ }
+
+ // Keep the originally matched controller name around
+ $matches->setParam(self::ORIGINAL_CONTROLLER, $controller);
+
+ // Prepend the controllername with the module, and replace it in the
+ // matches
+ $controller = $module . '\\' . str_replace(' ', '', ucwords(str_replace('-', ' ', $controller)));
+ $matches->setParam('controller', $controller);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc;
+
+use Zend\EventManager\Event;
+use Zend\Stdlib\RequestInterface as Request;
+use Zend\Stdlib\ResponseInterface as Response;
+use Zend\View\Model\ModelInterface as Model;
+use Zend\View\Model\ViewModel;
+
+class MvcEvent extends Event
+{
+ /**#@+
+ * Mvc events triggered by eventmanager
+ */
+ const EVENT_BOOTSTRAP = 'bootstrap';
+ const EVENT_DISPATCH = 'dispatch';
+ const EVENT_DISPATCH_ERROR = 'dispatch.error';
+ const EVENT_FINISH = 'finish';
+ const EVENT_RENDER = 'render';
+ const EVENT_RENDER_ERROR = 'render.error';
+ const EVENT_ROUTE = 'route';
+ /**#@-*/
+
+ protected $application;
+
+ /**
+ * @var Request
+ */
+ protected $request;
+
+ /**
+ * @var Response
+ */
+ protected $response;
+
+ /**
+ * @var mixed
+ */
+ protected $result;
+
+ /**
+ * @var Router\RouteStackInterface
+ */
+ protected $router;
+
+ /**
+ * @var null|Router\RouteMatch
+ */
+ protected $routeMatch;
+
+ /**
+ * @var Model
+ */
+ protected $viewModel;
+
+ /**
+ * Set application instance
+ *
+ * @param ApplicationInterface $application
+ * @return MvcEvent
+ */
+ public function setApplication(ApplicationInterface $application)
+ {
+ $this->setParam('application', $application);
+ $this->application = $application;
+ return $this;
+ }
+
+ /**
+ * Get application instance
+ *
+ * @return ApplicationInterface
+ */
+ public function getApplication()
+ {
+ return $this->application;
+ }
+
+ /**
+ * Get router
+ *
+ * @return Router\RouteStackInterface
+ */
+ public function getRouter()
+ {
+ return $this->router;
+ }
+
+ /**
+ * Set router
+ *
+ * @param Router\RouteStackInterface $router
+ * @return MvcEvent
+ */
+ public function setRouter(Router\RouteStackInterface $router)
+ {
+ $this->setParam('router', $router);
+ $this->router = $router;
+ return $this;
+ }
+
+ /**
+ * Get route match
+ *
+ * @return null|Router\RouteMatch
+ */
+ public function getRouteMatch()
+ {
+ return $this->routeMatch;
+ }
+
+ /**
+ * Set route match
+ *
+ * @param Router\RouteMatch $matches
+ * @return MvcEvent
+ */
+ public function setRouteMatch(Router\RouteMatch $matches)
+ {
+ $this->setParam('route-match', $matches);
+ $this->routeMatch = $matches;
+ return $this;
+ }
+
+ /**
+ * Get request
+ *
+ * @return Request
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * Set request
+ *
+ * @param Request $request
+ * @return MvcEvent
+ */
+ public function setRequest(Request $request)
+ {
+ $this->setParam('request', $request);
+ $this->request = $request;
+ return $this;
+ }
+
+ /**
+ * Get response
+ *
+ * @return Response
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ /**
+ * Set response
+ *
+ * @param Response $response
+ * @return MvcEvent
+ */
+ public function setResponse(Response $response)
+ {
+ $this->setParam('response', $response);
+ $this->response = $response;
+ return $this;
+ }
+
+ /**
+ * Set the view model
+ *
+ * @param Model $viewModel
+ * @return MvcEvent
+ */
+ public function setViewModel(Model $viewModel)
+ {
+ $this->viewModel = $viewModel;
+ return $this;
+ }
+
+ /**
+ * Get the view model
+ *
+ * @return Model
+ */
+ public function getViewModel()
+ {
+ if (null === $this->viewModel) {
+ $this->setViewModel(new ViewModel());
+ }
+ return $this->viewModel;
+ }
+
+ /**
+ * Get result
+ *
+ * @return mixed
+ */
+ public function getResult()
+ {
+ return $this->result;
+ }
+
+ /**
+ * Set result
+ *
+ * @param mixed $result
+ * @return MvcEvent
+ */
+ public function setResult($result)
+ {
+ $this->setParam('__RESULT__', $result);
+ $this->result = $result;
+ return $this;
+ }
+
+ /**
+ * Does the event represent an error response?
+ *
+ * @return bool
+ */
+ public function isError()
+ {
+ return (bool) $this->getParam('error', false);
+ }
+
+ /**
+ * Set the error message (indicating error in handling request)
+ *
+ * @param string $message
+ * @return MvcEvent
+ */
+ public function setError($message)
+ {
+ $this->setParam('error', $message);
+ return $this;
+ }
+
+ /**
+ * Retrieve the error message, if any
+ *
+ * @return string
+ */
+ public function getError()
+ {
+ return $this->getParam('error', '');
+ }
+
+ /**
+ * Get the currently registered controller name
+ *
+ * @return string
+ */
+ public function getController()
+ {
+ return $this->getParam('controller');
+ }
+
+ /**
+ * Set controller name
+ *
+ * @param string $name
+ * @return MvcEvent
+ */
+ public function setController($name)
+ {
+ $this->setParam('controller', $name);
+ return $this;
+ }
+
+ /**
+ * Get controller class
+ *
+ * @return string
+ */
+ public function getControllerClass()
+ {
+ return $this->getParam('controller-class');
+ }
+
+ /**
+ * Set controller class
+ *
+ * @param string $class
+ * @return MvcEvent
+ */
+ public function setControllerClass($class)
+ {
+ $this->setParam('controller-class', $class);
+ return $this;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\ResponseSender;
+
+use Zend\Http\Header\MultipleHeaderInterface;
+
+abstract class AbstractResponseSender implements ResponseSenderInterface
+{
+ /**
+ * Send HTTP headers
+ *
+ * @param SendResponseEvent $event
+ * @return self
+ */
+ public function sendHeaders(SendResponseEvent $event)
+ {
+ if (headers_sent() || $event->headersSent()) {
+ return $this;
+ }
+
+ $response = $event->getResponse();
+
+ foreach ($response->getHeaders() as $header) {
+ if ($header instanceof MultipleHeaderInterface) {
+ header($header->toString(), false);
+ continue;
+ }
+ header($header->toString());
+ }
+
+ $status = $response->renderStatusLine();
+ header($status);
+
+ $event->setHeadersSent();
+ return $this;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\ResponseSender;
+
+use Zend\Console\Response;
+
+class ConsoleResponseSender implements ResponseSenderInterface
+{
+ /**
+ * Send content
+ *
+ * @param SendResponseEvent $event
+ * @return ConsoleResponseSender
+ */
+ public function sendContent(SendResponseEvent $event)
+ {
+ if ($event->contentSent()) {
+ return $this;
+ }
+ $response = $event->getResponse();
+ echo $response->getContent();
+ $event->setContentSent();
+ return $this;
+ }
+
+ /**
+ * Send the response
+ *
+ * @param SendResponseEvent $event
+ */
+ public function __invoke(SendResponseEvent $event)
+ {
+ $response = $event->getResponse();
+ if (!$response instanceof Response) {
+ return;
+ }
+
+ $this->sendContent($event);
+ $errorLevel = (int) $response->getMetadata('errorLevel', 0);
+ $event->stopPropagation(true);
+ exit($errorLevel);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\ResponseSender;
+
+use Zend\Http\Response;
+
+class HttpResponseSender extends AbstractResponseSender
+{
+ /**
+ * Send content
+ *
+ * @param SendResponseEvent $event
+ * @return HttpResponseSender
+ */
+ public function sendContent(SendResponseEvent $event)
+ {
+ if ($event->contentSent()) {
+ return $this;
+ }
+ $response = $event->getResponse();
+ echo $response->getContent();
+ $event->setContentSent();
+ return $this;
+ }
+
+ /**
+ * Send HTTP response
+ *
+ * @param SendResponseEvent $event
+ * @return HttpResponseSender
+ */
+ public function __invoke(SendResponseEvent $event)
+ {
+ $response = $event->getResponse();
+ if (!$response instanceof Response) {
+ return $this;
+ }
+
+ $this->sendHeaders($event)
+ ->sendContent($event);
+ $event->stopPropagation(true);
+ return $this;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\ResponseSender;
+
+use Zend\Http\PhpEnvironment\Response;
+
+class PhpEnvironmentResponseSender extends HttpResponseSender
+{
+ /**
+ * Send php environment response
+ *
+ * @param SendResponseEvent $event
+ * @return PhpEnvironmentResponseSender
+ */
+ public function __invoke(SendResponseEvent $event)
+ {
+ $response = $event->getResponse();
+ if (!$response instanceof Response) {
+ return $this;
+ }
+
+ $this->sendHeaders($event)
+ ->sendContent($event);
+ $event->stopPropagation(true);
+ return $this;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\ResponseSender;
+
+interface ResponseSenderInterface
+{
+ /**
+ * Send the response
+ *
+ * @param SendResponseEvent $event
+ * @return void
+ */
+ public function __invoke(SendResponseEvent $event);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\ResponseSender;
+
+use Zend\EventManager\Event;
+use Zend\Stdlib\ResponseInterface;
+
+class SendResponseEvent extends Event
+{
+ /**#@+
+ * Send response events triggered by eventmanager
+ */
+ const EVENT_SEND_RESPONSE = 'sendResponse';
+ /**#@-*/
+
+ /**
+ * @var string Event name
+ */
+ protected $name = 'sendResponse';
+
+ /**
+ * @var ResponseInterface
+ */
+ protected $response;
+
+ /**
+ * @var array
+ */
+ protected $headersSent = [];
+
+ /**
+ * @var array
+ */
+ protected $contentSent = [];
+
+ /**
+ * @param ResponseInterface $response
+ * @return SendResponseEvent
+ */
+ public function setResponse(ResponseInterface $response)
+ {
+ $this->setParam('response', $response);
+ $this->response = $response;
+ return $this;
+ }
+
+ /**
+ * @return \Zend\Stdlib\ResponseInterface
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ /**
+ * Set content sent for current response
+ *
+ * @return SendResponseEvent
+ */
+ public function setContentSent()
+ {
+ $response = $this->getResponse();
+ $contentSent = $this->getParam('contentSent', []);
+ $contentSent[spl_object_hash($response)] = true;
+ $this->setParam('contentSent', $contentSent);
+ $this->contentSent[spl_object_hash($response)] = true;
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function contentSent()
+ {
+ $response = $this->getResponse();
+ if (isset($this->contentSent[spl_object_hash($response)])) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Set headers sent for current response object
+ *
+ * @return SendResponseEvent
+ */
+ public function setHeadersSent()
+ {
+ $response = $this->getResponse();
+ $headersSent = $this->getParam('headersSent', []);
+ $headersSent[spl_object_hash($response)] = true;
+ $this->setParam('headersSent', $headersSent);
+ $this->headersSent[spl_object_hash($response)] = true;
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function headersSent()
+ {
+ $response = $this->getResponse();
+ if (isset($this->headersSent[spl_object_hash($response)])) {
+ return true;
+ }
+ return false;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\ResponseSender;
+
+use Zend\Http\Response\Stream;
+
+class SimpleStreamResponseSender extends AbstractResponseSender
+{
+ /**
+ * Send the stream
+ *
+ * @param SendResponseEvent $event
+ * @return SimpleStreamResponseSender
+ */
+ public function sendStream(SendResponseEvent $event)
+ {
+ if ($event->contentSent()) {
+ return $this;
+ }
+ $response = $event->getResponse();
+ $stream = $response->getStream();
+ fpassthru($stream);
+ $event->setContentSent();
+ }
+
+ /**
+ * Send stream response
+ *
+ * @param SendResponseEvent $event
+ * @return SimpleStreamResponseSender
+ */
+ public function __invoke(SendResponseEvent $event)
+ {
+ $response = $event->getResponse();
+ if (!$response instanceof Stream) {
+ return $this;
+ }
+
+ $this->sendHeaders($event);
+ $this->sendStream($event);
+ $event->stopPropagation(true);
+ return $this;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc;
+
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+
+class RouteListener extends AbstractListenerAggregate
+{
+ /**
+ * Attach to an event manager
+ *
+ * @param EventManagerInterface $events
+ * @param int $priority
+ * @return void
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_ROUTE, [$this, 'onRoute']);
+ }
+
+ /**
+ * Listen to the "route" event and attempt to route the request
+ *
+ * If no matches are returned, triggers "dispatch.error" in order to
+ * create a 404 response.
+ *
+ * Seeds the event with the route match on completion.
+ *
+ * @param MvcEvent $e
+ * @return null|Router\RouteMatch
+ */
+ public function onRoute($e)
+ {
+ $target = $e->getTarget();
+ $request = $e->getRequest();
+ $router = $e->getRouter();
+ $routeMatch = $router->match($request);
+
+ if (!$routeMatch instanceof Router\RouteMatch) {
+ $e->setName(MvcEvent::EVENT_DISPATCH_ERROR);
+ $e->setError(Application::ERROR_ROUTER_NO_MATCH);
+
+ $results = $target->getEventManager()->triggerEvent($e);
+ if (count($results)) {
+ return $results->last();
+ }
+
+ return $e->getParams();
+ }
+
+ $e->setRouteMatch($routeMatch);
+ return $routeMatch;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+/**
+ * @namespace
+ */
+namespace Zend\Mvc\Router\Console;
+
+use Traversable;
+use Zend\Console\Request as ConsoleRequest;
+use Zend\Filter\FilterChain;
+use Zend\Stdlib\RequestInterface as Request;
+use Zend\Validator\ValidatorChain;
+
+/**
+ * Segment route.
+ *
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @see http://guides.rubyonrails.org/routing.html
+ */
+class Catchall implements RouteInterface
+{
+ /**
+ * Parts of the route.
+ *
+ * @var array
+ */
+ protected $parts;
+
+ /**
+ * Default values.
+ *
+ * @var array
+ */
+ protected $defaults;
+
+ /**
+ * Parameters' name aliases.
+ *
+ * @var array
+ */
+ protected $aliases;
+
+ /**
+ * List of assembled parameters.
+ *
+ * @var array
+ */
+ protected $assembledParams = [];
+
+ /**
+ * @var ValidatorChain
+ */
+ protected $validators;
+
+ /**
+ * @var FilterChain
+ */
+ protected $filters;
+
+ /**
+ * Create a new simple console route.
+ *
+ * @param array $defaults
+ * @return Catchall
+ */
+ public function __construct(array $defaults = [])
+ {
+ $this->defaults = $defaults;
+ }
+
+ /**
+ * factory(): defined by Route interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param array|Traversable $options
+ * @return Simple
+ */
+ public static function factory($options = [])
+ {
+ return new static(isset($options['defaults']) ? $options['defaults'] : []);
+ }
+
+ /**
+ * match(): defined by Route interface.
+ *
+ * @see Route::match()
+ * @param Request $request
+ * @return RouteMatch
+ */
+ public function match(Request $request)
+ {
+ if (!$request instanceof ConsoleRequest) {
+ return;
+ }
+
+ return new RouteMatch($this->defaults);
+ }
+
+ /**
+ * assemble(): Defined by Route interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ $this->assembledParams = [];
+ }
+
+ /**
+ * getAssembledParams(): defined by Route interface.
+ *
+ * @see RouteInterface::getAssembledParams
+ * @return array
+ */
+ public function getAssembledParams()
+ {
+ return $this->assembledParams;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+/**
+ * @namespace
+ */
+namespace Zend\Mvc\Router\Console;
+
+use Zend\Mvc\Router\RouteInterface as BaseRoute;
+
+/**
+ * Tree specific route interface.
+ *
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+interface RouteInterface extends BaseRoute
+{
+ /**
+ * Get a list of parameters used while assembling.
+ *
+ * @return array
+ */
+ public function getAssembledParams();
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+/**
+ * @namespace
+ */
+namespace Zend\Mvc\Router\Console;
+
+use Zend\Mvc\Router\RouteMatch as BaseRouteMatch;
+
+/**
+ * Part route match.
+ *
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class RouteMatch extends BaseRouteMatch
+{
+ /**
+ * Length of the matched path.
+ *
+ * @var int
+ */
+ protected $length;
+
+ /**
+ * Create a part RouteMatch with given parameters and length.
+ *
+ * @param array $params
+ * @param int $length
+ */
+ public function __construct(array $params, $length = 0)
+ {
+ parent::__construct($params);
+
+ $this->length = $length;
+ }
+
+ /**
+ * setMatchedRouteName(): defined by BaseRouteMatch.
+ *
+ * @see BaseRouteMatch::setMatchedRouteName()
+ * @param string $name
+ * @return self
+ */
+ public function setMatchedRouteName($name)
+ {
+ if ($this->matchedRouteName === null) {
+ $this->matchedRouteName = $name;
+ } else {
+ $this->matchedRouteName = $name . '/' . $this->matchedRouteName;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Merge parameters from another match.
+ *
+ * @param RouteMatch $match
+ * @return RouteMatch
+ */
+ public function merge(RouteMatch $match)
+ {
+ $this->params = array_merge($this->params, $match->getParams());
+ $this->length += $match->getLength();
+
+ $this->matchedRouteName = $match->getMatchedRouteName();
+
+ return $this;
+ }
+
+ /**
+ * Get the matched path length.
+ *
+ * @return int
+ */
+ public function getLength()
+ {
+ return $this->length;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+/**
+ * @namespace
+ */
+namespace Zend\Mvc\Router\Console;
+
+use Traversable;
+use Zend\Console\RouteMatcher\DefaultRouteMatcher;
+use Zend\Console\Request as ConsoleRequest;
+use Zend\Console\RouteMatcher\RouteMatcherInterface;
+use Zend\Filter\FilterChain;
+use Zend\Mvc\Router\Exception;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+use Zend\Validator\ValidatorChain;
+
+/**
+ * Segment route.
+ *
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @see http://guides.rubyonrails.org/routing.html
+ */
+class Simple implements RouteInterface
+{
+ /**
+ * List of assembled parameters.
+ *
+ * @var array
+ */
+ protected $assembledParams = [];
+
+ /**
+ * @var RouteMatcherInterface
+ */
+ protected $matcher;
+
+ /**
+ * Create a new simple console route.
+ *
+ * @param string|RouteMatcherInterface $routeOrRouteMatcher
+ * @param array $constraints
+ * @param array $defaults
+ * @param array $aliases
+ * @param null|array|Traversable|FilterChain $filters
+ * @param null|array|Traversable|ValidatorChain $validators
+ * @throws Exception\InvalidArgumentException
+ */
+ public function __construct(
+ $routeOrRouteMatcher,
+ array $constraints = [],
+ array $defaults = [],
+ array $aliases = [],
+ $filters = null,
+ $validators = null
+ ) {
+ if (is_string($routeOrRouteMatcher)) {
+ $this->matcher = new DefaultRouteMatcher($routeOrRouteMatcher, $constraints, $defaults, $aliases);
+ } elseif ($routeOrRouteMatcher instanceof RouteMatcherInterface) {
+ $this->matcher = $routeOrRouteMatcher;
+ } else {
+ throw new Exception\InvalidArgumentException(
+ "routeOrRouteMatcher should either be string, or class implementing RouteMatcherInterface. "
+ . gettype($routeOrRouteMatcher) . " was given."
+ );
+ }
+ }
+
+ /**
+ * factory(): defined by Route interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param array|Traversable $options
+ * @throws Exception\InvalidArgumentException
+ * @return self
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ } elseif (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
+ }
+
+ if (!isset($options['route'])) {
+ throw new Exception\InvalidArgumentException('Missing "route" in options array');
+ }
+
+ foreach ([
+ 'constraints',
+ 'defaults',
+ 'aliases',
+ ] as $opt) {
+ if (!isset($options[$opt])) {
+ $options[$opt] = [];
+ }
+ }
+
+ if (!isset($options['validators'])) {
+ $options['validators'] = null;
+ }
+
+ if (!isset($options['filters'])) {
+ $options['filters'] = null;
+ }
+
+ return new static(
+ $options['route'],
+ $options['constraints'],
+ $options['defaults'],
+ $options['aliases'],
+ $options['filters'],
+ $options['validators']
+ );
+ }
+
+ /**
+ * match(): defined by Route interface.
+ *
+ * @see Route::match()
+ * @param Request $request
+ * @param null|int $pathOffset
+ * @return RouteMatch
+ */
+ public function match(Request $request, $pathOffset = null)
+ {
+ if (!$request instanceof ConsoleRequest) {
+ return;
+ }
+
+ $params = $request->getParams()->toArray();
+ $matches = $this->matcher->match($params);
+
+ if (null !== $matches) {
+ return new RouteMatch($matches);
+ }
+ return;
+ }
+
+ /**
+ * assemble(): Defined by Route interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ $this->assembledParams = [];
+ }
+
+ /**
+ * getAssembledParams(): defined by Route interface.
+ *
+ * @see RouteInterface::getAssembledParams
+ * @return array
+ */
+ public function getAssembledParams()
+ {
+ return $this->assembledParams;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Console;
+
+use Traversable;
+use Zend\Mvc\Router\Exception;
+use Zend\Mvc\Router\RouteInvokableFactory;
+use Zend\Mvc\Router\SimpleRouteStack as BaseSimpleRouteStack;
+use Zend\ServiceManager\Config;
+use Zend\Stdlib\ArrayUtils;
+
+/**
+ * Tree search implementation.
+ */
+class SimpleRouteStack extends BaseSimpleRouteStack
+{
+ /**
+ * init(): defined by SimpleRouteStack.
+ *
+ * @see BaseSimpleRouteStack::init()
+ */
+ protected function init()
+ {
+ (new Config([
+ 'aliases' => [
+ 'catchall' => Catchall::class,
+ 'catchAll' => Catchall::class,
+ 'Catchall' => Catchall::class,
+ 'CatchAll' => Catchall::class,
+ 'simple' => Simple::class,
+ 'Simple' => Simple::class,
+ ],
+ 'factories' => [
+ Catchall::class => RouteInvokableFactory::class,
+ Simple::class => RouteInvokableFactory::class,
+
+ // v2 normalized names
+ 'zendmvcrouterconsolecatchall' => RouteInvokableFactory::class,
+ 'zendmvcrouterconsolesimple' => RouteInvokableFactory::class,
+ ],
+ ]))->configureServiceManager($this->routePluginManager);
+ }
+
+ /**
+ * addRoute(): defined by RouteStackInterface interface.
+ *
+ * @see RouteStackInterface::addRoute()
+ * @param string $name
+ * @param mixed $route
+ * @param int $priority
+ * @return SimpleRouteStack
+ */
+ public function addRoute($name, $route, $priority = null)
+ {
+ if (!$route instanceof RouteInterface) {
+ $route = $this->routeFromArray($route);
+ }
+
+ return parent::addRoute($name, $route, $priority);
+ }
+
+ /**
+ * routeFromArray(): defined by SimpleRouteStack.
+ *
+ * @see BaseSimpleRouteStack::routeFromArray()
+ * @param array|Traversable $specs
+ * @return RouteInterface
+ * @throws Exception\InvalidArgumentException
+ * @throws Exception\RuntimeException
+ */
+ protected function routeFromArray($specs)
+ {
+ if ($specs instanceof Traversable) {
+ $specs = ArrayUtils::iteratorToArray($specs);
+ }
+
+ if (! is_array($specs)) {
+ throw new Exception\InvalidArgumentException('Route definition must be an array or Traversable object');
+ }
+
+ // default to 'simple' console route
+ if (! isset($specs['type'])) {
+ $specs['type'] = Simple::class;
+ }
+
+ // build route object
+ $route = parent::routeFromArray($specs);
+
+ if (! $route instanceof RouteInterface) {
+ throw new Exception\RuntimeException('Given route does not implement Console route interface');
+ }
+
+ return $route;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Exception;
+
+use Zend\Mvc\Exception\ExceptionInterface as Exception;
+
+interface ExceptionInterface extends Exception
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Exception;
+
+use Zend\Mvc\Exception;
+
+class InvalidArgumentException extends Exception\InvalidArgumentException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Exception;
+
+use Zend\Mvc\Exception;
+
+class RuntimeException extends Exception\RuntimeException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use ArrayObject;
+use Traversable;
+use Zend\Mvc\Router\Exception;
+use Zend\Mvc\Router\PriorityList;
+use Zend\Mvc\Router\RoutePluginManager;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * Chain route.
+ */
+class Chain extends TreeRouteStack implements RouteInterface
+{
+ /**
+ * Chain routes.
+ *
+ * @var array
+ */
+ protected $chainRoutes;
+
+ /**
+ * List of assembled parameters.
+ *
+ * @var array
+ */
+ protected $assembledParams = [];
+
+ /**
+ * Create a new part route.
+ *
+ * @param array $routes
+ * @param RoutePluginManager $routePlugins
+ * @param ArrayObject|null $prototypes
+ */
+ public function __construct(array $routes, RoutePluginManager $routePlugins, ArrayObject $prototypes = null)
+ {
+ $this->chainRoutes = array_reverse($routes);
+ $this->routePluginManager = $routePlugins;
+ $this->routes = new PriorityList();
+ $this->prototypes = $prototypes;
+ }
+
+ /**
+ * factory(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param mixed $options
+ * @throws Exception\InvalidArgumentException
+ * @return Part
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ } elseif (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
+ }
+
+ if (!isset($options['routes'])) {
+ throw new Exception\InvalidArgumentException('Missing "routes" in options array');
+ }
+
+ if (!isset($options['prototypes'])) {
+ $options['prototypes'] = null;
+ }
+
+ if ($options['routes'] instanceof Traversable) {
+ $options['routes'] = ArrayUtils::iteratorToArray($options['child_routes']);
+ }
+
+ if (!isset($options['route_plugins'])) {
+ throw new Exception\InvalidArgumentException('Missing "route_plugins" in options array');
+ }
+
+ return new static(
+ $options['routes'],
+ $options['route_plugins'],
+ $options['prototypes']
+ );
+ }
+
+ /**
+ * match(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::match()
+ * @param Request $request
+ * @param int|null $pathOffset
+ * @param array $options
+ * @return RouteMatch|null
+ */
+ public function match(Request $request, $pathOffset = null, array $options = [])
+ {
+ if (!method_exists($request, 'getUri')) {
+ return;
+ }
+
+ if ($pathOffset === null) {
+ $mustTerminate = true;
+ $pathOffset = 0;
+ } else {
+ $mustTerminate = false;
+ }
+
+ if ($this->chainRoutes !== null) {
+ $this->addRoutes($this->chainRoutes);
+ $this->chainRoutes = null;
+ }
+
+ $match = new RouteMatch([]);
+ $uri = $request->getUri();
+ $pathLength = strlen($uri->getPath());
+
+ foreach ($this->routes as $route) {
+ $subMatch = $route->match($request, $pathOffset, $options);
+
+ if ($subMatch === null) {
+ return;
+ }
+
+ $match->merge($subMatch);
+ $pathOffset += $subMatch->getLength();
+ }
+
+ if ($mustTerminate && $pathOffset !== $pathLength) {
+ return;
+ }
+
+ return $match;
+ }
+
+ /**
+ * assemble(): Defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ if ($this->chainRoutes !== null) {
+ $this->addRoutes($this->chainRoutes);
+ $this->chainRoutes = null;
+ }
+
+ $this->assembledParams = [];
+
+ $routes = ArrayUtils::iteratorToArray($this->routes);
+
+ end($routes);
+ $lastRouteKey = key($routes);
+ $path = '';
+
+ foreach ($routes as $key => $route) {
+ $chainOptions = $options;
+ $hasChild = isset($options['has_child']) ? $options['has_child'] : false;
+
+ $chainOptions['has_child'] = ($hasChild || $key !== $lastRouteKey);
+
+ $path .= $route->assemble($params, $chainOptions);
+ $params = array_diff_key($params, array_flip($route->getAssembledParams()));
+
+ $this->assembledParams += $route->getAssembledParams();
+ }
+
+ return $path;
+ }
+
+ /**
+ * getAssembledParams(): defined by RouteInterface interface.
+ *
+ * @see RouteInterface::getAssembledParams
+ * @return array
+ */
+ public function getAssembledParams()
+ {
+ return $this->assembledParams;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use Traversable;
+use Zend\Mvc\Router\Exception;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * Hostname route.
+ */
+class Hostname implements RouteInterface
+{
+ /**
+ * Parts of the route.
+ *
+ * @var array
+ */
+ protected $parts;
+
+ /**
+ * Regex used for matching the route.
+ *
+ * @var string
+ */
+ protected $regex;
+
+ /**
+ * Map from regex groups to parameter names.
+ *
+ * @var array
+ */
+ protected $paramMap = [];
+
+ /**
+ * Default values.
+ *
+ * @var array
+ */
+ protected $defaults;
+
+ /**
+ * List of assembled parameters.
+ *
+ * @var array
+ */
+ protected $assembledParams = [];
+
+ /**
+ * Create a new hostname route.
+ *
+ * @param string $route
+ * @param array $constraints
+ * @param array $defaults
+ */
+ public function __construct($route, array $constraints = [], array $defaults = [])
+ {
+ $this->defaults = $defaults;
+ $this->parts = $this->parseRouteDefinition($route);
+ $this->regex = $this->buildRegex($this->parts, $constraints);
+ }
+
+ /**
+ * factory(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param array|Traversable $options
+ * @return Hostname
+ * @throws Exception\InvalidArgumentException
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ } elseif (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
+ }
+
+ if (!isset($options['route'])) {
+ throw new Exception\InvalidArgumentException('Missing "route" in options array');
+ }
+
+ if (!isset($options['constraints'])) {
+ $options['constraints'] = [];
+ }
+
+ if (!isset($options['defaults'])) {
+ $options['defaults'] = [];
+ }
+
+ return new static($options['route'], $options['constraints'], $options['defaults']);
+ }
+
+ /**
+ * Parse a route definition.
+ *
+ * @param string $def
+ * @return array
+ * @throws Exception\RuntimeException
+ */
+ protected function parseRouteDefinition($def)
+ {
+ $currentPos = 0;
+ $length = strlen($def);
+ $parts = [];
+ $levelParts = [&$parts];
+ $level = 0;
+
+ while ($currentPos < $length) {
+ if (!preg_match('(\G(?P<literal>[a-z0-9-.]*)(?P<token>[:{\[\]]|$))', $def, $matches, 0, $currentPos)) {
+ throw new Exception\RuntimeException('Matched hostname literal contains a disallowed character');
+ }
+
+ $currentPos += strlen($matches[0]);
+
+ if (!empty($matches['literal'])) {
+ $levelParts[$level][] = ['literal', $matches['literal']];
+ }
+
+ if ($matches['token'] === ':') {
+ if (!preg_match('(\G(?P<name>[^:.{\[\]]+)(?:{(?P<delimiters>[^}]+)})?:?)', $def, $matches, 0, $currentPos)) {
+ throw new Exception\RuntimeException('Found empty parameter name');
+ }
+
+ $levelParts[$level][] = ['parameter', $matches['name'], isset($matches['delimiters']) ? $matches['delimiters'] : null];
+
+ $currentPos += strlen($matches[0]);
+ } elseif ($matches['token'] === '[') {
+ $levelParts[$level][] = ['optional', []];
+ $levelParts[$level + 1] = &$levelParts[$level][count($levelParts[$level]) - 1][1];
+
+ $level++;
+ } elseif ($matches['token'] === ']') {
+ unset($levelParts[$level]);
+ $level--;
+
+ if ($level < 0) {
+ throw new Exception\RuntimeException('Found closing bracket without matching opening bracket');
+ }
+ } else {
+ break;
+ }
+ }
+
+ if ($level > 0) {
+ throw new Exception\RuntimeException('Found unbalanced brackets');
+ }
+
+ return $parts;
+ }
+
+ /**
+ * Build the matching regex from parsed parts.
+ *
+ * @param array $parts
+ * @param array $constraints
+ * @param int $groupIndex
+ * @return string
+ * @throws Exception\RuntimeException
+ */
+ protected function buildRegex(array $parts, array $constraints, &$groupIndex = 1)
+ {
+ $regex = '';
+
+ foreach ($parts as $part) {
+ switch ($part[0]) {
+ case 'literal':
+ $regex .= preg_quote($part[1]);
+ break;
+
+ case 'parameter':
+ $groupName = '?P<param' . $groupIndex . '>';
+
+ if (isset($constraints[$part[1]])) {
+ $regex .= '(' . $groupName . $constraints[$part[1]] . ')';
+ } elseif ($part[2] === null) {
+ $regex .= '(' . $groupName . '[^.]+)';
+ } else {
+ $regex .= '(' . $groupName . '[^' . $part[2] . ']+)';
+ }
+
+ $this->paramMap['param' . $groupIndex++] = $part[1];
+ break;
+
+ case 'optional':
+ $regex .= '(?:' . $this->buildRegex($part[1], $constraints, $groupIndex) . ')?';
+ break;
+ }
+ }
+
+ return $regex;
+ }
+
+ /**
+ * Build host.
+ *
+ * @param array $parts
+ * @param array $mergedParams
+ * @param bool $isOptional
+ * @return string
+ * @throws Exception\RuntimeException
+ * @throws Exception\InvalidArgumentException
+ */
+ protected function buildHost(array $parts, array $mergedParams, $isOptional)
+ {
+ $host = '';
+ $skip = true;
+ $skippable = false;
+
+ foreach ($parts as $part) {
+ switch ($part[0]) {
+ case 'literal':
+ $host .= $part[1];
+ break;
+
+ case 'parameter':
+ $skippable = true;
+
+ if (!isset($mergedParams[$part[1]])) {
+ if (!$isOptional) {
+ throw new Exception\InvalidArgumentException(sprintf('Missing parameter "%s"', $part[1]));
+ }
+
+ return '';
+ } elseif (!$isOptional || !isset($this->defaults[$part[1]]) || $this->defaults[$part[1]] !== $mergedParams[$part[1]]) {
+ $skip = false;
+ }
+
+ $host .= $mergedParams[$part[1]];
+
+ $this->assembledParams[] = $part[1];
+ break;
+
+ case 'optional':
+ $skippable = true;
+ $optionalPart = $this->buildHost($part[1], $mergedParams, true);
+
+ if ($optionalPart !== '') {
+ $host .= $optionalPart;
+ $skip = false;
+ }
+ break;
+ }
+ }
+
+ if ($isOptional && $skippable && $skip) {
+ return '';
+ }
+
+ return $host;
+ }
+
+ /**
+ * match(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::match()
+ * @param Request $request
+ * @return RouteMatch|null
+ */
+ public function match(Request $request)
+ {
+ if (!method_exists($request, 'getUri')) {
+ return;
+ }
+
+ $uri = $request->getUri();
+ $host = $uri->getHost();
+
+ $result = preg_match('(^' . $this->regex . '$)', $host, $matches);
+
+ if (!$result) {
+ return;
+ }
+
+ $params = [];
+
+ foreach ($this->paramMap as $index => $name) {
+ if (isset($matches[$index]) && $matches[$index] !== '') {
+ $params[$name] = $matches[$index];
+ }
+ }
+
+ return new RouteMatch(array_merge($this->defaults, $params));
+ }
+
+ /**
+ * assemble(): Defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ $this->assembledParams = [];
+
+ if (isset($options['uri'])) {
+ $host = $this->buildHost(
+ $this->parts,
+ array_merge($this->defaults, $params),
+ false
+ );
+
+ $options['uri']->setHost($host);
+ }
+
+ // A hostname does not contribute to the path, thus nothing is returned.
+ return '';
+ }
+
+ /**
+ * getAssembledParams(): defined by RouteInterface interface.
+ *
+ * @see RouteInterface::getAssembledParams
+ * @return array
+ */
+ public function getAssembledParams()
+ {
+ return $this->assembledParams;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use Traversable;
+use Zend\Mvc\Router\Exception;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * Literal route.
+ */
+class Literal implements RouteInterface
+{
+ /**
+ * RouteInterface to match.
+ *
+ * @var string
+ */
+ protected $route;
+
+ /**
+ * Default values.
+ *
+ * @var array
+ */
+ protected $defaults;
+
+ /**
+ * Create a new literal route.
+ *
+ * @param string $route
+ * @param array $defaults
+ */
+ public function __construct($route, array $defaults = [])
+ {
+ $this->route = $route;
+ $this->defaults = $defaults;
+ }
+
+ /**
+ * factory(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param array|Traversable $options
+ * @return Literal
+ * @throws Exception\InvalidArgumentException
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ } elseif (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
+ }
+
+ if (!isset($options['route'])) {
+ throw new Exception\InvalidArgumentException('Missing "route" in options array');
+ }
+
+ if (!isset($options['defaults'])) {
+ $options['defaults'] = [];
+ }
+
+ return new static($options['route'], $options['defaults']);
+ }
+
+ /**
+ * match(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::match()
+ * @param Request $request
+ * @param integer|null $pathOffset
+ * @return RouteMatch|null
+ */
+ public function match(Request $request, $pathOffset = null)
+ {
+ if (!method_exists($request, 'getUri')) {
+ return;
+ }
+
+ $uri = $request->getUri();
+ $path = $uri->getPath();
+
+ if ($pathOffset !== null) {
+ if ($pathOffset >= 0 && strlen($path) >= $pathOffset && !empty($this->route)) {
+ if (strpos($path, $this->route, $pathOffset) === $pathOffset) {
+ return new RouteMatch($this->defaults, strlen($this->route));
+ }
+ }
+
+ return;
+ }
+
+ if ($path === $this->route) {
+ return new RouteMatch($this->defaults, strlen($this->route));
+ }
+
+ return;
+ }
+
+ /**
+ * assemble(): Defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ return $this->route;
+ }
+
+ /**
+ * getAssembledParams(): defined by RouteInterface interface.
+ *
+ * @see RouteInterface::getAssembledParams
+ * @return array
+ */
+ public function getAssembledParams()
+ {
+ return [];
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use Traversable;
+use Zend\Mvc\Router\Exception;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * Method route.
+ */
+class Method implements RouteInterface
+{
+ /**
+ * Verb to match.
+ *
+ * @var string
+ */
+ protected $verb;
+
+ /**
+ * Default values.
+ *
+ * @var array
+ */
+ protected $defaults;
+
+ /**
+ * Create a new method route.
+ *
+ * @param string $verb
+ * @param array $defaults
+ */
+ public function __construct($verb, array $defaults = [])
+ {
+ $this->verb = $verb;
+ $this->defaults = $defaults;
+ }
+
+ /**
+ * factory(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param array|Traversable $options
+ * @return Method
+ * @throws Exception\InvalidArgumentException
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ } elseif (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
+ }
+
+ if (!isset($options['verb'])) {
+ throw new Exception\InvalidArgumentException('Missing "verb" in options array');
+ }
+
+ if (!isset($options['defaults'])) {
+ $options['defaults'] = [];
+ }
+
+ return new static($options['verb'], $options['defaults']);
+ }
+
+ /**
+ * match(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::match()
+ * @param Request $request
+ * @return RouteMatch|null
+ */
+ public function match(Request $request)
+ {
+ if (!method_exists($request, 'getMethod')) {
+ return;
+ }
+
+ $requestVerb = strtoupper($request->getMethod());
+ $matchVerbs = explode(',', strtoupper($this->verb));
+ $matchVerbs = array_map('trim', $matchVerbs);
+
+ if (in_array($requestVerb, $matchVerbs)) {
+ return new RouteMatch($this->defaults);
+ }
+
+ return;
+ }
+
+ /**
+ * assemble(): Defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ // The request method does not contribute to the path, thus nothing is returned.
+ return '';
+ }
+
+ /**
+ * getAssembledParams(): defined by RouteInterface interface.
+ *
+ * @see RouteInterface::getAssembledParams
+ * @return array
+ */
+ public function getAssembledParams()
+ {
+ return [];
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use ArrayObject;
+use Traversable;
+use Zend\Mvc\Router\Exception;
+use Zend\Mvc\Router\PriorityList;
+use Zend\Mvc\Router\RoutePluginManager;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * Part route.
+ */
+class Part extends TreeRouteStack implements RouteInterface
+{
+ /**
+ * RouteInterface to match.
+ *
+ * @var RouteInterface
+ */
+ protected $route;
+
+ /**
+ * Whether the route may terminate.
+ *
+ * @var bool
+ */
+ protected $mayTerminate;
+
+ /**
+ * Child routes.
+ *
+ * @var mixed
+ */
+ protected $childRoutes;
+
+ /**
+ * Create a new part route.
+ *
+ * @param mixed $route
+ * @param bool $mayTerminate
+ * @param RoutePluginManager $routePlugins
+ * @param array|null $childRoutes
+ * @param ArrayObject|null $prototypes
+ * @throws Exception\InvalidArgumentException
+ */
+ public function __construct($route, $mayTerminate, RoutePluginManager $routePlugins, array $childRoutes = null, ArrayObject $prototypes = null)
+ {
+ $this->routePluginManager = $routePlugins;
+
+ if (!$route instanceof RouteInterface) {
+ $route = $this->routeFromArray($route);
+ }
+
+ if ($route instanceof self) {
+ throw new Exception\InvalidArgumentException('Base route may not be a part route');
+ }
+
+ $this->route = $route;
+ $this->mayTerminate = $mayTerminate;
+ $this->childRoutes = $childRoutes;
+ $this->prototypes = $prototypes;
+ $this->routes = new PriorityList();
+ }
+
+ /**
+ * factory(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param mixed $options
+ * @return Part
+ * @throws Exception\InvalidArgumentException
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ } elseif (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
+ }
+
+ if (!isset($options['route'])) {
+ throw new Exception\InvalidArgumentException('Missing "route" in options array');
+ }
+
+ if (!isset($options['route_plugins'])) {
+ throw new Exception\InvalidArgumentException('Missing "route_plugins" in options array');
+ }
+
+ if (!isset($options['prototypes'])) {
+ $options['prototypes'] = null;
+ }
+
+ if (!isset($options['may_terminate'])) {
+ $options['may_terminate'] = false;
+ }
+
+ if (!isset($options['child_routes']) || !$options['child_routes']) {
+ $options['child_routes'] = null;
+ }
+
+ if ($options['child_routes'] instanceof Traversable) {
+ $options['child_routes'] = ArrayUtils::iteratorToArray($options['child_routes']);
+ }
+
+ return new static(
+ $options['route'],
+ $options['may_terminate'],
+ $options['route_plugins'],
+ $options['child_routes'],
+ $options['prototypes']
+ );
+ }
+
+ /**
+ * match(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::match()
+ * @param Request $request
+ * @param integer|null $pathOffset
+ * @param array $options
+ * @return RouteMatch|null
+ */
+ public function match(Request $request, $pathOffset = null, array $options = [])
+ {
+ if ($pathOffset === null) {
+ $pathOffset = 0;
+ }
+
+ $match = $this->route->match($request, $pathOffset, $options);
+
+ if ($match !== null && method_exists($request, 'getUri')) {
+ if ($this->childRoutes !== null) {
+ $this->addRoutes($this->childRoutes);
+ $this->childRoutes = null;
+ }
+
+ $nextOffset = $pathOffset + $match->getLength();
+
+ $uri = $request->getUri();
+ $pathLength = strlen($uri->getPath());
+
+ if ($this->mayTerminate && $nextOffset === $pathLength) {
+ $query = $uri->getQuery();
+ if ('' == trim($query) || !$this->hasQueryChild()) {
+ return $match;
+ }
+ }
+
+ if (isset($options['translator']) && !isset($options['locale']) && null !== ($locale = $match->getParam('locale', null))) {
+ $options['locale'] = $locale;
+ }
+
+ foreach ($this->routes as $name => $route) {
+ if (($subMatch = $route->match($request, $nextOffset, $options)) instanceof RouteMatch) {
+ if ($match->getLength() + $subMatch->getLength() + $pathOffset === $pathLength) {
+ return $match->merge($subMatch)->setMatchedRouteName($name);
+ }
+ }
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * assemble(): Defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ * @throws Exception\RuntimeException
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ if ($this->childRoutes !== null) {
+ $this->addRoutes($this->childRoutes);
+ $this->childRoutes = null;
+ }
+
+ $options['has_child'] = (isset($options['name']));
+
+ if (isset($options['translator']) && !isset($options['locale']) && isset($params['locale'])) {
+ $options['locale'] = $params['locale'];
+ }
+
+ $path = $this->route->assemble($params, $options);
+ $params = array_diff_key($params, array_flip($this->route->getAssembledParams()));
+
+ if (!isset($options['name'])) {
+ if (!$this->mayTerminate) {
+ throw new Exception\RuntimeException('Part route may not terminate');
+ } else {
+ return $path;
+ }
+ }
+
+ unset($options['has_child']);
+ $options['only_return_path'] = true;
+ $path .= parent::assemble($params, $options);
+
+ return $path;
+ }
+
+ /**
+ * getAssembledParams(): defined by RouteInterface interface.
+ *
+ * @see RouteInterface::getAssembledParams
+ * @return array
+ */
+ public function getAssembledParams()
+ {
+ // Part routes may not occur as base route of other part routes, so we
+ // don't have to return anything here.
+ return [];
+ }
+
+ /**
+ * Is one of the child routes a query route?
+ *
+ * @return bool
+ */
+ protected function hasQueryChild()
+ {
+ foreach ($this->routes as $route) {
+ if ($route instanceof Query) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use Traversable;
+use Zend\Mvc\Router\Exception;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * Query route.
+ *
+ * @deprecated
+ */
+class Query implements RouteInterface
+{
+ /**
+ * Default values.
+ *
+ * @var array
+ */
+ protected $defaults;
+
+ /**
+ * List of assembled parameters.
+ *
+ * @var array
+ */
+ protected $assembledParams = [];
+
+ /**
+ * Create a new wildcard route.
+ *
+ * @param array $defaults
+ */
+ public function __construct(array $defaults = [])
+ {
+ /**
+ * Legacy purposes only, to prevent code that uses it from breaking.
+ */
+ trigger_error('Query route deprecated as of ZF 2.1.4; use the "query" option of the HTTP router\'s assembling method instead', E_USER_DEPRECATED);
+ $this->defaults = $defaults;
+ }
+
+ /**
+ * factory(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param array|Traversable $options
+ * @return Query
+ * @throws Exception\InvalidArgumentException
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ } elseif (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
+ }
+
+ if (!isset($options['defaults'])) {
+ $options['defaults'] = [];
+ }
+
+ return new static($options['defaults']);
+ }
+
+ /**
+ * match(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::match()
+ * @param Request $request
+ * @return RouteMatch
+ */
+ public function match(Request $request)
+ {
+ // We don't merge the query parameters into the rotue match here because
+ // of possible security problems. Use the Query object instead which is
+ // included in the Request object.
+ return new RouteMatch($this->defaults);
+ }
+
+ /**
+ * Recursively urldecodes keys and values from an array
+ *
+ * @param array $array
+ * @return array
+ */
+ protected function recursiveUrldecode(array $array)
+ {
+ $matches = [];
+
+ foreach ($array as $key => $value) {
+ if (is_array($value)) {
+ $matches[urldecode($key)] = $this->recursiveUrldecode($value);
+ } else {
+ $matches[urldecode($key)] = urldecode($value);
+ }
+ }
+
+ return $matches;
+ }
+
+ /**
+ * assemble(): Defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ $mergedParams = array_merge($this->defaults, $params);
+ $this->assembledParams = [];
+
+ if (isset($options['uri']) && count($mergedParams)) {
+ foreach ($mergedParams as $key => $value) {
+ $this->assembledParams[] = $key;
+ }
+
+ $options['uri']->setQuery($mergedParams);
+ }
+
+ // A query does not contribute to the path, thus nothing is returned.
+ return '';
+ }
+
+ /**
+ * getAssembledParams(): defined by RouteInterface interface.
+ *
+ * @see RouteInterface::getAssembledParams
+ * @return array
+ */
+ public function getAssembledParams()
+ {
+ return $this->assembledParams;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use Traversable;
+use Zend\Mvc\Router\Exception;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * Regex route.
+ */
+class Regex implements RouteInterface
+{
+ /**
+ * Regex to match.
+ *
+ * @var string
+ */
+ protected $regex;
+
+ /**
+ * Default values.
+ *
+ * @var array
+ */
+ protected $defaults;
+
+ /**
+ * Specification for URL assembly.
+ *
+ * Parameters accepting substitutions should be denoted as "%key%"
+ *
+ * @var string
+ */
+ protected $spec;
+
+ /**
+ * List of assembled parameters.
+ *
+ * @var array
+ */
+ protected $assembledParams = [];
+
+ /**
+ * Create a new regex route.
+ *
+ * @param string $regex
+ * @param string $spec
+ * @param array $defaults
+ */
+ public function __construct($regex, $spec, array $defaults = [])
+ {
+ $this->regex = $regex;
+ $this->spec = $spec;
+ $this->defaults = $defaults;
+ }
+
+ /**
+ * factory(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param array|Traversable $options
+ * @return Regex
+ * @throws \Zend\Mvc\Router\Exception\InvalidArgumentException
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ } elseif (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
+ }
+
+ if (!isset($options['regex'])) {
+ throw new Exception\InvalidArgumentException('Missing "regex" in options array');
+ }
+
+ if (!isset($options['spec'])) {
+ throw new Exception\InvalidArgumentException('Missing "spec" in options array');
+ }
+
+ if (!isset($options['defaults'])) {
+ $options['defaults'] = [];
+ }
+
+ return new static($options['regex'], $options['spec'], $options['defaults']);
+ }
+
+ /**
+ * match(): defined by RouteInterface interface.
+ *
+ * @param Request $request
+ * @param int $pathOffset
+ * @return RouteMatch|null
+ */
+ public function match(Request $request, $pathOffset = null)
+ {
+ if (!method_exists($request, 'getUri')) {
+ return;
+ }
+
+ $uri = $request->getUri();
+ $path = $uri->getPath();
+
+ if ($pathOffset !== null) {
+ $result = preg_match('(\G' . $this->regex . ')', $path, $matches, null, $pathOffset);
+ } else {
+ $result = preg_match('(^' . $this->regex . '$)', $path, $matches);
+ }
+
+ if (!$result) {
+ die("here");
+ return;
+ }
+
+ $matchedLength = strlen($matches[0]);
+
+ foreach ($matches as $key => $value) {
+ if (is_numeric($key) || is_int($key) || $value === '') {
+ unset($matches[$key]);
+ } else {
+ $matches[$key] = rawurldecode($value);
+ }
+ }
+ var_dump($matches);
+ return new RouteMatch(array_merge($this->defaults, $matches), $matchedLength);
+ }
+
+ /**
+ * assemble(): Defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ $url = $this->spec;
+ $mergedParams = array_merge($this->defaults, $params);
+ $this->assembledParams = [];
+
+ foreach ($mergedParams as $key => $value) {
+ $spec = '%' . $key . '%';
+
+ if (strpos($url, $spec) !== false) {
+ $url = str_replace($spec, rawurlencode($value), $url);
+
+ $this->assembledParams[] = $key;
+ }
+ }
+
+ return $url;
+ }
+
+ /**
+ * getAssembledParams(): defined by RouteInterface interface.
+ *
+ * @see RouteInterface::getAssembledParams
+ * @return array
+ */
+ public function getAssembledParams()
+ {
+ return $this->assembledParams;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use Zend\Mvc\Router\RouteInterface as BaseRoute;
+
+/**
+ * Tree specific route interface.
+ */
+interface RouteInterface extends BaseRoute
+{
+ /**
+ * Get a list of parameters used while assembling.
+ *
+ * @return array
+ */
+ public function getAssembledParams();
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use Zend\Mvc\Router\RouteMatch as BaseRouteMatch;
+
+/**
+ * Part route match.
+ */
+class RouteMatch extends BaseRouteMatch
+{
+ /**
+ * Length of the matched path.
+ *
+ * @var int
+ */
+ protected $length;
+
+ /**
+ * Create a part RouteMatch with given parameters and length.
+ *
+ * @param array $params
+ * @param int $length
+ */
+ public function __construct(array $params, $length = 0)
+ {
+ parent::__construct($params);
+
+ $this->length = $length;
+ }
+
+ /**
+ * setMatchedRouteName(): defined by BaseRouteMatch.
+ *
+ * @see BaseRouteMatch::setMatchedRouteName()
+ * @param string $name
+ * @return RouteMatch
+ */
+ public function setMatchedRouteName($name)
+ {
+ if ($this->matchedRouteName === null) {
+ $this->matchedRouteName = $name;
+ } else {
+ $this->matchedRouteName = $name . '/' . $this->matchedRouteName;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Merge parameters from another match.
+ *
+ * @param RouteMatch $match
+ * @return RouteMatch
+ */
+ public function merge(RouteMatch $match)
+ {
+ $this->params = array_merge($this->params, $match->getParams());
+ $this->length += $match->getLength();
+
+ $this->matchedRouteName = $match->getMatchedRouteName();
+
+ return $this;
+ }
+
+ /**
+ * Get the matched path length.
+ *
+ * @return int
+ */
+ public function getLength()
+ {
+ return $this->length;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use Traversable;
+use Zend\Mvc\Router\Exception;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * Scheme route.
+ */
+class Scheme implements RouteInterface
+{
+ /**
+ * Scheme to match.
+ *
+ * @var string
+ */
+ protected $scheme;
+
+ /**
+ * Default values.
+ *
+ * @var array
+ */
+ protected $defaults;
+
+ /**
+ * Create a new scheme route.
+ *
+ * @param string $scheme
+ * @param array $defaults
+ */
+ public function __construct($scheme, array $defaults = [])
+ {
+ $this->scheme = $scheme;
+ $this->defaults = $defaults;
+ }
+
+ /**
+ * factory(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param array|Traversable $options
+ * @return Scheme
+ * @throws Exception\InvalidArgumentException
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ } elseif (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
+ }
+
+ if (!isset($options['scheme'])) {
+ throw new Exception\InvalidArgumentException('Missing "scheme" in options array');
+ }
+
+ if (!isset($options['defaults'])) {
+ $options['defaults'] = [];
+ }
+
+ return new static($options['scheme'], $options['defaults']);
+ }
+
+ /**
+ * match(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::match()
+ * @param Request $request
+ * @return RouteMatch|null
+ */
+ public function match(Request $request)
+ {
+ if (!method_exists($request, 'getUri')) {
+ return;
+ }
+
+ $uri = $request->getUri();
+ $scheme = $uri->getScheme();
+
+ if ($scheme !== $this->scheme) {
+ return;
+ }
+
+ return new RouteMatch($this->defaults);
+ }
+
+ /**
+ * assemble(): Defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ if (isset($options['uri'])) {
+ $options['uri']->setScheme($this->scheme);
+ }
+
+ // A scheme does not contribute to the path, thus nothing is returned.
+ return '';
+ }
+
+ /**
+ * getAssembledParams(): defined by RouteInterface interface.
+ *
+ * @see RouteInterface::getAssembledParams
+ * @return array
+ */
+ public function getAssembledParams()
+ {
+ return [];
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use Traversable;
+use Zend\I18n\Translator\TranslatorInterface as Translator;
+use Zend\Mvc\Router\Exception;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * Segment route.
+ */
+class Segment implements RouteInterface
+{
+ /**
+ * Cache for the encode output.
+ *
+ * @var array
+ */
+ protected static $cacheEncode = [];
+
+ /**
+ * Map of allowed special chars in path segments.
+ *
+ * http://tools.ietf.org/html/rfc3986#appendix-A
+ * segement = *pchar
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ * / "*" / "+" / "," / ";" / "="
+ *
+ * @var array
+ */
+ protected static $urlencodeCorrectionMap = [
+ '%21' => "!", // sub-delims
+ '%24' => "$", // sub-delims
+ '%26' => "&", // sub-delims
+ '%27' => "'", // sub-delims
+ '%28' => "(", // sub-delims
+ '%29' => ")", // sub-delims
+ '%2A' => "*", // sub-delims
+ '%2B' => "+", // sub-delims
+ '%2C' => ",", // sub-delims
+// '%2D' => "-", // unreserved - not touched by rawurlencode
+// '%2E' => ".", // unreserved - not touched by rawurlencode
+ '%3A' => ":", // pchar
+ '%3B' => ";", // sub-delims
+ '%3D' => "=", // sub-delims
+ '%40' => "@", // pchar
+// '%5F' => "_", // unreserved - not touched by rawurlencode
+// '%7E' => "~", // unreserved - not touched by rawurlencode
+ ];
+
+ /**
+ * Parts of the route.
+ *
+ * @var array
+ */
+ protected $parts;
+
+ /**
+ * Regex used for matching the route.
+ *
+ * @var string
+ */
+ protected $regex;
+
+ /**
+ * Map from regex groups to parameter names.
+ *
+ * @var array
+ */
+ protected $paramMap = [];
+
+ /**
+ * Default values.
+ *
+ * @var array
+ */
+ protected $defaults;
+
+ /**
+ * List of assembled parameters.
+ *
+ * @var array
+ */
+ protected $assembledParams = [];
+
+ /**
+ * Translation keys used in the regex.
+ *
+ * @var array
+ */
+ protected $translationKeys = [];
+
+ /**
+ * Create a new regex route.
+ *
+ * @param string $route
+ * @param array $constraints
+ * @param array $defaults
+ */
+ public function __construct($route, array $constraints = [], array $defaults = [])
+ {
+ $this->defaults = $defaults;
+ $this->parts = $this->parseRouteDefinition($route);
+ $this->regex = $this->buildRegex($this->parts, $constraints);
+ }
+
+ /**
+ * factory(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param array|Traversable $options
+ * @return Segment
+ * @throws Exception\InvalidArgumentException
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ } elseif (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
+ }
+
+ if (!isset($options['route'])) {
+ throw new Exception\InvalidArgumentException('Missing "route" in options array');
+ }
+
+ if (!isset($options['constraints'])) {
+ $options['constraints'] = [];
+ }
+
+ if (!isset($options['defaults'])) {
+ $options['defaults'] = [];
+ }
+
+ return new static($options['route'], $options['constraints'], $options['defaults']);
+ }
+
+ /**
+ * Parse a route definition.
+ *
+ * @param string $def
+ * @return array
+ * @throws Exception\RuntimeException
+ */
+ protected function parseRouteDefinition($def)
+ {
+ $currentPos = 0;
+ $length = strlen($def);
+ $parts = [];
+ $levelParts = [&$parts];
+ $level = 0;
+
+ while ($currentPos < $length) {
+ preg_match('(\G(?P<literal>[^:{\[\]]*)(?P<token>[:{\[\]]|$))', $def, $matches, 0, $currentPos);
+
+ $currentPos += strlen($matches[0]);
+
+ if (!empty($matches['literal'])) {
+ $levelParts[$level][] = ['literal', $matches['literal']];
+ }
+
+ if ($matches['token'] === ':') {
+ if (!preg_match('(\G(?P<name>[^:/{\[\]]+)(?:{(?P<delimiters>[^}]+)})?:?)', $def, $matches, 0, $currentPos)) {
+ throw new Exception\RuntimeException('Found empty parameter name');
+ }
+
+ $levelParts[$level][] = ['parameter', $matches['name'], isset($matches['delimiters']) ? $matches['delimiters'] : null];
+
+ $currentPos += strlen($matches[0]);
+ } elseif ($matches['token'] === '{') {
+ if (!preg_match('(\G(?P<literal>[^}]+)\})', $def, $matches, 0, $currentPos)) {
+ throw new Exception\RuntimeException('Translated literal missing closing bracket');
+ }
+
+ $currentPos += strlen($matches[0]);
+
+ $levelParts[$level][] = ['translated-literal', $matches['literal']];
+ } elseif ($matches['token'] === '[') {
+ $levelParts[$level][] = ['optional', []];
+ $levelParts[$level + 1] = &$levelParts[$level][count($levelParts[$level]) - 1][1];
+
+ $level++;
+ } elseif ($matches['token'] === ']') {
+ unset($levelParts[$level]);
+ $level--;
+
+ if ($level < 0) {
+ throw new Exception\RuntimeException('Found closing bracket without matching opening bracket');
+ }
+ } else {
+ break;
+ }
+ }
+
+ if ($level > 0) {
+ throw new Exception\RuntimeException('Found unbalanced brackets');
+ }
+
+ return $parts;
+ }
+
+ /**
+ * Build the matching regex from parsed parts.
+ *
+ * @param array $parts
+ * @param array $constraints
+ * @param int $groupIndex
+ * @return string
+ */
+ protected function buildRegex(array $parts, array $constraints, &$groupIndex = 1)
+ {
+ $regex = '';
+
+ foreach ($parts as $part) {
+ switch ($part[0]) {
+ case 'literal':
+ $regex .= preg_quote($part[1]);
+ break;
+
+ case 'parameter':
+ $groupName = '?P<param' . $groupIndex . '>';
+
+ if (isset($constraints[$part[1]])) {
+ $regex .= '(' . $groupName . $constraints[$part[1]] . ')';
+ } elseif ($part[2] === null) {
+ $regex .= '(' . $groupName . '[^/]+)';
+ } else {
+ $regex .= '(' . $groupName . '[^' . $part[2] . ']+)';
+ }
+
+ $this->paramMap['param' . $groupIndex++] = $part[1];
+ break;
+
+ case 'optional':
+ $regex .= '(?:' . $this->buildRegex($part[1], $constraints, $groupIndex) . ')?';
+ break;
+
+ case 'translated-literal':
+ $regex .= '#' . $part[1] . '#';
+ $this->translationKeys[] = $part[1];
+ break;
+ }
+ }
+
+ return $regex;
+ }
+
+ /**
+ * Build a path.
+ *
+ * @param array $parts
+ * @param array $mergedParams
+ * @param bool $isOptional
+ * @param bool $hasChild
+ * @param array $options
+ * @return string
+ * @throws Exception\InvalidArgumentException
+ * @throws Exception\RuntimeException
+ */
+ protected function buildPath(array $parts, array $mergedParams, $isOptional, $hasChild, array $options)
+ {
+ if ($this->translationKeys) {
+ if (!isset($options['translator']) || !$options['translator'] instanceof Translator) {
+ throw new Exception\RuntimeException('No translator provided');
+ }
+
+ $translator = $options['translator'];
+ $textDomain = (isset($options['text_domain']) ? $options['text_domain'] : 'default');
+ $locale = (isset($options['locale']) ? $options['locale'] : null);
+ }
+
+ $path = '';
+ $skip = true;
+ $skippable = false;
+
+ foreach ($parts as $part) {
+ switch ($part[0]) {
+ case 'literal':
+ $path .= $part[1];
+ break;
+
+ case 'parameter':
+ $skippable = true;
+
+ if (!isset($mergedParams[$part[1]])) {
+ if (!$isOptional || $hasChild) {
+ throw new Exception\InvalidArgumentException(sprintf('Missing parameter "%s"', $part[1]));
+ }
+
+ return '';
+ } elseif (!$isOptional || $hasChild || !isset($this->defaults[$part[1]]) || $this->defaults[$part[1]] !== $mergedParams[$part[1]]) {
+ $skip = false;
+ }
+
+ $path .= $this->encode($mergedParams[$part[1]]);
+
+ $this->assembledParams[] = $part[1];
+ break;
+
+ case 'optional':
+ $skippable = true;
+ $optionalPart = $this->buildPath($part[1], $mergedParams, true, $hasChild, $options);
+
+ if ($optionalPart !== '') {
+ $path .= $optionalPart;
+ $skip = false;
+ }
+ break;
+
+ case 'translated-literal':
+ $path .= $translator->translate($part[1], $textDomain, $locale);
+ break;
+ }
+ }
+
+ if ($isOptional && $skippable && $skip) {
+ return '';
+ }
+
+ return $path;
+ }
+
+ /**
+ * match(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::match()
+ * @param Request $request
+ * @param string|null $pathOffset
+ * @param array $options
+ * @return RouteMatch|null
+ * @throws Exception\RuntimeException
+ */
+ public function match(Request $request, $pathOffset = null, array $options = [])
+ {
+ if (!method_exists($request, 'getUri')) {
+ return;
+ }
+
+ $uri = $request->getUri();
+ $path = $uri->getPath();
+
+ $regex = $this->regex;
+
+ if ($this->translationKeys) {
+ if (!isset($options['translator']) || !$options['translator'] instanceof Translator) {
+ throw new Exception\RuntimeException('No translator provided');
+ }
+
+ $translator = $options['translator'];
+ $textDomain = (isset($options['text_domain']) ? $options['text_domain'] : 'default');
+ $locale = (isset($options['locale']) ? $options['locale'] : null);
+
+ foreach ($this->translationKeys as $key) {
+ $regex = str_replace('#' . $key . '#', $translator->translate($key, $textDomain, $locale), $regex);
+ }
+ }
+
+ if ($pathOffset !== null) {
+ $result = preg_match('(\G' . $regex . ')', $path, $matches, null, $pathOffset);
+ } else {
+ $result = preg_match('(^' . $regex . '$)', $path, $matches);
+ }
+
+ if (!$result) {
+ return;
+ }
+
+ $matchedLength = strlen($matches[0]);
+ $params = [];
+
+ foreach ($this->paramMap as $index => $name) {
+ if (isset($matches[$index]) && $matches[$index] !== '') {
+ $params[$name] = $this->decode($matches[$index]);
+ }
+ }
+
+ return new RouteMatch(array_merge($this->defaults, $params), $matchedLength);
+ }
+
+ /**
+ * assemble(): Defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ $this->assembledParams = [];
+
+ return $this->buildPath(
+ $this->parts,
+ array_merge($this->defaults, $params),
+ false,
+ (isset($options['has_child']) ? $options['has_child'] : false),
+ $options
+ );
+ }
+
+ /**
+ * getAssembledParams(): defined by RouteInterface interface.
+ *
+ * @see RouteInterface::getAssembledParams
+ * @return array
+ */
+ public function getAssembledParams()
+ {
+ return $this->assembledParams;
+ }
+
+ /**
+ * Encode a path segment.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected function encode($value)
+ {
+ $key = (string) $value;
+ if (!isset(static::$cacheEncode[$key])) {
+ static::$cacheEncode[$key] = rawurlencode($value);
+ static::$cacheEncode[$key] = strtr(static::$cacheEncode[$key], static::$urlencodeCorrectionMap);
+ }
+ return static::$cacheEncode[$key];
+ }
+
+ /**
+ * Decode a path segment.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected function decode($value)
+ {
+ return rawurldecode($value);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use Zend\I18n\Translator\TranslatorInterface as Translator;
+use Zend\I18n\Translator\TranslatorAwareInterface;
+use Zend\Mvc\Router\Exception;
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * Translator aware tree route stack.
+ */
+class TranslatorAwareTreeRouteStack extends TreeRouteStack implements TranslatorAwareInterface
+{
+ /**
+ * Translator used for translatable segments.
+ *
+ * @var Translator
+ */
+ protected $translator;
+
+ /**
+ * Whether the translator is enabled.
+ *
+ * @var bool
+ */
+ protected $translatorEnabled = true;
+
+ /**
+ * Translator text domain to use.
+ *
+ * @var string
+ */
+ protected $translatorTextDomain = 'default';
+
+ /**
+ * match(): defined by \Zend\Mvc\Router\RouteInterface
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::match()
+ * @param Request $request
+ * @param integer|null $pathOffset
+ * @param array $options
+ * @return RouteMatch|null
+ */
+ public function match(Request $request, $pathOffset = null, array $options = [])
+ {
+ if ($this->hasTranslator() && $this->isTranslatorEnabled() && !isset($options['translator'])) {
+ $options['translator'] = $this->getTranslator();
+ }
+
+ if (!isset($options['text_domain'])) {
+ $options['text_domain'] = $this->getTranslatorTextDomain();
+ }
+
+ return parent::match($request, $pathOffset, $options);
+ }
+
+ /**
+ * assemble(): defined by \Zend\Mvc\Router\RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ * @throws Exception\InvalidArgumentException
+ * @throws Exception\RuntimeException
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ if ($this->hasTranslator() && $this->isTranslatorEnabled() && !isset($options['translator'])) {
+ $options['translator'] = $this->getTranslator();
+ }
+
+ if (!isset($options['text_domain'])) {
+ $options['text_domain'] = $this->getTranslatorTextDomain();
+ }
+
+ return parent::assemble($params, $options);
+ }
+
+ /**
+ * setTranslator(): defined by TranslatorAwareInterface.
+ *
+ * @see TranslatorAwareInterface::setTranslator()
+ * @param Translator $translator
+ * @param string $textDomain
+ * @return TreeRouteStack
+ */
+ public function setTranslator(Translator $translator = null, $textDomain = null)
+ {
+ $this->translator = $translator;
+
+ if ($textDomain !== null) {
+ $this->setTranslatorTextDomain($textDomain);
+ }
+
+ return $this;
+ }
+
+ /**
+ * getTranslator(): defined by TranslatorAwareInterface.
+ *
+ * @see TranslatorAwareInterface::getTranslator()
+ * @return Translator
+ */
+ public function getTranslator()
+ {
+ return $this->translator;
+ }
+
+ /**
+ * hasTranslator(): defined by TranslatorAwareInterface.
+ *
+ * @see TranslatorAwareInterface::hasTranslator()
+ * @return bool
+ */
+ public function hasTranslator()
+ {
+ return $this->translator !== null;
+ }
+
+ /**
+ * setTranslatorEnabled(): defined by TranslatorAwareInterface.
+ *
+ * @see TranslatorAwareInterface::setTranslatorEnabled()
+ * @param bool $enabled
+ * @return TreeRouteStack
+ */
+ public function setTranslatorEnabled($enabled = true)
+ {
+ $this->translatorEnabled = $enabled;
+ return $this;
+ }
+
+ /**
+ * isTranslatorEnabled(): defined by TranslatorAwareInterface.
+ *
+ * @see TranslatorAwareInterface::isTranslatorEnabled()
+ * @return bool
+ */
+ public function isTranslatorEnabled()
+ {
+ return $this->translatorEnabled;
+ }
+
+ /**
+ * setTranslatorTextDomain(): defined by TranslatorAwareInterface.
+ *
+ * @see TranslatorAwareInterface::setTranslatorTextDomain()
+ * @param string $textDomain
+ * @return self
+ */
+ public function setTranslatorTextDomain($textDomain = 'default')
+ {
+ $this->translatorTextDomain = $textDomain;
+
+ return $this;
+ }
+
+ /**
+ * getTranslatorTextDomain(): defined by TranslatorAwareInterface.
+ *
+ * @see TranslatorAwareInterface::getTranslatorTextDomain()
+ * @return string
+ */
+ public function getTranslatorTextDomain()
+ {
+ return $this->translatorTextDomain;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use ArrayObject;
+use Traversable;
+use Zend\Mvc\Router\Exception;
+use Zend\Mvc\Router\RouteInvokableFactory;
+use Zend\Mvc\Router\SimpleRouteStack;
+use Zend\ServiceManager\Config;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+use Zend\Uri\Http as HttpUri;
+
+/**
+ * Tree search implementation.
+ */
+class TreeRouteStack extends SimpleRouteStack
+{
+ /**
+ * Base URL.
+ *
+ * @var string
+ */
+ protected $baseUrl;
+
+ /**
+ * Request URI.
+ *
+ * @var HttpUri
+ */
+ protected $requestUri;
+
+ /**
+ * Prototype routes.
+ *
+ * We use an ArrayObject in this case so we can easily pass it down the tree
+ * by reference.
+ *
+ * @var ArrayObject
+ */
+ protected $prototypes;
+
+ /**
+ * factory(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param array|Traversable $options
+ * @return SimpleRouteStack
+ * @throws Exception\InvalidArgumentException
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ }
+
+ if (! is_array($options)) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
+ }
+
+ $instance = parent::factory($options);
+
+ if (isset($options['prototypes'])) {
+ $instance->addPrototypes($options['prototypes']);
+ }
+
+ return $instance;
+ }
+
+ /**
+ * init(): defined by SimpleRouteStack.
+ *
+ * @see SimpleRouteStack::init()
+ */
+ protected function init()
+ {
+ $this->prototypes = new ArrayObject;
+
+ (new Config([
+ 'aliases' => [
+ 'chain' => Chain::class,
+ 'Chain' => Chain::class,
+ 'hostname' => Hostname::class,
+ 'Hostname' => Hostname::class,
+ 'hostName' => Hostname::class,
+ 'HostName' => Hostname::class,
+ 'literal' => Literal::class,
+ 'Literal' => Literal::class,
+ 'method' => Method::class,
+ 'Method' => Method::class,
+ 'part' => Part::class,
+ 'Part' => Part::class,
+ 'query' => Query::class,
+ 'Query' => Query::class,
+ 'regex' => Regex::class,
+ 'Regex' => Regex::class,
+ 'scheme' => Scheme::class,
+ 'Scheme' => Scheme::class,
+ 'segment' => Segment::class,
+ 'Segment' => Segment::class,
+ 'wildcard' => Wildcard::class,
+ 'Wildcard' => Wildcard::class,
+ 'wildCard' => Wildcard::class,
+ 'WildCard' => Wildcard::class,
+ ],
+ 'factories' => [
+ Chain::class => RouteInvokableFactory::class,
+ Hostname::class => RouteInvokableFactory::class,
+ Literal::class => RouteInvokableFactory::class,
+ Method::class => RouteInvokableFactory::class,
+ Part::class => RouteInvokableFactory::class,
+ Query::class => RouteInvokableFactory::class,
+ Regex::class => RouteInvokableFactory::class,
+ Scheme::class => RouteInvokableFactory::class,
+ Segment::class => RouteInvokableFactory::class,
+ Wildcard::class => RouteInvokableFactory::class,
+
+ // v2 normalized names
+
+ 'zendmvcrouterhttpchain' => RouteInvokableFactory::class,
+ 'zendmvcrouterhttphostname' => RouteInvokableFactory::class,
+ 'zendmvcrouterhttpliteral' => RouteInvokableFactory::class,
+ 'zendmvcrouterhttpmethod' => RouteInvokableFactory::class,
+ 'zendmvcrouterhttppart' => RouteInvokableFactory::class,
+ 'zendmvcrouterhttpquery' => RouteInvokableFactory::class,
+ 'zendmvcrouterhttpregex' => RouteInvokableFactory::class,
+ 'zendmvcrouterhttpscheme' => RouteInvokableFactory::class,
+ 'zendmvcrouterhttpsegment' => RouteInvokableFactory::class,
+ 'zendmvcrouterhttpwildcard' => RouteInvokableFactory::class,
+ ],
+ ]))->configureServiceManager($this->routePluginManager);
+ }
+
+ /**
+ * addRoute(): defined by RouteStackInterface interface.
+ *
+ * @see RouteStackInterface::addRoute()
+ * @param string $name
+ * @param mixed $route
+ * @param int $priority
+ * @return TreeRouteStack
+ */
+ public function addRoute($name, $route, $priority = null)
+ {
+ if (!$route instanceof RouteInterface) {
+ $route = $this->routeFromArray($route);
+ }
+
+ return parent::addRoute($name, $route, $priority);
+ }
+
+ /**
+ * routeFromArray(): defined by SimpleRouteStack.
+ *
+ * @see SimpleRouteStack::routeFromArray()
+ * @param string|array|Traversable $specs
+ * @return RouteInterface
+ * @throws Exception\InvalidArgumentException When route definition is not an array nor traversable
+ * @throws Exception\InvalidArgumentException When chain routes are not an array nor traversable
+ * @throws Exception\RuntimeException When a generated routes does not implement the HTTP route interface
+ */
+ protected function routeFromArray($specs)
+ {
+ if (is_string($specs)) {
+ if (null === ($route = $this->getPrototype($specs))) {
+ throw new Exception\RuntimeException(sprintf('Could not find prototype with name %s', $specs));
+ }
+
+ return $route;
+ } elseif ($specs instanceof Traversable) {
+ $specs = ArrayUtils::iteratorToArray($specs);
+ } elseif (!is_array($specs)) {
+ throw new Exception\InvalidArgumentException('Route definition must be an array or Traversable object');
+ }
+
+ if (isset($specs['chain_routes'])) {
+ if (!is_array($specs['chain_routes'])) {
+ throw new Exception\InvalidArgumentException('Chain routes must be an array or Traversable object');
+ }
+
+ $chainRoutes = array_merge([$specs], $specs['chain_routes']);
+ unset($chainRoutes[0]['chain_routes']);
+
+ if (isset($specs['child_routes'])) {
+ unset($chainRoutes[0]['child_routes']);
+ }
+
+ $options = [
+ 'routes' => $chainRoutes,
+ 'route_plugins' => $this->routePluginManager,
+ 'prototypes' => $this->prototypes,
+ ];
+
+ $route = $this->routePluginManager->get('chain', $options);
+ } else {
+ $route = parent::routeFromArray($specs);
+ }
+
+ if (!$route instanceof RouteInterface) {
+ throw new Exception\RuntimeException('Given route does not implement HTTP route interface');
+ }
+
+ if (isset($specs['child_routes'])) {
+ $options = [
+ 'route' => $route,
+ 'may_terminate' => (isset($specs['may_terminate']) && $specs['may_terminate']),
+ 'child_routes' => $specs['child_routes'],
+ 'route_plugins' => $this->routePluginManager,
+ 'prototypes' => $this->prototypes,
+ ];
+
+ $priority = (isset($route->priority) ? $route->priority : null);
+
+ $route = $this->routePluginManager->get('part', $options);
+ $route->priority = $priority;
+ }
+
+ return $route;
+ }
+
+ /**
+ * Add multiple prototypes at once.
+ *
+ * @param Traversable $routes
+ * @return TreeRouteStack
+ * @throws Exception\InvalidArgumentException
+ */
+ public function addPrototypes($routes)
+ {
+ if (!is_array($routes) && !$routes instanceof Traversable) {
+ throw new Exception\InvalidArgumentException('addPrototypes expects an array or Traversable set of routes');
+ }
+
+ foreach ($routes as $name => $route) {
+ $this->addPrototype($name, $route);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add a prototype.
+ *
+ * @param string $name
+ * @param mixed $route
+ * @return TreeRouteStack
+ */
+ public function addPrototype($name, $route)
+ {
+ if (!$route instanceof RouteInterface) {
+ $route = $this->routeFromArray($route);
+ }
+
+ $this->prototypes[$name] = $route;
+
+ return $this;
+ }
+
+ /**
+ * Get a prototype.
+ *
+ * @param string $name
+ * @return RouteInterface|null
+ */
+ public function getPrototype($name)
+ {
+ if (isset($this->prototypes[$name])) {
+ return $this->prototypes[$name];
+ }
+
+ return;
+ }
+
+ /**
+ * match(): defined by \Zend\Mvc\Router\RouteInterface
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::match()
+ * @param Request $request
+ * @param integer|null $pathOffset
+ * @param array $options
+ * @return RouteMatch|null
+ */
+ public function match(Request $request, $pathOffset = null, array $options = [])
+ {
+ if (!method_exists($request, 'getUri')) {
+ return;
+ }
+
+ if ($this->baseUrl === null && method_exists($request, 'getBaseUrl')) {
+ $this->setBaseUrl($request->getBaseUrl());
+ }
+
+ $uri = $request->getUri();
+ $baseUrlLength = strlen($this->baseUrl) ?: null;
+
+ if ($pathOffset !== null) {
+ $baseUrlLength += $pathOffset;
+ }
+
+ if ($this->requestUri === null) {
+ $this->setRequestUri($uri);
+ }
+
+ if ($baseUrlLength !== null) {
+ $pathLength = strlen($uri->getPath()) - $baseUrlLength;
+ } else {
+ $pathLength = null;
+ }
+
+ foreach ($this->routes as $name => $route) {
+ if (($match = $route->match($request, $baseUrlLength, $options)) instanceof RouteMatch
+ && ($pathLength === null || $match->getLength() === $pathLength)
+ ) {
+ $match->setMatchedRouteName($name);
+
+ foreach ($this->defaultParams as $paramName => $value) {
+ if ($match->getParam($paramName) === null) {
+ $match->setParam($paramName, $value);
+ }
+ }
+
+ return $match;
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * assemble(): defined by \Zend\Mvc\Router\RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ * @throws Exception\InvalidArgumentException
+ * @throws Exception\RuntimeException
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ if (!isset($options['name'])) {
+ throw new Exception\InvalidArgumentException('Missing "name" option');
+ }
+
+ $names = explode('/', $options['name'], 2);
+ $route = $this->routes->get($names[0]);
+
+ if (!$route) {
+ throw new Exception\RuntimeException(sprintf('Route with name "%s" not found', $names[0]));
+ }
+
+ if (isset($names[1])) {
+ if (!$route instanceof TreeRouteStack) {
+ throw new Exception\RuntimeException(sprintf('Route with name "%s" does not have child routes', $names[0]));
+ }
+ $options['name'] = $names[1];
+ } else {
+ unset($options['name']);
+ }
+
+ if (isset($options['only_return_path']) && $options['only_return_path']) {
+ return $this->baseUrl . $route->assemble(array_merge($this->defaultParams, $params), $options);
+ }
+
+ if (!isset($options['uri'])) {
+ $uri = new HttpUri();
+
+ if (isset($options['force_canonical']) && $options['force_canonical']) {
+ if ($this->requestUri === null) {
+ throw new Exception\RuntimeException('Request URI has not been set');
+ }
+
+ $uri->setScheme($this->requestUri->getScheme())
+ ->setHost($this->requestUri->getHost())
+ ->setPort($this->requestUri->getPort());
+ }
+
+ $options['uri'] = $uri;
+ } else {
+ $uri = $options['uri'];
+ }
+
+ $path = $this->baseUrl . $route->assemble(array_merge($this->defaultParams, $params), $options);
+
+ if (isset($options['query'])) {
+ $uri->setQuery($options['query']);
+ }
+
+ if (isset($options['fragment'])) {
+ $uri->setFragment($options['fragment']);
+ }
+
+ if ((isset($options['force_canonical']) && $options['force_canonical']) || $uri->getHost() !== null || $uri->getScheme() !== null) {
+ if (($uri->getHost() === null || $uri->getScheme() === null) && $this->requestUri === null) {
+ throw new Exception\RuntimeException('Request URI has not been set');
+ }
+
+ if ($uri->getHost() === null) {
+ $uri->setHost($this->requestUri->getHost());
+ }
+
+ if ($uri->getScheme() === null) {
+ $uri->setScheme($this->requestUri->getScheme());
+ }
+
+ $uri->setPath($path);
+
+ if (!isset($options['normalize_path']) || $options['normalize_path']) {
+ $uri->normalize();
+ }
+
+ return $uri->toString();
+ } elseif (!$uri->isAbsolute() && $uri->isValidRelative()) {
+ $uri->setPath($path);
+
+ if (!isset($options['normalize_path']) || $options['normalize_path']) {
+ $uri->normalize();
+ }
+
+ return $uri->toString();
+ }
+
+ return $path;
+ }
+
+ /**
+ * Set the base URL.
+ *
+ * @param string $baseUrl
+ * @return self
+ */
+ public function setBaseUrl($baseUrl)
+ {
+ $this->baseUrl = rtrim($baseUrl, '/');
+ return $this;
+ }
+
+ /**
+ * Get the base URL.
+ *
+ * @return string
+ */
+ public function getBaseUrl()
+ {
+ return $this->baseUrl;
+ }
+
+ /**
+ * Set the request URI.
+ *
+ * @param HttpUri $uri
+ * @return TreeRouteStack
+ */
+ public function setRequestUri(HttpUri $uri)
+ {
+ $this->requestUri = $uri;
+ return $this;
+ }
+
+ /**
+ * Get the request URI.
+ *
+ * @return HttpUri
+ */
+ public function getRequestUri()
+ {
+ return $this->requestUri;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router\Http;
+
+use Traversable;
+use Zend\Mvc\Router\Exception;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * Wildcard route.
+ */
+class Wildcard implements RouteInterface
+{
+ /**
+ * Delimiter between keys and values.
+ *
+ * @var string
+ */
+ protected $keyValueDelimiter;
+
+ /**
+ * Delimiter before parameters.
+ *
+ * @var array
+ */
+ protected $paramDelimiter;
+
+ /**
+ * Default values.
+ *
+ * @var array
+ */
+ protected $defaults;
+
+ /**
+ * List of assembled parameters.
+ *
+ * @var array
+ */
+ protected $assembledParams = [];
+
+ /**
+ * Create a new wildcard route.
+ *
+ * @param string $keyValueDelimiter
+ * @param string $paramDelimiter
+ * @param array $defaults
+ */
+ public function __construct($keyValueDelimiter = '/', $paramDelimiter = '/', array $defaults = [])
+ {
+ $this->keyValueDelimiter = $keyValueDelimiter;
+ $this->paramDelimiter = $paramDelimiter;
+ $this->defaults = $defaults;
+ }
+
+ /**
+ * factory(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param array|Traversable $options
+ * @return Wildcard
+ * @throws Exception\InvalidArgumentException
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ } elseif (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ '%s expects an array or Traversable set of options',
+ __METHOD__
+ ));
+ }
+
+ if (!isset($options['key_value_delimiter'])) {
+ $options['key_value_delimiter'] = '/';
+ }
+
+ if (!isset($options['param_delimiter'])) {
+ $options['param_delimiter'] = '/';
+ }
+
+ if (!isset($options['defaults'])) {
+ $options['defaults'] = [];
+ }
+
+ return new static($options['key_value_delimiter'], $options['param_delimiter'], $options['defaults']);
+ }
+
+ /**
+ * match(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::match()
+ * @param Request $request
+ * @param integer|null $pathOffset
+ * @return RouteMatch|null
+ */
+ public function match(Request $request, $pathOffset = null)
+ {
+ if (!method_exists($request, 'getUri')) {
+ return;
+ }
+
+ $uri = $request->getUri();
+ $path = $uri->getPath() ?: '';
+
+ if ($path === '/') {
+ $path = '';
+ }
+
+ if ($pathOffset !== null) {
+ $path = substr($path, $pathOffset) ?: '';
+ }
+
+ $matches = [];
+ $params = explode($this->paramDelimiter, $path);
+
+ if (count($params) > 1 && ($params[0] !== '' || end($params) === '')) {
+ return;
+ }
+
+ if ($this->keyValueDelimiter === $this->paramDelimiter) {
+ $count = count($params);
+
+ for ($i = 1; $i < $count; $i += 2) {
+ if (isset($params[$i + 1])) {
+ $matches[rawurldecode($params[$i])] = rawurldecode($params[$i + 1]);
+ }
+ }
+ } else {
+ array_shift($params);
+
+ foreach ($params as $param) {
+ $param = explode($this->keyValueDelimiter, $param, 2);
+
+ if (isset($param[1])) {
+ $matches[rawurldecode($param[0])] = rawurldecode($param[1]);
+ }
+ }
+ }
+
+ return new RouteMatch(array_merge($this->defaults, $matches), strlen($path));
+ }
+
+ /**
+ * assemble(): Defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ $elements = [];
+ $mergedParams = array_merge($this->defaults, $params);
+ $this->assembledParams = [];
+
+ if ($mergedParams) {
+ foreach ($mergedParams as $key => $value) {
+ $elements[] = rawurlencode($key) . $this->keyValueDelimiter . rawurlencode($value);
+
+ $this->assembledParams[] = $key;
+ }
+
+ return $this->paramDelimiter . implode($this->paramDelimiter, $elements);
+ }
+
+ return '';
+ }
+
+ /**
+ * getAssembledParams(): defined by RouteInterface interface.
+ *
+ * @see RouteInterface::getAssembledParams
+ * @return array
+ */
+ public function getAssembledParams()
+ {
+ return $this->assembledParams;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router;
+
+use Zend\Stdlib\PriorityList as StdlibPriorityList;
+
+/**
+ * Priority list
+ */
+class PriorityList extends StdlibPriorityList
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router;
+
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * RouteInterface interface.
+ */
+interface RouteInterface
+{
+ /**
+ * Priority used for route stacks.
+ *
+ * @var int
+ * public $priority;
+ */
+
+ /**
+ * Create a new route with given options.
+ *
+ * @param array|\Traversable $options
+ * @return void
+ */
+ public static function factory($options = []);
+
+ /**
+ * Match a given request.
+ *
+ * @param Request $request
+ * @return RouteMatch|null
+ */
+ public function match(Request $request);
+
+ /**
+ * Assemble the route.
+ *
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ */
+ public function assemble(array $params = [], array $options = []);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\Exception\ServiceNotCreatedException;
+use Zend\ServiceManager\AbstractFactoryInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+/**
+ * Specialized invokable/abstract factory for use with RoutePluginManager.
+ *
+ * Can be mapped directly to specific route plugin names, or used as an
+ * abstract factory to map FQCN services to invokables.
+ */
+class RouteInvokableFactory implements
+ AbstractFactoryInterface,
+ FactoryInterface
+{
+ /**
+ * Options used to create instance (used with zend-servicemanager v2)
+ *
+ * @var array
+ */
+ protected $creationOptions = [];
+
+ /**
+ * Can we create a route instance with the given name? (v3)
+ *
+ * Only works for FQCN $routeName values, for classes that implement RouteInterface.
+ *
+ * @param ContainerInterface $container
+ * @param string $routeName
+ * @return bool
+ */
+ public function canCreate(ContainerInterface $container, $routeName)
+ {
+ if (! class_exists($routeName)) {
+ return false;
+ }
+
+ if (! is_subclass_of($routeName, RouteInterface::class)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Can we create a route instance with the given name? (v2)
+ *
+ * Proxies to canCreate().
+ *
+ * @param ServiceLocatorInterface $container
+ * @param string $normalizedName
+ * @param string $routeName
+ * @return bool
+ */
+ public function canCreateServiceWithName(ServiceLocatorInterface $container, $normalizedName, $routeName)
+ {
+ return $this->canCreate($container, $routeName);
+ }
+
+ /**
+ * Create and return a RouteInterface instance.
+ *
+ * If the specified $routeName class does not exist or does not implement
+ * RouteInterface, this method will raise an exception.
+ *
+ * Otherwise, it uses the class' `factory()` method with the provided
+ * $options to produce an instance.
+ *
+ * @param ContainerInterface $container
+ * @param string $routeName
+ * @param null|array $options
+ * @return RouteInterface
+ */
+ public function __invoke(ContainerInterface $container, $routeName, array $options = null)
+ {
+ $options = $options ?: [];
+
+ if (! class_exists($routeName)) {
+ throw new ServiceNotCreatedException(sprintf(
+ '%s: failed retrieving invokable class "%s"; class does not exist',
+ __CLASS__,
+ $routeName
+ ));
+ }
+
+ if (! is_subclass_of($routeName, RouteInterface::class)) {
+ throw new ServiceNotCreatedException(sprintf(
+ '%s: failed retrieving invokable class "%s"; class does not implement %s',
+ __CLASS__,
+ $routeName,
+ RouteInterface::class
+ ));
+ }
+
+ return $routeName::factory($options);
+ }
+
+ /**
+ * Create a route instance with the given name. (v2)
+ *
+ * Proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @param string $normalizedName
+ * @param string $routeName
+ * @return RouteInterface
+ */
+ public function createServiceWithName(ServiceLocatorInterface $container, $normalizedName, $routeName)
+ {
+ return $this($container, $routeName, $this->creationOptions);
+ }
+
+ /**
+ * Create and return RouteInterface instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return RouteInterface
+ */
+ public function createService(ServiceLocatorInterface $container, $normalizedName = null, $routeName = null)
+ {
+ $routeName = $routeName ?: RouteInterface::class;
+ return $this($container, $routeName, $this->creationOptions);
+ }
+
+ /**
+ * Set options to use when creating a service (v2)
+ *
+ * @param array $creationOptions
+ */
+ public function setCreationOptions(array $creationOptions)
+ {
+ $this->creationOptions = $creationOptions;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router;
+
+/**
+ * RouteInterface match.
+ */
+class RouteMatch
+{
+ /**
+ * Match parameters.
+ *
+ * @var array
+ */
+ protected $params = [];
+
+ /**
+ * Matched route name.
+ *
+ * @var string
+ */
+ protected $matchedRouteName;
+
+ /**
+ * Create a RouteMatch with given parameters.
+ *
+ * @param array $params
+ */
+ public function __construct(array $params)
+ {
+ $this->params = $params;
+ }
+
+ /**
+ * Set name of matched route.
+ *
+ * @param string $name
+ * @return RouteMatch
+ */
+ public function setMatchedRouteName($name)
+ {
+ $this->matchedRouteName = $name;
+ return $this;
+ }
+
+ /**
+ * Get name of matched route.
+ *
+ * @return string
+ */
+ public function getMatchedRouteName()
+ {
+ return $this->matchedRouteName;
+ }
+
+ /**
+ * Set a parameter.
+ *
+ * @param string $name
+ * @param mixed $value
+ * @return RouteMatch
+ */
+ public function setParam($name, $value)
+ {
+ $this->params[$name] = $value;
+ return $this;
+ }
+
+ /**
+ * Get all parameters.
+ *
+ * @return array
+ */
+ public function getParams()
+ {
+ return $this->params;
+ }
+
+ /**
+ * Get a specific parameter.
+ *
+ * @param string $name
+ * @param mixed $default
+ * @return mixed
+ */
+ public function getParam($name, $default = null)
+ {
+ if (array_key_exists($name, $this->params)) {
+ return $this->params[$name];
+ }
+
+ return $default;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\AbstractPluginManager;
+use Zend\ServiceManager\Exception\InvalidServiceException;
+
+/**
+ * Plugin manager implementation for routes
+ *
+ * Enforces that routes retrieved are instances of RouteInterface. It overrides
+ * configure() to map invokables to the component-specific
+ * RouteInvokableFactory.
+ *
+ * The manager is marked to not share by default, in order to allow multiple
+ * route instances of the same type.
+ */
+class RoutePluginManager extends AbstractPluginManager
+{
+ /**
+ * Only RouteInterface instances are valid
+ *
+ * @var string
+ */
+ protected $instanceOf = RouteInterface::class;
+
+ /**
+ * Do not share instances. (v3)
+ *
+ * @var bool
+ */
+ protected $shareByDefault = false;
+
+ /**
+ * Do not share instances. (v2)
+ *
+ * @var bool
+ */
+ protected $sharedByDefault = false;
+
+ /**
+ * Constructor
+ *
+ * Ensure that the instance is seeded with the RouteInvokableFactory as an
+ * abstract factory.
+ *
+ * @param ContainerInterface|\Zend\ServiceManager\ConfigInterface $configOrContainerInstance
+ * @param array $v3config
+ */
+ public function __construct($configOrContainerInstance, array $v3config = [])
+ {
+ $this->addAbstractFactory(RouteInvokableFactory::class);
+ parent::__construct($configOrContainerInstance, $v3config);
+ }
+
+ /**
+ * Validate a route plugin. (v2)
+ *
+ * @param object $plugin
+ * @throws InvalidServiceException
+ */
+ public function validate($plugin)
+ {
+ if (! $plugin instanceof $this->instanceOf) {
+ throw new InvalidServiceException(sprintf(
+ 'Plugin of type %s is invalid; must implement %s',
+ (is_object($plugin) ? get_class($plugin) : gettype($plugin)),
+ RouteInterface::class
+ ));
+ }
+ }
+
+ /**
+ * Validate a route plugin. (v2)
+ *
+ * @param object $plugin
+ * @throws Exception\RuntimeException
+ */
+ public function validatePlugin($plugin)
+ {
+ try {
+ $this->validate($plugin);
+ } catch (InvalidServiceException $e) {
+ throw new Exception\RuntimeException(
+ $e->getMessage(),
+ $e->getCode(),
+ $e
+ );
+ }
+ }
+
+ /**
+ * Pre-process configuration. (v3)
+ *
+ * Checks for invokables, and, if found, maps them to the
+ * component-specific RouteInvokableFactory; removes the invokables entry
+ * before passing to the parent.
+ *
+ * @param array $config
+ * @return void
+ */
+ public function configure(array $config)
+ {
+ 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']);
+ }
+
+ parent::configure($config);
+ }
+
+ /**
+ * Create aliases for invokable classes.
+ *
+ * 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 array $invokables
+ * @return array
+ */
+ protected function createAliasesForInvokables(array $invokables)
+ {
+ $aliases = [];
+ foreach ($invokables as $name => $class) {
+ if ($name === $class) {
+ continue;
+ }
+ $aliases[$name] = $class;
+ }
+ return $aliases;
+ }
+
+ /**
+ * 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;
+ }
+
+ $factories[$class] = RouteInvokableFactory::class;
+ }
+ return $factories;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router;
+
+interface RouteStackInterface extends RouteInterface
+{
+ /**
+ * Add a route to the stack.
+ *
+ * @param string $name
+ * @param mixed $route
+ * @param int $priority
+ * @return RouteStackInterface
+ */
+ public function addRoute($name, $route, $priority = null);
+
+ /**
+ * Add multiple routes to the stack.
+ *
+ * @param array|\Traversable $routes
+ * @return RouteStackInterface
+ */
+ public function addRoutes($routes);
+
+ /**
+ * Remove a route from the stack.
+ *
+ * @param string $name
+ * @return RouteStackInterface
+ */
+ public function removeRoute($name);
+
+ /**
+ * Remove all routes from the stack and set new ones.
+ *
+ * @param array|\Traversable $routes
+ * @return RouteStackInterface
+ */
+ public function setRoutes($routes);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Router;
+
+use Traversable;
+use Zend\ServiceManager\ServiceManager;
+use Zend\Stdlib\ArrayUtils;
+use Zend\Stdlib\RequestInterface as Request;
+
+/**
+ * Simple route stack implementation.
+ */
+class SimpleRouteStack implements RouteStackInterface
+{
+ /**
+ * Stack containing all routes.
+ *
+ * @var PriorityList
+ */
+ protected $routes;
+
+ /**
+ * Route plugin manager
+ *
+ * @var RoutePluginManager
+ */
+ protected $routePluginManager;
+
+ /**
+ * Default parameters.
+ *
+ * @var array
+ */
+ protected $defaultParams = [];
+
+ /**
+ * Create a new simple route stack.
+ *
+ * @param RoutePluginManager $routePluginManager
+ */
+ public function __construct(RoutePluginManager $routePluginManager = null)
+ {
+ $this->routes = new PriorityList();
+
+ if (null === $routePluginManager) {
+ $routePluginManager = new RoutePluginManager(new ServiceManager());
+ }
+
+ $this->routePluginManager = $routePluginManager;
+
+ $this->init();
+ }
+
+ /**
+ * factory(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::factory()
+ * @param array|Traversable $options
+ * @return SimpleRouteStack
+ * @throws Exception\InvalidArgumentException
+ */
+ public static function factory($options = [])
+ {
+ if ($options instanceof Traversable) {
+ $options = ArrayUtils::iteratorToArray($options);
+ } elseif (!is_array($options)) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
+ }
+
+ $routePluginManager = null;
+ if (isset($options['route_plugins'])) {
+ $routePluginManager = $options['route_plugins'];
+ }
+
+ $instance = new static($routePluginManager);
+
+ if (isset($options['routes'])) {
+ $instance->addRoutes($options['routes']);
+ }
+
+ if (isset($options['default_params'])) {
+ $instance->setDefaultParams($options['default_params']);
+ }
+
+ return $instance;
+ }
+
+ /**
+ * Init method for extending classes.
+ *
+ * @return void
+ */
+ protected function init()
+ {
+ }
+
+ /**
+ * Set the route plugin manager.
+ *
+ * @param RoutePluginManager $routePlugins
+ * @return SimpleRouteStack
+ */
+ public function setRoutePluginManager(RoutePluginManager $routePlugins)
+ {
+ $this->routePluginManager = $routePlugins;
+ return $this;
+ }
+
+ /**
+ * Get the route plugin manager.
+ *
+ * @return RoutePluginManager
+ */
+ public function getRoutePluginManager()
+ {
+ return $this->routePluginManager;
+ }
+
+ /**
+ * addRoutes(): defined by RouteStackInterface interface.
+ *
+ * @see RouteStackInterface::addRoutes()
+ * @param array|Traversable $routes
+ * @return SimpleRouteStack
+ * @throws Exception\InvalidArgumentException
+ */
+ public function addRoutes($routes)
+ {
+ if (!is_array($routes) && !$routes instanceof Traversable) {
+ throw new Exception\InvalidArgumentException('addRoutes expects an array or Traversable set of routes');
+ }
+
+ foreach ($routes as $name => $route) {
+ $this->addRoute($name, $route);
+ }
+
+ return $this;
+ }
+
+ /**
+ * addRoute(): defined by RouteStackInterface interface.
+ *
+ * @see RouteStackInterface::addRoute()
+ * @param string $name
+ * @param mixed $route
+ * @param int $priority
+ * @return SimpleRouteStack
+ */
+ public function addRoute($name, $route, $priority = null)
+ {
+ if (!$route instanceof RouteInterface) {
+ $route = $this->routeFromArray($route);
+ }
+
+ if ($priority === null && isset($route->priority)) {
+ $priority = $route->priority;
+ }
+
+ $this->routes->insert($name, $route, $priority);
+
+ return $this;
+ }
+
+ /**
+ * removeRoute(): defined by RouteStackInterface interface.
+ *
+ * @see RouteStackInterface::removeRoute()
+ * @param string $name
+ * @return SimpleRouteStack
+ */
+ public function removeRoute($name)
+ {
+ $this->routes->remove($name);
+ return $this;
+ }
+
+ /**
+ * setRoutes(): defined by RouteStackInterface interface.
+ *
+ * @param array|Traversable $routes
+ * @return SimpleRouteStack
+ */
+ public function setRoutes($routes)
+ {
+ $this->routes->clear();
+ $this->addRoutes($routes);
+ return $this;
+ }
+
+ /**
+ * Get the added routes
+ *
+ * @return Traversable list of all routes
+ */
+ public function getRoutes()
+ {
+ return $this->routes;
+ }
+
+ /**
+ * Check if a route with a specific name exists
+ *
+ * @param string $name
+ * @return bool true if route exists
+ */
+ public function hasRoute($name)
+ {
+ return $this->routes->get($name) !== null;
+ }
+
+ /**
+ * Get a route by name
+ *
+ * @param string $name
+ * @return RouteInterface the route
+ */
+ public function getRoute($name)
+ {
+ return $this->routes->get($name);
+ }
+
+ /**
+ * Set a default parameters.
+ *
+ * @param array $params
+ * @return SimpleRouteStack
+ */
+ public function setDefaultParams(array $params)
+ {
+ $this->defaultParams = $params;
+ return $this;
+ }
+
+ /**
+ * Set a default parameter.
+ *
+ * @param string $name
+ * @param mixed $value
+ * @return SimpleRouteStack
+ */
+ public function setDefaultParam($name, $value)
+ {
+ $this->defaultParams[$name] = $value;
+ return $this;
+ }
+
+ /**
+ * Create a route from array specifications.
+ *
+ * @param array|Traversable $specs
+ * @return RouteInterface
+ * @throws Exception\InvalidArgumentException
+ */
+ protected function routeFromArray($specs)
+ {
+ if ($specs instanceof Traversable) {
+ $specs = ArrayUtils::iteratorToArray($specs);
+ }
+
+ if (! is_array($specs)) {
+ throw new Exception\InvalidArgumentException('Route definition must be an array or Traversable object');
+ }
+
+ if (! isset($specs['type'])) {
+ throw new Exception\InvalidArgumentException('Missing "type" option');
+ }
+
+ if (! isset($specs['options'])) {
+ $specs['options'] = [];
+ }
+
+ $route = $this->getRoutePluginManager()->get($specs['type'], $specs['options']);
+
+ if (isset($specs['priority'])) {
+ $route->priority = $specs['priority'];
+ }
+
+ return $route;
+ }
+
+ /**
+ * match(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::match()
+ * @param Request $request
+ * @return RouteMatch|null
+ */
+ public function match(Request $request)
+ {
+ foreach ($this->routes as $name => $route) {
+ if (($match = $route->match($request)) instanceof RouteMatch) {
+ $match->setMatchedRouteName($name);
+
+ foreach ($this->defaultParams as $paramName => $value) {
+ if ($match->getParam($paramName) === null) {
+ $match->setParam($paramName, $value);
+ }
+ }
+
+ return $match;
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * assemble(): defined by RouteInterface interface.
+ *
+ * @see \Zend\Mvc\Router\RouteInterface::assemble()
+ * @param array $params
+ * @param array $options
+ * @return mixed
+ * @throws Exception\InvalidArgumentException
+ * @throws Exception\RuntimeException
+ */
+ public function assemble(array $params = [], array $options = [])
+ {
+ if (!isset($options['name'])) {
+ throw new Exception\InvalidArgumentException('Missing "name" option');
+ }
+
+ $route = $this->routes->get($options['name']);
+
+ if (!$route) {
+ throw new Exception\RuntimeException(sprintf('Route with name "%s" not found', $options['name']));
+ }
+
+ unset($options['name']);
+
+ return $route->assemble(array_merge($this->defaultParams, $params), $options);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc;
+
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManager;
+use Zend\EventManager\EventManagerAwareInterface;
+use Zend\EventManager\EventManagerInterface;
+use Zend\Mvc\ResponseSender\ConsoleResponseSender;
+use Zend\Mvc\ResponseSender\HttpResponseSender;
+use Zend\Mvc\ResponseSender\PhpEnvironmentResponseSender;
+use Zend\Mvc\ResponseSender\SendResponseEvent;
+use Zend\Mvc\ResponseSender\SimpleStreamResponseSender;
+use Zend\Stdlib\ResponseInterface as Response;
+
+class SendResponseListener extends AbstractListenerAggregate implements
+ EventManagerAwareInterface
+{
+ /**
+ * @var SendResponseEvent
+ */
+ protected $event;
+
+ /**
+ * @var EventManagerInterface
+ */
+ protected $eventManager;
+
+ /**
+ * Inject an EventManager instance
+ *
+ * @param EventManagerInterface $eventManager
+ * @return SendResponseListener
+ */
+ public function setEventManager(EventManagerInterface $eventManager)
+ {
+ $eventManager->setIdentifiers([
+ __CLASS__,
+ get_class($this),
+ ]);
+ $this->eventManager = $eventManager;
+ $this->attachDefaultListeners();
+ return $this;
+ }
+
+ /**
+ * Retrieve the event manager
+ *
+ * Lazy-loads an EventManager instance if none registered.
+ *
+ * @return EventManagerInterface
+ */
+ public function getEventManager()
+ {
+ if (!$this->eventManager instanceof EventManagerInterface) {
+ $this->setEventManager(new EventManager());
+ }
+ return $this->eventManager;
+ }
+
+ /**
+ * Attach the aggregate to the specified event manager
+ *
+ * @param EventManagerInterface $events
+ * @param int $priority
+ * @return void
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_FINISH, [$this, 'sendResponse'], -10000);
+ }
+
+ /**
+ * Send the response
+ *
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function sendResponse(MvcEvent $e)
+ {
+ $response = $e->getResponse();
+ if (!$response instanceof Response) {
+ return; // there is no response to send
+ }
+ $event = $this->getEvent();
+ $event->setResponse($response);
+ $event->setTarget($this);
+ $this->getEventManager()->triggerEvent($event);
+ }
+
+ /**
+ * Get the send response event
+ *
+ * @return SendResponseEvent
+ */
+ public function getEvent()
+ {
+ if (!$this->event instanceof SendResponseEvent) {
+ $this->setEvent(new SendResponseEvent());
+ }
+ return $this->event;
+ }
+
+ /**
+ * Set the send response event
+ *
+ * @param SendResponseEvent $e
+ * @return SendResponseEvent
+ */
+ public function setEvent(SendResponseEvent $e)
+ {
+ $this->event = $e;
+ return $this;
+ }
+
+ /**
+ * Register the default event listeners
+ *
+ * The order in which the response sender are listed here, is by their usage:
+ * PhpEnvironmentResponseSender has highest priority, because it's used most often.
+ * ConsoleResponseSender and SimpleStreamResponseSender are not used that often, yo they have a lower priority.
+ * You can attach your response sender before or after every default response sender implementation.
+ * All default response sender implementation have negative priority.
+ * You are able to attach listeners without giving a priority and your response sender would be first to try.
+ *
+ * @return SendResponseListener
+ */
+ protected function attachDefaultListeners()
+ {
+ $events = $this->getEventManager();
+ $events->attach(SendResponseEvent::EVENT_SEND_RESPONSE, new PhpEnvironmentResponseSender(), -1000);
+ $events->attach(SendResponseEvent::EVENT_SEND_RESPONSE, new ConsoleResponseSender(), -2000);
+ $events->attach(SendResponseEvent::EVENT_SEND_RESPONSE, new SimpleStreamResponseSender(), -3000);
+ $events->attach(SendResponseEvent::EVENT_SEND_RESPONSE, new HttpResponseSender(), -4000);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\AbstractPluginManager;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+abstract class AbstractPluginManagerFactory implements FactoryInterface
+{
+ const PLUGIN_MANAGER_CLASS = 'AbstractPluginManager';
+
+ /**
+ * Create and return a plugin manager.
+ *
+ * Classes that extend this should provide a valid class for
+ * the PLUGIN_MANGER_CLASS constant.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return AbstractPluginManager
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $options = $options ?: [];
+ $pluginManagerClass = static::PLUGIN_MANAGER_CLASS;
+ return new $pluginManagerClass($container, $options);
+ }
+
+ /**
+ * Create and return AbstractPluginManager instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return AbstractPluginManager
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, AbstractPluginManager::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\Application;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class ApplicationFactory implements FactoryInterface
+{
+ /**
+ * Create the Application service (v3)
+ *
+ * Creates a Zend\Mvc\Application service, passing it the configuration
+ * service and the service manager instance.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return Application
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ return new Application(
+ $container->get('config'),
+ $container,
+ $container->get('EventManager'),
+ $container->get('Request'),
+ $container->get('Response')
+ );
+ }
+
+ /**
+ * Create the Application service (v2)
+ *
+ * Proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return Application
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, Application::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class ConfigFactory implements FactoryInterface
+{
+ /**
+ * Create the application configuration service
+ *
+ * Retrieves the Module Manager from the service locator, and executes
+ * {@link Zend\ModuleManager\ModuleManager::loadModules()}.
+ *
+ * It then retrieves the config listener from the module manager, and from
+ * that the merged configuration.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return array|\Traversable
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $moduleManager = $container->get('ModuleManager');
+ $moduleManager->loadModules();
+ $moduleParams = $moduleManager->getEvent()->getParams();
+ return $moduleParams['configListener']->getMergedConfig(false);
+ }
+
+ /**
+ * Create and return config instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return array|\Traversable
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, 'config');
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+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;
+
+class ConsoleAdapterFactory implements FactoryInterface
+{
+ /**
+ * Create and return a Console adapter instance.
+ * In case we're not in a Console environment, return a dummy stdClass object.
+ *
+ * In order to disable adapter auto-detection and use a specific adapter (and charset),
+ * add the following fields to application configuration, for example:
+ *
+ * 'console' => array(
+ * 'adapter' => 'MyConsoleAdapter', // always use this console adapter
+ * 'charset' => 'MyConsoleCharset', // always use this console charset
+ * ),
+ * 'service_manager' => array(
+ * 'invokables' => array(
+ * 'MyConsoleAdapter' => 'Zend\Console\Adapter\Windows',
+ * 'MyConsoleCharset' => 'Zend\Console\Charset\DESCG',
+ * )
+ * )
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return AdapterInterface|stdClass
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ // First, check if we're actually in a Console environment
+ 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 = $container->get('config');
+ if (! empty($config['console']) && ! empty($config['console']['adapter'])) {
+ // use the adapter supplied in application config
+ $adapter = $container->get($config['console']['adapter']);
+ } else {
+ // try to detect best console adapter
+ $adapter = Console::detectBestAdapter();
+ $adapter = new $adapter();
+ }
+
+ // check if we have a valid console adapter
+ 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'])) {
+ // use the charset supplied in application config
+ $charset = $container->get($config['console']['charset']);
+ $adapter->setCharset($charset);
+ }
+
+ return $adapter;
+ }
+
+ /**
+ * Create and return AdapterInterface instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return AdapterInterface|stdClass
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, AdapterInterface::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\View\Console\ExceptionStrategy;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class ConsoleExceptionStrategyFactory implements FactoryInterface
+{
+ use ConsoleViewManagerConfigTrait;
+
+ /**
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return ExceptionStrategy
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $strategy = new ExceptionStrategy();
+ $config = $this->getConfig($container);
+
+ $this->injectDisplayExceptions($strategy, $config);
+ $this->injectExceptionMessage($strategy, $config);
+
+ return $strategy;
+ }
+
+ /**
+ * Create and return ExceptionStrategy instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return ExceptionStrategy
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, ExceptionStrategy::class);
+ }
+
+ /**
+ * 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)
+ {
+ if (isset($config['exception_message'])) {
+ $strategy->setMessage($config['exception_message']);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\View\Console\RouteNotFoundStrategy;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class ConsoleRouteNotFoundStrategyFactory implements FactoryInterface
+{
+ use ConsoleViewManagerConfigTrait;
+
+ /**
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return RouteNotFoundStrategy
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $strategy = new RouteNotFoundStrategy();
+ $config = $this->getConfig($container);
+
+ $this->injectDisplayNotFoundReason($strategy, $config);
+
+ return $strategy;
+ }
+
+ /**
+ * Create and return RouteNotFoundStrategy instance
+ *
+ * @param ServiceLocatorInterface $container
+ * @return RouteNotFoundStrategy
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, RouteNotFoundStrategy::class);
+ }
+
+ /**
+ * 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);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Console\Console;
+use Zend\Mvc\Router\RouteStackInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class ConsoleRouterFactory implements FactoryInterface
+{
+ use RouterConfigTrait;
+
+ /**
+ * Create and return the console router
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return RouteStackInterface
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $config = $container->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);
+ }
+
+ /**
+ * Create and return RouteStackInterface instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return RouteStackInterface
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, RouteStackInterface::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use ArrayAccess;
+use Interop\Container\ContainerInterface;
+
+trait ConsoleViewManagerConfigTrait
+{
+ /**
+ * Retrieve view_manager configuration, if present.
+ *
+ * @param ContainerInterface $container
+ * @return array
+ */
+ private function getConfig(ContainerInterface $container)
+ {
+ $config = $container->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
+ : [];
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+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\Mvc\View\Console\ViewManager as ConsoleViewManager;
+
+class ConsoleViewManagerFactory implements FactoryInterface
+{
+ /**
+ * Create and return the view manager for the console environment
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return ConsoleViewManager
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ if (! Console::isConsole()) {
+ throw new ServiceNotCreatedException(
+ 'ConsoleViewManager requires a Console environment; console environment not detected'
+ );
+ }
+
+ return new ConsoleViewManager();
+ }
+
+ /**
+ * Create and return ConsoleViewManager instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return ConsoleViewManager
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, ConsoleViewManager::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\Mvc\Controller\ControllerManager;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+/**
+ * @see \Zend\Mvc\Service\ControllerManagerFactory
+ * @deprecated please use Zend\Mvc\Service\ControllerManagerFactory instead;
+ * this class will be removed in release 3.0
+ */
+class ControllerLoaderFactory implements FactoryInterface
+{
+ /**
+ * Create the controller loader service
+ *
+ * Creates and returns an instance of ControllerManager. The
+ * only controllers this manager will allow are those defined in the
+ * application configuration's "controllers" array. If a controller is
+ * matched, the scoped manager will attempt to load the controller.
+ * Finally, it will attempt to inject the controller plugin manager
+ * if the controller implements a setPluginManager() method.
+ *
+ * This plugin manager is _not_ peered against DI, and as such, will
+ * not load unknown classes.
+ *
+ * @param ServiceLocatorInterface $serviceLocator
+ * @return ControllerManager
+ */
+ public function createService(ServiceLocatorInterface $serviceLocator)
+ {
+ trigger_error(sprintf(
+ '%s is deprecated; please use %s instead',
+ __CLASS__,
+ ControllerManagerFactory::class
+ ), E_USER_DEPRECATED);
+
+ $controllerLoader = new ControllerManager($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;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\Controller\ControllerManager;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class ControllerManagerFactory implements FactoryInterface
+{
+ /**
+ * Create the controller manager service
+ *
+ * Creates and returns an instance of ControllerManager. The
+ * only controllers this manager will allow are those defined in the
+ * application configuration's "controllers" array. If a controller is
+ * matched, the scoped manager will attempt to load the controller.
+ * Finally, it will attempt to inject the controller plugin manager
+ * if the controller implements a setPluginManager() method.
+ *
+ * @param ContainerInterface $container
+ * @param string $Name
+ * @param null|array $options
+ * @return ControllerManager
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ if ($options) {
+ return new ControllerManager($container, $options);
+ }
+ return new ControllerManager($container);
+ }
+
+ /**
+ * Create and return ControllerManager instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return ControllerManager
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, ControllerManager::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\Mvc\Controller\PluginManager as ControllerPluginManager;
+
+class ControllerPluginManagerFactory extends AbstractPluginManagerFactory
+{
+ const PLUGIN_MANAGER_CLASS = ControllerPluginManager::class;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\Exception;
+use Zend\ServiceManager\Di\DiAbstractServiceFactory;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\ServiceManager\ServiceManager;
+
+/**
+ * @deprecated Since 2.7.9. The factory is now defined in zend-servicemanager-di,
+ * and removed in 3.0.0. Use Zend\ServiceManager\Di\DiAbstractServiceFactoryFactory
+ * from zend-servicemanager-di if you are using zend-servicemanager v3, and/or when
+ * ready to migrate to zend-mvc 3.0.
+ */
+class DiAbstractServiceFactoryFactory implements FactoryInterface
+{
+ /**
+ * Class responsible for instantiating a DiAbstractServiceFactory
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return DiAbstractServiceFactory
+ * @throws Exception\RuntimeException if zend-servicemanager v3 is in use.
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ if (! class_exists(DiAbstractServiceFactory::class)) {
+ throw new Exception\RuntimeException(sprintf(
+ "%s is not compatible with zend-servicemanager v3, which you are currently using. \n"
+ . "Please run 'composer require zendframework/zend-servicemanager-di', and then update\n"
+ . "your configuration to use Zend\ServiceManager\Di\DiAbstractServiceFactoryFactory instead.",
+ __CLASS__
+ ));
+ }
+
+ $factory = new DiAbstractServiceFactory($container->get('Di'), DiAbstractServiceFactory::USE_SL_BEFORE_DI);
+
+ if ($container instanceof ServiceManager) {
+ $container->addAbstractFactory($factory, false);
+ }
+
+ return $factory;
+ }
+
+ /**
+ * Create and return DiAbstractServiceFactory instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return DiAbstractServiceFactory
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, DiAbstractServiceFactory::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Di\Config;
+use Zend\Di\Di;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+/**
+ * @deprecated Since 2.7.9. The factory is now defined in zend-servicemanager-di,
+ * and removed in 3.0.0. Use Zend\ServiceManager\Di\DiFactory from
+ * from zend-servicemanager-di if you are using zend-servicemanager v3, and/or when
+ * ready to migrate to zend-mvc 3.0.
+ */
+class DiFactory implements FactoryInterface
+{
+ /**
+ * Create and return abstract factory seeded by dependency injector
+ *
+ * Creates and returns an abstract factory seeded by the dependency
+ * injector. If the "di" key of the configuration service is set, that
+ * sub-array is passed to a DiConfig object and used to configure
+ * the DI instance. The DI instance is then used to seed the
+ * DiAbstractServiceFactory, which is then registered with the service
+ * manager.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return Di
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $di = new Di();
+ $config = $container->has('config') ? $container->get('config') : [];
+
+ if (isset($config['di'])) {
+ (new Config($config['di']))->configure($di);
+ }
+
+ return $di;
+ }
+
+ /**
+ * Create and return Di instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return Di
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, Di::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\Exception;
+use Zend\ServiceManager\Di\DiServiceInitializer;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\ServiceManager\ServiceManager;
+
+/**
+ * @deprecated Since 2.7.9. The factory is now defined in zend-servicemanager-di,
+ * and removed in 3.0.0. Use Zend\ServiceManager\Di\DiServiceInitializerFactory
+ * from zend-servicemanager-di if you are using zend-servicemanager v3, and/or when
+ * ready to migrate to zend-mvc 3.0.
+ */
+class DiServiceInitializerFactory implements FactoryInterface
+{
+ /**
+ * Class responsible for instantiating a DiServiceInitializer
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return DiServiceInitializer
+ */
+ public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
+ {
+ if (! class_exists(DiServiceInitializer::class)) {
+ throw new Exception\RuntimeException(sprintf(
+ "%s is not compatible with zend-servicemanager v3, which you are currently using. \n"
+ . "Please run 'composer require zendframework/zend-servicemanager-di', and then update\n"
+ . "your configuration to use Zend\ServiceManager\Di\DiServiceInitializerFactory instead.",
+ __CLASS__
+ ));
+ }
+
+ return new DiServiceInitializer($container->get('Di'), $container);
+ }
+
+ /**
+ * Create and return DiServiceInitializer instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return DiServiceInitializer
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, DiServiceInitializer::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Di\Di;
+use Zend\Di\Exception\ClassNotFoundException;
+use Zend\ServiceManager\AbstractFactoryInterface;
+use Zend\ServiceManager\AbstractPluginManager;
+use Zend\ServiceManager\Exception;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+/**
+ * Create and return instances from a DI container and/or the parent container.
+ *
+ * This abstract factory can be mapped to arbitrary class names, and used to
+ * pull them from the composed Di instance, using the following behaviors:
+ *
+ * - If USE_SL_BEFORE_DI is passed as the second argument to the constructor,
+ * the factory will attempt to fetch the service from the passed container
+ * first, and fall back to the composed DI container only on failure.
+ * - If USE_SL_AFTER_DI is passed as the second argument to the constructor,
+ * the factory will attempt to fetch the service from the composed DI
+ * container first, and fall back to the passed container only on failure.
+ * - If USE_SL_NONE is passed as the second argument to the constructor (or no
+ * argument is passed), then the factory will only fetch from the composed
+ * DI container.
+ *
+ * Unlike DiAbstractServiceFactory and DiServiceFactory, this abstract factory
+ * requires that classes requested are in a provided whitelist; if the requested
+ * service is not, an exception is raised. This is useful to provide a scoped
+ * container, e.g., to limit to known controller classes, etc.
+ *
+ * @deprecated Since 2.7.9. The factory is now defined in zend-servicemanager-di,
+ * and removed in 3.0.0. Use Zend\ServiceManager\Di\DiStrictAbstractServiceFactory
+ * from zend-servicemanager-di if you are using zend-servicemanager v3, and/or when
+ * ready to migrate to zend-mvc 3.0.
+ */
+class DiStrictAbstractServiceFactory extends Di implements AbstractFactoryInterface
+{
+ /**@#+
+ * constants
+ */
+ const USE_SL_BEFORE_DI = 'before';
+ const USE_SL_AFTER_DI = 'after';
+ const USE_SL_NONE = 'none';
+ /**@#-*/
+
+ /**
+ * @var Di
+ */
+ protected $di = null;
+
+ /**
+ * @var string
+ */
+ protected $useContainer = self::USE_SL_AFTER_DI;
+
+ /**
+ * @var ContainerInterface
+ */
+ protected $container = null;
+
+ /**
+ * @var array an array of whitelisted service names (keys are the service names)
+ */
+ protected $allowedServiceNames = [];
+
+ /**
+ * @param Di $di
+ * @param string $useContainer
+ */
+ public function __construct(Di $di, $useContainer = self::USE_SL_NONE)
+ {
+ $this->useContainer = $useContainer;
+
+ // 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 __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ if (! isset($this->allowedServiceNames[$name])) {
+ throw new Exception\InvalidServiceException(sprintf(
+ 'Service "%s" is not whitelisted',
+ $name
+ ));
+ }
+
+ $this->container = ($container instanceof AbstractPluginManager)
+ ? $container->getServiceLocator()
+ : $container;
+
+ return parent::get($name);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ */
+ public function createServiceWithName(ServiceLocatorInterface $container, $serviceName, $requestedName)
+ {
+ return $this($container, $requestedName);
+ }
+
+ /**
+ * Overrides Zend\Di to allow the given container's services to be reused by Di itself
+ *
+ * {@inheritDoc}
+ *
+ * @throws Exception\InvalidServiceNameException
+ */
+ public function get($name, array $params = [])
+ {
+ if (null === $this->container) {
+ throw new Exception\DomainException(
+ 'No ServiceLocator defined, use `createServiceWithName` instead of `get`'
+ );
+ }
+
+ if (self::USE_SL_BEFORE_DI === $this->useContainer && $this->container->has($name)) {
+ return $this->container->get($name);
+ }
+
+ try {
+ return parent::get($name, $params);
+ } catch (ClassNotFoundException $e) {
+ if (self::USE_SL_AFTER_DI === $this->useContainer && $this->container->has($name)) {
+ return $this->container->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 canCreate(ContainerInterface $container, $requestedName)
+ {
+ // won't check if the service exists, we are trusting the user's whitelist
+ return isset($this->allowedServiceNames[$requestedName]);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * For use with zend-servicemanager v2; proxies to canCreate().
+ */
+ public function canCreateServiceWithName(ServiceLocatorInterface $container, $name, $requestedName)
+ {
+ return $this->canCreate($container, $requestedName);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+/**
+ * @deprecated Since 2.7.9. The factory is now defined in zend-servicemanager-di,
+ * and removed in 3.0.0. Use Zend\ServiceManager\Di\DiStrictAbstractServiceFactoryFactory
+ * from zend-servicemanager-di if you are using zend-servicemanager v3, and/or when
+ * ready to migrate to zend-mvc 3.0.
+ */
+class DiStrictAbstractServiceFactoryFactory implements FactoryInterface
+{
+ /**
+ * Class responsible for instantiating a DiStrictAbstractServiceFactory
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return DiStrictAbstractServiceFactory
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $diAbstractFactory = new DiStrictAbstractServiceFactory(
+ $container->get('Di'),
+ DiStrictAbstractServiceFactory::USE_SL_BEFORE_DI
+ );
+ $config = $container->get('config');
+
+ if (isset($config['di']['allowed_controllers'])) {
+ $diAbstractFactory->setAllowedServiceNames($config['di']['allowed_controllers']);
+ }
+
+ return $diAbstractFactory;
+ }
+
+ /**
+ * Create and return DiStrictAbstractServiceFactory instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return DiStrictAbstractServiceFactory
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, DiStrictAbstractServiceFactory::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\DispatchListener;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class DispatchListenerFactory implements FactoryInterface
+{
+ /**
+ * Create the default dispatch listener.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return DispatchListener
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ return new DispatchListener($container->get('ControllerManager'));
+ }
+
+ /**
+ * Create and return DispatchListener instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return DispatchListener
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, DispatchListener::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use ReflectionClass;
+use Zend\EventManager\EventManager;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class EventManagerFactory implements FactoryInterface
+{
+ /**
+ * Create an EventManager instance
+ *
+ * Creates a new EventManager instance, seeding it with a shared instance
+ * of SharedEventManager.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return EventManager
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ if ($this->acceptsSharedManagerToConstructor()) {
+ // zend-eventmanager v3
+ return new EventManager(
+ $container->has('SharedEventManager') ? $container->get('SharedEventManager') : null
+ );
+ }
+
+ // zend-eventmanager v2
+ $events = new EventManager();
+
+ if ($container->has('SharedEventManager')) {
+ $events->setSharedManager($container->get('SharedEventManager'));
+ }
+
+ return $events;
+ }
+
+ /**
+ * Create and return EventManager instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return EventManager
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, EventManager::class);
+ }
+
+ /**
+ * Does the EventManager accept the shared manager to the constructor?
+ *
+ * In zend-eventmanager v3, the EventManager accepts the shared manager
+ * instance to the constructor *only*, while in v2, it must be injected
+ * via the setSharedManager() method.
+ *
+ * @return bool
+ */
+ private function acceptsSharedManagerToConstructor()
+ {
+ $r = new ReflectionClass(EventManager::class);
+ return ! $r->hasMethod('setSharedManager');
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\Filter\FilterPluginManager;
+
+class FilterManagerFactory extends AbstractPluginManagerFactory
+{
+ const PLUGIN_MANAGER_CLASS = FilterPluginManager::class;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\EventManager\ListenerAggregateInterface;
+use Zend\Form\Annotation\AnnotationBuilder;
+use Zend\ServiceManager\Exception\ServiceNotCreatedException;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class FormAnnotationBuilderFactory implements FactoryInterface
+{
+ /**
+ * Create service
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return AnnotationBuilder
+ * @throws ServiceNotCreatedException for invalid listener configuration.
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ //setup a form factory which can use custom form elements
+ $annotationBuilder = new AnnotationBuilder();
+ $eventManager = $container->get('EventManager');
+ $annotationBuilder->setEventManager($eventManager);
+
+ $formElementManager = $container->get('FormElementManager');
+ $formElementManager->injectFactory($container, $annotationBuilder);
+
+ $config = $container->get('config');
+ if (isset($config['form_annotation_builder'])) {
+ $config = $config['form_annotation_builder'];
+
+ if (isset($config['annotations'])) {
+ foreach ((array) $config['annotations'] as $fullyQualifiedClassName) {
+ $annotationBuilder->getAnnotationParser()->registerAnnotation($fullyQualifiedClassName);
+ }
+ }
+
+ if (isset($config['listeners'])) {
+ foreach ((array) $config['listeners'] as $listenerName) {
+ $listener = $container->get($listenerName);
+ if (!($listener instanceof ListenerAggregateInterface)) {
+ throw new ServiceNotCreatedException(sprintf('Invalid event listener (%s) provided', $listenerName));
+ }
+ $listener->attach($eventManager);
+ }
+ }
+
+ if (isset($config['preserve_defined_order'])) {
+ $annotationBuilder->setPreserveDefinedOrder($config['preserve_defined_order']);
+ }
+ }
+
+ return $annotationBuilder;
+ }
+
+ /**
+ * Create and return AnnotationBuilder instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return AnnotationBuilder
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, AnnotationBuilder::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\Form\FormElementManager;
+
+class FormElementManagerFactory extends AbstractPluginManagerFactory
+{
+ const PLUGIN_MANAGER_CLASS = FormElementManager::class;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\View\Http\DefaultRenderingStrategy;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\View\View;
+
+class HttpDefaultRenderingStrategyFactory implements FactoryInterface
+{
+ use HttpViewManagerConfigTrait;
+
+ /**
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return DefaultRenderingStrategy
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $strategy = new DefaultRenderingStrategy($container->get(View::class));
+ $config = $this->getConfig($container);
+
+ $this->injectLayoutTemplate($strategy, $config);
+
+ return $strategy;
+ }
+
+ /**
+ * Create and return DefaultRendererStrategy instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return DefaultRendererStrategy
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, DefaultRendererStrategy::class);
+ }
+
+ /**
+ * Inject layout template.
+ *
+ * Uses layout template from configuration; if none available, defaults to "layout/layout".
+ *
+ * @param DefaultRendererStrategy $strategy
+ * @param array $config
+ */
+ private function injectLayoutTemplate(DefaultRenderingStrategy $strategy, array $config)
+ {
+ $layout = isset($config['layout']) ? $config['layout'] : 'layout/layout';
+ $strategy->setLayoutTemplate($layout);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\View\Http\ExceptionStrategy;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class HttpExceptionStrategyFactory implements FactoryInterface
+{
+ use HttpViewManagerConfigTrait;
+
+ /**
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return ExceptionStrategy
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $strategy = new ExceptionStrategy();
+ $config = $this->getConfig($container);
+
+ $this->injectDisplayExceptions($strategy, $config);
+ $this->injectExceptionTemplate($strategy, $config);
+
+ return $strategy;
+ }
+
+ /**
+ * Create and return ExceptionStrategy instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return ExceptionStrategy
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, ExceptionStrategy::class);
+ }
+
+ /**
+ * 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);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\HttpMethodListener;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class HttpMethodListenerFactory implements FactoryInterface
+{
+ /**
+ * {@inheritdoc}
+ * @return HttpMethodListener
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $config = $container->get('config');
+
+ if (! isset($config['http_methods_listener'])) {
+ return new HttpMethodListener();
+ }
+
+ $listenerConfig = $config['http_methods_listener'];
+ $enabled = array_key_exists('enabled', $listenerConfig)
+ ? $listenerConfig['enabled']
+ : true;
+ $allowedMethods = (isset($listenerConfig['allowed_methods']) && is_array($listenerConfig['allowed_methods']))
+ ? $listenerConfig['allowed_methods']
+ : null;
+
+ return new HttpMethodListener($enabled, $allowedMethods);
+ }
+
+ /**
+ * Create and return HttpMethodListener instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return HttpMethodListener
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, HttpMethodListener::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\View\Http\RouteNotFoundStrategy;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class HttpRouteNotFoundStrategyFactory implements FactoryInterface
+{
+ use HttpViewManagerConfigTrait;
+
+ /**
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return RouteNotFoundStrategy
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $strategy = new RouteNotFoundStrategy();
+ $config = $this->getConfig($container);
+
+ $this->injectDisplayExceptions($strategy, $config);
+ $this->injectDisplayNotFoundReason($strategy, $config);
+ $this->injectNotFoundTemplate($strategy, $config);
+
+ return $strategy;
+ }
+
+ /**
+ * Create and return RouteNotFoundStrategy instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return RouteNotFoundStrategy
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, RouteNotFoundStrategy::class);
+ }
+
+ /**
+ * 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);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\Router\RouteStackInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class HttpRouterFactory implements FactoryInterface
+{
+ use RouterConfigTrait;
+
+ /**
+ * Create and return the HTTP router
+ *
+ * Retrieves the "router" key of the Config service, and uses it
+ * to instantiate the router. Uses the TreeRouteStack implementation by
+ * default.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return RouteStackInterface
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $config = $container->has('config') ? $container->get('config') : [];
+
+ // Defaults
+ $class = 'Zend\Mvc\Router\Http\TreeRouteStack';
+ $config = isset($config['router']) ? $config['router'] : [];
+
+ return $this->createRouter($class, $config, $container);
+ }
+
+ /**
+ * Create and return RouteStackInterface instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return RouteStackInterface
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, RouteStackInterface::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use ArrayAccess;
+use Interop\Container\ContainerInterface;
+
+trait HttpViewManagerConfigTrait
+{
+ /**
+ * Retrieve view_manager configuration, if present.
+ *
+ * @param ContainerInterface $container
+ * @return array
+ */
+ private function getConfig(ContainerInterface $container)
+ {
+ $config = $container->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 [];
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\View\Http\ViewManager as HttpViewManager;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class HttpViewManagerFactory implements FactoryInterface
+{
+ /**
+ * Create and return a view manager for the HTTP environment
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return HttpViewManager
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ return new HttpViewManager();
+ }
+
+ /**
+ * Create and return HttpViewManager instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return HttpViewManager
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, HttpViewManager::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\Hydrator\HydratorPluginManager;
+
+class HydratorManagerFactory extends AbstractPluginManagerFactory
+{
+ const PLUGIN_MANAGER_CLASS = HydratorPluginManager::class;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Mvc\View\Http\InjectTemplateListener;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class InjectTemplateListenerFactory implements FactoryInterface
+{
+ /**
+ * {@inheritDoc}
+ *
+ * Create and return an InjectTemplateListener instance.
+ *
+ * @return InjectTemplateListener
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $listener = new InjectTemplateListener();
+ $config = $container->get('config');
+
+ if (isset($config['view_manager']['controller_map'])
+ && (is_array($config['view_manager']['controller_map']))
+ ) {
+ $listener->setControllerMap($config['view_manager']['controller_map']);
+ }
+
+ return $listener;
+ }
+
+ /**
+ * Create and return InjectTemplateListener instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return InjectTemplateListener
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, InjectTemplateListener::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\InputFilter\InputFilterPluginManager;
+
+class InputFilterManagerFactory extends AbstractPluginManagerFactory
+{
+ const PLUGIN_MANAGER_CLASS = InputFilterPluginManager::class;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\Log\ProcessorPluginManager as LogProcessorPluginManager;
+
+class LogProcessorManagerFactory extends AbstractPluginManagerFactory
+{
+ const PLUGIN_MANAGER_CLASS = LogProcessorPluginManager::class;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\Log\WriterPluginManager as LogWriterPluginManager;
+
+class LogWriterManagerFactory extends AbstractPluginManagerFactory
+{
+ const PLUGIN_MANAGER_CLASS = LogWriterPluginManager::class;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+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;
+
+class ModuleManagerFactory implements FactoryInterface
+{
+ /**
+ * Creates and returns the module manager
+ *
+ * Instantiates the default module listeners, providing them configuration
+ * from the "module_listener_options" key of the ApplicationConfig
+ * service. Also sets the default config glob path.
+ *
+ * Module manager is instantiated and provided with an EventManager, to which
+ * the default listener aggregate is attached. The ModuleEvent is also created
+ * and attached to the module manager.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return ModuleManager
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $configuration = $container->get('ApplicationConfig');
+ $listenerOptions = new ListenerOptions($configuration['module_listener_options']);
+ $defaultListeners = new DefaultListenerAggregate($listenerOptions);
+ $serviceListener = $container->get('ServiceListener');
+
+ $serviceListener->addServiceManager(
+ $container,
+ 'service_manager',
+ 'Zend\ModuleManager\Feature\ServiceProviderInterface',
+ 'getServiceConfig'
+ );
+
+ $serviceListener->addServiceManager(
+ 'ControllerManager',
+ 'controllers',
+ 'Zend\ModuleManager\Feature\ControllerProviderInterface',
+ 'getControllerConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'ControllerPluginManager',
+ 'controller_plugins',
+ 'Zend\ModuleManager\Feature\ControllerPluginProviderInterface',
+ 'getControllerPluginConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'ViewHelperManager',
+ 'view_helpers',
+ 'Zend\ModuleManager\Feature\ViewHelperProviderInterface',
+ 'getViewHelperConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'ValidatorManager',
+ 'validators',
+ 'Zend\ModuleManager\Feature\ValidatorProviderInterface',
+ 'getValidatorConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'FilterManager',
+ 'filters',
+ 'Zend\ModuleManager\Feature\FilterProviderInterface',
+ 'getFilterConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'FormElementManager',
+ 'form_elements',
+ 'Zend\ModuleManager\Feature\FormElementProviderInterface',
+ 'getFormElementConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'RoutePluginManager',
+ 'route_manager',
+ 'Zend\ModuleManager\Feature\RouteProviderInterface',
+ 'getRouteConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'SerializerAdapterManager',
+ 'serializers',
+ 'Zend\ModuleManager\Feature\SerializerProviderInterface',
+ 'getSerializerConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'HydratorManager',
+ 'hydrators',
+ 'Zend\ModuleManager\Feature\HydratorProviderInterface',
+ 'getHydratorConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'InputFilterManager',
+ 'input_filters',
+ 'Zend\ModuleManager\Feature\InputFilterProviderInterface',
+ 'getInputFilterConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'LogProcessorManager',
+ 'log_processors',
+ 'Zend\ModuleManager\Feature\LogProcessorProviderInterface',
+ 'getLogProcessorConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'LogWriterManager',
+ 'log_writers',
+ 'Zend\ModuleManager\Feature\LogWriterProviderInterface',
+ 'getLogWriterConfig'
+ );
+ $serviceListener->addServiceManager(
+ 'TranslatorPluginManager',
+ 'translator_plugins',
+ 'Zend\ModuleManager\Feature\TranslatorPluginProviderInterface',
+ 'getTranslatorPluginConfig'
+ );
+
+ $events = $container->get('EventManager');
+ $defaultListeners->attach($events);
+ $serviceListener->attach($events);
+
+ $moduleEvent = new ModuleEvent;
+ $moduleEvent->setParam('ServiceManager', $container);
+
+ $moduleManager = new ModuleManager($configuration['modules'], $events);
+ $moduleManager->setEvent($moduleEvent);
+
+ return $moduleManager;
+ }
+
+ /**
+ * Create and return ModuleManager instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return ModuleManager
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, ModuleManager::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\Paginator\AdapterPluginManager as PaginatorPluginManager;
+
+class PaginatorPluginManagerFactory extends AbstractPluginManagerFactory
+{
+ const PLUGIN_MANAGER_CLASS = PaginatorPluginManager::class;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+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;
+
+class RequestFactory implements FactoryInterface
+{
+ /**
+ * Create and return a request instance, according to current environment.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return ConsoleRequest|HttpRequest
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ if (Console::isConsole()) {
+ return new ConsoleRequest();
+ }
+
+ return new HttpRequest();
+ }
+
+ /**
+ * Create and return HttpRequest or ConsoleRequest instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return HttpRequest|ConsoleRequest
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ $type = Console::isConsole() ? ConsoleRequest::class : HttpRequest::class;
+ return $this($container, $type);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+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\Stdlib\MessageInterface;
+
+class ResponseFactory implements FactoryInterface
+{
+ /**
+ * Create and return a response instance, according to current environment.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return MessageInterface
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ if (Console::isConsole()) {
+ return new ConsoleResponse();
+ }
+
+ return new HttpResponse();
+ }
+
+ /**
+ * Create and return MessageInterface instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return MessageInterface
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, MessageInterface::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\Mvc\Router\RoutePluginManager;
+
+class RoutePluginManagerFactory extends AbstractPluginManagerFactory
+{
+ const PLUGIN_MANAGER_CLASS = RoutePluginManager::class;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+
+trait RouterConfigTrait
+{
+ /**
+ * Create and return a router instance, by calling the appropriate factory.
+ *
+ * @param string $class
+ * @param array $config
+ * @param ContainerInterface $container
+ */
+ private function createRouter($class, array $config, ContainerInterface $container)
+ {
+ // Obtain the configured router class, if any
+ if (isset($config['router_class']) && class_exists($config['router_class'])) {
+ $class = $config['router_class'];
+ }
+
+ // Inject the route plugins
+ if (! isset($config['route_plugins'])) {
+ $routePluginManager = $container->get('RoutePluginManager');
+ $config['route_plugins'] = $routePluginManager;
+ }
+
+ // Obtain an instance
+ $factory = sprintf('%s::factory', $class);
+ return call_user_func($factory, $config);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Console\Console;
+use Zend\Mvc\Router\RouteStackInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class RouterFactory implements FactoryInterface
+{
+ /**
+ * Create and return the router
+ *
+ * Delegates to either the ConsoleRouter or HttpRouter service based
+ * on the environment type.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return RouteStackInterface
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ // Console environment?
+ if ($name === 'ConsoleRouter' // force console router
+ || (strtolower($name) === 'router' && Console::isConsole()) // auto detect console
+ ) {
+ return $container->get('ConsoleRouter');
+ }
+
+ return $container->get('HttpRouter');
+ }
+
+ /**
+ * Create and return RouteStackInterface instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @param null|string $normalizedName
+ * @param null|string $requestedName
+ * @return RouteStackInterface
+ */
+ public function createService(ServiceLocatorInterface $container, $normalizedName = null, $requestedName = null)
+ {
+ if ($normalizedName === 'router' && Console::isConsole()) {
+ $requestedName = 'ConsoleRouter';
+ }
+
+ return $this($container, $requestedName);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\Serializer\AdapterPluginManager as SerializerAdapterPluginManager;
+
+class SerializerAdapterPluginManagerFactory extends AbstractPluginManagerFactory
+{
+ const PLUGIN_MANAGER_CLASS = SerializerAdapterPluginManager::class;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use ReflectionClass;
+use Zend\Config\Config;
+use Zend\ModuleManager\Listener\ServiceListener;
+use Zend\ModuleManager\Listener\ServiceListenerInterface;
+use Zend\Mvc\Application;
+use Zend\Mvc\View;
+use Zend\ServiceManager\Exception\ServiceNotCreatedException;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\Factory\InvokableFactory;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class ServiceListenerFactory implements FactoryInterface
+{
+ /**
+ * @var string
+ */
+ const MISSING_KEY_ERROR = 'Invalid service listener options detected, %s array must contain %s key.';
+
+ /**
+ * @var string
+ */
+ const VALUE_TYPE_ERROR = 'Invalid service listener options detected, %s must be a string, %s given.';
+
+ /**
+ * 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 = [
+ 'aliases' => [
+ 'configuration' => 'config',
+ 'Configuration' => 'config',
+ 'console' => 'ConsoleAdapter',
+ 'Console' => 'ConsoleAdapter',
+ 'ConsoleDefaultRenderingStrategy' => View\Console\DefaultRenderingStrategy::class,
+ 'ControllerLoader' => 'ControllerManager',
+ 'Di' => 'DependencyInjector',
+ 'HttpDefaultRenderingStrategy' => View\Http\DefaultRenderingStrategy::class,
+ 'MiddlewareListener' => 'Zend\Mvc\MiddlewareListener',
+ 'RouteListener' => 'Zend\Mvc\RouteListener',
+ 'SendResponseListener' => 'Zend\Mvc\SendResponseListener',
+ 'View' => 'Zend\View\View',
+ 'ViewFeedRenderer' => 'Zend\View\Renderer\FeedRenderer',
+ 'ViewJsonRenderer' => 'Zend\View\Renderer\JsonRenderer',
+ 'ViewPhpRendererStrategy' => 'Zend\View\Strategy\PhpRendererStrategy',
+ 'ViewPhpRenderer' => 'Zend\View\Renderer\PhpRenderer',
+ 'ViewRenderer' => 'Zend\View\Renderer\PhpRenderer',
+ 'Zend\Di\LocatorInterface' => 'DependencyInjector',
+ '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',
+ ],
+ 'invokables' => [],
+ 'factories' => [
+ 'Application' => ApplicationFactory::class,
+ 'config' => 'Zend\Mvc\Service\ConfigFactory',
+ 'ControllerManager' => 'Zend\Mvc\Service\ControllerManagerFactory',
+ 'ControllerPluginManager' => 'Zend\Mvc\Service\ControllerPluginManagerFactory',
+ 'ConsoleAdapter' => 'Zend\Mvc\Service\ConsoleAdapterFactory',
+ 'ConsoleExceptionStrategy' => ConsoleExceptionStrategyFactory::class,
+ 'ConsoleRouter' => ConsoleRouterFactory::class,
+ 'ConsoleRouteNotFoundStrategy' => ConsoleRouteNotFoundStrategyFactory::class,
+ 'ConsoleViewManager' => 'Zend\Mvc\Service\ConsoleViewManagerFactory',
+ 'DependencyInjector' => DiFactory::class,
+ 'DiAbstractServiceFactory' => DiAbstractServiceFactoryFactory::class,
+ 'DiServiceInitializer' => DiServiceInitializerFactory::class,
+ 'DiStrictAbstractServiceFactory' => DiStrictAbstractServiceFactoryFactory::class,
+ 'DispatchListener' => 'Zend\Mvc\Service\DispatchListenerFactory',
+ 'FilterManager' => 'Zend\Mvc\Service\FilterManagerFactory',
+ 'FormAnnotationBuilder' => 'Zend\Mvc\Service\FormAnnotationBuilderFactory',
+ 'FormElementManager' => 'Zend\Mvc\Service\FormElementManagerFactory',
+ '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',
+ 'InputFilterManager' => 'Zend\Mvc\Service\InputFilterManagerFactory',
+ 'LogProcessorManager' => 'Zend\Mvc\Service\LogProcessorManagerFactory',
+ 'LogWriterManager' => 'Zend\Mvc\Service\LogWriterManagerFactory',
+ 'MvcTranslator' => 'Zend\Mvc\Service\TranslatorServiceFactory',
+ 'PaginatorPluginManager' => 'Zend\Mvc\Service\PaginatorPluginManagerFactory',
+ 'Request' => 'Zend\Mvc\Service\RequestFactory',
+ 'Response' => 'Zend\Mvc\Service\ResponseFactory',
+ 'Router' => 'Zend\Mvc\Service\RouterFactory',
+ 'RoutePluginManager' => 'Zend\Mvc\Service\RoutePluginManagerFactory',
+ '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',
+ 'ViewResolver' => 'Zend\Mvc\Service\ViewResolverFactory',
+ 'ViewTemplateMapResolver' => 'Zend\Mvc\Service\ViewTemplateMapResolverFactory',
+ 'ViewTemplatePathStack' => 'Zend\Mvc\Service\ViewTemplatePathStackFactory',
+ 'ViewPrefixPathStackResolver' => 'Zend\Mvc\Service\ViewPrefixPathStackResolverFactory',
+ 'Zend\Mvc\MiddlewareListener' => InvokableFactory::class,
+ 'Zend\Mvc\RouteListener' => InvokableFactory::class,
+ 'Zend\Mvc\SendResponseListener' => InvokableFactory::class,
+ 'Zend\View\Renderer\FeedRenderer' => InvokableFactory::class,
+ 'Zend\View\Renderer\JsonRenderer' => InvokableFactory::class,
+ 'Zend\View\Renderer\PhpRenderer' => ViewPhpRendererFactory::class,
+ 'Zend\View\Strategy\PhpRendererStrategy' => ViewPhpRendererStrategyFactory::class,
+ 'Zend\View\View' => ViewFactory::class,
+ ],
+ 'abstract_factories' => [
+ 'Zend\Form\FormAbstractServiceFactory',
+ ],
+ ];
+
+ /**
+ * Constructor
+ *
+ * When executed under zend-servicemanager v3, injects additional aliases
+ * to ensure backwards compatibility.
+ */
+ public function __construct()
+ {
+ $r = new ReflectionClass(ServiceLocatorInterface::class);
+ if ($r->hasMethod('build')) {
+ $this->injectV3Aliases();
+ }
+ }
+
+ /**
+ * Create the service listener service
+ *
+ * Tries to get a service named ServiceListenerInterface from the service
+ * locator, otherwise creates a ServiceListener instance, passing it the
+ * container instance and the default service configuration, which can be
+ * overridden by modules.
+ *
+ * It looks for the 'service_listener_options' key in the application
+ * config and tries to add service/plugin managers as configured. The value
+ * of 'service_listener_options' must be a list (array) which contains the
+ * following keys:
+ *
+ * - service_manager: the name of the service manage to create as string
+ * - config_key: the name of the configuration key to search for as string
+ * - interface: the name of the interface that modules can implement as string
+ * - method: the name of the method that modules have to implement as string
+ *
+ * @param ServiceLocatorInterface $serviceLocator
+ * @return ServiceListenerInterface
+ * @throws ServiceNotCreatedException for invalid ServiceListener service
+ * @throws ServiceNotCreatedException For invalid configurations.
+ */
+ public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
+ {
+ $configuration = $container->get('ApplicationConfig');
+
+ $serviceListener = $container->has('ServiceListenerInterface')
+ ? $container->get('ServiceListenerInterface')
+ : new ServiceListener($container);
+
+ if (! $serviceListener instanceof ServiceListenerInterface) {
+ throw new ServiceNotCreatedException(
+ 'The service named ServiceListenerInterface must implement '
+ . ServiceListenerInterface::class
+ );
+ }
+
+ $serviceListener->setDefaultServiceConfig($this->defaultServiceConfig);
+
+ if (isset($configuration['service_listener_options'])) {
+ $this->injectServiceListenerOptions($configuration['service_listener_options'], $serviceListener);
+ }
+
+ return $serviceListener;
+ }
+
+ /**
+ * Create and return the ServiceListener (v2)
+ *
+ * @param ServiceLocatorInterface $container
+ * @return ServiceListenerInterface
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, ServiceListener::class);
+ }
+
+ /**
+ * 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'])
+ ));
+ }
+ }
+
+ /**
+ * Inject additional aliases for zend-servicemanager v3 usage
+ *
+ * If the constructor detects that we're operating under zend-servicemanager v3,
+ * this method injects additional aliases to ensure that common services
+ * can be retrieved using both Titlecase and lowercase, and will get the
+ * same instances.
+ *
+ * @return void
+ */
+ private function injectV3Aliases()
+ {
+ $this->defaultServiceConfig['aliases']['application'] = 'Application';
+ $this->defaultServiceConfig['aliases']['Config'] = 'config';
+ $this->defaultServiceConfig['aliases']['request'] = 'Request';
+ $this->defaultServiceConfig['aliases']['response'] = 'Response';
+ $this->defaultServiceConfig['aliases']['router'] = 'Router';
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\EventManager\EventManager;
+use Zend\EventManager\EventManagerAwareInterface;
+use Zend\EventManager\EventManagerInterface;
+use Zend\EventManager\SharedEventManager;
+use Zend\EventManager\SharedEventManagerInterface;
+use Zend\ModuleManager\Listener\ServiceListener;
+use Zend\ModuleManager\ModuleManager;
+use Zend\ServiceManager\AbstractPluginManager;
+use Zend\ServiceManager\Config;
+use Zend\ServiceManager\ServiceLocatorAwareInterface;
+use Zend\ServiceManager\ServiceManager;
+use Zend\ServiceManager\ServiceManagerAwareInterface;
+use Zend\Stdlib\ArrayUtils;
+
+class ServiceManagerConfig extends Config
+{
+
+ /**
+ * Default service configuration.
+ *
+ * In addition to these, the constructor registers several factories and
+ * initializers; see that method for details.
+ *
+ * @var array
+ */
+ protected $config = [
+ 'abstract_factories' => [],
+ 'aliases' => [
+ 'EventManagerInterface' => EventManager::class,
+ EventManagerInterface::class => 'EventManager',
+ ModuleManager::class => 'ModuleManager',
+ ServiceListener::class => 'ServiceListener',
+ SharedEventManager::class => 'SharedEventManager',
+ 'SharedEventManagerInterface' => 'SharedEventManager',
+ SharedEventManagerInterface::class => 'SharedEventManager',
+ ],
+ 'delegators' => [],
+ 'factories' => [
+ 'EventManager' => EventManagerFactory::class,
+ 'ModuleManager' => ModuleManagerFactory::class,
+ 'ServiceListener' => ServiceListenerFactory::class,
+ ],
+ 'lazy_services' => [],
+ 'initializers' => [],
+ 'invokables' => [],
+ 'services' => [],
+ 'shared' => [
+ 'EventManager' => false,
+ ],
+ ];
+
+ /**
+ * Constructor
+ *
+ * Merges internal arrays with those passed via configuration, and also
+ * defines:
+ *
+ * - factory for the service 'SharedEventManager'.
+ * - initializer for EventManagerAwareInterface implementations
+ * - initializer for ServiceManagerAwareInterface implementations
+ * - initializer for ServiceLocatorAwareInterface implementations
+ *
+ * @param array $config
+ */
+ public function __construct(array $config = [])
+ {
+ $this->config['factories']['ServiceManager'] = function ($container) {
+ return $container;
+ };
+
+ $this->config['factories']['SharedEventManager'] = function () {
+ return new SharedEventManager();
+ };
+
+ $this->config['initializers'] = ArrayUtils::merge($this->config['initializers'], [
+ 'EventManagerAwareInitializer' => function ($first, $second) {
+ if ($first instanceof ContainerInterface) {
+ $container = $first;
+ $instance = $second;
+ } else {
+ $container = $second;
+ $instance = $first;
+ }
+
+ if (! $instance instanceof EventManagerAwareInterface) {
+ return;
+ }
+
+ $eventManager = $instance->getEventManager();
+
+ // If the instance has an EM WITH an SEM composed, do nothing.
+ if ($eventManager instanceof EventManagerInterface
+ && $eventManager->getSharedManager() instanceof SharedEventManagerInterface
+ ) {
+ return;
+ }
+
+ $instance->setEventManager($container->get('EventManager'));
+ },
+ 'ServiceManagerAwareInitializer' => function ($first, $second) {
+ if ($first instanceof ContainerInterface) {
+ // zend-servicemanager v3
+ $container = $first;
+ $instance = $second;
+ } else {
+ // zend-servicemanager v2
+ $container = $second;
+ $instance = $first;
+ }
+
+ if ($container instanceof ServiceManager && $instance instanceof ServiceManagerAwareInterface) {
+ trigger_error(sprintf(
+ 'ServiceManagerAwareInterface is deprecated and will be removed in version 3.0, along '
+ . 'with the ServiceManagerAwareInitializer. Please update your class %s to remove '
+ . 'the implementation, and start injecting your dependencies via factory instead.',
+ get_class($instance)
+ ), E_USER_DEPRECATED);
+ $instance->setServiceManager($container);
+ }
+ },
+ 'ServiceLocatorAwareInitializer' => function ($first, $second) {
+ if ($first instanceof AbstractPluginManager) {
+ // Edge case under zend-servicemanager v2
+ $container = $second;
+ $instance = $first;
+ } elseif ($first instanceof ContainerInterface) {
+ // zend-servicemanager v3
+ $container = $first;
+ $instance = $second;
+ } else {
+ // zend-servicemanager v2
+ $container = $second;
+ $instance = $first;
+ }
+
+ // For service locator aware classes, inject the service
+ // locator, but emit a deprecation notice. Skip plugin manager
+ // implementations; they're dealt with later.
+ if ($instance instanceof ServiceLocatorAwareInterface
+ && ! $instance instanceof AbstractPluginManager
+ ) {
+ trigger_error(sprintf(
+ 'ServiceLocatorAwareInterface is deprecated and will be removed in version 3.0, along '
+ . 'with the ServiceLocatorAwareInitializer. Please update your class %s to remove '
+ . 'the implementation, and start injecting your dependencies via factory instead.',
+ get_class($instance)
+ ), E_USER_DEPRECATED);
+ $instance->setServiceLocator($container);
+ }
+
+ // For service locator aware plugin managers that do not have
+ // the service locator already injected, inject it, but emit a
+ // deprecation notice.
+ if ($instance instanceof ServiceLocatorAwareInterface
+ && $instance instanceof AbstractPluginManager
+ && ! $instance->getServiceLocator()
+ ) {
+ trigger_error(sprintf(
+ 'ServiceLocatorAwareInterface is deprecated and will be removed in version 3.0, along '
+ . 'with the ServiceLocatorAwareInitializer. Please update your %s plugin manager factory '
+ . 'to inject the parent service locator via the constructor.',
+ get_class($instance)
+ ), E_USER_DEPRECATED);
+ $instance->setServiceLocator($container);
+ }
+ },
+ ]);
+
+ // In zend-servicemanager v2, incoming configuration is not merged
+ // with existing; it replaces. So we need to detect that and merge.
+ if (method_exists($this, 'getAllowOverride')) {
+ $config = ArrayUtils::merge($this->config, $config);
+ }
+
+ parent::__construct($config);
+ }
+
+ /**
+ * Configure service container.
+ *
+ * Uses the configuration present in the instance to configure the provided
+ * service container.
+ *
+ * Before doing so, it adds a "service" entry for the ServiceManager class,
+ * pointing to the provided service container.
+ *
+ * @param ServiceManager $services
+ * @return ServiceManager
+ */
+ public function configureServiceManager(ServiceManager $services)
+ {
+ $this->config['services'][ServiceManager::class] = $services;
+
+ /*
+ printf("Configuration prior to configuring servicemanager:\n");
+ foreach ($this->config as $type => $list) {
+ switch ($type) {
+ case 'aliases':
+ case 'delegators':
+ case 'factories':
+ case 'invokables':
+ case 'lazy_services':
+ case 'services':
+ case 'shared':
+ foreach (array_keys($list) as $name) {
+ printf(" %s (%s)\n", $name, $type);
+ }
+ break;
+
+ case 'initializers':
+ case 'abstract_factories':
+ foreach ($list as $callable) {
+ printf(" %s (%s)\n", (is_object($callable) ? get_class($callable) : $callable), $type);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ */
+
+ // This is invoked as part of the bootstrapping process, and requires
+ // the ability to override services.
+ $services->setAllowOverride(true);
+ parent::configureServiceManager($services);
+ $services->setAllowOverride(false);
+
+ return $services;
+ }
+
+ /**
+ * Return all service configuration (v3)
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return $this->config;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\I18n\Translator\LoaderPluginManager as TranslatorLoaderPluginManager;
+
+class TranslatorPluginManagerFactory extends AbstractPluginManagerFactory
+{
+ const PLUGIN_MANAGER_CLASS = TranslatorLoaderPluginManager::class;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+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;
+
+/**
+ * Overrides the translator factory from the i18n component in order to
+ * replace it with the bridge class from this namespace.
+ */
+class TranslatorServiceFactory implements FactoryInterface
+{
+ /**
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return MvcTranslator
+ */
+ 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 ($container->has('Zend\I18n\Translator\TranslatorInterface')) {
+ return new MvcTranslator($container->get('Zend\I18n\Translator\TranslatorInterface'));
+ }
+
+ // Load a translator from configuration, if possible
+ if ($container->has('config')) {
+ $config = $container->get('config');
+
+ // 'translator' => false
+ if (array_key_exists('translator', $config) && $config['translator'] === false) {
+ return new MvcTranslator(new DummyTranslator());
+ }
+
+ // 'translator' => array( ... translator options ... )
+ if (array_key_exists('translator', $config)
+ && ((is_array($config['translator']) && !empty($config['translator']))
+ || $config['translator'] instanceof Traversable)
+ ) {
+ $i18nTranslator = Translator::factory($config['translator']);
+ $i18nTranslator->setPluginManager($container->get('TranslatorPluginManager'));
+ $container->setService('Zend\I18n\Translator\TranslatorInterface', $i18nTranslator);
+ return new MvcTranslator($i18nTranslator);
+ }
+ }
+
+ // If ext/intl is not loaded, return a dummy translator
+ if (!extension_loaded('intl')) {
+ return new MvcTranslator(new DummyTranslator());
+ }
+
+ // For BC purposes (pre-2.3.0), use the I18n Translator
+ return new MvcTranslator(new Translator());
+ }
+
+ /**
+ * Create and return MvcTranslator instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return MvcTranslator
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, MvcTranslator::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Zend\Validator\ValidatorPluginManager;
+
+class ValidatorManagerFactory extends AbstractPluginManagerFactory
+{
+ const PLUGIN_MANAGER_CLASS = ValidatorPluginManager::class;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\View\Strategy\PhpRendererStrategy;
+use Zend\View\View;
+
+class ViewFactory implements FactoryInterface
+{
+ /**
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return View
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $view = new View();
+ $events = $container->get('EventManager');
+
+ $view->setEventManager($events);
+ $container->get(PhpRendererStrategy::class)->attach($events);
+
+ return $view;
+ }
+
+ /**
+ * Create and return View instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return View
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, View::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\View\Strategy\FeedStrategy;
+
+class ViewFeedStrategyFactory implements FactoryInterface
+{
+ /**
+ * Create and return the Feed view strategy
+ *
+ * Retrieves the ViewFeedRenderer service from the service locator, and
+ * injects it into the constructor for the feed strategy.
+ *
+ * It then attaches the strategy to the View service, at a priority of 100.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return FeedStrategy
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ return new FeedStrategy($container->get('ViewFeedRenderer'));
+ }
+
+ /**
+ * Create and return FeedStrategy instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return FeedStrategy
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, FeedStrategy::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Console\Console;
+use Zend\Mvc\Router\RouteMatch;
+use Zend\ServiceManager\ConfigInterface;
+use Zend\ServiceManager\Exception\ServiceNotCreatedException;
+use Zend\View\Helper as ViewHelper;
+use Zend\View\HelperPluginManager;
+
+class ViewHelperManagerFactory extends AbstractPluginManagerFactory
+{
+ 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',
+ ];
+
+ /**
+ * Create and return the view helper manager
+ *
+ * @param ContainerInterface $container
+ * @return HelperPluginManager
+ * @throws ServiceNotCreatedException
+ */
+ public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
+ {
+ $options = $options ?: [];
+ $options['factories'] = isset($options['factories']) ? $options['factories'] : [];
+ $plugins = parent::__invoke($container, $requestedName, $options);
+
+ // Configure default helpers from other components
+ $plugins = $this->configureHelpers($plugins);
+
+ // Override plugin factories
+ $plugins = $this->injectOverrideFactories($plugins, $container);
+
+ return $plugins;
+ }
+
+ /**
+ * Configure helpers from other components.
+ *
+ * Loops through the list of default helper configuration classes, and uses
+ * each to configure the helper plugin manager.
+ *
+ * @param HelperPluginManager $plugins
+ * @return HelperPluginManager
+ */
+ private function configureHelpers(HelperPluginManager $plugins)
+ {
+ foreach ($this->defaultHelperMapClasses as $configClass) {
+ 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
+ ));
+ }
+
+ $config->configureServiceManager($plugins);
+ }
+
+ return $plugins;
+ }
+
+ /**
+ * Inject override factories into the plugin manager.
+ *
+ * @param HelperPluginManager $plugins
+ * @param ContainerInterface $services
+ * @return HelperPluginManager
+ */
+ private function injectOverrideFactories(HelperPluginManager $plugins, ContainerInterface $services)
+ {
+ // Configure URL view helper
+ $urlFactory = $this->createUrlHelperFactory($services);
+ $plugins->setFactory(ViewHelper\Url::class, $urlFactory);
+ $plugins->setFactory('zendviewhelperurl', $urlFactory);
+
+ // Configure base path helper
+ $basePathFactory = $this->createBasePathHelperFactory($services);
+ $plugins->setFactory(ViewHelper\BasePath::class, $basePathFactory);
+ $plugins->setFactory('zendviewhelperbasepath', $basePathFactory);
+
+ // Configure doctype view helper
+ $doctypeFactory = $this->createDoctypeHelperFactory($services);
+ $plugins->setFactory(ViewHelper\Doctype::class, $doctypeFactory);
+ $plugins->setFactory('zendviewhelperdoctype', $doctypeFactory);
+
+ return $plugins;
+ }
+
+ /**
+ * Create and return a factory for creating a URL helper.
+ *
+ * Retrieves the application and router from the servicemanager,
+ * and the route match from the MvcEvent composed by the application,
+ * using them to configure the helper.
+ *
+ * @param ContainerInterface $services
+ * @return callable
+ */
+ private function createUrlHelperFactory(ContainerInterface $services)
+ {
+ return function () use ($services) {
+ $helper = new ViewHelper\Url;
+ $router = Console::isConsole() ? 'HttpRouter' : 'Router';
+ $helper->setRouter($services->get($router));
+
+ $match = $services->get('Application')
+ ->getMvcEvent()
+ ->getRouteMatch()
+ ;
+
+ if ($match instanceof RouteMatch) {
+ $helper->setRouteMatch($match);
+ }
+
+ return $helper;
+ };
+ }
+
+ /**
+ * Create and return a factory for creating a BasePath helper.
+ *
+ * Uses configuration and request services to configure the helper.
+ *
+ * @param ContainerInterface $services
+ * @return callable
+ */
+ private function createBasePathHelperFactory(ContainerInterface $services)
+ {
+ return function () use ($services) {
+ $config = $services->has('config') ? $services->get('config') : [];
+ $helper = new ViewHelper\BasePath;
+
+ if (Console::isConsole()
+ && isset($config['view_manager']['base_path_console'])
+ ) {
+ $helper->setBasePath($config['view_manager']['base_path_console']);
+ return $helper;
+ }
+
+ if (isset($config['view_manager']) && isset($config['view_manager']['base_path'])) {
+ $helper->setBasePath($config['view_manager']['base_path']);
+ return $helper;
+ }
+
+ $request = $services->get('Request');
+
+ if (is_callable([$request, 'getBasePath'])) {
+ $helper->setBasePath($request->getBasePath());
+ }
+
+ return $helper;
+ };
+ }
+
+ /**
+ * Create and return a Doctype helper factory.
+ *
+ * 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.
+ *
+ * @param ContainerInterface $services
+ * @return callable
+ */
+ private function createDoctypeHelperFactory(ContainerInterface $services)
+ {
+ return function () use ($services) {
+ $config = $services->has('config') ? $services->get('config') : [];
+ $config = isset($config['view_manager']) ? $config['view_manager'] : [];
+ $helper = new ViewHelper\Doctype;
+ if (isset($config['doctype']) && $config['doctype']) {
+ $helper->setDoctype($config['doctype']);
+ }
+ return $helper;
+ };
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\View\Strategy\JsonStrategy;
+
+class ViewJsonStrategyFactory implements FactoryInterface
+{
+ /**
+ * Create and return the JSON view strategy
+ *
+ * Retrieves the ViewJsonRenderer service from the service locator, and
+ * injects it into the constructor for the JSON strategy.
+ *
+ * It then attaches the strategy to the View service, at a priority of 100.
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return JsonStrategy
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $jsonRenderer = $container->get('ViewJsonRenderer');
+ $jsonStrategy = new JsonStrategy($jsonRenderer);
+ return $jsonStrategy;
+ }
+
+ /**
+ * Create and return JsonStrategy instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return JsonStrategy
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, JsonStrategy::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\Console\Console;
+use Zend\Mvc\View\Console\ViewManager as ConsoleViewManager;
+use Zend\Mvc\View\Http\ViewManager as HttpViewManager;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class ViewManagerFactory implements FactoryInterface
+{
+ /**
+ * Create and return a view manager based on detected environment
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return ConsoleViewManager|HttpViewManager
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ if (Console::isConsole()) {
+ return $container->get('ConsoleViewManager');
+ }
+
+ return $container->get('HttpViewManager');
+ }
+
+ /**
+ * Create and return HttpViewManager or ConsoleViewManager instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return HttpViewManager|ConsoleViewManager
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ $type = Console::isConsole() ? ConsoleViewManager::class : HttpViewManager::class;
+ return $this($container, $type);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\View\Renderer\PhpRenderer;
+
+class ViewPhpRendererFactory implements FactoryInterface
+{
+ /**
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return PhpRenderer
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $renderer = new PhpRenderer();
+ $renderer->setHelperPluginManager($container->get('ViewHelperManager'));
+ $renderer->setResolver($container->get('ViewResolver'));
+
+ return $renderer;
+ }
+
+ /**
+ * Create and return PhpRenderer instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return PhpRenderer
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, PhpRenderer::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\View\Strategy\PhpRendererStrategy;
+use Zend\View\Renderer\PhpRenderer;
+
+class ViewPhpRendererStrategyFactory implements FactoryInterface
+{
+ /**
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return PhpRendererStrategy
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ return new PhpRendererStrategy($container->get(PhpRenderer::class));
+ }
+
+ /**
+ * Create and return PhpRendererStrategy instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return PhpRendererStrategy
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, PhpRendererStrategy::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\View\Resolver\PrefixPathStackResolver;
+
+class ViewPrefixPathStackResolverFactory implements FactoryInterface
+{
+ /**
+ * Create the template prefix view resolver
+ *
+ * Creates a Zend\View\Resolver\PrefixPathStackResolver and populates it with the
+ * ['view_manager']['prefix_template_path_stack']
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return PrefixPathStackResolver
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $config = $container->get('config');
+ $prefixes = [];
+
+ if (isset($config['view_manager']['prefix_template_path_stack'])) {
+ $prefixes = $config['view_manager']['prefix_template_path_stack'];
+ }
+
+ return new PrefixPathStackResolver($prefixes);
+ }
+
+ /**
+ * Create and return PrefixPathStackResolver instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return PrefixPathStackResolver
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, PrefixPathStackResolver::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\View\Resolver as ViewResolver;
+
+class ViewResolverFactory implements FactoryInterface
+{
+ /**
+ * Create the aggregate view resolver
+ *
+ * Creates a Zend\View\Resolver\AggregateResolver and attaches the template
+ * map resolver and path stack resolver
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return ViewResolver\AggregateResolver
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $resolver = new ViewResolver\AggregateResolver();
+
+ /* @var $mapResolver \Zend\View\Resolver\ResolverInterface */
+ $mapResolver = $container->get('ViewTemplateMapResolver');
+ /* @var $pathResolver \Zend\View\Resolver\ResolverInterface */
+ $pathResolver = $container->get('ViewTemplatePathStack');
+ /* @var $prefixPathStackResolver \Zend\View\Resolver\ResolverInterface */
+ $prefixPathStackResolver = $container->get('ViewPrefixPathStackResolver');
+
+ $resolver
+ ->attach($mapResolver)
+ ->attach($pathResolver)
+ ->attach($prefixPathStackResolver)
+ ->attach(new ViewResolver\RelativeFallbackResolver($mapResolver))
+ ->attach(new ViewResolver\RelativeFallbackResolver($pathResolver))
+ ->attach(new ViewResolver\RelativeFallbackResolver($prefixPathStackResolver));
+
+ return $resolver;
+ }
+
+ /**
+ * Create and return ViewResolver\AggregateResolver instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return ViewResolver\AggregateResolver
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, ViewResolver\AggregateResolver::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\View\Resolver as ViewResolver;
+
+class ViewTemplateMapResolverFactory implements FactoryInterface
+{
+ /**
+ * Create the template map view resolver
+ *
+ * Creates a Zend\View\Resolver\AggregateResolver and populates it with the
+ * ['view_manager']['template_map']
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return ViewResolver\TemplateMapResolver
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $config = $container->get('config');
+ $map = [];
+ if (is_array($config) && isset($config['view_manager'])) {
+ $config = $config['view_manager'];
+ if (is_array($config) && isset($config['template_map'])) {
+ $map = $config['template_map'];
+ }
+ }
+ return new ViewResolver\TemplateMapResolver($map);
+ }
+
+ /**
+ * Create and return ViewResolver\TemplateMapResolver instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return ViewResolver\TemplateMapResolver
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, ViewResolver\TemplateMapResolver::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\Service;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\View\Resolver as ViewResolver;
+
+class ViewTemplatePathStackFactory implements FactoryInterface
+{
+ /**
+ * Create the template path stack view resolver
+ *
+ * Creates a Zend\View\Resolver\TemplatePathStack and populates it with the
+ * ['view_manager']['template_path_stack'] and sets the default suffix with the
+ * ['view_manager']['default_template_suffix']
+ *
+ * @param ContainerInterface $container
+ * @param string $name
+ * @param null|array $options
+ * @return ViewResolver\TemplatePathStack
+ */
+ public function __invoke(ContainerInterface $container, $name, array $options = null)
+ {
+ $config = $container->get('config');
+
+ $templatePathStack = new ViewResolver\TemplatePathStack();
+
+ if (is_array($config) && isset($config['view_manager'])) {
+ $config = $config['view_manager'];
+ if (is_array($config)) {
+ if (isset($config['template_path_stack'])) {
+ $templatePathStack->addPaths($config['template_path_stack']);
+ }
+ if (isset($config['default_template_suffix'])) {
+ $templatePathStack->setDefaultSuffix($config['default_template_suffix']);
+ }
+ }
+ }
+
+ return $templatePathStack;
+ }
+
+ /**
+ * Create and return ViewResolver\TemplatePathStack instance
+ *
+ * For use with zend-servicemanager v2; proxies to __invoke().
+ *
+ * @param ServiceLocatorInterface $container
+ * @return ViewResolver\TemplatePathStack
+ */
+ public function createService(ServiceLocatorInterface $container)
+ {
+ return $this($container, ViewResolver\TemplatePathStack::class);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Console;
+
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface as Events;
+use Zend\Mvc\MvcEvent;
+use Zend\Stdlib\ArrayUtils;
+use Zend\View\Model\ConsoleModel;
+
+class CreateViewModelListener extends AbstractListenerAggregate
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(Events $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'createViewModelFromString'], -80);
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'createViewModelFromArray'], -80);
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'createViewModelFromNull'], -80);
+ }
+
+ /**
+ * Inspect the result, and cast it to a ViewModel if a string is detected
+ *
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function createViewModelFromString(MvcEvent $e)
+ {
+ $result = $e->getResult();
+ if (!is_string($result)) {
+ return;
+ }
+
+ // create Console model
+ $model = new ConsoleModel;
+
+ // store the result in a model variable
+ $model->setVariable(ConsoleModel::RESULT, $result);
+ $e->setResult($model);
+ }
+
+ /**
+ * Inspect the result, and cast it to a ViewModel if an assoc array is detected
+ *
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function createViewModelFromArray(MvcEvent $e)
+ {
+ $result = $e->getResult();
+ if (!ArrayUtils::hasStringKeys($result, true)) {
+ return;
+ }
+
+ $model = new ConsoleModel($result);
+ $e->setResult($model);
+ }
+
+ /**
+ * Inspect the result, and cast it to a ViewModel if null is detected
+ *
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function createViewModelFromNull(MvcEvent $e)
+ {
+ $result = $e->getResult();
+ if (null !== $result) {
+ return;
+ }
+
+ $model = new ConsoleModel;
+ $e->setResult($model);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Console;
+
+use Zend\Console\Response as ConsoleResponse;
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+use Zend\Mvc\MvcEvent;
+use Zend\Stdlib\ResponseInterface as Response;
+use Zend\View\Model\ConsoleModel as ConsoleViewModel;
+use Zend\View\Model\ModelInterface;
+
+class DefaultRenderingStrategy extends AbstractListenerAggregate
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_RENDER, [$this, 'render'], -10000);
+ }
+
+ /**
+ * Render the view
+ *
+ * @param MvcEvent $e
+ * @return Response
+ */
+ public function render(MvcEvent $e)
+ {
+ $result = $e->getResult();
+ if ($result instanceof Response) {
+ return $result; // the result is already rendered ...
+ }
+
+ // marshal arguments
+ $response = $e->getResponse();
+
+ if (!$result instanceof ModelInterface) {
+ // There is absolutely no result, so there's nothing to display.
+ // We will return an empty response object
+ return $response;
+ }
+
+ // Collect results from child models
+ $responseText = '';
+ if ($result->hasChildren()) {
+ /* @var ModelInterface $child */
+ foreach ($result->getChildren() as $child) {
+ // Do not use ::getResult() method here as we cannot be sure if
+ // children are also console models.
+ $responseText .= $child->getVariable(ConsoleViewModel::RESULT);
+ }
+ }
+
+ // Fetch result from primary model
+ if ($result instanceof ConsoleViewModel) {
+ $responseText .= $result->getResult();
+ } else {
+ $responseText .= $result->getVariable(ConsoleViewModel::RESULT);
+ }
+
+ // Fetch service manager
+ $sm = $e->getApplication()->getServiceManager();
+
+ // Fetch console
+ $console = $sm->get('console');
+
+ // Append console response to response object
+ $content = $response->getContent() . $responseText;
+ if (is_callable([$console, 'encodeText'])) {
+ $content = $console->encodeText($content);
+ }
+ $response->setContent($content);
+
+ // Pass on console-specific options
+ if ($response instanceof ConsoleResponse
+ && $result instanceof ConsoleViewModel
+ ) {
+ $errorLevel = $result->getErrorLevel();
+ $response->setErrorLevel($errorLevel);
+ }
+
+ return $response;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Console;
+
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+use Zend\Mvc\Application;
+use Zend\Mvc\MvcEvent;
+use Zend\Stdlib\ResponseInterface as Response;
+use Zend\View\Model\ConsoleModel;
+
+class ExceptionStrategy extends AbstractListenerAggregate
+{
+ /**
+ * Display exceptions?
+ * @var bool
+ */
+ protected $displayExceptions = true;
+
+ /**
+ * A template for message to show in console when an exception has occurred.
+ * @var string|callable
+ */
+ protected $message = <<<EOT
+======================================================================
+ The application has thrown an exception!
+======================================================================
+ :className
+ :message
+----------------------------------------------------------------------
+:file::line
+:stack
+======================================================================
+ Previous Exception(s):
+:previous
+
+EOT;
+
+ /**
+ * A template for message to show in console when an exception has previous exceptions.
+ * @var string
+ */
+ protected $previousMessage = <<<EOT
+======================================================================
+ :className
+ :message
+----------------------------------------------------------------------
+:file::line
+:stack
+
+EOT;
+
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, [$this, 'prepareExceptionViewModel']);
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_RENDER_ERROR, [$this, 'prepareExceptionViewModel']);
+ }
+
+ /**
+ * Flag: display exceptions in error pages?
+ *
+ * @param bool $displayExceptions
+ * @return ExceptionStrategy
+ */
+ public function setDisplayExceptions($displayExceptions)
+ {
+ $this->displayExceptions = (bool) $displayExceptions;
+ return $this;
+ }
+
+ /**
+ * Should we display exceptions in error pages?
+ *
+ * @return bool
+ */
+ public function displayExceptions()
+ {
+ return $this->displayExceptions;
+ }
+
+ /**
+ * Get current template for message that will be shown in Console.
+ *
+ * @return string
+ */
+ public function getMessage()
+ {
+ return $this->message;
+ }
+
+ /**
+ * Set template for message that will be shown in Console.
+ * The message can be a string (template) or a callable (i.e. a closure).
+ *
+ * The closure is expected to return a string and will be called with 2 parameters:
+ * Exception $exception - the exception being thrown
+ * boolean $displayExceptions - whether to display exceptions or not
+ *
+ * If the message is a string, one can use the following template params:
+ *
+ * :className - full class name of exception instance
+ * :message - exception message
+ * :code - exception code
+ * :file - the file where the exception has been thrown
+ * :line - the line where the exception has been thrown
+ * :stack - full exception stack
+ *
+ * @param string|callable $message
+ * @return ExceptionStrategy
+ */
+ public function setMessage($message)
+ {
+ $this->message = $message;
+ return $this;
+ }
+
+ /**
+ * Sets template for previous message that will be shown in Console.
+ *
+ * @param string $previousMessage
+ * @return ExceptionStrategy
+ */
+ public function setPreviousMessage($previousMessage)
+ {
+ $this->previousMessage = $previousMessage;
+ return $this;
+ }
+
+ /**
+ * @return callable|string
+ */
+ public function getPreviousMessage()
+ {
+ return $this->previousMessage;
+ }
+
+ /**
+ * Create an exception view model, and set the HTTP status code
+ *
+ * @todo dispatch.error does not halt dispatch unless a response is
+ * returned. As such, we likely need to trigger rendering as a low
+ * priority dispatch.error event (or goto a render event) to ensure
+ * rendering occurs, and that munging of view models occurs when
+ * expected.
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function prepareExceptionViewModel(MvcEvent $e)
+ {
+ // Do nothing if no error in the event
+ $error = $e->getError();
+ if (empty($error)) {
+ return;
+ }
+
+ // Do nothing if the result is a response object
+ $result = $e->getResult();
+ if ($result instanceof Response) {
+ return;
+ }
+
+ switch ($error) {
+ case Application::ERROR_CONTROLLER_NOT_FOUND:
+ case Application::ERROR_CONTROLLER_INVALID:
+ case Application::ERROR_ROUTER_NO_MATCH:
+ // Specifically not handling these because they are handled by routeNotFound strategy
+ return;
+
+ case Application::ERROR_EXCEPTION:
+ default:
+ // Prepare error message
+ $exception = $e->getParam('exception');
+
+ if (is_callable($this->message)) {
+ $callback = $this->message;
+ $message = (string) $callback($exception, $this->displayExceptions);
+ } elseif ($this->displayExceptions
+ // @TODO clean up once PHP 7 requirement is enforced
+ && ($exception instanceof \Exception || $exception instanceof \Throwable)
+ ) {
+ $previous = '';
+ $previousException = $exception->getPrevious();
+ while ($previousException) {
+ $previous .= str_replace(
+ [
+ ':className',
+ ':message',
+ ':code',
+ ':file',
+ ':line',
+ ':stack',
+ ],
+ [
+ get_class($previousException),
+ $previousException->getMessage(),
+ $previousException->getCode(),
+ $previousException->getFile(),
+ $previousException->getLine(),
+ $exception->getTraceAsString(),
+ ],
+ $this->previousMessage
+ );
+ $previousException = $previousException->getPrevious();
+ }
+
+ /* @var $exception \Exception */
+ $message = str_replace(
+ [
+ ':className',
+ ':message',
+ ':code',
+ ':file',
+ ':line',
+ ':stack',
+ ':previous',
+ ],
+ [
+ get_class($exception),
+ $exception->getMessage(),
+ $exception->getCode(),
+ $exception->getFile(),
+ $exception->getLine(),
+ $exception->getTraceAsString(),
+ $previous
+ ],
+ $this->message
+ );
+ } else {
+ $message = str_replace(
+ [
+ ':className',
+ ':message',
+ ':code',
+ ':file',
+ ':line',
+ ':stack',
+ ':previous',
+ ],
+ [
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ ],
+ $this->message
+ );
+ }
+
+ // Prepare view model
+ $model = new ConsoleModel();
+ $model->setResult($message);
+ $model->setErrorLevel(1);
+
+ // Inject it into MvcEvent
+ $e->setResult($model);
+
+ break;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Console;
+
+use Zend\Console\Request as ConsoleRequest;
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface as Events;
+use Zend\Mvc\MvcEvent;
+
+class InjectNamedConsoleParamsListener extends AbstractListenerAggregate
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(Events $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'injectNamedParams'], -80);
+ }
+
+ /**
+ * Inspect the result, and cast it to a ViewModel if a string is detected
+ *
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function injectNamedParams(MvcEvent $e)
+ {
+ if (!$routeMatch = $e->getRouteMatch()) {
+ return; // cannot work without route match
+ }
+
+ $request = $e->getRequest();
+ if (!$request instanceof ConsoleRequest) {
+ return; // will not inject non-console requests
+ }
+
+ // Inject route match params into request
+ $params = array_merge(
+ $request->getParams()->toArray(),
+ $routeMatch->getParams()
+ );
+ $request->getParams()->fromArray($params);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Console;
+
+use Zend\Mvc\View\Http\InjectViewModelListener as HttpInjectViewModelListener;
+
+class InjectViewModelListener extends HttpInjectViewModelListener
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Console;
+
+use Zend\Console\Adapter\AdapterInterface as ConsoleAdapter;
+use Zend\Console\ColorInterface;
+use Zend\Console\Response as ConsoleResponse;
+use Zend\Console\Request as ConsoleRequest;
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+use Zend\ModuleManager\ModuleManagerInterface;
+use Zend\ModuleManager\Feature\ConsoleBannerProviderInterface;
+use Zend\ModuleManager\Feature\ConsoleUsageProviderInterface;
+use Zend\Mvc\Application;
+use Zend\Mvc\Exception\RuntimeException;
+use Zend\Mvc\MvcEvent;
+use Zend\ServiceManager\Exception\ServiceNotFoundException;
+use Zend\Stdlib\ResponseInterface as Response;
+use Zend\Stdlib\StringUtils;
+use Zend\Text\Table;
+use Zend\Version\Version;
+use Zend\View\Model\ConsoleModel;
+
+class RouteNotFoundStrategy extends AbstractListenerAggregate
+{
+ /**
+ * Whether or not to display the reason for routing failure
+ *
+ * @var bool
+ */
+ protected $displayNotFoundReason = true;
+
+ /**
+ * The reason for a not-found condition
+ *
+ * @var bool|string
+ */
+ protected $reason = false;
+
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, [$this, 'handleRouteNotFoundError']);
+ }
+
+ /**
+ * Set flag indicating whether or not to display the routing failure
+ *
+ * @param bool $displayNotFoundReason
+ * @return RouteNotFoundStrategy
+ */
+ public function setDisplayNotFoundReason($displayNotFoundReason)
+ {
+ $this->displayNotFoundReason = (bool) $displayNotFoundReason;
+ return $this;
+ }
+
+ /**
+ * Do we display the routing failure?
+ *
+ * @return bool
+ */
+ public function displayNotFoundReason()
+ {
+ return $this->displayNotFoundReason;
+ }
+
+ /**
+ * Detect if an error is a route not found condition
+ *
+ * If a "controller not found" or "invalid controller" error type is
+ * encountered, sets the response status code to 404.
+ *
+ * @param MvcEvent $e
+ * @throws RuntimeException
+ * @throws ServiceNotFoundException
+ * @return void
+ */
+ public function handleRouteNotFoundError(MvcEvent $e)
+ {
+ $error = $e->getError();
+ if (empty($error)) {
+ return;
+ }
+
+ $response = $e->getResponse();
+ $request = $e->getRequest();
+
+ switch ($error) {
+ case Application::ERROR_CONTROLLER_NOT_FOUND:
+ case Application::ERROR_CONTROLLER_INVALID:
+ case Application::ERROR_ROUTER_NO_MATCH:
+ $this->reason = $error;
+ if (!$response) {
+ $response = new ConsoleResponse();
+ $e->setResponse($response);
+ }
+ $response->setMetadata('error', $error);
+ break;
+ default:
+ return;
+ }
+
+ $result = $e->getResult();
+ if ($result instanceof Response) {
+ // Already have a response as the result
+ return;
+ }
+
+ // Prepare Console View Model
+ $model = new ConsoleModel();
+ $model->setErrorLevel(1);
+
+ // Fetch service manager
+ $sm = $e->getApplication()->getServiceManager();
+
+ // Try to fetch module manager
+ $mm = null;
+ try {
+ $mm = $sm->get('ModuleManager');
+ } catch (ServiceNotFoundException $exception) {
+ // The application does not have or use module manager, so we cannot use it
+ }
+
+ // Try to fetch current console adapter
+ try {
+ $console = $sm->get('console');
+ if (!$console instanceof ConsoleAdapter) {
+ throw new ServiceNotFoundException();
+ }
+ } catch (ServiceNotFoundException $exception) {
+ // The application does not have console adapter
+ throw new RuntimeException('Cannot access Console adapter - is it defined in ServiceManager?');
+ }
+
+ // Retrieve the script's name (entry point)
+ $scriptName = '';
+ if ($request instanceof ConsoleRequest) {
+ $scriptName = basename($request->getScriptName());
+ }
+
+ // Get application banner
+ $banner = $this->getConsoleBanner($console, $mm);
+
+ // Get application usage information
+ $usage = $this->getConsoleUsage($console, $scriptName, $mm);
+
+ // Inject the text into view
+ $result = $banner ? rtrim($banner, "\r\n") : '';
+ $result .= $usage ? "\n\n" . trim($usage, "\r\n") : '';
+ $result .= "\n"; // to ensure we output a final newline
+ $result .= $this->reportNotFoundReason($e);
+ $model->setResult($result);
+
+ // Inject the result into MvcEvent
+ $e->setResult($model);
+ }
+
+ /**
+ * Build Console application banner text by querying currently loaded
+ * modules.
+ *
+ * @param ModuleManagerInterface $moduleManager
+ * @param ConsoleAdapter $console
+ * @return string
+ */
+ protected function getConsoleBanner(ConsoleAdapter $console, ModuleManagerInterface $moduleManager = null)
+ {
+ /*
+ * Loop through all loaded modules and collect banners
+ */
+ $banners = [];
+ if ($moduleManager !== null) {
+ foreach ($moduleManager->getLoadedModules(false) as $module) {
+ // Strict-type on ConsoleBannerProviderInterface, or duck-type
+ // on the method it defines
+ if (!$module instanceof ConsoleBannerProviderInterface
+ && !method_exists($module, 'getConsoleBanner')
+ ) {
+ continue; // this module does not provide a banner
+ }
+
+ // Don't render empty completely empty lines
+ $banner = $module->getConsoleBanner($console);
+ if ($banner == '') {
+ continue;
+ }
+
+ // We colorize each banners in blue for visual emphasis
+ $banners[] = $console->colorize($banner, ColorInterface::BLUE);
+ }
+ }
+
+ /*
+ * Handle an application with no defined banners
+ */
+ if (!count($banners)) {
+ return sprintf("Zend Framework %s application\nUsage:\n", Version::VERSION);
+ }
+
+ /*
+ * Join the banners by a newline character
+ */
+ return implode("\n", $banners);
+ }
+
+ /**
+ * Build Console usage information by querying currently loaded modules.
+ *
+ * @param ConsoleAdapter $console
+ * @param string $scriptName
+ * @param ModuleManagerInterface $moduleManager
+ * @return string
+ * @throws RuntimeException
+ */
+ protected function getConsoleUsage(
+ ConsoleAdapter $console,
+ $scriptName,
+ ModuleManagerInterface $moduleManager = null
+ ) {
+ /*
+ * Loop through all loaded modules and collect usage info
+ */
+ $usageInfo = [];
+
+ if ($moduleManager !== null) {
+ foreach ($moduleManager->getLoadedModules(false) as $name => $module) {
+ // Strict-type on ConsoleUsageProviderInterface, or duck-type
+ // on the method it defines
+ if (!$module instanceof ConsoleUsageProviderInterface
+ && !method_exists($module, 'getConsoleUsage')
+ ) {
+ continue; // this module does not provide usage info
+ }
+
+ // We prepend the usage by the module name (printed in red), so that each module is
+ // clearly visible by the user
+ $moduleName = sprintf(
+ "%s\n%s\n%s\n",
+ str_repeat('-', $console->getWidth()),
+ $name,
+ str_repeat('-', $console->getWidth())
+ );
+
+ $moduleName = $console->colorize($moduleName, ColorInterface::RED);
+
+ $usage = $module->getConsoleUsage($console);
+
+ // Normalize what we got from the module or discard
+ if (is_array($usage) && !empty($usage)) {
+ array_unshift($usage, $moduleName);
+ $usageInfo[$name] = $usage;
+ } elseif (is_string($usage) && ($usage != '')) {
+ $usageInfo[$name] = [$moduleName, $usage];
+ }
+ }
+ }
+
+ /*
+ * Handle an application with no usage information
+ */
+ if (!count($usageInfo)) {
+ // TODO: implement fetching available console routes from router
+ return '';
+ }
+
+ /*
+ * Transform arrays in usage info into columns, otherwise join everything together
+ */
+ $result = '';
+ $table = false;
+ $tableCols = 0;
+ $tableType = 0;
+ foreach ($usageInfo as $moduleName => $usage) {
+ if (!is_string($usage) && !is_array($usage)) {
+ throw new RuntimeException(sprintf(
+ 'Cannot understand usage info for module "%s"',
+ $moduleName
+ ));
+ }
+
+ if (is_string($usage)) {
+ // It's a plain string - output as is
+ $result .= $usage . "\n";
+ continue;
+ }
+
+ // It's an array, analyze it
+ foreach ($usage as $a => $b) {
+ /*
+ * 'invocation method' => 'explanation'
+ */
+ if (is_string($a) && is_string($b)) {
+ if (($tableCols !== 2 || $tableType != 1) && $table !== false) {
+ // render last table
+ $result .= $this->renderTable($table, $tableCols, $console->getWidth());
+ $table = false;
+
+ // add extra newline for clarity
+ $result .= "\n";
+ }
+
+ // Colorize the command
+ $a = $console->colorize($scriptName . ' ' . $a, ColorInterface::GREEN);
+
+ $tableCols = 2;
+ $tableType = 1;
+ $table[] = [$a, $b];
+ continue;
+ }
+
+ /*
+ * array('--param', '--explanation')
+ */
+ if (is_array($b)) {
+ if ((count($b) != $tableCols || $tableType != 2) && $table !== false) {
+ // render last table
+ $result .= $this->renderTable($table, $tableCols, $console->getWidth());
+ $table = false;
+
+ // add extra newline for clarity
+ $result .= "\n";
+ }
+
+ $tableCols = count($b);
+ $tableType = 2;
+ $table[] = $b;
+ continue;
+ }
+
+ /*
+ * 'A single line of text'
+ */
+ if ($table !== false) {
+ // render last table
+ $result .= $this->renderTable($table, $tableCols, $console->getWidth());
+ $table = false;
+
+ // add extra newline for clarity
+ $result .= "\n";
+ }
+
+ $tableType = 0;
+ $result .= $b . "\n";
+ }
+ }
+
+ // Finish last table
+ if ($table !== false) {
+ $result .= $this->renderTable($table, $tableCols, $console->getWidth());
+ }
+
+ return $result;
+ }
+
+ /**
+ * Render a text table containing the data provided, that will fit inside console window's width.
+ *
+ * @param $data
+ * @param $cols
+ * @param $consoleWidth
+ * @return string
+ */
+ protected function renderTable($data, $cols, $consoleWidth)
+ {
+ $result = '';
+ $padding = 2;
+
+
+ // If there is only 1 column, just concatenate it
+ if ($cols == 1) {
+ foreach ($data as $row) {
+ if (! isset($row[0])) {
+ continue;
+ }
+ $result .= $row[0] . "\n";
+ }
+ return $result;
+ }
+
+ // Get the string wrapper supporting UTF-8 character encoding
+ $strWrapper = StringUtils::getWrapper('UTF-8');
+
+ // Determine max width for each column
+ $maxW = [];
+ for ($x = 1; $x <= $cols; $x += 1) {
+ $maxW[$x] = 0;
+ foreach ($data as $row) {
+ $maxW[$x] = max($maxW[$x], $strWrapper->strlen($row[$x-1]) + $padding * 2);
+ }
+ }
+
+ /*
+ * Check if the sum of x-1 columns fit inside console window width - 10
+ * chars. If columns do not fit inside console window, then we'll just
+ * concatenate them and output as is.
+ */
+ $width = 0;
+ for ($x = 1; $x < $cols; $x += 1) {
+ $width += $maxW[$x];
+ }
+
+ if ($width >= $consoleWidth - 10) {
+ foreach ($data as $row) {
+ $result .= implode(" ", $row) . "\n";
+ }
+ return $result;
+ }
+
+ /*
+ * Use Zend\Text\Table to render the table.
+ * The last column will use the remaining space in console window
+ * (minus 1 character to prevent double wrapping at the edge of the
+ * screen).
+ */
+ $maxW[$cols] = $consoleWidth - $width -1;
+ $table = new Table\Table();
+ $table->setColumnWidths($maxW);
+ $table->setDecorator(new Table\Decorator\Blank());
+ $table->setPadding(2);
+
+ foreach ($data as $row) {
+ $table->appendRow($row);
+ }
+
+ return $table->render();
+ }
+
+ /**
+ * Report the 404 reason and/or exceptions
+ *
+ * @param \Zend\EventManager\EventInterface $e
+ * @return string
+ */
+ protected function reportNotFoundReason($e)
+ {
+ if (!$this->displayNotFoundReason()) {
+ return '';
+ }
+ $exception = $e->getParam('exception', false);
+ if (!$exception && !$this->reason) {
+ return '';
+ }
+
+ $reason = (!empty($this->reason)) ? $this->reason : 'unknown';
+ $reasons = [
+ Application::ERROR_CONTROLLER_NOT_FOUND => 'Could not match to a controller',
+ Application::ERROR_CONTROLLER_INVALID => 'Invalid controller specified',
+ Application::ERROR_ROUTER_NO_MATCH => 'Invalid arguments or no arguments provided',
+ 'unknown' => 'Unknown',
+ ];
+ $report = sprintf("\nReason for failure: %s\n", $reasons[$reason]);
+
+ // @TODO clean up once PHP 7 requirement is enforced
+ while ($exception instanceof \Exception || $exception instanceof \Throwable) {
+ $report .= sprintf("Exception: %s\nTrace:\n%s\n", $exception->getMessage(), $exception->getTraceAsString());
+ $exception = $exception->getPrevious();
+ }
+ return $report;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Console;
+
+use ArrayAccess;
+use Zend\Mvc\MvcEvent;
+use Zend\Mvc\View\Http\ViewManager as BaseViewManager;
+
+/**
+ * Prepares the view layer for console applications
+ */
+class ViewManager extends BaseViewManager
+{
+ /**
+ * Prepares the view layer
+ *
+ * Overriding, as several operations are omitted in the console view
+ * algorithms, as well as to ensure we pick up the Console variants
+ * of several listeners and strategies.
+ *
+ * @param \Zend\Mvc\MvcEvent $event
+ * @return void
+ */
+ public function onBootstrap($event)
+ {
+ $application = $event->getApplication();
+ $services = $application->getServiceManager();
+ $events = $application->getEventManager();
+ $sharedEvents = $events->getSharedManager();
+ $this->config = $this->loadConfig($services->get('config'));
+ $this->services = $services;
+ $this->event = $event;
+
+ $routeNotFoundStrategy = $services->get('ConsoleRouteNotFoundStrategy');
+ $exceptionStrategy = $services->get('ConsoleExceptionStrategy');
+ $mvcRenderingStrategy = $services->get('ConsoleDefaultRenderingStrategy');
+ $createViewModelListener = new CreateViewModelListener();
+ $injectViewModelListener = new InjectViewModelListener();
+ $injectParamsListener = new InjectNamedConsoleParamsListener();
+
+ $this->registerMvcRenderingStrategies($events);
+ $this->registerViewStrategies();
+
+ $routeNotFoundStrategy->attach($events);
+ $exceptionStrategy->attach($events);
+ $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, [$injectViewModelListener, 'injectViewModel'], -100);
+ $events->attach(MvcEvent::EVENT_RENDER_ERROR, [$injectViewModelListener, 'injectViewModel'], -100);
+ $mvcRenderingStrategy->attach($events);
+
+ $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, [$injectParamsListener, 'injectNamedParams'], 1000);
+ $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, [$createViewModelListener, 'createViewModelFromArray'], -80);
+ $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, [$createViewModelListener, 'createViewModelFromString'], -80);
+ $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, [$createViewModelListener, 'createViewModelFromNull'], -80);
+ $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, [$injectViewModelListener, 'injectViewModel'], -100);
+ }
+
+ /**
+ * Extract view manager configuration from the application's configuration
+ *
+ * @param array|ArrayAccess $configService
+ *
+ * @return array
+ */
+ private function loadConfig($configService)
+ {
+ $config = [];
+
+ // override when console config is provided, otherwise use the standard definition
+ if (isset($configService['console']['view_manager'])) {
+ $config = $configService['console']['view_manager'];
+ } elseif (isset($configService['view_manager'])) {
+ $config = $configService['view_manager'];
+ }
+
+ return ($config instanceof ArrayAccess || is_array($config))
+ ? $config
+ : [];
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Http;
+
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface as Events;
+use Zend\Mvc\MvcEvent;
+use Zend\Stdlib\ArrayUtils;
+use Zend\View\Model\ViewModel;
+
+class CreateViewModelListener extends AbstractListenerAggregate
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(Events $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'createViewModelFromArray'], -80);
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'createViewModelFromNull'], -80);
+ }
+
+ /**
+ * Inspect the result, and cast it to a ViewModel if an assoc array is detected
+ *
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function createViewModelFromArray(MvcEvent $e)
+ {
+ $result = $e->getResult();
+ if (!ArrayUtils::hasStringKeys($result, true)) {
+ return;
+ }
+
+ $model = new ViewModel($result);
+ $e->setResult($model);
+ }
+
+ /**
+ * Inspect the result, and cast it to a ViewModel if null is detected
+ *
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function createViewModelFromNull(MvcEvent $e)
+ {
+ $result = $e->getResult();
+ if (null !== $result) {
+ return;
+ }
+
+ $model = new ViewModel;
+ $e->setResult($model);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Http;
+
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+use Zend\Mvc\Application;
+use Zend\Mvc\MvcEvent;
+use Zend\Stdlib\ResponseInterface as Response;
+use Zend\View\Model\ModelInterface as ViewModel;
+use Zend\View\View;
+
+class DefaultRenderingStrategy extends AbstractListenerAggregate
+{
+ /**
+ * Layout template - template used in root ViewModel of MVC event.
+ *
+ * @var string
+ */
+ protected $layoutTemplate = 'layout';
+
+ /**
+ * @var View
+ */
+ protected $view;
+
+ /**
+ * Set view
+ *
+ * @param View $view
+ * @return DefaultRenderingStrategy
+ */
+ public function __construct(View $view)
+ {
+ $this->view = $view;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_RENDER, [$this, 'render'], -10000);
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_RENDER_ERROR, [$this, 'render'], -10000);
+ }
+
+ /**
+ * Set layout template value
+ *
+ * @param string $layoutTemplate
+ * @return DefaultRenderingStrategy
+ */
+ public function setLayoutTemplate($layoutTemplate)
+ {
+ $this->layoutTemplate = (string) $layoutTemplate;
+ return $this;
+ }
+
+ /**
+ * Get layout template value
+ *
+ * @return string
+ */
+ public function getLayoutTemplate()
+ {
+ return $this->layoutTemplate;
+ }
+
+ /**
+ * Render the view
+ *
+ * @param MvcEvent $e
+ * @return Response|null
+ * @throws \Exception
+ */
+ public function render(MvcEvent $e)
+ {
+ $result = $e->getResult();
+ if ($result instanceof Response) {
+ return $result;
+ }
+
+ // Martial arguments
+ $request = $e->getRequest();
+ $response = $e->getResponse();
+ $viewModel = $e->getViewModel();
+ if (!$viewModel instanceof ViewModel) {
+ return;
+ }
+
+ $view = $this->view;
+ $view->setRequest($request);
+ $view->setResponse($response);
+
+ $caughtException = null;
+
+ try {
+ $view->render($viewModel);
+ } catch (\Throwable $ex) {
+ $caughtException = $ex;
+ } catch (\Exception $ex) { // @TODO clean up once PHP 7 requirement is enforced
+ $caughtException = $ex;
+ }
+
+ if ($caughtException !== null) {
+ if ($e->getName() === MvcEvent::EVENT_RENDER_ERROR) {
+ throw $caughtException;
+ }
+
+ $application = $e->getApplication();
+ $events = $application->getEventManager();
+
+ $e->setError(Application::ERROR_EXCEPTION);
+ $e->setParam('exception', $caughtException);
+ $e->setName(MvcEvent::EVENT_RENDER_ERROR);
+ $events->triggerEvent($e);
+ }
+
+ return $response;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Http;
+
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+use Zend\Http\Response as HttpResponse;
+use Zend\Mvc\Application;
+use Zend\Mvc\MvcEvent;
+use Zend\Stdlib\ResponseInterface as Response;
+use Zend\View\Model\ViewModel;
+
+class ExceptionStrategy extends AbstractListenerAggregate
+{
+ /**
+ * Display exceptions?
+ * @var bool
+ */
+ protected $displayExceptions = false;
+
+ /**
+ * Name of exception template
+ * @var string
+ */
+ protected $exceptionTemplate = 'error';
+
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, [$this, 'prepareExceptionViewModel']);
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_RENDER_ERROR, [$this, 'prepareExceptionViewModel']);
+ }
+
+ /**
+ * Flag: display exceptions in error pages?
+ *
+ * @param bool $displayExceptions
+ * @return ExceptionStrategy
+ */
+ public function setDisplayExceptions($displayExceptions)
+ {
+ $this->displayExceptions = (bool) $displayExceptions;
+ return $this;
+ }
+
+ /**
+ * Should we display exceptions in error pages?
+ *
+ * @return bool
+ */
+ public function displayExceptions()
+ {
+ return $this->displayExceptions;
+ }
+
+ /**
+ * Set the exception template
+ *
+ * @param string $exceptionTemplate
+ * @return ExceptionStrategy
+ */
+ public function setExceptionTemplate($exceptionTemplate)
+ {
+ $this->exceptionTemplate = (string) $exceptionTemplate;
+ return $this;
+ }
+
+ /**
+ * Retrieve the exception template
+ *
+ * @return string
+ */
+ public function getExceptionTemplate()
+ {
+ return $this->exceptionTemplate;
+ }
+
+ /**
+ * Create an exception view model, and set the HTTP status code
+ *
+ * @todo dispatch.error does not halt dispatch unless a response is
+ * returned. As such, we likely need to trigger rendering as a low
+ * priority dispatch.error event (or goto a render event) to ensure
+ * rendering occurs, and that munging of view models occurs when
+ * expected.
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function prepareExceptionViewModel(MvcEvent $e)
+ {
+ // Do nothing if no error in the event
+ $error = $e->getError();
+ if (empty($error)) {
+ return;
+ }
+
+ // Do nothing if the result is a response object
+ $result = $e->getResult();
+ if ($result instanceof Response) {
+ return;
+ }
+
+ switch ($error) {
+ case Application::ERROR_CONTROLLER_NOT_FOUND:
+ case Application::ERROR_CONTROLLER_INVALID:
+ case Application::ERROR_ROUTER_NO_MATCH:
+ // Specifically not handling these
+ return;
+
+ case Application::ERROR_EXCEPTION:
+ default:
+ $model = new ViewModel([
+ 'message' => 'An error occurred during execution; please try again later.',
+ 'exception' => $e->getParam('exception'),
+ 'display_exceptions' => $this->displayExceptions(),
+ ]);
+ $model->setTemplate($this->getExceptionTemplate());
+ $e->setResult($model);
+
+ $response = $e->getResponse();
+ if (!$response) {
+ $response = new HttpResponse();
+ $response->setStatusCode(500);
+ $e->setResponse($response);
+ } else {
+ $statusCode = $response->getStatusCode();
+ if ($statusCode === 200) {
+ $response->setStatusCode(500);
+ }
+ }
+
+ break;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Http;
+
+use Zend\Console\Request as ConsoleRequest;
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+use Zend\Http\Request as HttpRequest;
+use Zend\Mvc\MvcEvent;
+
+class InjectRoutematchParamsListener extends AbstractListenerAggregate
+{
+ /**
+ * Should request params overwrite existing request params?
+ *
+ * @var bool
+ */
+ protected $overwrite = true;
+
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'injectParams'], 90);
+ }
+
+ /**
+ * Take parameters from RouteMatch and inject them into the request.
+ *
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function injectParams(MvcEvent $e)
+ {
+ $routeMatchParams = $e->getRouteMatch()->getParams();
+ $request = $e->getRequest();
+
+ /** @var $params \Zend\Stdlib\Parameters */
+ if ($request instanceof ConsoleRequest) {
+ $params = $request->params();
+ } elseif ($request instanceof HttpRequest) {
+ $params = $request->get();
+ } else {
+ // unsupported request type
+ return;
+ }
+
+ if ($this->overwrite) {
+ foreach ($routeMatchParams as $key => $val) {
+ $params->$key = $val;
+ }
+ } else {
+ foreach ($routeMatchParams as $key => $val) {
+ if (!$params->offsetExists($key)) {
+ $params->$key = $val;
+ }
+ }
+ }
+ }
+
+ /**
+ * Should RouteMatch parameters replace existing Request params?
+ *
+ * @param bool $overwrite
+ */
+ public function setOverwrite($overwrite)
+ {
+ $this->overwrite = $overwrite;
+ }
+
+ /**
+ * @return bool
+ */
+ public function getOverwrite()
+ {
+ return $this->overwrite;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Http;
+
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface as Events;
+use Zend\Filter\Word\CamelCaseToDash as CamelCaseToDashFilter;
+use Zend\Mvc\MvcEvent;
+use Zend\Mvc\ModuleRouteListener;
+use Zend\View\Model\ModelInterface as ViewModel;
+
+class InjectTemplateListener extends AbstractListenerAggregate
+{
+ /**
+ * FilterInterface/inflector used to normalize names for use as template identifiers
+ *
+ * @var mixed
+ */
+ protected $inflector;
+
+ /**
+ * Array of controller namespace -> template mappings
+ *
+ * @var array
+ */
+ protected $controllerMap = [];
+
+ /**
+ * Flag to force the use of the route match controller param
+ *
+ * @var boolean
+ */
+ protected $preferRouteMatchController = false;
+
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(Events $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'injectTemplate'], -90);
+ }
+
+ /**
+ * Inject a template into the view model, if none present
+ *
+ * Template is derived from the controller found in the route match, and,
+ * optionally, the action, if present.
+ *
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function injectTemplate(MvcEvent $e)
+ {
+ $model = $e->getResult();
+ if (!$model instanceof ViewModel) {
+ return;
+ }
+
+ $template = $model->getTemplate();
+ if (!empty($template)) {
+ return;
+ }
+
+ $routeMatch = $e->getRouteMatch();
+ $controller = $e->getTarget();
+ if (is_object($controller)) {
+ $controller = get_class($controller);
+ }
+
+ $routeMatchController = $routeMatch->getParam('controller', '');
+ if (!$controller || ($this->preferRouteMatchController && $routeMatchController)) {
+ $controller = $routeMatchController;
+ }
+
+ $template = $this->mapController($controller);
+ if (!$template) {
+ $module = $this->deriveModuleNamespace($controller);
+
+ if ($namespace = $routeMatch->getParam(ModuleRouteListener::MODULE_NAMESPACE)) {
+ $controllerSubNs = $this->deriveControllerSubNamespace($namespace);
+ if (!empty($controllerSubNs)) {
+ if (!empty($module)) {
+ $module .= '/' . $controllerSubNs;
+ } else {
+ $module = $controllerSubNs;
+ }
+ }
+ }
+
+ $controller = $this->deriveControllerClass($controller);
+ $template = $this->inflectName($module);
+
+ if (!empty($template)) {
+ $template .= '/';
+ }
+ $template .= $this->inflectName($controller);
+ }
+
+ $action = $routeMatch->getParam('action');
+ if (null !== $action) {
+ $template .= '/' . $this->inflectName($action);
+ }
+ $model->setTemplate($template);
+ }
+
+ /**
+ * Set map of controller namespace -> template pairs
+ *
+ * @param array $map
+ * @return self
+ */
+ public function setControllerMap(array $map)
+ {
+ krsort($map);
+ $this->controllerMap = $map;
+ return $this;
+ }
+
+ /**
+ * Maps controller to template if controller namespace is whitelisted or mapped
+ *
+ * @param string $controller controller FQCN
+ * @return string|false template name or false if controller was not matched
+ */
+ public function mapController($controller)
+ {
+ if (! is_string($controller)) {
+ return false;
+ }
+
+ foreach ($this->controllerMap as $namespace => $replacement) {
+ if (// Allow disabling rule by setting value to false since config
+ // merging have no feature to remove entries
+ false == $replacement
+ // Match full class or full namespace
+ || !($controller === $namespace || strpos($controller, $namespace . '\\') === 0)
+ ) {
+ continue;
+ }
+
+ $map = '';
+ // Map namespace to $replacement if its value is string
+ if (is_string($replacement)) {
+ $map = rtrim($replacement, '/') . '/';
+ $controller = substr($controller, strlen($namespace) + 1) ?: '';
+ }
+
+ //strip Controller namespace(s) (but not classname)
+ $parts = explode('\\', $controller);
+ array_pop($parts);
+ $parts = array_diff($parts, ['Controller']);
+ //strip trailing Controller in class name
+ $parts[] = $this->deriveControllerClass($controller);
+ $controller = implode('/', $parts);
+
+ $template = trim($map . $controller, '/');
+
+ //inflect CamelCase to dash
+ return $this->inflectName($template);
+ }
+ return false;
+ }
+
+ /**
+ * Inflect a name to a normalized value
+ *
+ * @param string $name
+ * @return string
+ */
+ protected function inflectName($name)
+ {
+ if (!$this->inflector) {
+ $this->inflector = new CamelCaseToDashFilter();
+ }
+ $name = $this->inflector->filter($name);
+ return strtolower($name);
+ }
+
+ /**
+ * Determine the top-level namespace of the controller
+ *
+ * @param string $controller
+ * @return string
+ */
+ protected function deriveModuleNamespace($controller)
+ {
+ if (!strstr($controller, '\\')) {
+ return '';
+ }
+ $module = substr($controller, 0, strpos($controller, '\\'));
+ return $module;
+ }
+
+ /**
+ * @param $namespace
+ * @return string
+ */
+ protected function deriveControllerSubNamespace($namespace)
+ {
+ if (!strstr($namespace, '\\')) {
+ return '';
+ }
+ $nsArray = explode('\\', $namespace);
+
+ // Remove the first two elements representing the module and controller directory.
+ $subNsArray = array_slice($nsArray, 2);
+ if (empty($subNsArray)) {
+ return '';
+ }
+ return implode('/', $subNsArray);
+ }
+
+ /**
+ * Determine the name of the controller
+ *
+ * Strip the namespace, and the suffix "Controller" if present.
+ *
+ * @param string $controller
+ * @return string
+ */
+ protected function deriveControllerClass($controller)
+ {
+ if (strstr($controller, '\\')) {
+ $controller = substr($controller, strrpos($controller, '\\') + 1);
+ }
+
+ if ((10 < strlen($controller))
+ && ('Controller' == substr($controller, -10))
+ ) {
+ $controller = substr($controller, 0, -10);
+ }
+
+ return $controller;
+ }
+
+ /**
+ * Sets the flag to instruct the listener to prefer the route match controller param
+ * over the class name
+ *
+ * @param boolean $preferRouteMatchController
+ */
+ public function setPreferRouteMatchController($preferRouteMatchController)
+ {
+ $this->preferRouteMatchController = (bool) $preferRouteMatchController;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isPreferRouteMatchController()
+ {
+ return $this->preferRouteMatchController;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Http;
+
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface as Events;
+use Zend\Mvc\MvcEvent;
+use Zend\View\Model\ClearableModelInterface;
+use Zend\View\Model\ModelInterface as ViewModel;
+
+class InjectViewModelListener extends AbstractListenerAggregate
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(Events $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'injectViewModel'], -100);
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, [$this, 'injectViewModel'], -100);
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_RENDER_ERROR, [$this, 'injectViewModel'], -100);
+ }
+
+ /**
+ * Insert the view model into the event
+ *
+ * Inspects the MVC result; if it's a view model, it then either (a) adds
+ * it as a child to the default, composed view model, or (b) replaces it
+ * if the result is marked as terminable.
+ *
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function injectViewModel(MvcEvent $e)
+ {
+ $result = $e->getResult();
+ if (!$result instanceof ViewModel) {
+ return;
+ }
+
+ $model = $e->getViewModel();
+
+ if ($result->terminate()) {
+ $e->setViewModel($result);
+ return;
+ }
+
+ if ($e->getError() && $model instanceof ClearableModelInterface) {
+ $model->clearChildren();
+ }
+
+ $model->addChild($result);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Http;
+
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+use Zend\Http\Response as HttpResponse;
+use Zend\Mvc\Application;
+use Zend\Mvc\MvcEvent;
+use Zend\Stdlib\ResponseInterface as Response;
+use Zend\View\Model\ViewModel;
+
+class RouteNotFoundStrategy extends AbstractListenerAggregate
+{
+ /**
+ * Whether or not to display exceptions related to the 404 condition
+ *
+ * @var bool
+ */
+ protected $displayExceptions = false;
+
+ /**
+ * Whether or not to display the reason for a 404
+ *
+ * @var bool
+ */
+ protected $displayNotFoundReason = false;
+
+ /**
+ * Template to use to report page not found conditions
+ *
+ * @var string
+ */
+ protected $notFoundTemplate = 'error';
+
+ /**
+ * The reason for a not-found condition
+ *
+ * @var false|string
+ */
+ protected $reason = false;
+
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH, [$this, 'prepareNotFoundViewModel'], -90);
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, [$this, 'detectNotFoundError']);
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, [$this, 'prepareNotFoundViewModel']);
+ }
+
+ /**
+ * Set value indicating whether or not to display exceptions related to a not-found condition
+ *
+ * @param bool $displayExceptions
+ * @return RouteNotFoundStrategy
+ */
+ public function setDisplayExceptions($displayExceptions)
+ {
+ $this->displayExceptions = (bool) $displayExceptions;
+ return $this;
+ }
+
+ /**
+ * Should we display exceptions related to a not-found condition?
+ *
+ * @return bool
+ */
+ public function displayExceptions()
+ {
+ return $this->displayExceptions;
+ }
+
+ /**
+ * Set value indicating whether or not to display the reason for a not-found condition
+ *
+ * @param bool $displayNotFoundReason
+ * @return RouteNotFoundStrategy
+ */
+ public function setDisplayNotFoundReason($displayNotFoundReason)
+ {
+ $this->displayNotFoundReason = (bool) $displayNotFoundReason;
+ return $this;
+ }
+
+ /**
+ * Should we display the reason for a not-found condition?
+ *
+ * @return bool
+ */
+ public function displayNotFoundReason()
+ {
+ return $this->displayNotFoundReason;
+ }
+
+ /**
+ * Get template for not found conditions
+ *
+ * @param string $notFoundTemplate
+ * @return RouteNotFoundStrategy
+ */
+ public function setNotFoundTemplate($notFoundTemplate)
+ {
+ $this->notFoundTemplate = (string) $notFoundTemplate;
+ return $this;
+ }
+
+ /**
+ * Get template for not found conditions
+ *
+ * @return string
+ */
+ public function getNotFoundTemplate()
+ {
+ return $this->notFoundTemplate;
+ }
+
+ /**
+ * Detect if an error is a 404 condition
+ *
+ * If a "controller not found" or "invalid controller" error type is
+ * encountered, sets the response status code to 404.
+ *
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function detectNotFoundError(MvcEvent $e)
+ {
+ $error = $e->getError();
+ if (empty($error)) {
+ return;
+ }
+
+ switch ($error) {
+ case Application::ERROR_CONTROLLER_NOT_FOUND:
+ case Application::ERROR_CONTROLLER_INVALID:
+ case Application::ERROR_ROUTER_NO_MATCH:
+ $this->reason = $error;
+ $response = $e->getResponse();
+ if (!$response) {
+ $response = new HttpResponse();
+ $e->setResponse($response);
+ }
+ $response->setStatusCode(404);
+ break;
+ default:
+ return;
+ }
+ }
+
+ /**
+ * Create and return a 404 view model
+ *
+ * @param MvcEvent $e
+ * @return void
+ */
+ public function prepareNotFoundViewModel(MvcEvent $e)
+ {
+ $vars = $e->getResult();
+ if ($vars instanceof Response) {
+ // Already have a response as the result
+ return;
+ }
+
+ $response = $e->getResponse();
+ if ($response->getStatusCode() != 404) {
+ // Only handle 404 responses
+ return;
+ }
+
+ if (!$vars instanceof ViewModel) {
+ $model = new ViewModel();
+ if (is_string($vars)) {
+ $model->setVariable('message', $vars);
+ } else {
+ $model->setVariable('message', 'Page not found.');
+ }
+ } else {
+ $model = $vars;
+ if ($model->getVariable('message') === null) {
+ $model->setVariable('message', 'Page not found.');
+ }
+ }
+
+ $model->setTemplate($this->getNotFoundTemplate());
+
+ // If displaying reasons, inject the reason
+ $this->injectNotFoundReason($model);
+
+ // If displaying exceptions, inject
+ $this->injectException($model, $e);
+
+ // Inject controller if we're displaying either the reason or the exception
+ $this->injectController($model, $e);
+
+ $e->setResult($model);
+ }
+
+ /**
+ * Inject the not-found reason into the model
+ *
+ * If $displayNotFoundReason is enabled, checks to see if $reason is set,
+ * and, if so, injects it into the model. If not, it injects
+ * Application::ERROR_CONTROLLER_CANNOT_DISPATCH.
+ *
+ * @param ViewModel $model
+ * @return void
+ */
+ protected function injectNotFoundReason(ViewModel $model)
+ {
+ if (!$this->displayNotFoundReason()) {
+ return;
+ }
+
+ // no route match, controller not found, or controller invalid
+ if ($this->reason) {
+ $model->setVariable('reason', $this->reason);
+ return;
+ }
+
+ // otherwise, must be a case of the controller not being able to
+ // dispatch itself.
+ $model->setVariable('reason', Application::ERROR_CONTROLLER_CANNOT_DISPATCH);
+ }
+
+ /**
+ * Inject the exception message into the model
+ *
+ * If $displayExceptions is enabled, and an exception is found in the
+ * event, inject it into the model.
+ *
+ * @param ViewModel $model
+ * @param MvcEvent $e
+ * @return void
+ */
+ protected function injectException($model, $e)
+ {
+ if (!$this->displayExceptions()) {
+ return;
+ }
+
+ $model->setVariable('display_exceptions', true);
+
+ $exception = $e->getParam('exception', false);
+
+ // @TODO clean up once PHP 7 requirement is enforced
+ if (!$exception instanceof \Exception && !$exception instanceof \Throwable) {
+ return;
+ }
+
+ $model->setVariable('exception', $exception);
+ }
+
+ /**
+ * Inject the controller and controller class into the model
+ *
+ * If either $displayExceptions or $displayNotFoundReason are enabled,
+ * injects the controllerClass from the MvcEvent. It checks to see if a
+ * controller is present in the MvcEvent, and, if not, grabs it from
+ * the route match if present; if a controller is found, it injects it into
+ * the model.
+ *
+ * @param ViewModel $model
+ * @param MvcEvent $e
+ * @return void
+ */
+ protected function injectController($model, $e)
+ {
+ if (!$this->displayExceptions() && !$this->displayNotFoundReason()) {
+ return;
+ }
+
+ $controller = $e->getController();
+ if (empty($controller)) {
+ $routeMatch = $e->getRouteMatch();
+ if (empty($routeMatch)) {
+ return;
+ }
+
+ $controller = $routeMatch->getParam('controller', false);
+ if (!$controller) {
+ return;
+ }
+ }
+
+ $controllerClass = $e->getControllerClass();
+ $model->setVariable('controller', $controller);
+ $model->setVariable('controller_class', $controllerClass);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View\Http;
+
+use ArrayAccess;
+use Traversable;
+use Zend\EventManager\AbstractListenerAggregate;
+use Zend\EventManager\EventManagerInterface;
+use Zend\EventManager\ListenerAggregateInterface;
+use Zend\Mvc\MvcEvent;
+use Zend\ServiceManager\ServiceManager;
+use Zend\View\HelperPluginManager as ViewHelperManager;
+use Zend\View\Resolver as ViewResolver;
+use Zend\View\View;
+
+/**
+ * Prepares the view layer
+ *
+ * Instantiates and configures all classes related to the view layer, including
+ * the renderer (and its associated resolver(s) and helper manager), the view
+ * object (and its associated rendering strategies), and the various MVC
+ * strategies and listeners.
+ *
+ * Defines and manages the following services:
+ *
+ * - ViewHelperManager (also aliased to Zend\View\HelperPluginManager)
+ * - ViewTemplateMapResolver (also aliased to Zend\View\Resolver\TemplateMapResolver)
+ * - ViewTemplatePathStack (also aliased to Zend\View\Resolver\TemplatePathStack)
+ * - ViewResolver (also aliased to Zend\View\Resolver\AggregateResolver and ResolverInterface)
+ * - ViewRenderer (also aliased to Zend\View\Renderer\PhpRenderer and RendererInterface)
+ * - ViewPhpRendererStrategy (also aliased to Zend\View\Strategy\PhpRendererStrategy)
+ * - View (also aliased to Zend\View\View)
+ * - DefaultRenderingStrategy (also aliased to Zend\Mvc\View\Http\DefaultRenderingStrategy)
+ * - ExceptionStrategy (also aliased to Zend\Mvc\View\Http\ExceptionStrategy)
+ * - RouteNotFoundStrategy (also aliased to Zend\Mvc\View\Http\RouteNotFoundStrategy and 404Strategy)
+ * - ViewModel
+ */
+class ViewManager extends AbstractListenerAggregate
+{
+ /**
+ * @var object application configuration service
+ */
+ protected $config;
+
+ /**
+ * @var MvcEvent
+ */
+ protected $event;
+
+ /**
+ * @var ServiceManager
+ */
+ protected $services;
+
+ /**@+
+ * Various properties representing strategies and objects instantiated and
+ * configured by the view manager
+ */
+ protected $helperManager;
+ protected $mvcRenderingStrategy;
+ protected $renderer;
+ protected $rendererStrategy;
+ protected $resolver;
+ protected $view;
+ protected $viewModel;
+ /**@-*/
+
+ /**
+ * {@inheritDoc}
+ */
+ public function attach(EventManagerInterface $events, $priority = 1)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_BOOTSTRAP, [$this, 'onBootstrap'], 10000);
+ }
+
+ /**
+ * Prepares the view layer
+ *
+ * @param $event
+ * @return void
+ */
+ public function onBootstrap($event)
+ {
+ $application = $event->getApplication();
+ $services = $application->getServiceManager();
+ $config = $services->get('config');
+ $events = $application->getEventManager();
+ $sharedEvents = $events->getSharedManager();
+
+ $this->config = isset($config['view_manager']) && (is_array($config['view_manager']) || $config['view_manager'] instanceof ArrayAccess)
+ ? $config['view_manager']
+ : [];
+ $this->services = $services;
+ $this->event = $event;
+
+ $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();
+
+ $this->registerMvcRenderingStrategies($events);
+ $this->registerViewStrategies();
+
+ $routeNotFoundStrategy->attach($events);
+ $exceptionStrategy->attach($events);
+ $events->attach(MvcEvent::EVENT_DISPATCH_ERROR, [$injectViewModelListener, 'injectViewModel'], -100);
+ $events->attach(MvcEvent::EVENT_RENDER_ERROR, [$injectViewModelListener, 'injectViewModel'], -100);
+ $mvcRenderingStrategy->attach($events);
+
+ $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, [$createViewModelListener, 'createViewModelFromArray'], -80);
+ $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, [$routeNotFoundStrategy, 'prepareNotFoundViewModel'], -90);
+ $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, [$createViewModelListener, 'createViewModelFromNull'], -80);
+ $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, [$injectTemplateListener, 'injectTemplate'], -90);
+ $sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, [$injectViewModelListener, 'injectViewModel'], -100);
+ }
+
+ /**
+ * Retrieves the View instance
+ *
+ * @return View
+ */
+ public function getView()
+ {
+ if ($this->view) {
+ return $this->view;
+ }
+
+ $this->view = $this->services->get(View::class);
+ return $this->view;
+ }
+
+ /**
+ * Configures the MvcEvent view model to ensure it has the template injected
+ *
+ * @return \Zend\View\Model\ModelInterface
+ */
+ public function getViewModel()
+ {
+ if ($this->viewModel) {
+ return $this->viewModel;
+ }
+
+ $this->viewModel = $model = $this->event->getViewModel();
+ $layoutTemplate = $this->services->get('HttpDefaultRenderingStrategy')->getLayoutTemplate();
+ $model->setTemplate($layoutTemplate);
+
+ return $this->viewModel;
+ }
+
+ /**
+ * Register additional mvc rendering strategies
+ *
+ * If there is a "mvc_strategies" key of the view manager configuration, loop
+ * through it. Pull each as a service from the service manager, and, if it
+ * is a ListenerAggregate, attach it to the view, at priority 100. This
+ * latter allows each to trigger before the default mvc rendering strategy,
+ * and for them to trigger in the order they are registered.
+ *
+ * @param EventManagerInterface $events
+ * @return void
+ */
+ protected function registerMvcRenderingStrategies(EventManagerInterface $events)
+ {
+ 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) {
+ return;
+ }
+
+ foreach ($mvcStrategies as $mvcStrategy) {
+ if (! is_string($mvcStrategy)) {
+ continue;
+ }
+
+ $listener = $this->services->get($mvcStrategy);
+ if ($listener instanceof ListenerAggregateInterface) {
+ $listener->attach($events, 100);
+ }
+ }
+ }
+
+ /**
+ * Register additional view strategies
+ *
+ * If there is a "strategies" key of the view manager configuration, loop
+ * through it. Pull each as a service from the service manager, and, if it
+ * is a ListenerAggregate, attach it to the view, at priority 100. This
+ * latter allows each to trigger before the default strategy, and for them
+ * to trigger in the order they are registered.
+ *
+ * @return void
+ */
+ protected function registerViewStrategies()
+ {
+ if (! isset($this->config['strategies'])) {
+ return;
+ }
+ $strategies = $this->config['strategies'];
+ if (is_string($strategies)) {
+ $strategies = [$strategies];
+ }
+ if (! is_array($strategies) && ! $strategies instanceof Traversable) {
+ return;
+ }
+
+ $view = $this->getView();
+ $events = $view->getEventManager();
+
+ foreach ($strategies as $strategy) {
+ if (! is_string($strategy)) {
+ continue;
+ }
+
+ $listener = $this->services->get($strategy);
+ if ($listener instanceof ListenerAggregateInterface) {
+ $listener->attach($events, 100);
+ }
+ }
+ }
+
+ /**
+ * 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);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Mvc\View;
+
+use Zend\Mvc\SendResponseListener as MvcSendResponseListener;
+
+/**
+ * @deprecated
+ */
+class SendResponseListener extends MvcSendResponseListener
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+interface AbstractFactoryInterface
+{
+ /**
+ * Determine if we can create a service with name
+ *
+ * @param ServiceLocatorInterface $serviceLocator
+ * @param $name
+ * @param $requestedName
+ * @return bool
+ */
+ public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName);
+
+ /**
+ * Create service with name
+ *
+ * @param ServiceLocatorInterface $serviceLocator
+ * @param $name
+ * @param $requestedName
+ * @return mixed
+ */
+ public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+use Interop\Container\ContainerInterface;
+use Exception as BaseException;
+
+/**
+ * ServiceManager implementation for managing plugins
+ *
+ * Automatically registers an initializer which should be used to verify that
+ * a plugin instance is of a valid type. Additionally, allows plugins to accept
+ * an array of options for the constructor, which can be used to configure
+ * the plugin when retrieved. Finally, enables the allowOverride property by
+ * default to allow registering factories, aliases, and invokables to take
+ * the place of those provided by the implementing class.
+ */
+abstract class AbstractPluginManager extends ServiceManager implements ServiceLocatorAwareInterface
+{
+ /**
+ * Allow overriding by default
+ *
+ * @var bool
+ */
+ protected $allowOverride = true;
+
+ /**
+ * Whether or not to auto-add a class as an invokable class if it exists
+ *
+ * @var bool
+ */
+ protected $autoAddInvokableClass = true;
+
+ /**
+ * Options to use when creating an instance
+ *
+ * @var mixed
+ */
+ protected $creationOptions = null;
+
+ /**
+ * The main service locator
+ *
+ * @var ServiceLocatorInterface
+ */
+ protected $serviceLocator;
+
+ /**
+ * Constructor
+ *
+ * Add a default initializer to ensure the plugin is valid after instance
+ * creation.
+ *
+ * Additionally, the constructor provides forwards compatibility with v3 by
+ * overloading the initial argument. v2 usage expects either null or a
+ * ConfigInterface instance, and will ignore any other arguments. v3 expects
+ * a ContainerInterface instance, and will use an array of configuration to
+ * seed the current instance with services. In most cases, you can ignore the
+ * constructor unless you are writing a specialized factory for your plugin
+ * manager or overriding it.
+ *
+ * @param null|ConfigInterface|ContainerInterface $configOrContainerInstance
+ * @param array $v3config If $configOrContainerInstance is a container, this
+ * value will be passed to the parent constructor.
+ * @throws Exception\InvalidArgumentException if $configOrContainerInstance
+ * is neither null, nor a ConfigInterface, nor a ContainerInterface.
+ */
+ public function __construct($configOrContainerInstance = null, array $v3config = [])
+ {
+ if (null !== $configOrContainerInstance
+ && ! $configOrContainerInstance instanceof ConfigInterface
+ && ! $configOrContainerInstance instanceof ContainerInterface
+ ) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ '%s expects a ConfigInterface instance or ContainerInterface instance; received %s',
+ get_class($this),
+ (is_object($configOrContainerInstance)
+ ? get_class($configOrContainerInstance)
+ : gettype($configOrContainerInstance)
+ )
+ ));
+ }
+
+ if ($configOrContainerInstance instanceof ContainerInterface) {
+ if (property_exists($this, 'serviceLocator')) {
+ if (! empty($v3config)) {
+ parent::__construct(new Config($v3config));
+ }
+ $this->serviceLocator = $configOrContainerInstance;
+ }
+
+ if (property_exists($this, 'creationContext')) {
+ if (! empty($v3config)) {
+ parent::__construct($v3config);
+ }
+ $this->creationContext = $configOrContainerInstance;
+ }
+ }
+
+ if ($configOrContainerInstance instanceof ConfigInterface) {
+ parent::__construct($configOrContainerInstance);
+ }
+
+ $this->addInitializer(function ($instance) {
+ if ($instance instanceof ServiceLocatorAwareInterface) {
+ $instance->setServiceLocator($this);
+ }
+ });
+ }
+
+ /**
+ * Validate the plugin
+ *
+ * Checks that the filter loaded is either a valid callback or an instance
+ * of FilterInterface.
+ *
+ * @param mixed $plugin
+ * @return void
+ * @throws Exception\RuntimeException if invalid
+ */
+ abstract public function validatePlugin($plugin);
+
+ /**
+ * Retrieve a service from the manager by name
+ *
+ * Allows passing an array of options to use when creating the instance.
+ * createFromInvokable() will use these and pass them to the instance
+ * constructor if not null and a non-empty array.
+ *
+ * @param string $name
+ * @param array $options
+ * @param bool $usePeeringServiceManagers
+ *
+ * @return object
+ *
+ * @throws Exception\ServiceNotFoundException
+ * @throws Exception\ServiceNotCreatedException
+ * @throws Exception\RuntimeException
+ */
+ public function get($name, $options = [], $usePeeringServiceManagers = true)
+ {
+ $isAutoInvokable = false;
+
+ // Allow specifying a class name directly; registers as an invokable class
+ if (!$this->has($name) && $this->autoAddInvokableClass && class_exists($name)) {
+ $isAutoInvokable = true;
+
+ $this->setInvokableClass($name, $name);
+ }
+
+ $this->creationOptions = $options;
+
+ try {
+ $instance = parent::get($name, $usePeeringServiceManagers);
+ } catch (Exception\ServiceNotFoundException $exception) {
+ $this->tryThrowingServiceLocatorUsageException($name, $isAutoInvokable, $exception);
+ } catch (Exception\ServiceNotCreatedException $exception) {
+ $this->tryThrowingServiceLocatorUsageException($name, $isAutoInvokable, $exception);
+ }
+
+ $this->creationOptions = null;
+
+ try {
+ $this->validatePlugin($instance);
+ } catch (Exception\RuntimeException $exception) {
+ $this->tryThrowingServiceLocatorUsageException($name, $isAutoInvokable, $exception);
+ }
+
+ return $instance;
+ }
+
+ /**
+ * Register a service with the locator.
+ *
+ * Validates that the service object via validatePlugin() prior to
+ * attempting to register it.
+ *
+ * @param string $name
+ * @param mixed $service
+ * @param bool $shared
+ * @return AbstractPluginManager
+ * @throws Exception\InvalidServiceNameException
+ */
+ public function setService($name, $service, $shared = true)
+ {
+ if ($service) {
+ $this->validatePlugin($service);
+ }
+ parent::setService($name, $service, $shared);
+
+ return $this;
+ }
+
+ /**
+ * Set the main service locator so factories can have access to it to pull deps
+ *
+ * @param ServiceLocatorInterface $serviceLocator
+ * @return AbstractPluginManager
+ */
+ public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
+ {
+ $this->serviceLocator = $serviceLocator;
+
+ return $this;
+ }
+
+ /**
+ * Get the main plugin manager. Useful for fetching dependencies from within factories.
+ *
+ * @return ServiceLocatorInterface
+ */
+ public function getServiceLocator()
+ {
+ return $this->serviceLocator;
+ }
+
+ /**
+ * Attempt to create an instance via an invokable class
+ *
+ * Overrides parent implementation by passing $creationOptions to the
+ * constructor, if non-null.
+ *
+ * @param string $canonicalName
+ * @param string $requestedName
+ * @return null|\stdClass
+ * @throws Exception\ServiceNotCreatedException If resolved class does not exist
+ */
+ protected function createFromInvokable($canonicalName, $requestedName)
+ {
+ $invokable = $this->invokableClasses[$canonicalName];
+
+ if (!class_exists($invokable)) {
+ throw new Exception\ServiceNotFoundException(sprintf(
+ '%s: failed retrieving "%s%s" via invokable class "%s"; class does not exist',
+ get_class($this) . '::' . __FUNCTION__,
+ $canonicalName,
+ ($requestedName ? '(alias: ' . $requestedName . ')' : ''),
+ $invokable
+ ));
+ }
+
+ if (null === $this->creationOptions
+ || (is_array($this->creationOptions) && empty($this->creationOptions))
+ ) {
+ $instance = new $invokable();
+ } else {
+ $instance = new $invokable($this->creationOptions);
+ }
+
+ return $instance;
+ }
+
+ /**
+ * Attempt to create an instance via a factory class
+ *
+ * Overrides parent implementation by passing $creationOptions to the
+ * constructor, if non-null.
+ *
+ * @param string $canonicalName
+ * @param string $requestedName
+ * @return mixed
+ * @throws Exception\ServiceNotCreatedException If factory is not callable
+ */
+ protected function createFromFactory($canonicalName, $requestedName)
+ {
+ $factory = $this->factories[$canonicalName];
+ $hasCreationOptions = !(null === $this->creationOptions || (is_array($this->creationOptions) && empty($this->creationOptions)));
+
+ if (is_string($factory) && class_exists($factory, true)) {
+ if (!$hasCreationOptions) {
+ $factory = new $factory();
+ } else {
+ $factory = new $factory($this->creationOptions);
+ }
+
+ $this->factories[$canonicalName] = $factory;
+ }
+
+ if ($factory instanceof FactoryInterface) {
+ $instance = $this->createServiceViaCallback([$factory, 'createService'], $canonicalName, $requestedName);
+ } elseif (is_callable($factory)) {
+ $instance = $this->createServiceViaCallback($factory, $canonicalName, $requestedName);
+ } else {
+ throw new Exception\ServiceNotCreatedException(sprintf(
+ 'While attempting to create %s%s an invalid factory was registered for this instance type.',
+ $canonicalName,
+ ($requestedName ? '(alias: ' . $requestedName . ')' : '')
+ ));
+ }
+
+ return $instance;
+ }
+
+ /**
+ * Create service via callback
+ *
+ * @param callable $callable
+ * @param string $cName
+ * @param string $rName
+ * @throws Exception\ServiceNotCreatedException
+ * @throws Exception\ServiceNotFoundException
+ * @throws Exception\CircularDependencyFoundException
+ * @return object
+ */
+ protected function createServiceViaCallback($callable, $cName, $rName)
+ {
+ if (is_object($callable)) {
+ $factory = $callable;
+ } elseif (is_array($callable)) {
+ // reset both rewinds and returns the value of the first array element
+ $factory = reset($callable);
+ }
+
+ // duck-type MutableCreationOptionsInterface for forward compatibility
+ if (isset($factory)
+ && method_exists($factory, 'setCreationOptions')
+ && is_array($this->creationOptions)
+ && !empty($this->creationOptions)
+ ) {
+ $factory->setCreationOptions($this->creationOptions);
+ }
+
+ return parent::createServiceViaCallback($callable, $cName, $rName);
+ }
+
+ /**
+ * @param string $serviceName
+ * @param bool $isAutoInvokable
+ * @param BaseException $exception
+ *
+ * @throws BaseException
+ * @throws Exception\ServiceLocatorUsageException
+ */
+ private function tryThrowingServiceLocatorUsageException(
+ $serviceName,
+ $isAutoInvokable,
+ BaseException $exception
+ ) {
+ if ($isAutoInvokable) {
+ $this->unregisterService($this->canonicalizeName($serviceName));
+ }
+
+ $serviceLocator = $this->getServiceLocator();
+
+ if ($serviceLocator && $serviceLocator->has($serviceName)) {
+ throw Exception\ServiceLocatorUsageException::fromInvalidPluginManagerRequestedServiceName(
+ $this,
+ $serviceLocator,
+ $serviceName,
+ $exception
+ );
+ }
+
+ throw $exception;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+class Config implements ConfigInterface
+{
+ /**
+ * @var array
+ */
+ protected $config = [];
+
+ /**
+ * Constructor
+ *
+ * @param array $config
+ */
+ public function __construct($config = [])
+ {
+ $this->config = $config;
+ }
+
+ /**
+ * Get allow override
+ *
+ * @return null|bool
+ */
+ public function getAllowOverride()
+ {
+ return (isset($this->config['allow_override'])) ? $this->config['allow_override'] : null;
+ }
+
+ /**
+ * Get factories
+ *
+ * @return array
+ */
+ public function getFactories()
+ {
+ return (isset($this->config['factories'])) ? $this->config['factories'] : [];
+ }
+
+ /**
+ * Get abstract factories
+ *
+ * @return array
+ */
+ public function getAbstractFactories()
+ {
+ return (isset($this->config['abstract_factories'])) ? $this->config['abstract_factories'] : [];
+ }
+
+ /**
+ * Get invokables
+ *
+ * @return array
+ */
+ public function getInvokables()
+ {
+ return (isset($this->config['invokables'])) ? $this->config['invokables'] : [];
+ }
+
+ /**
+ * Get services
+ *
+ * @return array
+ */
+ public function getServices()
+ {
+ return (isset($this->config['services'])) ? $this->config['services'] : [];
+ }
+
+ /**
+ * Get aliases
+ *
+ * @return array
+ */
+ public function getAliases()
+ {
+ return (isset($this->config['aliases'])) ? $this->config['aliases'] : [];
+ }
+
+ /**
+ * Get initializers
+ *
+ * @return array
+ */
+ public function getInitializers()
+ {
+ return (isset($this->config['initializers'])) ? $this->config['initializers'] : [];
+ }
+
+ /**
+ * Get shared
+ *
+ * @return array
+ */
+ public function getShared()
+ {
+ return (isset($this->config['shared'])) ? $this->config['shared'] : [];
+ }
+
+ /**
+ * Get the delegator services map, with keys being the services acting as delegates,
+ * and values being the delegator factories names
+ *
+ * @return array
+ */
+ public function getDelegators()
+ {
+ return (isset($this->config['delegators'])) ? $this->config['delegators'] : [];
+ }
+
+ /**
+ * Configure service manager
+ *
+ * @param ServiceManager $serviceManager
+ * @return void
+ */
+ public function configureServiceManager(ServiceManager $serviceManager)
+ {
+ if (($allowOverride = $this->getAllowOverride()) !== null) {
+ $serviceManager->setAllowOverride($allowOverride);
+ }
+
+ foreach ($this->getFactories() as $name => $factory) {
+ $serviceManager->setFactory($name, $factory);
+ }
+
+ foreach ($this->getAbstractFactories() as $factory) {
+ $serviceManager->addAbstractFactory($factory);
+ }
+
+ foreach ($this->getInvokables() as $name => $invokable) {
+ $serviceManager->setInvokableClass($name, $invokable);
+ }
+
+ foreach ($this->getServices() as $name => $service) {
+ $serviceManager->setService($name, $service);
+ }
+
+ foreach ($this->getAliases() as $alias => $nameOrAlias) {
+ $serviceManager->setAlias($alias, $nameOrAlias);
+ }
+
+ foreach ($this->getInitializers() as $initializer) {
+ $serviceManager->addInitializer($initializer);
+ }
+
+ foreach ($this->getShared() as $name => $isShared) {
+ $serviceManager->setShared($name, $isShared);
+ }
+
+ foreach ($this->getDelegators() as $originalServiceName => $delegators) {
+ foreach ($delegators as $delegator) {
+ $serviceManager->addDelegator($originalServiceName, $delegator);
+ }
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+interface ConfigInterface
+{
+ /**
+ * Configure service manager
+ *
+ * @param ServiceManager $serviceManager
+ * @return void
+ */
+ public function configureServiceManager(ServiceManager $serviceManager);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+/**
+ * Interface for factories that can create delegates for services
+ */
+interface DelegatorFactoryInterface
+{
+ /**
+ * A factory that creates delegates of a given service
+ *
+ * @param ServiceLocatorInterface $serviceLocator the service locator which requested the service
+ * @param string $name the normalized service name
+ * @param string $requestedName the requested service name
+ * @param callable $callback the callback that is responsible for creating the service
+ *
+ * @return mixed
+ */
+ public function createDelegatorWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName, $callback);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Di;
+
+use Zend\Di\Di;
+use Zend\ServiceManager\AbstractFactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class DiAbstractServiceFactory extends DiServiceFactory implements AbstractFactoryInterface
+{
+ /**
+ * Constructor
+ *
+ * @param \Zend\Di\Di $di
+ * @param null|string|\Zend\Di\InstanceManager $useServiceLocator
+ */
+ public function __construct(Di $di, $useServiceLocator = self::USE_SL_NONE)
+ {
+ $this->di = $di;
+ if (in_array($useServiceLocator, [self::USE_SL_BEFORE_DI, self::USE_SL_AFTER_DI, self::USE_SL_NONE])) {
+ $this->useServiceLocator = $useServiceLocator;
+ }
+
+ // since we are using this in a proxy-fashion, localize state
+ $this->definitions = $this->di->definitions;
+ $this->instanceManager = $this->di->instanceManager;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
+ {
+ $this->serviceLocator = $serviceLocator;
+ if ($requestedName) {
+ return $this->get($requestedName, []);
+ }
+
+ return $this->get($name, []);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
+ {
+ if ($this->instanceManager->hasSharedInstance($requestedName)
+ || $this->instanceManager->hasAlias($requestedName)
+ || $this->instanceManager->hasConfig($requestedName)
+ || $this->instanceManager->hasTypePreferences($requestedName)
+ ) {
+ return true;
+ }
+
+ if (! $this->definitions->hasClass($requestedName) || interface_exists($requestedName)) {
+ return false;
+ }
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Di;
+
+use Zend\Di\InstanceManager as DiInstanceManager;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class DiInstanceManagerProxy extends DiInstanceManager
+{
+ /**
+ * @var DiInstanceManager
+ */
+ protected $diInstanceManager = null;
+
+ /**
+ * @var ServiceLocatorInterface
+ */
+ protected $serviceLocator = null;
+
+ /**
+ * Constructor
+ *
+ * @param DiInstanceManager $diInstanceManager
+ * @param ServiceLocatorInterface $serviceLocator
+ */
+ public function __construct(DiInstanceManager $diInstanceManager, ServiceLocatorInterface $serviceLocator)
+ {
+ $this->diInstanceManager = $diInstanceManager;
+ $this->serviceLocator = $serviceLocator;
+
+ // localize state
+ $this->aliases = &$diInstanceManager->aliases;
+ $this->sharedInstances = &$diInstanceManager->sharedInstances;
+ $this->sharedInstancesWithParams = &$diInstanceManager->sharedInstancesWithParams;
+ $this->configurations = &$diInstanceManager->configurations;
+ $this->typePreferences = &$diInstanceManager->typePreferences;
+ }
+
+ /**
+ * Determine if we have a shared instance by class or alias
+ *
+ * @param $classOrAlias
+ * @return bool
+ */
+ public function hasSharedInstance($classOrAlias)
+ {
+ return ($this->serviceLocator->has($classOrAlias) || $this->diInstanceManager->hasSharedInstance($classOrAlias));
+ }
+
+ /**
+ * Get shared instance
+ *
+ * @param $classOrAlias
+ * @return mixed
+ */
+ public function getSharedInstance($classOrAlias)
+ {
+ if ($this->serviceLocator->has($classOrAlias)) {
+ return $this->serviceLocator->get($classOrAlias);
+ }
+
+ return $this->diInstanceManager->getSharedInstance($classOrAlias);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Di;
+
+use Zend\Di\Di;
+use Zend\Di\Exception\ClassNotFoundException as DiClassNotFoundException;
+use Zend\ServiceManager\Exception;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class DiServiceFactory extends Di implements FactoryInterface
+{
+ /**@#+
+ * constants
+ */
+ const USE_SL_BEFORE_DI = 'before';
+ const USE_SL_AFTER_DI = 'after';
+ const USE_SL_NONE = 'none';
+ /**@#-*/
+
+ /**
+ * @var \Zend\Di\Di
+ */
+ protected $di = null;
+
+ /**
+ * @var \Zend\Di\InstanceManager
+ */
+ protected $name = null;
+
+ /**
+ * @var array
+ */
+ protected $parameters = [];
+
+ /**
+ * @var string
+ */
+ protected $useServiceLocator = self::USE_SL_AFTER_DI;
+
+ /**
+ * @var ServiceLocatorInterface
+ */
+ protected $serviceLocator = null;
+
+ /**
+ * Constructor
+ *
+ * @param \Zend\Di\Di $di
+ * @param null|\Zend\Di\InstanceManager $name
+ * @param array $parameters
+ * @param string $useServiceLocator
+ */
+ public function __construct(Di $di, $name, array $parameters = [], $useServiceLocator = self::USE_SL_NONE)
+ {
+ $this->di = $di;
+ $this->name = $name;
+ $this->parameters = $parameters;
+ if (in_array($useServiceLocator, [self::USE_SL_BEFORE_DI, self::USE_SL_AFTER_DI, self::USE_SL_NONE])) {
+ $this->useServiceLocator = $useServiceLocator;
+ }
+
+ // since we are using this in a proxy-fashion, localize state
+ $this->definitions = $this->di->definitions;
+ $this->instanceManager = $this->di->instanceManager;
+ }
+
+ /**
+ * Create service
+ *
+ * @param ServiceLocatorInterface $serviceLocator
+ * @return object
+ */
+ public function createService(ServiceLocatorInterface $serviceLocator)
+ {
+ $this->serviceLocator = $serviceLocator;
+ return $this->get($this->name, $this->parameters);
+ }
+
+ /**
+ * Override, as we want it to use the functionality defined in the proxy
+ *
+ * @param string $name
+ * @param array $params
+ * @return object
+ * @throws Exception\ServiceNotFoundException
+ */
+ public function get($name, array $params = [])
+ {
+ // allow this di service to get dependencies from the service locator BEFORE trying di
+ if ($this->useServiceLocator == self::USE_SL_BEFORE_DI && $this->serviceLocator->has($name)) {
+ return $this->serviceLocator->get($name);
+ }
+
+ try {
+ $service = parent::get($name, $params);
+ return $service;
+ } catch (DiClassNotFoundException $e) {
+ // allow this di service to get dependencies from the service locator AFTER trying di
+ if ($this->useServiceLocator == self::USE_SL_AFTER_DI && $this->serviceLocator->has($name)) {
+ return $this->serviceLocator->get($name);
+ } else {
+ throw new Exception\ServiceNotFoundException(
+ sprintf('Service %s was not found in this DI instance', $name),
+ null,
+ $e
+ );
+ }
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Di;
+
+use Zend\Di\Di;
+use Zend\ServiceManager\InitializerInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class DiServiceInitializer extends Di implements InitializerInterface
+{
+ /**
+ * @var Di
+ */
+ protected $di = null;
+
+ /**
+ * @var DiInstanceManagerProxy
+ */
+ protected $diInstanceManagerProxy = null;
+
+ /**
+ * @var ServiceLocatorInterface
+ */
+ protected $serviceLocator = null;
+
+ /**
+ * Constructor
+ *
+ * @param \Zend\Di\Di $di
+ * @param \Zend\ServiceManager\ServiceLocatorInterface $serviceLocator
+ * @param null|DiInstanceManagerProxy $diImProxy
+ */
+ public function __construct(Di $di, ServiceLocatorInterface $serviceLocator, DiInstanceManagerProxy $diImProxy = null)
+ {
+ $this->di = $di;
+ $this->serviceLocator = $serviceLocator;
+ $this->diInstanceManagerProxy = ($diImProxy) ?: new DiInstanceManagerProxy($di->instanceManager(), $serviceLocator);
+ }
+
+ /**
+ * Initialize
+ *
+ * @param $instance
+ * @param ServiceLocatorInterface $serviceLocator
+ * @throws \Exception
+ */
+ public function initialize($instance, ServiceLocatorInterface $serviceLocator)
+ {
+ $instanceManager = $this->di->instanceManager;
+ $this->di->instanceManager = $this->diInstanceManagerProxy;
+ try {
+ $this->di->injectDependencies($instance);
+ $this->di->instanceManager = $instanceManager;
+ } catch (\Exception $e) {
+ $this->di->instanceManager = $instanceManager;
+ throw $e;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Exception;
+
+class CircularDependencyFoundException extends RuntimeException
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Exception;
+
+class CircularReferenceException extends RuntimeException
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Exception;
+
+use Interop\Container\Exception\ContainerException;
+
+interface ExceptionInterface extends ContainerException
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Exception;
+
+class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Exception;
+
+class InvalidServiceException extends RuntimeException
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Exception;
+
+class InvalidServiceNameException extends RuntimeException
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Exception;
+
+class RuntimeException extends \RuntimeException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Exception;
+
+use Exception as BaseException;
+use Zend\ServiceManager\AbstractPluginManager;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+class ServiceLocatorUsageException extends ServiceNotFoundException
+{
+ /**
+ * Static constructor
+ *
+ * @param AbstractPluginManager $pluginManager
+ * @param ServiceLocatorInterface $parentLocator
+ * @param string $serviceName
+ * @param BaseException $previousException
+ *
+ * @return self
+ */
+ public static function fromInvalidPluginManagerRequestedServiceName(
+ AbstractPluginManager $pluginManager,
+ ServiceLocatorInterface $parentLocator,
+ $serviceName,
+ BaseException $previousException
+ ) {
+ return new self(
+ sprintf(
+ "Service \"%s\" has been requested to plugin manager of type \"%s\", but couldn't be retrieved.\n"
+ . "A previous exception of type \"%s\" has been raised in the process.\n"
+ . "By the way, a service with the name \"%s\" has been found in the parent service locator \"%s\": "
+ . 'did you forget to use $parentLocator = $serviceLocator->getServiceLocator() in your factory code?',
+ $serviceName,
+ get_class($pluginManager),
+ get_class($previousException),
+ $serviceName,
+ get_class($parentLocator)
+ ),
+ 0,
+ $previousException
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Exception;
+
+class ServiceNotCreatedException extends RuntimeException
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Exception;
+
+use Interop\Container\Exception\NotFoundException;
+
+class ServiceNotFoundException extends InvalidArgumentException implements
+ NotFoundException
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Factory;
+
+use Interop\Container\ContainerInterface;
+use Zend\ServiceManager\Exception\InvalidServiceException;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+/**
+ * Factory for instantiating classes with no dependencies or which accept a single array.
+ *
+ * The InvokableFactory can be used for any class that:
+ *
+ * - has no constructor arguments;
+ * - accepts a single array of arguments via the constructor.
+ *
+ * It replaces the "invokables" and "invokable class" functionality of the v2
+ * service manager, and can also be used in v2 code for forwards compatibility
+ * with v3.
+ */
+final class InvokableFactory implements FactoryInterface
+{
+ /**
+ * Options to pass to the constructor (when used in v2), if any.
+ *
+ * @param null|array
+ */
+ private $creationOptions;
+
+ /**
+ * @param null|array|Traversable $creationOptions
+ * @throws InvalidServiceException if $creationOptions cannot be coerced to
+ * an array.
+ */
+ public function __construct($creationOptions = null)
+ {
+ if (null === $creationOptions) {
+ return;
+ }
+
+ $this->setCreationOptions($creationOptions);
+ }
+
+ /**
+ * Create an instance of the requested class name.
+ *
+ * @param ContainerInterface $container
+ * @param string $requestedName
+ * @param null|array $options
+ * @return object
+ */
+ public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
+ {
+ return (null === $options) ? new $requestedName : new $requestedName($options);
+ }
+
+ /**
+ * Create an instance of the named service.
+ *
+ * First, it checks if `$canonicalName` resolves to a class, and, if so, uses
+ * that value to proxy to `__invoke()`.
+ *
+ * Next, if `$requestedName` is non-empty and resolves to a class, this
+ * method uses that value to proxy to `__invoke()`.
+ *
+ * Finally, if the above each fail, it raises an exception.
+ *
+ * The approach above is performed as version 2 has two distinct behaviors
+ * under which factories are invoked:
+ *
+ * - If an alias was used, $canonicalName is the resolved name, and
+ * $requestedName is the service name requested, in which case $canonicalName
+ * is likely the qualified class name;
+ * - Otherwise, $canonicalName is the normalized name, and $requestedName
+ * is the original service name requested (typically the qualified class name).
+ *
+ * @param ServiceLocatorInterface $serviceLocator
+ * @param null|string $canonicalName
+ * @param null|string $requestedName
+ * @return object
+ * @throws InvalidServiceException
+ */
+ public function createService(ServiceLocatorInterface $serviceLocator, $canonicalName = null, $requestedName = null)
+ {
+ if (class_exists($canonicalName)) {
+ return $this($serviceLocator, $canonicalName, $this->creationOptions);
+ }
+
+ if (is_string($requestedName) && class_exists($requestedName)) {
+ return $this($serviceLocator, $requestedName, $this->creationOptions);
+ }
+
+ throw new InvalidServiceException(sprintf(
+ '%s requires that the requested name is provided on invocation; please update your tests or consuming container',
+ __CLASS__
+ ));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setCreationOptions(array $creationOptions)
+ {
+ $this->creationOptions = $creationOptions;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+interface FactoryInterface
+{
+ /**
+ * Create service
+ *
+ * @param ServiceLocatorInterface $serviceLocator
+ * @return mixed
+ */
+ public function createService(ServiceLocatorInterface $serviceLocator);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+interface InitializerInterface
+{
+ /**
+ * Initialize
+ *
+ * @param $instance
+ * @param ServiceLocatorInterface $serviceLocator
+ * @return mixed
+ */
+ public function initialize($instance, ServiceLocatorInterface $serviceLocator);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+interface MutableCreationOptionsInterface
+{
+ /**
+ * Set creation options
+ *
+ * @param array $options
+ * @return void
+ */
+ public function setCreationOptions(array $options);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+/**
+ * Trait for MutableCreationOptions Factories
+ */
+trait MutableCreationOptionsTrait
+{
+ /**
+ * @var array
+ */
+ protected $creationOptions = [];
+
+ /**
+ * Set creation options
+ *
+ * @param array $creationOptions
+ * @return void
+ */
+ public function setCreationOptions(array $creationOptions)
+ {
+ $this->creationOptions = $creationOptions;
+ }
+
+ /**
+ * Get creation options
+ *
+ * @return array
+ */
+ public function getCreationOptions()
+ {
+ return $this->creationOptions;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Proxy;
+
+use ProxyManager\Factory\LazyLoadingValueHolderFactory;
+use ProxyManager\Proxy\LazyLoadingInterface;
+use Zend\ServiceManager\DelegatorFactoryInterface;
+use Zend\ServiceManager\Exception;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+/**
+ * Delegator factory responsible of instantiating lazy loading value holder proxies of
+ * given services at runtime
+ *
+ * @link https://github.com/Ocramius/ProxyManager/blob/master/docs/lazy-loading-value-holder.md
+ */
+class LazyServiceFactory implements DelegatorFactoryInterface
+{
+ /**
+ * @var \ProxyManager\Factory\LazyLoadingValueHolderFactory
+ */
+ protected $proxyFactory;
+
+ /**
+ * @var string[] map of service names to class names
+ */
+ protected $servicesMap;
+
+ /**
+ * @param LazyLoadingValueHolderFactory $proxyFactory
+ * @param string[] $servicesMap a map of service names to class names of their
+ * respective classes
+ */
+ public function __construct(LazyLoadingValueHolderFactory $proxyFactory, array $servicesMap)
+ {
+ $this->proxyFactory = $proxyFactory;
+ $this->servicesMap = $servicesMap;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return object|\ProxyManager\Proxy\LazyLoadingInterface|\ProxyManager\Proxy\ValueHolderInterface
+ */
+ public function createDelegatorWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName, $callback)
+ {
+ $initializer = function (& $wrappedInstance, LazyLoadingInterface $proxy) use ($callback) {
+ $proxy->setProxyInitializer(null);
+
+ $wrappedInstance = call_user_func($callback);
+
+ return true;
+ };
+
+ if (isset($this->servicesMap[$requestedName])) {
+ return $this->proxyFactory->createProxy($this->servicesMap[$requestedName], $initializer);
+ } elseif (isset($this->servicesMap[$name])) {
+ return $this->proxyFactory->createProxy($this->servicesMap[$name], $initializer);
+ }
+
+ throw new Exception\InvalidServiceNameException(
+ sprintf('The requested service "%s" was not found in the provided services map', $requestedName)
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Proxy;
+
+use ProxyManager\Configuration;
+use ProxyManager\Factory\LazyLoadingValueHolderFactory;
+use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+use Zend\ServiceManager\Exception;
+
+/**
+ * Service factory responsible of instantiating {@see \Zend\ServiceManager\Proxy\LazyServiceFactory}
+ * and configuring it starting from application configuration
+ */
+class LazyServiceFactoryFactory implements FactoryInterface
+{
+ /**
+ * {@inheritDoc}
+ *
+ * @return \Zend\ServiceManager\Proxy\LazyServiceFactory
+ */
+ public function createService(ServiceLocatorInterface $serviceLocator)
+ {
+ $config = $serviceLocator->get('Config');
+
+ if (!isset($config['lazy_services'])) {
+ throw new Exception\InvalidArgumentException('Missing "lazy_services" config key');
+ }
+
+ $lazyServices = $config['lazy_services'];
+
+ if (!isset($lazyServices['class_map'])) {
+ throw new Exception\InvalidArgumentException('Missing "class_map" config key in "lazy_services"');
+ }
+
+ $factoryConfig = new Configuration();
+
+ if (isset($lazyServices['proxies_namespace'])) {
+ $factoryConfig->setProxiesNamespace($lazyServices['proxies_namespace']);
+ }
+
+ if (isset($lazyServices['proxies_target_dir'])) {
+ $factoryConfig->setProxiesTargetDir($lazyServices['proxies_target_dir']);
+ }
+
+ if (!isset($lazyServices['write_proxy_files']) || ! $lazyServices['write_proxy_files']) {
+ $factoryConfig->setGeneratorStrategy(new EvaluatingGeneratorStrategy());
+ }
+
+ spl_autoload_register($factoryConfig->getProxyAutoloader());
+
+ return new LazyServiceFactory(new LazyLoadingValueHolderFactory($factoryConfig), $lazyServices['class_map']);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+interface ServiceLocatorAwareInterface
+{
+ /**
+ * Set service locator
+ *
+ * @param ServiceLocatorInterface $serviceLocator
+ */
+ public function setServiceLocator(ServiceLocatorInterface $serviceLocator);
+
+ /**
+ * Get service locator
+ *
+ * @return ServiceLocatorInterface
+ */
+ public function getServiceLocator();
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+trait ServiceLocatorAwareTrait
+{
+ /**
+ * @var ServiceLocatorInterface
+ */
+ protected $serviceLocator = null;
+
+ /**
+ * Set service locator
+ *
+ * @param ServiceLocatorInterface $serviceLocator
+ * @return mixed
+ */
+ public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
+ {
+ $this->serviceLocator = $serviceLocator;
+
+ return $this;
+ }
+
+ /**
+ * Get service locator
+ *
+ * @return ServiceLocatorInterface
+ */
+ public function getServiceLocator()
+ {
+ return $this->serviceLocator;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+use Interop\Container\ContainerInterface;
+
+/**
+ * Service locator interface
+ */
+interface ServiceLocatorInterface extends ContainerInterface
+{
+ /**
+ * Retrieve a registered instance
+ *
+ * @param string $name
+ * @throws Exception\ServiceNotFoundException
+ * @return object|array
+ */
+ public function get($name);
+
+ /**
+ * Check for a registered instance
+ *
+ * @param string|array $name
+ * @return bool
+ */
+ public function has($name);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+class ServiceManager implements ServiceLocatorInterface
+{
+ /**@#+
+ * Constants
+ */
+ const SCOPE_PARENT = 'parent';
+ const SCOPE_CHILD = 'child';
+ /**@#-*/
+
+ /**
+ * Lookup for canonicalized names.
+ *
+ * @var array
+ */
+ protected $canonicalNames = [];
+
+ /**
+ * @var bool
+ */
+ protected $allowOverride = false;
+
+ /**
+ * @var array
+ */
+ protected $invokableClasses = [];
+
+ /**
+ * @var string|callable|\Closure|FactoryInterface[]
+ */
+ protected $factories = [];
+
+ /**
+ * @var AbstractFactoryInterface[]
+ */
+ protected $abstractFactories = [];
+
+ /**
+ * @var array[]
+ */
+ protected $delegators = [];
+
+ /**
+ * @var array
+ */
+ protected $pendingAbstractFactoryRequests = [];
+
+ /**
+ * @var integer
+ */
+ protected $nestedContextCounter = -1;
+
+ /**
+ * @var array
+ */
+ protected $nestedContext = [];
+
+ /**
+ * @var array
+ */
+ protected $shared = [];
+
+ /**
+ * Registered services and cached values
+ *
+ * @var array
+ */
+ protected $instances = [];
+
+ /**
+ * @var array
+ */
+ protected $aliases = [];
+
+ /**
+ * @var array
+ */
+ protected $initializers = [];
+
+ /**
+ * @var ServiceManager[]
+ */
+ protected $peeringServiceManagers = [];
+
+ /**
+ * Whether or not to share by default
+ *
+ * @var bool
+ */
+ protected $shareByDefault = true;
+
+ /**
+ * @var bool
+ */
+ protected $retrieveFromPeeringManagerFirst = false;
+
+ /**
+ * @var bool Track whether not to throw exceptions during create()
+ */
+ protected $throwExceptionInCreate = true;
+
+ /**
+ * @var array map of characters to be replaced through strtr
+ */
+ protected $canonicalNamesReplacements = ['-' => '', '_' => '', ' ' => '', '\\' => '', '/' => ''];
+
+ /**
+ * @var ServiceLocatorInterface
+ */
+ protected $serviceManagerCaller;
+
+ /**
+ * Constructor
+ *
+ * @param ConfigInterface $config
+ */
+ public function __construct(ConfigInterface $config = null)
+ {
+ if ($config) {
+ $config->configureServiceManager($this);
+ }
+ }
+
+ /**
+ * Set allow override
+ *
+ * @param $allowOverride
+ * @return ServiceManager
+ */
+ public function setAllowOverride($allowOverride)
+ {
+ $this->allowOverride = (bool) $allowOverride;
+ return $this;
+ }
+
+ /**
+ * Get allow override
+ *
+ * @return bool
+ */
+ public function getAllowOverride()
+ {
+ return $this->allowOverride;
+ }
+
+ /**
+ * Set flag indicating whether services are shared by default
+ *
+ * @param bool $shareByDefault
+ * @return ServiceManager
+ * @throws Exception\RuntimeException if allowOverride is false
+ */
+ public function setShareByDefault($shareByDefault)
+ {
+ if ($this->allowOverride === false) {
+ throw new Exception\RuntimeException(sprintf(
+ '%s: cannot alter default shared service setting; container is marked immutable (allow_override is false)',
+ get_class($this) . '::' . __FUNCTION__
+ ));
+ }
+ $this->shareByDefault = (bool) $shareByDefault;
+ return $this;
+ }
+
+ /**
+ * Are services shared by default?
+ *
+ * @return bool
+ */
+ public function shareByDefault()
+ {
+ return $this->shareByDefault;
+ }
+
+ /**
+ * Set throw exceptions in create
+ *
+ * @param bool $throwExceptionInCreate
+ * @return ServiceManager
+ */
+ public function setThrowExceptionInCreate($throwExceptionInCreate)
+ {
+ $this->throwExceptionInCreate = $throwExceptionInCreate;
+ return $this;
+ }
+
+ /**
+ * Get throw exceptions in create
+ *
+ * @return bool
+ */
+ public function getThrowExceptionInCreate()
+ {
+ return $this->throwExceptionInCreate;
+ }
+
+ /**
+ * Set flag indicating whether to pull from peering manager before attempting creation
+ *
+ * @param bool $retrieveFromPeeringManagerFirst
+ * @return ServiceManager
+ */
+ public function setRetrieveFromPeeringManagerFirst($retrieveFromPeeringManagerFirst = true)
+ {
+ $this->retrieveFromPeeringManagerFirst = (bool) $retrieveFromPeeringManagerFirst;
+ return $this;
+ }
+
+ /**
+ * Should we retrieve from the peering manager prior to attempting to create a service?
+ *
+ * @return bool
+ */
+ public function retrieveFromPeeringManagerFirst()
+ {
+ return $this->retrieveFromPeeringManagerFirst;
+ }
+
+ /**
+ * Set invokable class
+ *
+ * @param string $name
+ * @param string $invokableClass
+ * @param bool $shared
+ * @return ServiceManager
+ * @throws Exception\InvalidServiceNameException
+ */
+ public function setInvokableClass($name, $invokableClass, $shared = null)
+ {
+ $cName = $this->canonicalizeName($name);
+
+ if ($this->has([$cName, $name], false)) {
+ if ($this->allowOverride === false) {
+ throw new Exception\InvalidServiceNameException(sprintf(
+ 'A service by the name or alias "%s" already exists and cannot be overridden; please use an alternate name',
+ $name
+ ));
+ }
+ $this->unregisterService($cName);
+ }
+
+ if ($shared === null) {
+ $shared = $this->shareByDefault;
+ }
+
+ $this->invokableClasses[$cName] = $invokableClass;
+ $this->shared[$cName] = (bool) $shared;
+
+ return $this;
+ }
+
+ /**
+ * Set factory
+ *
+ * @param string $name
+ * @param string|FactoryInterface|callable $factory
+ * @param bool $shared
+ * @return ServiceManager
+ * @throws Exception\InvalidArgumentException
+ * @throws Exception\InvalidServiceNameException
+ */
+ public function setFactory($name, $factory, $shared = null)
+ {
+ $cName = $this->canonicalizeName($name);
+
+ if (!($factory instanceof FactoryInterface || is_string($factory) || is_callable($factory))) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ 'Provided factory must be the class name of a factory, callable or an instance of "%s".',
+ FactoryInterface::class
+ ));
+ }
+
+ if ($this->has([$cName, $name], false)) {
+ if ($this->allowOverride === false) {
+ throw new Exception\InvalidServiceNameException(sprintf(
+ 'A service by the name or alias "%s" already exists and cannot be overridden, please use an alternate name',
+ $name
+ ));
+ }
+ $this->unregisterService($cName);
+ }
+
+ if ($shared === null) {
+ $shared = $this->shareByDefault;
+ }
+
+ $this->factories[$cName] = $factory;
+ $this->shared[$cName] = (bool) $shared;
+
+ return $this;
+ }
+
+ /**
+ * Add abstract factory
+ *
+ * @param AbstractFactoryInterface|string $factory
+ * @param bool $topOfStack
+ * @return ServiceManager
+ * @throws Exception\InvalidArgumentException if the abstract factory is invalid
+ */
+ public function addAbstractFactory($factory, $topOfStack = true)
+ {
+ if (!$factory instanceof AbstractFactoryInterface && is_string($factory)) {
+ $factory = new $factory();
+ }
+
+ if (!$factory instanceof AbstractFactoryInterface) {
+ throw new Exception\InvalidArgumentException(
+ 'Provided abstract factory must be the class name of an abstract'
+ . ' factory or an instance of an AbstractFactoryInterface.'
+ );
+ }
+
+ if ($topOfStack) {
+ array_unshift($this->abstractFactories, $factory);
+ } else {
+ array_push($this->abstractFactories, $factory);
+ }
+ return $this;
+ }
+
+ /**
+ * Sets the given service name as to be handled by a delegator factory
+ *
+ * @param string $serviceName name of the service being the delegate
+ * @param string $delegatorFactoryName name of the service being the delegator factory
+ *
+ * @return ServiceManager
+ */
+ public function addDelegator($serviceName, $delegatorFactoryName)
+ {
+ $cName = $this->canonicalizeName($serviceName);
+
+ if (!isset($this->delegators[$cName])) {
+ $this->delegators[$cName] = [];
+ }
+
+ $this->delegators[$cName][] = $delegatorFactoryName;
+
+ return $this;
+ }
+
+ /**
+ * Add initializer
+ *
+ * @param callable|InitializerInterface $initializer
+ * @param bool $topOfStack
+ * @return ServiceManager
+ * @throws Exception\InvalidArgumentException
+ */
+ public function addInitializer($initializer, $topOfStack = true)
+ {
+ if (!($initializer instanceof InitializerInterface || is_callable($initializer))) {
+ if (is_string($initializer)) {
+ $initializer = new $initializer;
+ }
+
+ if (!($initializer instanceof InitializerInterface || is_callable($initializer))) {
+ throw new Exception\InvalidArgumentException('$initializer should be callable.');
+ }
+ }
+
+ if ($topOfStack) {
+ array_unshift($this->initializers, $initializer);
+ } else {
+ array_push($this->initializers, $initializer);
+ }
+ return $this;
+ }
+
+ /**
+ * Register a service with the locator
+ *
+ * @param string $name
+ * @param mixed $service
+ * @return ServiceManager
+ * @throws Exception\InvalidServiceNameException
+ */
+ public function setService($name, $service)
+ {
+ $cName = $this->canonicalizeName($name);
+
+ if ($this->has($cName, false)) {
+ if ($this->allowOverride === false) {
+ throw new Exception\InvalidServiceNameException(sprintf(
+ '%s: A service by the name "%s" or alias already exists and cannot be overridden, please use an alternate name.',
+ get_class($this) . '::' . __FUNCTION__,
+ $name
+ ));
+ }
+ $this->unregisterService($cName);
+ }
+
+ $this->instances[$cName] = $service;
+
+ return $this;
+ }
+
+ /**
+ * @param string $name
+ * @param bool $isShared
+ * @return ServiceManager
+ * @throws Exception\ServiceNotFoundException
+ */
+ public function setShared($name, $isShared)
+ {
+ $cName = $this->canonicalizeName($name);
+
+ if (!isset($this->invokableClasses[$cName])
+ && !isset($this->factories[$cName])
+ && !$this->canCreateFromAbstractFactory($cName, $name)
+ ) {
+ throw new Exception\ServiceNotFoundException(sprintf(
+ '%s: A service by the name "%s" was not found and could not be marked as shared',
+ get_class($this) . '::' . __FUNCTION__,
+ $name
+ ));
+ }
+
+ $this->shared[$cName] = (bool) $isShared;
+ return $this;
+ }
+
+ /**
+ * @param string $name
+ * @return bool
+ * @throws Exception\ServiceNotFoundException
+ */
+ public function isShared($name)
+ {
+ $cName = $this->canonicalizeName($name);
+
+ if (!$this->has($name)) {
+ throw new Exception\ServiceNotFoundException(sprintf(
+ '%s: A service by the name "%s" was not found',
+ get_class($this) . '::' . __FUNCTION__,
+ $name
+ ));
+ }
+
+ if (!isset($this->shared[$cName])) {
+ return $this->shareByDefault();
+ }
+
+ return $this->shared[$cName];
+ }
+
+ /**
+ * Resolve the alias for the given canonical name
+ *
+ * @param string $cName The canonical name to resolve
+ * @return string The resolved canonical name
+ */
+ protected function resolveAlias($cName)
+ {
+ $stack = [];
+
+ while ($this->hasAlias($cName)) {
+ if (isset($stack[$cName])) {
+ throw new Exception\CircularReferenceException(sprintf(
+ 'Circular alias reference: %s -> %s',
+ implode(' -> ', $stack),
+ $cName
+ ));
+ }
+
+ $stack[$cName] = $cName;
+ $cName = $this->aliases[$this->canonicalizeName($cName)];
+ }
+
+ return $cName;
+ }
+
+ /**
+ * Retrieve a registered instance
+ *
+ * @param string $name
+ * @param bool $usePeeringServiceManagers
+ * @throws Exception\ServiceNotFoundException
+ * @return object|array
+ */
+ public function get($name, $usePeeringServiceManagers = true)
+ {
+ // inlined code from ServiceManager::canonicalizeName for performance
+ if (isset($this->canonicalNames[$name])) {
+ $cName = $this->canonicalNames[$name];
+ } else {
+ $cName = $this->canonicalizeName($name);
+ }
+
+ $isAlias = false;
+
+ if ($this->hasAlias($cName)) {
+ $isAlias = true;
+ $name = $this->resolveAlias($cName);
+ $cName = $this->canonicalizeName($name);
+ }
+
+ $instance = null;
+
+ if ($usePeeringServiceManagers && $this->retrieveFromPeeringManagerFirst) {
+ $instance = $this->retrieveFromPeeringManager($name);
+
+ if (null !== $instance) {
+ return $instance;
+ }
+ }
+
+ if (isset($this->instances[$cName])) {
+ return $this->instances[$cName];
+ }
+
+ if (!$instance) {
+ $this->checkNestedContextStart($cName);
+ if (isset($this->invokableClasses[$cName])
+ || isset($this->factories[$cName])
+ || isset($this->aliases[$cName])
+ || $this->canCreateFromAbstractFactory($cName, $name)
+ ) {
+ $instance = $this->create([$cName, $name]);
+ } elseif ($isAlias && $this->canCreateFromAbstractFactory($name, $cName)) {
+ /*
+ * case of an alias leading to an abstract factory :
+ * 'my-alias' => 'my-abstract-defined-service'
+ * $name = 'my-alias'
+ * $cName = 'my-abstract-defined-service'
+ */
+ $instance = $this->create([$name, $cName]);
+ } elseif ($usePeeringServiceManagers && !$this->retrieveFromPeeringManagerFirst) {
+ $instance = $this->retrieveFromPeeringManager($name);
+ }
+ $this->checkNestedContextStop();
+ }
+
+ // Still no instance? raise an exception
+ if ($instance === null) {
+ $this->checkNestedContextStop(true);
+ if ($isAlias) {
+ throw new Exception\ServiceNotFoundException(sprintf(
+ 'An alias "%s" was requested but no service could be found.',
+ $name
+ ));
+ }
+
+ throw new Exception\ServiceNotFoundException(sprintf(
+ '%s was unable to fetch or create an instance for %s',
+ get_class($this) . '::' . __FUNCTION__,
+ $name
+ ));
+ }
+
+ if (($this->shareByDefault && !isset($this->shared[$cName]))
+ || (isset($this->shared[$cName]) && $this->shared[$cName] === true)
+ ) {
+ $this->instances[$cName] = $instance;
+ }
+
+ return $instance;
+ }
+
+ /**
+ * Create an instance of the requested service
+ *
+ * @param string|array $name
+ *
+ * @return bool|object
+ */
+ public function create($name)
+ {
+ if (is_array($name)) {
+ list($cName, $rName) = $name;
+ } else {
+ $rName = $name;
+
+ // inlined code from ServiceManager::canonicalizeName for performance
+ if (isset($this->canonicalNames[$rName])) {
+ $cName = $this->canonicalNames[$name];
+ } else {
+ $cName = $this->canonicalizeName($name);
+ }
+ }
+
+ if (isset($this->delegators[$cName])) {
+ return $this->createDelegatorFromFactory($cName, $rName);
+ }
+
+ return $this->doCreate($rName, $cName);
+ }
+
+ /**
+ * Creates a callback that uses a delegator to create a service
+ *
+ * @param DelegatorFactoryInterface|callable $delegatorFactory the delegator factory
+ * @param string $rName requested service name
+ * @param string $cName canonical service name
+ * @param callable $creationCallback callback for instantiating the real service
+ *
+ * @return callable
+ */
+ private function createDelegatorCallback($delegatorFactory, $rName, $cName, $creationCallback)
+ {
+ return function () use ($delegatorFactory, $rName, $cName, $creationCallback) {
+ return $delegatorFactory instanceof DelegatorFactoryInterface
+ ? $delegatorFactory->createDelegatorWithName($this, $cName, $rName, $creationCallback)
+ : $delegatorFactory($this, $cName, $rName, $creationCallback);
+ };
+ }
+
+ /**
+ * Actually creates the service
+ *
+ * @param string $rName real service name
+ * @param string $cName canonicalized service name
+ *
+ * @return bool|mixed|null|object
+ * @throws Exception\ServiceNotFoundException
+ *
+ */
+ protected function doCreate($rName, $cName)
+ {
+ $instance = null;
+
+ if (isset($this->factories[$cName])) {
+ $instance = $this->createFromFactory($cName, $rName);
+ }
+
+ if ($instance === null && isset($this->invokableClasses[$cName])) {
+ $instance = $this->createFromInvokable($cName, $rName);
+ }
+ $this->checkNestedContextStart($cName);
+ if ($instance === null && $this->canCreateFromAbstractFactory($cName, $rName)) {
+ $instance = $this->createFromAbstractFactory($cName, $rName);
+ }
+ $this->checkNestedContextStop();
+
+ if ($instance === null && $this->throwExceptionInCreate) {
+ $this->checkNestedContextStop(true);
+ throw new Exception\ServiceNotFoundException(sprintf(
+ 'No valid instance was found for %s%s',
+ $cName,
+ ($rName ? '(alias: ' . $rName . ')' : '')
+ ));
+ }
+
+ // Do not call initializers if we do not have an instance
+ if ($instance === null) {
+ return $instance;
+ }
+
+ foreach ($this->initializers as $initializer) {
+ if ($initializer instanceof InitializerInterface) {
+ $initializer->initialize($instance, $this);
+ } else {
+ call_user_func($initializer, $instance, $this);
+ }
+ }
+
+ return $instance;
+ }
+
+ /**
+ * Determine if we can create an instance.
+ * Proxies to has()
+ *
+ * @param string|array $name
+ * @param bool $checkAbstractFactories
+ * @return bool
+ * @deprecated this method is being deprecated as of zendframework 2.3, and may be removed in future major versions
+ */
+ public function canCreate($name, $checkAbstractFactories = true)
+ {
+ trigger_error(sprintf('%s is deprecated; please use %s::has', __METHOD__, __CLASS__), E_USER_DEPRECATED);
+ return $this->has($name, $checkAbstractFactories, false);
+ }
+
+ /**
+ * Determine if an instance exists.
+ *
+ * @param string|array $name An array argument accepts exactly two values.
+ * Example: array('canonicalName', 'requestName')
+ * @param bool $checkAbstractFactories
+ * @param bool $usePeeringServiceManagers
+ * @return bool
+ */
+ public function has($name, $checkAbstractFactories = true, $usePeeringServiceManagers = true)
+ {
+ if (is_string($name)) {
+ $rName = $name;
+
+ // inlined code from ServiceManager::canonicalizeName for performance
+ if (isset($this->canonicalNames[$rName])) {
+ $cName = $this->canonicalNames[$rName];
+ } else {
+ $cName = $this->canonicalizeName($name);
+ }
+ } elseif (is_array($name) && count($name) >= 2) {
+ list($cName, $rName) = $name;
+ } else {
+ return false;
+ }
+
+ if (isset($this->invokableClasses[$cName])
+ || isset($this->factories[$cName])
+ || isset($this->aliases[$cName])
+ || isset($this->instances[$cName])
+ || ($checkAbstractFactories && $this->canCreateFromAbstractFactory($cName, $rName))
+ ) {
+ return true;
+ }
+
+ if ($usePeeringServiceManagers) {
+ $caller = $this->serviceManagerCaller;
+ foreach ($this->peeringServiceManagers as $peeringServiceManager) {
+ // ignore peering service manager if they are the same instance
+ if ($caller === $peeringServiceManager) {
+ continue;
+ }
+
+ $peeringServiceManager->serviceManagerCaller = $this;
+
+ if ($peeringServiceManager->has($name)) {
+ $peeringServiceManager->serviceManagerCaller = null;
+ return true;
+ }
+
+ $peeringServiceManager->serviceManagerCaller = null;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Determine if we can create an instance from an abstract factory.
+ *
+ * @param string $cName
+ * @param string $rName
+ * @return bool
+ */
+ public function canCreateFromAbstractFactory($cName, $rName)
+ {
+ if (array_key_exists($cName, $this->nestedContext)) {
+ $context = $this->nestedContext[$cName];
+ if ($context === false) {
+ return false;
+ } elseif (is_object($context)) {
+ return !isset($this->pendingAbstractFactoryRequests[get_class($context).$cName]);
+ }
+ }
+ $this->checkNestedContextStart($cName);
+ // check abstract factories
+ $result = false;
+ $this->nestedContext[$cName] = false;
+ foreach ($this->abstractFactories as $abstractFactory) {
+ $pendingKey = get_class($abstractFactory).$cName;
+ if (isset($this->pendingAbstractFactoryRequests[$pendingKey])) {
+ $result = false;
+ break;
+ }
+
+ if ($abstractFactory->canCreateServiceWithName($this, $cName, $rName)) {
+ $this->nestedContext[$cName] = $abstractFactory;
+ $result = true;
+ break;
+ }
+ }
+ $this->checkNestedContextStop();
+ return $result;
+ }
+
+ /**
+ * Ensure the alias definition will not result in a circular reference
+ *
+ * @param string $alias
+ * @param string $nameOrAlias
+ * @throws Exception\CircularReferenceException
+ * @return self
+ */
+ protected function checkForCircularAliasReference($alias, $nameOrAlias)
+ {
+ $aliases = $this->aliases;
+ $aliases[$alias] = $this->canonicalizeName($nameOrAlias);
+ $stack = [];
+
+ while (isset($aliases[$alias])) {
+ if (isset($stack[$alias])) {
+ throw new Exception\CircularReferenceException(sprintf(
+ 'The alias definition "%s" : "%s" results in a circular reference: "%s" -> "%s"',
+ $alias,
+ $nameOrAlias,
+ implode('" -> "', $stack),
+ $alias
+ ));
+ }
+
+ $stack[$alias] = $alias;
+ $alias = $this->canonicalizeName($aliases[$alias]);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $alias
+ * @param string $nameOrAlias
+ * @return ServiceManager
+ * @throws Exception\ServiceNotFoundException
+ * @throws Exception\InvalidServiceNameException
+ */
+ public function setAlias($alias, $nameOrAlias)
+ {
+ if (!is_string($alias) || !is_string($nameOrAlias)) {
+ throw new Exception\InvalidServiceNameException('Service or alias names must be strings.');
+ }
+
+ $cAlias = $this->canonicalizeName($alias);
+
+ if ($alias == '' || $nameOrAlias == '') {
+ throw new Exception\InvalidServiceNameException('Invalid service name alias');
+ }
+
+ if ($this->allowOverride === false && $this->has([$cAlias, $alias], false)) {
+ throw new Exception\InvalidServiceNameException(sprintf(
+ 'An alias by the name "%s" or "%s" already exists',
+ $cAlias,
+ $alias
+ ));
+ }
+
+ if ($this->hasAlias($alias)) {
+ $this->checkForCircularAliasReference($cAlias, $nameOrAlias);
+ }
+
+ $this->aliases[$cAlias] = $nameOrAlias;
+ return $this;
+ }
+
+ /**
+ * Determine if we have an alias
+ *
+ * @param string $alias
+ * @return bool
+ */
+ public function hasAlias($alias)
+ {
+ return isset($this->aliases[$this->canonicalizeName($alias)]);
+ }
+
+ /**
+ * Create scoped service manager
+ *
+ * @param string $peering
+ * @return ServiceManager
+ */
+ public function createScopedServiceManager($peering = self::SCOPE_PARENT)
+ {
+ $scopedServiceManager = new ServiceManager();
+ if ($peering == self::SCOPE_PARENT) {
+ $scopedServiceManager->peeringServiceManagers[] = $this;
+ }
+ if ($peering == self::SCOPE_CHILD) {
+ $this->peeringServiceManagers[] = $scopedServiceManager;
+ }
+ return $scopedServiceManager;
+ }
+
+ /**
+ * Add a peering relationship
+ *
+ * @param ServiceManager $manager
+ * @param string $peering
+ * @return ServiceManager
+ */
+ public function addPeeringServiceManager(ServiceManager $manager, $peering = self::SCOPE_PARENT)
+ {
+ if ($peering == self::SCOPE_PARENT) {
+ $this->peeringServiceManagers[] = $manager;
+ }
+ if ($peering == self::SCOPE_CHILD) {
+ $manager->peeringServiceManagers[] = $this;
+ }
+ return $this;
+ }
+
+ /**
+ * Canonicalize name
+ *
+ * @param string $name
+ * @return string
+ */
+ protected function canonicalizeName($name)
+ {
+ if (isset($this->canonicalNames[$name])) {
+ return $this->canonicalNames[$name];
+ }
+
+ // this is just for performance instead of using str_replace
+ return $this->canonicalNames[$name] = strtolower(strtr($name, $this->canonicalNamesReplacements));
+ }
+
+ /**
+ * Create service via callback
+ *
+ * @param callable $callable
+ * @param string $cName
+ * @param string $rName
+ * @throws Exception\ServiceNotCreatedException
+ * @throws Exception\ServiceNotFoundException
+ * @throws Exception\CircularDependencyFoundException
+ * @return object
+ */
+ protected function createServiceViaCallback($callable, $cName, $rName)
+ {
+ static $circularDependencyResolver = [];
+ $depKey = spl_object_hash($this) . '-' . $cName;
+
+ if (isset($circularDependencyResolver[$depKey])) {
+ $circularDependencyResolver = [];
+ throw new Exception\CircularDependencyFoundException('Circular dependency for LazyServiceLoader was found for instance ' . $rName);
+ }
+
+ try {
+ $circularDependencyResolver[$depKey] = true;
+ $instance = call_user_func($callable, $this, $cName, $rName);
+ unset($circularDependencyResolver[$depKey]);
+ } catch (Exception\ServiceNotFoundException $e) {
+ unset($circularDependencyResolver[$depKey]);
+ throw $e;
+ } catch (\Exception $e) {
+ unset($circularDependencyResolver[$depKey]);
+ throw new Exception\ServiceNotCreatedException(
+ sprintf('An exception was raised while creating "%s"; no instance returned', $rName),
+ $e->getCode(),
+ $e
+ );
+ }
+ if ($instance === null) {
+ throw new Exception\ServiceNotCreatedException('The factory was called but did not return an instance.');
+ }
+
+ return $instance;
+ }
+
+ /**
+ * Retrieve a keyed list of all registered services. Handy for debugging!
+ *
+ * @return array
+ */
+ public function getRegisteredServices()
+ {
+ return [
+ 'invokableClasses' => array_keys($this->invokableClasses),
+ 'factories' => array_keys($this->factories),
+ 'aliases' => array_keys($this->aliases),
+ 'instances' => array_keys($this->instances),
+ ];
+ }
+
+ /**
+ * Retrieve a keyed list of all canonical names. Handy for debugging!
+ *
+ * @return array
+ */
+ public function getCanonicalNames()
+ {
+ return $this->canonicalNames;
+ }
+
+ /**
+ * Allows to override the canonical names lookup map with predefined
+ * values.
+ *
+ * @param array $canonicalNames
+ * @return ServiceManager
+ */
+ public function setCanonicalNames($canonicalNames)
+ {
+ $this->canonicalNames = $canonicalNames;
+
+ return $this;
+ }
+
+ /**
+ * Attempt to retrieve an instance via a peering manager
+ *
+ * @param string $name
+ * @return mixed
+ */
+ protected function retrieveFromPeeringManager($name)
+ {
+ if (null !== ($service = $this->loopPeeringServiceManagers($name))) {
+ return $service;
+ }
+
+ $name = $this->canonicalizeName($name);
+
+ if ($this->hasAlias($name)) {
+ do {
+ $name = $this->aliases[$name];
+ } while ($this->hasAlias($name));
+ }
+
+ if (null !== ($service = $this->loopPeeringServiceManagers($name))) {
+ return $service;
+ }
+
+ return;
+ }
+
+ /**
+ * Loop over peering service managers.
+ *
+ * @param string $name
+ * @return mixed
+ */
+ protected function loopPeeringServiceManagers($name)
+ {
+ $caller = $this->serviceManagerCaller;
+
+ foreach ($this->peeringServiceManagers as $peeringServiceManager) {
+ // ignore peering service manager if they are the same instance
+ if ($caller === $peeringServiceManager) {
+ continue;
+ }
+
+ // pass this instance to peering service manager
+ $peeringServiceManager->serviceManagerCaller = $this;
+
+ if ($peeringServiceManager->has($name)) {
+ $this->shared[$name] = $peeringServiceManager->isShared($name);
+ $instance = $peeringServiceManager->get($name);
+ $peeringServiceManager->serviceManagerCaller = null;
+ return $instance;
+ }
+
+ $peeringServiceManager->serviceManagerCaller = null;
+ }
+
+ return;
+ }
+
+ /**
+ * Attempt to create an instance via an invokable class
+ *
+ * @param string $canonicalName
+ * @param string $requestedName
+ * @return null|\stdClass
+ * @throws Exception\ServiceNotFoundException If resolved class does not exist
+ */
+ protected function createFromInvokable($canonicalName, $requestedName)
+ {
+ $invokable = $this->invokableClasses[$canonicalName];
+ if (!class_exists($invokable)) {
+ throw new Exception\ServiceNotFoundException(sprintf(
+ '%s: failed retrieving "%s%s" via invokable class "%s"; class does not exist',
+ get_class($this) . '::' . __FUNCTION__,
+ $canonicalName,
+ ($requestedName ? '(alias: ' . $requestedName . ')' : ''),
+ $invokable
+ ));
+ }
+ $instance = new $invokable;
+ return $instance;
+ }
+
+ /**
+ * Attempt to create an instance via a factory
+ *
+ * @param string $canonicalName
+ * @param string $requestedName
+ * @return mixed
+ * @throws Exception\ServiceNotCreatedException If factory is not callable
+ */
+ protected function createFromFactory($canonicalName, $requestedName)
+ {
+ $factory = $this->factories[$canonicalName];
+ if (is_string($factory) && class_exists($factory, true)) {
+ $factory = new $factory;
+ $this->factories[$canonicalName] = $factory;
+ }
+ if ($factory instanceof FactoryInterface) {
+ $instance = $this->createServiceViaCallback([$factory, 'createService'], $canonicalName, $requestedName);
+ } elseif (is_callable($factory)) {
+ $instance = $this->createServiceViaCallback($factory, $canonicalName, $requestedName);
+ } else {
+ throw new Exception\ServiceNotCreatedException(sprintf(
+ 'While attempting to create %s%s an invalid factory was registered for this instance type.',
+ $canonicalName,
+ ($requestedName ? '(alias: ' . $requestedName . ')' : '')
+ ));
+ }
+ return $instance;
+ }
+
+ /**
+ * Attempt to create an instance via an abstract factory
+ *
+ * @param string $canonicalName
+ * @param string $requestedName
+ * @return object|null
+ * @throws Exception\ServiceNotCreatedException If abstract factory is not callable
+ */
+ protected function createFromAbstractFactory($canonicalName, $requestedName)
+ {
+ if (isset($this->nestedContext[$canonicalName])) {
+ $abstractFactory = $this->nestedContext[$canonicalName];
+ $pendingKey = get_class($abstractFactory).$canonicalName;
+ try {
+ $this->pendingAbstractFactoryRequests[$pendingKey] = true;
+ $instance = $this->createServiceViaCallback(
+ [$abstractFactory, 'createServiceWithName'],
+ $canonicalName,
+ $requestedName
+ );
+ unset($this->pendingAbstractFactoryRequests[$pendingKey]);
+ return $instance;
+ } catch (\Exception $e) {
+ unset($this->pendingAbstractFactoryRequests[$pendingKey]);
+ $this->checkNestedContextStop(true);
+ throw new Exception\ServiceNotCreatedException(
+ sprintf(
+ 'An abstract factory could not create an instance of %s%s.',
+ $canonicalName,
+ ($requestedName ? '(alias: ' . $requestedName . ')' : '')
+ ),
+ $e->getCode(),
+ $e
+ );
+ }
+ }
+ return;
+ }
+
+ /**
+ *
+ * @param string $cName
+ * @return self
+ */
+ protected function checkNestedContextStart($cName)
+ {
+ if ($this->nestedContextCounter === -1 || !isset($this->nestedContext[$cName])) {
+ $this->nestedContext[$cName] = null;
+ }
+ $this->nestedContextCounter++;
+ return $this;
+ }
+
+ /**
+ *
+ * @param bool $force
+ * @return self
+ */
+ protected function checkNestedContextStop($force = false)
+ {
+ if ($force) {
+ $this->nestedContextCounter = -1;
+ $this->nestedContext = [];
+ return $this;
+ }
+
+ $this->nestedContextCounter--;
+ if ($this->nestedContextCounter === -1) {
+ $this->nestedContext = [];
+ }
+ return $this;
+ }
+
+ /**
+ * @param $canonicalName
+ * @param $requestedName
+ * @return mixed
+ * @throws Exception\ServiceNotCreatedException
+ */
+ protected function createDelegatorFromFactory($canonicalName, $requestedName)
+ {
+ $delegatorsCount = count($this->delegators[$canonicalName]);
+ $creationCallback = function () use ($requestedName, $canonicalName) {
+ return $this->doCreate($requestedName, $canonicalName);
+ };
+
+ for ($i = 0; $i < $delegatorsCount; $i += 1) {
+ $delegatorFactory = $this->delegators[$canonicalName][$i];
+
+ if (is_string($delegatorFactory)) {
+ $delegatorFactory = !$this->has($delegatorFactory) && class_exists($delegatorFactory, true) ?
+ new $delegatorFactory
+ : $this->get($delegatorFactory);
+ $this->delegators[$canonicalName][$i] = $delegatorFactory;
+ }
+
+ if (!$delegatorFactory instanceof DelegatorFactoryInterface && !is_callable($delegatorFactory)) {
+ throw new Exception\ServiceNotCreatedException(sprintf(
+ 'While attempting to create %s%s an invalid factory was registered for this instance type.',
+ $canonicalName,
+ ($requestedName ? '(alias: ' . $requestedName . ')' : '')
+ ));
+ }
+
+ $creationCallback = $this->createDelegatorCallback(
+ $delegatorFactory,
+ $requestedName,
+ $canonicalName,
+ $creationCallback
+ );
+ }
+
+ return $creationCallback($this, $canonicalName, $requestedName, $creationCallback);
+ }
+
+ /**
+ * Checks if the object has this class as one of its parents
+ *
+ * @see https://bugs.php.net/bug.php?id=53727
+ * @see https://github.com/zendframework/zf2/pull/1807
+ *
+ * @deprecated since zf 2.3 requires PHP >= 5.3.23
+ *
+ * @param string $className
+ * @param string $type
+ * @return bool
+ *
+ * @deprecated this method is being deprecated as of zendframework 2.2, and may be removed in future major versions
+ */
+ protected static function isSubclassOf($className, $type)
+ {
+ return is_subclass_of($className, $type);
+ }
+
+ /**
+ * Unregister a service
+ *
+ * Called when $allowOverride is true and we detect that a service being
+ * added to the instance already exists. This will remove the duplicate
+ * entry, and also any shared flags previously registered.
+ *
+ * @param string $canonical
+ * @return void
+ */
+ protected function unregisterService($canonical)
+ {
+ $types = ['invokableClasses', 'factories', 'aliases'];
+ foreach ($types as $type) {
+ if (isset($this->{$type}[$canonical])) {
+ unset($this->{$type}[$canonical]);
+ break;
+ }
+ }
+
+ if (isset($this->instances[$canonical])) {
+ unset($this->instances[$canonical]);
+ }
+
+ if (isset($this->shared[$canonical])) {
+ unset($this->shared[$canonical]);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager;
+
+interface ServiceManagerAwareInterface
+{
+ /**
+ * Set service manager
+ *
+ * @param ServiceManager $serviceManager
+ */
+ public function setServiceManager(ServiceManager $serviceManager);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2016 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\ServiceManager\Test;
+
+use ReflectionClass;
+use ReflectionProperty;
+use Zend\ServiceManager\Exception\InvalidServiceException;
+
+/**
+ * Trait for testing plugin managers for v2-v3 compatibility
+ *
+ * To use this trait:
+ * * implement the `getPluginManager()` method to return your plugin manager
+ * * implement the `getV2InvalidPluginException()` method to return the class `validatePlugin()` throws under v2
+ */
+trait CommonPluginManagerTrait
+{
+ public function testInstanceOfMatches()
+ {
+ $manager = $this->getPluginManager();
+ $reflection = new ReflectionProperty($manager, 'instanceOf');
+ $reflection->setAccessible(true);
+ $this->assertEquals($this->getInstanceOf(), $reflection->getValue($manager), 'instanceOf does not match');
+ }
+
+ public function testShareByDefaultAndSharedByDefault()
+ {
+ $manager = $this->getPluginManager();
+ $reflection = new ReflectionClass($manager);
+ $shareByDefault = $sharedByDefault = true;
+
+ foreach ($reflection->getProperties() as $prop) {
+ if ($prop->getName() == 'shareByDefault') {
+ $prop->setAccessible(true);
+ $shareByDefault = $prop->getValue($manager);
+ }
+ if ($prop->getName() == 'sharedByDefault') {
+ $prop->setAccessible(true);
+ $sharedByDefault = $prop->getValue($manager);
+ }
+ }
+
+ $this->assertTrue(
+ $shareByDefault == $sharedByDefault,
+ 'Values of shareByDefault and sharedByDefault do not match'
+ );
+ }
+
+ public function testRegisteringInvalidElementRaisesException()
+ {
+ $this->setExpectedException($this->getServiceNotFoundException());
+ $this->getPluginManager()->setService('test', $this);
+ }
+
+ public function testLoadingInvalidElementRaisesException()
+ {
+ $manager = $this->getPluginManager();
+ $manager->setInvokableClass('test', get_class($this));
+ $this->setExpectedException($this->getServiceNotFoundException());
+ $manager->get('test');
+ }
+
+ /**
+ * @dataProvider aliasProvider
+ */
+ public function testPluginAliasesResolve($alias, $expected)
+ {
+ $this->assertInstanceOf($expected, $this->getPluginManager()->get($alias), "Alias '$alias' does not resolve'");
+ }
+
+ public function aliasProvider()
+ {
+ $manager = $this->getPluginManager();
+ $reflection = new ReflectionProperty($manager, 'aliases');
+ $reflection->setAccessible(true);
+ $data = [];
+ foreach ($reflection->getValue($manager) as $alias => $expected) {
+ $data[] = [$alias, $expected];
+ }
+ return $data;
+ }
+
+ protected function getServiceNotFoundException()
+ {
+ $manager = $this->getPluginManager();
+ if (method_exists($manager, 'configure')) {
+ return InvalidServiceException::class;
+ }
+ return $this->getV2InvalidPluginException();
+ }
+
+ /**
+ * Returns the plugin manager to test
+ * @return \Zend\ServiceManager\AbstractPluginManager
+ */
+ abstract protected function getPluginManager();
+
+ /**
+ * Returns the FQCN of the exception thrown under v2 by `validatePlugin()`
+ * @return mixed
+ */
+ abstract protected function getV2InvalidPluginException();
+
+ /**
+ * Returns the value the instanceOf property has been set to
+ * @return string
+ */
+ abstract protected function getInstanceOf();
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use Traversable;
+
+abstract class AbstractOptions implements ParameterObjectInterface
+{
+ /**
+ * We use the __ prefix to avoid collisions with properties in
+ * user-implementations.
+ *
+ * @var bool
+ */
+ protected $__strictMode__ = true;
+
+ /**
+ * Constructor
+ *
+ * @param array|Traversable|null $options
+ */
+ public function __construct($options = null)
+ {
+ if (null !== $options) {
+ $this->setFromArray($options);
+ }
+ }
+
+ /**
+ * Set one or more configuration properties
+ *
+ * @param array|Traversable|AbstractOptions $options
+ * @throws Exception\InvalidArgumentException
+ * @return AbstractOptions Provides fluent interface
+ */
+ public function setFromArray($options)
+ {
+ if ($options instanceof self) {
+ $options = $options->toArray();
+ }
+
+ if (!is_array($options) && !$options instanceof Traversable) {
+ throw new Exception\InvalidArgumentException(
+ sprintf(
+ 'Parameter provided to %s must be an %s, %s or %s',
+ __METHOD__,
+ 'array',
+ 'Traversable',
+ 'Zend\Stdlib\AbstractOptions'
+ )
+ );
+ }
+
+ foreach ($options as $key => $value) {
+ $this->__set($key, $value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Cast to array
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $array = [];
+ $transform = function ($letters) {
+ $letter = array_shift($letters);
+ return '_' . strtolower($letter);
+ };
+ foreach ($this as $key => $value) {
+ if ($key === '__strictMode__') {
+ continue;
+ }
+ $normalizedKey = preg_replace_callback('/([A-Z])/', $transform, $key);
+ $array[$normalizedKey] = $value;
+ }
+ return $array;
+ }
+
+ /**
+ * Set a configuration property
+ *
+ * @see ParameterObject::__set()
+ * @param string $key
+ * @param mixed $value
+ * @throws Exception\BadMethodCallException
+ * @return void
+ */
+ public function __set($key, $value)
+ {
+ $setter = 'set' . str_replace('_', '', $key);
+
+ if (is_callable([$this, $setter])) {
+ $this->{$setter}($value);
+
+ return;
+ }
+
+ if ($this->__strictMode__) {
+ throw new Exception\BadMethodCallException(sprintf(
+ 'The option "%s" does not have a callable "%s" ("%s") setter method which must be defined',
+ $key,
+ 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))),
+ $setter
+ ));
+ }
+ }
+
+ /**
+ * Get a configuration property
+ *
+ * @see ParameterObject::__get()
+ * @param string $key
+ * @throws Exception\BadMethodCallException
+ * @return mixed
+ */
+ public function __get($key)
+ {
+ $getter = 'get' . str_replace('_', '', $key);
+
+ if (is_callable([$this, $getter])) {
+ return $this->{$getter}();
+ }
+
+ throw new Exception\BadMethodCallException(sprintf(
+ 'The option "%s" does not have a callable "%s" getter method which must be defined',
+ $key,
+ 'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key)))
+ ));
+ }
+
+ /**
+ * Test if a configuration property is null
+ * @see ParameterObject::__isset()
+ * @param string $key
+ * @return bool
+ */
+ public function __isset($key)
+ {
+ $getter = 'get' . str_replace('_', '', $key);
+
+ return method_exists($this, $getter) && null !== $this->__get($key);
+ }
+
+ /**
+ * Set a configuration property to NULL
+ *
+ * @see ParameterObject::__unset()
+ * @param string $key
+ * @throws Exception\InvalidArgumentException
+ * @return void
+ */
+ public function __unset($key)
+ {
+ try {
+ $this->__set($key, null);
+ } catch (Exception\BadMethodCallException $e) {
+ throw new Exception\InvalidArgumentException(
+ 'The class property $' . $key . ' cannot be unset as'
+ . ' NULL is an invalid value for it',
+ 0,
+ $e
+ );
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use ArrayAccess;
+use Countable;
+use IteratorAggregate;
+use Serializable;
+
+/**
+ * Custom framework ArrayObject implementation
+ *
+ * Extends version-specific "abstract" implementation.
+ */
+class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Countable
+{
+ /**
+ * Properties of the object have their normal functionality
+ * when accessed as list (var_dump, foreach, etc.).
+ */
+ const STD_PROP_LIST = 1;
+
+ /**
+ * Entries can be accessed as properties (read and write).
+ */
+ const ARRAY_AS_PROPS = 2;
+
+ /**
+ * @var array
+ */
+ protected $storage;
+
+ /**
+ * @var int
+ */
+ protected $flag;
+
+ /**
+ * @var string
+ */
+ protected $iteratorClass;
+
+ /**
+ * @var array
+ */
+ protected $protectedProperties;
+
+ /**
+ * Constructor
+ *
+ * @param array $input
+ * @param int $flags
+ * @param string $iteratorClass
+ */
+ public function __construct($input = [], $flags = self::STD_PROP_LIST, $iteratorClass = 'ArrayIterator')
+ {
+ $this->setFlags($flags);
+ $this->storage = $input;
+ $this->setIteratorClass($iteratorClass);
+ $this->protectedProperties = array_keys(get_object_vars($this));
+ }
+
+ /**
+ * Returns whether the requested key exists
+ *
+ * @param mixed $key
+ * @return bool
+ */
+ public function __isset($key)
+ {
+ if ($this->flag == self::ARRAY_AS_PROPS) {
+ return $this->offsetExists($key);
+ }
+ if (in_array($key, $this->protectedProperties)) {
+ throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
+ }
+
+ return isset($this->$key);
+ }
+
+ /**
+ * Sets the value at the specified key to value
+ *
+ * @param mixed $key
+ * @param mixed $value
+ * @return void
+ */
+ public function __set($key, $value)
+ {
+ if ($this->flag == self::ARRAY_AS_PROPS) {
+ return $this->offsetSet($key, $value);
+ }
+ if (in_array($key, $this->protectedProperties)) {
+ throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
+ }
+ $this->$key = $value;
+ }
+
+ /**
+ * Unsets the value at the specified key
+ *
+ * @param mixed $key
+ * @return void
+ */
+ public function __unset($key)
+ {
+ if ($this->flag == self::ARRAY_AS_PROPS) {
+ return $this->offsetUnset($key);
+ }
+ if (in_array($key, $this->protectedProperties)) {
+ throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
+ }
+ unset($this->$key);
+ }
+
+ /**
+ * Returns the value at the specified key by reference
+ *
+ * @param mixed $key
+ * @return mixed
+ */
+ public function &__get($key)
+ {
+ $ret = null;
+ if ($this->flag == self::ARRAY_AS_PROPS) {
+ $ret =& $this->offsetGet($key);
+
+ return $ret;
+ }
+ if (in_array($key, $this->protectedProperties)) {
+ throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
+ }
+
+ return $this->$key;
+ }
+
+ /**
+ * Appends the value
+ *
+ * @param mixed $value
+ * @return void
+ */
+ public function append($value)
+ {
+ $this->storage[] = $value;
+ }
+
+ /**
+ * Sort the entries by value
+ *
+ * @return void
+ */
+ public function asort()
+ {
+ asort($this->storage);
+ }
+
+ /**
+ * Get the number of public properties in the ArrayObject
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->storage);
+ }
+
+ /**
+ * Exchange the array for another one.
+ *
+ * @param array|ArrayObject $data
+ * @return array
+ */
+ public function exchangeArray($data)
+ {
+ if (!is_array($data) && !is_object($data)) {
+ throw new Exception\InvalidArgumentException('Passed variable is not an array or object, using empty array instead');
+ }
+
+ if (is_object($data) && ($data instanceof self || $data instanceof \ArrayObject)) {
+ $data = $data->getArrayCopy();
+ }
+ if (!is_array($data)) {
+ $data = (array) $data;
+ }
+
+ $storage = $this->storage;
+
+ $this->storage = $data;
+
+ return $storage;
+ }
+
+ /**
+ * Creates a copy of the ArrayObject.
+ *
+ * @return array
+ */
+ public function getArrayCopy()
+ {
+ return $this->storage;
+ }
+
+ /**
+ * Gets the behavior flags.
+ *
+ * @return int
+ */
+ public function getFlags()
+ {
+ return $this->flag;
+ }
+
+ /**
+ * Create a new iterator from an ArrayObject instance
+ *
+ * @return \Iterator
+ */
+ public function getIterator()
+ {
+ $class = $this->iteratorClass;
+
+ return new $class($this->storage);
+ }
+
+ /**
+ * Gets the iterator classname for the ArrayObject.
+ *
+ * @return string
+ */
+ public function getIteratorClass()
+ {
+ return $this->iteratorClass;
+ }
+
+ /**
+ * Sort the entries by key
+ *
+ * @return void
+ */
+ public function ksort()
+ {
+ ksort($this->storage);
+ }
+
+ /**
+ * Sort an array using a case insensitive "natural order" algorithm
+ *
+ * @return void
+ */
+ public function natcasesort()
+ {
+ natcasesort($this->storage);
+ }
+
+ /**
+ * Sort entries using a "natural order" algorithm
+ *
+ * @return void
+ */
+ public function natsort()
+ {
+ natsort($this->storage);
+ }
+
+ /**
+ * Returns whether the requested key exists
+ *
+ * @param mixed $key
+ * @return bool
+ */
+ public function offsetExists($key)
+ {
+ return isset($this->storage[$key]);
+ }
+
+ /**
+ * Returns the value at the specified key
+ *
+ * @param mixed $key
+ * @return mixed
+ */
+ public function &offsetGet($key)
+ {
+ $ret = null;
+ if (!$this->offsetExists($key)) {
+ return $ret;
+ }
+ $ret =& $this->storage[$key];
+
+ return $ret;
+ }
+
+ /**
+ * Sets the value at the specified key to value
+ *
+ * @param mixed $key
+ * @param mixed $value
+ * @return void
+ */
+ public function offsetSet($key, $value)
+ {
+ $this->storage[$key] = $value;
+ }
+
+ /**
+ * Unsets the value at the specified key
+ *
+ * @param mixed $key
+ * @return void
+ */
+ public function offsetUnset($key)
+ {
+ if ($this->offsetExists($key)) {
+ unset($this->storage[$key]);
+ }
+ }
+
+ /**
+ * Serialize an ArrayObject
+ *
+ * @return string
+ */
+ public function serialize()
+ {
+ return serialize(get_object_vars($this));
+ }
+
+ /**
+ * Sets the behavior flags
+ *
+ * @param int $flags
+ * @return void
+ */
+ public function setFlags($flags)
+ {
+ $this->flag = $flags;
+ }
+
+ /**
+ * Sets the iterator classname for the ArrayObject
+ *
+ * @param string $class
+ * @return void
+ */
+ public function setIteratorClass($class)
+ {
+ if (class_exists($class)) {
+ $this->iteratorClass = $class;
+
+ return ;
+ }
+
+ if (strpos($class, '\\') === 0) {
+ $class = '\\' . $class;
+ if (class_exists($class)) {
+ $this->iteratorClass = $class;
+
+ return ;
+ }
+ }
+
+ throw new Exception\InvalidArgumentException('The iterator class does not exist');
+ }
+
+ /**
+ * Sort the entries with a user-defined comparison function and maintain key association
+ *
+ * @param callable $function
+ * @return void
+ */
+ public function uasort($function)
+ {
+ if (is_callable($function)) {
+ uasort($this->storage, $function);
+ }
+ }
+
+ /**
+ * Sort the entries by keys using a user-defined comparison function
+ *
+ * @param callable $function
+ * @return void
+ */
+ public function uksort($function)
+ {
+ if (is_callable($function)) {
+ uksort($this->storage, $function);
+ }
+ }
+
+ /**
+ * Unserialize an ArrayObject
+ *
+ * @param string $data
+ * @return void
+ */
+ public function unserialize($data)
+ {
+ $ar = unserialize($data);
+ $this->protectedProperties = array_keys(get_object_vars($this));
+
+ $this->setFlags($ar['flag']);
+ $this->exchangeArray($ar['storage']);
+ $this->setIteratorClass($ar['iteratorClass']);
+
+ foreach ($ar as $k => $v) {
+ switch ($k) {
+ case 'flag':
+ $this->setFlags($v);
+ break;
+ case 'storage':
+ $this->exchangeArray($v);
+ break;
+ case 'iteratorClass':
+ $this->setIteratorClass($v);
+ break;
+ case 'protectedProperties':
+ continue;
+ default:
+ $this->__set($k, $v);
+ }
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+interface ArraySerializableInterface
+{
+ /**
+ * Exchange internal values from provided array
+ *
+ * @param array $array
+ * @return void
+ */
+ public function exchangeArray(array $array);
+
+ /**
+ * Return an array representation of the object
+ *
+ * @return array
+ */
+ public function getArrayCopy();
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use ArrayIterator;
+use ArrayObject as PhpArrayObject;
+
+/**
+ * ArrayObject that acts as a stack with regards to iteration
+ */
+class ArrayStack extends PhpArrayObject
+{
+ /**
+ * Retrieve iterator
+ *
+ * Retrieve an array copy of the object, reverse its order, and return an
+ * ArrayIterator with that reversed array.
+ *
+ * @return ArrayIterator
+ */
+ public function getIterator()
+ {
+ $array = $this->getArrayCopy();
+ return new ArrayIterator(array_reverse($array));
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use Traversable;
+use Zend\Stdlib\ArrayUtils\MergeRemoveKey;
+use Zend\Stdlib\ArrayUtils\MergeReplaceKeyInterface;
+
+/**
+ * Utility class for testing and manipulation of PHP arrays.
+ *
+ * Declared abstract, as we have no need for instantiation.
+ */
+abstract class ArrayUtils
+{
+ /**
+ * Compatibility Flag for ArrayUtils::filter
+ */
+ const ARRAY_FILTER_USE_BOTH = 1;
+
+ /**
+ * Compatibility Flag for ArrayUtils::filter
+ */
+ const ARRAY_FILTER_USE_KEY = 2;
+
+ /**
+ * Test whether an array contains one or more string keys
+ *
+ * @param mixed $value
+ * @param bool $allowEmpty Should an empty array() return true
+ * @return bool
+ */
+ public static function hasStringKeys($value, $allowEmpty = false)
+ {
+ if (!is_array($value)) {
+ return false;
+ }
+
+ if (!$value) {
+ return $allowEmpty;
+ }
+
+ return count(array_filter(array_keys($value), 'is_string')) > 0;
+ }
+
+ /**
+ * Test whether an array contains one or more integer keys
+ *
+ * @param mixed $value
+ * @param bool $allowEmpty Should an empty array() return true
+ * @return bool
+ */
+ public static function hasIntegerKeys($value, $allowEmpty = false)
+ {
+ if (!is_array($value)) {
+ return false;
+ }
+
+ if (!$value) {
+ return $allowEmpty;
+ }
+
+ return count(array_filter(array_keys($value), 'is_int')) > 0;
+ }
+
+ /**
+ * Test whether an array contains one or more numeric keys.
+ *
+ * A numeric key can be one of the following:
+ * - an integer 1,
+ * - a string with a number '20'
+ * - a string with negative number: '-1000'
+ * - a float: 2.2120, -78.150999
+ * - a string with float: '4000.99999', '-10.10'
+ *
+ * @param mixed $value
+ * @param bool $allowEmpty Should an empty array() return true
+ * @return bool
+ */
+ public static function hasNumericKeys($value, $allowEmpty = false)
+ {
+ if (!is_array($value)) {
+ return false;
+ }
+
+ if (!$value) {
+ return $allowEmpty;
+ }
+
+ return count(array_filter(array_keys($value), 'is_numeric')) > 0;
+ }
+
+ /**
+ * Test whether an array is a list
+ *
+ * A list is a collection of values assigned to continuous integer keys
+ * starting at 0 and ending at count() - 1.
+ *
+ * For example:
+ * <code>
+ * $list = array('a', 'b', 'c', 'd');
+ * $list = array(
+ * 0 => 'foo',
+ * 1 => 'bar',
+ * 2 => array('foo' => 'baz'),
+ * );
+ * </code>
+ *
+ * @param mixed $value
+ * @param bool $allowEmpty Is an empty list a valid list?
+ * @return bool
+ */
+ public static function isList($value, $allowEmpty = false)
+ {
+ if (!is_array($value)) {
+ return false;
+ }
+
+ if (!$value) {
+ return $allowEmpty;
+ }
+
+ return (array_values($value) === $value);
+ }
+
+ /**
+ * Test whether an array is a hash table.
+ *
+ * An array is a hash table if:
+ *
+ * 1. Contains one or more non-integer keys, or
+ * 2. Integer keys are non-continuous or misaligned (not starting with 0)
+ *
+ * For example:
+ * <code>
+ * $hash = array(
+ * 'foo' => 15,
+ * 'bar' => false,
+ * );
+ * $hash = array(
+ * 1995 => 'Birth of PHP',
+ * 2009 => 'PHP 5.3.0',
+ * 2012 => 'PHP 5.4.0',
+ * );
+ * $hash = array(
+ * 'formElement,
+ * 'options' => array( 'debug' => true ),
+ * );
+ * </code>
+ *
+ * @param mixed $value
+ * @param bool $allowEmpty Is an empty array() a valid hash table?
+ * @return bool
+ */
+ public static function isHashTable($value, $allowEmpty = false)
+ {
+ if (!is_array($value)) {
+ return false;
+ }
+
+ if (!$value) {
+ return $allowEmpty;
+ }
+
+ return (array_values($value) !== $value);
+ }
+
+ /**
+ * Checks if a value exists in an array.
+ *
+ * Due to "foo" == 0 === TRUE with in_array when strict = false, an option
+ * has been added to prevent this. When $strict = 0/false, the most secure
+ * non-strict check is implemented. if $strict = -1, the default in_array
+ * non-strict behaviour is used.
+ *
+ * @param mixed $needle
+ * @param array $haystack
+ * @param int|bool $strict
+ * @return bool
+ */
+ public static function inArray($needle, array $haystack, $strict = false)
+ {
+ if (!$strict) {
+ if (is_int($needle) || is_float($needle)) {
+ $needle = (string) $needle;
+ }
+ if (is_string($needle)) {
+ foreach ($haystack as &$h) {
+ if (is_int($h) || is_float($h)) {
+ $h = (string) $h;
+ }
+ }
+ }
+ }
+ return in_array($needle, $haystack, $strict);
+ }
+
+ /**
+ * Convert an iterator to an array.
+ *
+ * Converts an iterator to an array. The $recursive flag, on by default,
+ * hints whether or not you want to do so recursively.
+ *
+ * @param array|Traversable $iterator The array or Traversable object to convert
+ * @param bool $recursive Recursively check all nested structures
+ * @throws Exception\InvalidArgumentException if $iterator is not an array or a Traversable object
+ * @return array
+ */
+ public static function iteratorToArray($iterator, $recursive = true)
+ {
+ if (!is_array($iterator) && !$iterator instanceof Traversable) {
+ throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable object');
+ }
+
+ if (!$recursive) {
+ if (is_array($iterator)) {
+ return $iterator;
+ }
+
+ return iterator_to_array($iterator);
+ }
+
+ if (method_exists($iterator, 'toArray')) {
+ return $iterator->toArray();
+ }
+
+ $array = [];
+ foreach ($iterator as $key => $value) {
+ if (is_scalar($value)) {
+ $array[$key] = $value;
+ continue;
+ }
+
+ if ($value instanceof Traversable) {
+ $array[$key] = static::iteratorToArray($value, $recursive);
+ continue;
+ }
+
+ if (is_array($value)) {
+ $array[$key] = static::iteratorToArray($value, $recursive);
+ continue;
+ }
+
+ $array[$key] = $value;
+ }
+
+ return $array;
+ }
+
+ /**
+ * Merge two arrays together.
+ *
+ * If an integer key exists in both arrays and preserveNumericKeys is false, the value
+ * from the second array will be appended to the first array. If both values are arrays, they
+ * are merged together, else the value of the second array overwrites the one of the first array.
+ *
+ * @param array $a
+ * @param array $b
+ * @param bool $preserveNumericKeys
+ * @return array
+ */
+ public static function merge(array $a, array $b, $preserveNumericKeys = false)
+ {
+ foreach ($b as $key => $value) {
+ if ($value instanceof MergeReplaceKeyInterface) {
+ $a[$key] = $value->getData();
+ } elseif (isset($a[$key]) || array_key_exists($key, $a)) {
+ if ($value instanceof MergeRemoveKey) {
+ unset($a[$key]);
+ } elseif (!$preserveNumericKeys && is_int($key)) {
+ $a[] = $value;
+ } elseif (is_array($value) && is_array($a[$key])) {
+ $a[$key] = static::merge($a[$key], $value, $preserveNumericKeys);
+ } else {
+ $a[$key] = $value;
+ }
+ } else {
+ if (!$value instanceof MergeRemoveKey) {
+ $a[$key] = $value;
+ }
+ }
+ }
+
+ return $a;
+ }
+
+ /**
+ * Compatibility Method for array_filter on <5.6 systems
+ *
+ * @param array $data
+ * @param callable $callback
+ * @param null|int $flag
+ * @return array
+ */
+ public static function filter(array $data, $callback, $flag = null)
+ {
+ if (! is_callable($callback)) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ 'Second parameter of %s must be callable',
+ __METHOD__
+ ));
+ }
+
+ if (version_compare(PHP_VERSION, '5.6.0') >= 0) {
+ return array_filter($data, $callback, $flag);
+ }
+
+ $output = [];
+ foreach ($data as $key => $value) {
+ $params = [$value];
+
+ if ($flag === static::ARRAY_FILTER_USE_BOTH) {
+ $params[] = $key;
+ }
+
+ if ($flag === static::ARRAY_FILTER_USE_KEY) {
+ $params = [$key];
+ }
+
+ $response = call_user_func_array($callback, $params);
+ if ($response) {
+ $output[$key] = $value;
+ }
+ }
+
+ return $output;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\ArrayUtils;
+
+final class MergeRemoveKey
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\ArrayUtils;
+
+final class MergeReplaceKey implements MergeReplaceKeyInterface
+{
+ /**
+ * @var mixed
+ */
+ protected $data;
+
+ /**
+ * @param mixed $data
+ */
+ public function __construct($data)
+ {
+ $this->data = $data;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getData()
+ {
+ return $this->data;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\ArrayUtils;
+
+/**
+ * Marker interface: can be used to replace keys completely in {@see ArrayUtils::merge()} operations
+ */
+interface MergeReplaceKeyInterface
+{
+ /**
+ * @return mixed
+ */
+ public function getData();
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use ReflectionClass;
+
+/**
+ * CallbackHandler
+ *
+ * A handler for an event, event, filterchain, etc. Abstracts PHP callbacks,
+ * primarily to allow for lazy-loading and ensuring availability of default
+ * arguments (currying).
+ *
+ * This was primarily used in zend-eventmanager for managing listeners; as that
+ * component removes its usage of this class for v3, it is deprecated.
+ *
+ * @deprecated as of v2.7.4.
+ */
+class CallbackHandler
+{
+ /**
+ * @var string|array|callable PHP callback to invoke
+ */
+ protected $callback;
+
+ /**
+ * Callback metadata, if any
+ * @var array
+ */
+ protected $metadata;
+
+ /**
+ * Constructor
+ *
+ * @param string|array|object|callable $callback PHP callback
+ * @param array $metadata Callback metadata
+ */
+ public function __construct($callback, array $metadata = [])
+ {
+ $this->metadata = $metadata;
+ $this->registerCallback($callback);
+ }
+
+ /**
+ * Registers the callback provided in the constructor
+ *
+ * @param callable $callback
+ * @throws Exception\InvalidCallbackException
+ * @return void
+ */
+ protected function registerCallback($callback)
+ {
+ if (!is_callable($callback)) {
+ throw new Exception\InvalidCallbackException('Invalid callback provided; not callable');
+ }
+
+ $this->callback = $callback;
+ }
+
+ /**
+ * Retrieve registered callback
+ *
+ * @return callable
+ */
+ public function getCallback()
+ {
+ return $this->callback;
+ }
+
+ /**
+ * Invoke handler
+ *
+ * @param array $args Arguments to pass to callback
+ * @return mixed
+ */
+ public function call(array $args = [])
+ {
+ $callback = $this->getCallback();
+ $argCount = count($args);
+
+ if (is_string($callback)) {
+ $result = $this->validateStringCallbackFor54($callback);
+
+ if ($result !== true && $argCount <= 3) {
+ $callback = $result;
+ // Minor performance tweak, if the callback gets called more
+ // than once
+ $this->callback = $result;
+ }
+ }
+
+ // Minor performance tweak; use call_user_func() until > 3 arguments
+ // reached
+ switch ($argCount) {
+ case 0:
+ return $callback();
+ case 1:
+ return $callback(array_shift($args));
+ case 2:
+ $arg1 = array_shift($args);
+ $arg2 = array_shift($args);
+ return $callback($arg1, $arg2);
+ case 3:
+ $arg1 = array_shift($args);
+ $arg2 = array_shift($args);
+ $arg3 = array_shift($args);
+ return $callback($arg1, $arg2, $arg3);
+ default:
+ return call_user_func_array($callback, $args);
+ }
+ }
+
+ /**
+ * Invoke as functor
+ *
+ * @return mixed
+ */
+ public function __invoke()
+ {
+ return $this->call(func_get_args());
+ }
+
+ /**
+ * Get all callback metadata
+ *
+ * @return array
+ */
+ public function getMetadata()
+ {
+ return $this->metadata;
+ }
+
+ /**
+ * Retrieve a single metadatum
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function getMetadatum($name)
+ {
+ if (array_key_exists($name, $this->metadata)) {
+ return $this->metadata[$name];
+ }
+ return;
+ }
+
+ /**
+ * Validate a static method call
+ *
+ *
+ * @param string $callback
+ * @return true|array
+ * @throws Exception\InvalidCallbackException if invalid
+ */
+ protected function validateStringCallbackFor54($callback)
+ {
+ if (!strstr($callback, '::')) {
+ return true;
+ }
+
+ list($class, $method) = explode('::', $callback, 2);
+
+ if (!class_exists($class)) {
+ throw new Exception\InvalidCallbackException(sprintf(
+ 'Static method call "%s" refers to a class that does not exist',
+ $callback
+ ));
+ }
+
+ $r = new ReflectionClass($class);
+ if (!$r->hasMethod($method)) {
+ throw new Exception\InvalidCallbackException(sprintf(
+ 'Static method call "%s" refers to a method that does not exist',
+ $callback
+ ));
+ }
+ $m = $r->getMethod($method);
+ if (!$m->isStatic()) {
+ throw new Exception\InvalidCallbackException(sprintf(
+ 'Static method call "%s" refers to a method that is not static',
+ $callback
+ ));
+ }
+
+ // returning a non boolean value may not be nice for a validate method,
+ // but that allows the usage of a static string callback without using
+ // the call_user_func function.
+ return [$class, $method];
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use DateTimeZone;
+
+trigger_error('DateTime extension deprecated as of ZF 2.1.4; use the \DateTime constructor to parse extended ISO8601 dates instead', E_USER_DEPRECATED);
+
+/**
+ * DateTime
+ *
+ * An extension of the \DateTime object.
+ *
+ * @deprecated
+ */
+class DateTime extends \DateTime
+{
+ /**
+ * The DateTime::ISO8601 constant used by php's native DateTime object does
+ * not allow for fractions of a second. This function better handles ISO8601
+ * formatted date strings.
+ *
+ * @param string $time
+ * @param DateTimeZone $timezone
+ * @return mixed
+ */
+ public static function createFromISO8601($time, DateTimeZone $timezone = null)
+ {
+ $format = self::ISO8601;
+ if (isset($time[19]) && $time[19] === '.') {
+ $format = 'Y-m-d\TH:i:s.uO';
+ }
+
+ if ($timezone !== null) {
+ return self::createFromFormat($format, $time, $timezone);
+ }
+
+ return self::createFromFormat($format, $time);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+interface DispatchableInterface
+{
+ /**
+ * Dispatch a request
+ *
+ * @param RequestInterface $request
+ * @param null|ResponseInterface $response
+ * @return Response|mixed
+ */
+ public function dispatch(RequestInterface $request, ResponseInterface $response = null);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use ErrorException;
+
+/**
+ * ErrorHandler that can be used to catch internal PHP errors
+ * and convert to an ErrorException instance.
+ */
+abstract class ErrorHandler
+{
+ /**
+ * Active stack
+ *
+ * @var array
+ */
+ protected static $stack = [];
+
+ /**
+ * Check if this error handler is active
+ *
+ * @return bool
+ */
+ public static function started()
+ {
+ return (bool) static::getNestedLevel();
+ }
+
+ /**
+ * Get the current nested level
+ *
+ * @return int
+ */
+ public static function getNestedLevel()
+ {
+ return count(static::$stack);
+ }
+
+ /**
+ * Starting the error handler
+ *
+ * @param int $errorLevel
+ */
+ public static function start($errorLevel = \E_WARNING)
+ {
+ if (!static::$stack) {
+ set_error_handler([get_called_class(), 'addError'], $errorLevel);
+ }
+
+ static::$stack[] = null;
+ }
+
+ /**
+ * Stopping the error handler
+ *
+ * @param bool $throw Throw the ErrorException if any
+ * @return null|ErrorException
+ * @throws ErrorException If an error has been catched and $throw is true
+ */
+ public static function stop($throw = false)
+ {
+ $errorException = null;
+
+ if (static::$stack) {
+ $errorException = array_pop(static::$stack);
+
+ if (!static::$stack) {
+ restore_error_handler();
+ }
+
+ if ($errorException && $throw) {
+ throw $errorException;
+ }
+ }
+
+ return $errorException;
+ }
+
+ /**
+ * Stop all active handler
+ *
+ * @return void
+ */
+ public static function clean()
+ {
+ if (static::$stack) {
+ restore_error_handler();
+ }
+
+ static::$stack = [];
+ }
+
+ /**
+ * Add an error to the stack
+ *
+ * @param int $errno
+ * @param string $errstr
+ * @param string $errfile
+ * @param int $errline
+ * @return void
+ */
+ public static function addError($errno, $errstr = '', $errfile = '', $errline = 0)
+ {
+ $stack = & static::$stack[count(static::$stack) - 1];
+ $stack = new ErrorException($errstr, 0, $errno, $errfile, $errline, $stack);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Exception;
+
+/**
+ * Bad method call exception
+ */
+class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Exception;
+
+/**
+ * Domain exception
+ */
+class DomainException extends \DomainException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Exception;
+
+/**
+ * Exception marker interface
+ */
+interface ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Exception;
+
+/**
+ * Extension not loaded exception
+ */
+class ExtensionNotLoadedException extends RuntimeException
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Exception;
+
+/**
+ * Invalid Argument Exception
+ */
+class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Exception;
+
+/**
+ * Invalid callback exception
+ */
+class InvalidCallbackException extends DomainException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Exception;
+
+/**
+ * Logic exception
+ */
+class LogicException extends \LogicException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Exception;
+
+/**
+ * Runtime exception
+ */
+class RuntimeException extends \RuntimeException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Extractor;
+
+use Zend\Hydrator\ExtractionInterface as BaseExtractionInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\ExtractionInterface from zendframework/zend-hydrator instead.
+ */
+interface ExtractionInterface extends BaseExtractionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use Iterator;
+use Countable;
+use Serializable;
+use SplPriorityQueue as PhpSplPriorityQueue;
+
+/**
+ * This is an efficient implementation of an integer priority queue in PHP
+ *
+ * This class acts like a queue with insert() and extract(), removing the
+ * elements from the queue and it also acts like an Iterator without removing
+ * the elements. This behaviour can be used in mixed scenarios with high
+ * performance boost.
+ */
+class FastPriorityQueue implements Iterator, Countable, Serializable
+{
+ const EXTR_DATA = PhpSplPriorityQueue::EXTR_DATA;
+ const EXTR_PRIORITY = PhpSplPriorityQueue::EXTR_PRIORITY;
+ const EXTR_BOTH = PhpSplPriorityQueue::EXTR_BOTH;
+
+ /**
+ * @var integer
+ */
+ protected $extractFlag = self::EXTR_DATA;
+
+ /**
+ * Elements of the queue, divided by priorities
+ *
+ * @var array
+ */
+ protected $values = [];
+
+ /**
+ * Array of priorities
+ *
+ * @var array
+ */
+ protected $priorities = [];
+
+ /**
+ * Array of priorities used for the iteration
+ *
+ * @var array
+ */
+ protected $subPriorities = [];
+
+ /**
+ * Max priority
+ *
+ * @var integer
+ */
+ protected $maxPriority = 0;
+
+ /**
+ * Total number of elements in the queue
+ *
+ * @var integer
+ */
+ protected $count = 0;
+
+ /**
+ * Index of the current element in the queue
+ *
+ * @var integer
+ */
+ protected $index = 0;
+
+ /**
+ * Sub index of the current element in the same priority level
+ *
+ * @var integer
+ */
+ protected $subIndex = 0;
+
+ /**
+ * Insert an element in the queue with a specified priority
+ *
+ * @param mixed $value
+ * @param integer $priority a positive integer
+ */
+ public function insert($value, $priority)
+ {
+ if (! is_int($priority)) {
+ throw new Exception\InvalidArgumentException('The priority must be an integer');
+ }
+ $this->values[$priority][] = $value;
+ if (! isset($this->priorities[$priority])) {
+ $this->priorities[$priority] = $priority;
+ $this->maxPriority = max($priority, $this->maxPriority);
+ }
+ ++$this->count;
+ }
+
+ /**
+ * Extract an element in the queue according to the priority and the
+ * order of insertion
+ *
+ * @return mixed
+ */
+ public function extract()
+ {
+ if (! $this->valid()) {
+ return false;
+ }
+ $value = $this->current();
+ $this->nextAndRemove();
+ return $value;
+ }
+
+ /**
+ * Remove an item from the queue
+ *
+ * This is different than {@link extract()}; its purpose is to dequeue an
+ * item.
+ *
+ * Note: this removes the first item matching the provided item found. If
+ * the same item has been added multiple times, it will not remove other
+ * instances.
+ *
+ * @param mixed $datum
+ * @return bool False if the item was not found, true otherwise.
+ */
+ public function remove($datum)
+ {
+ $this->rewind();
+ while ($this->valid()) {
+ if (current($this->values[$this->maxPriority]) === $datum) {
+ $index = key($this->values[$this->maxPriority]);
+ unset($this->values[$this->maxPriority][$index]);
+ --$this->count;
+ return true;
+ }
+ $this->next();
+ }
+ return false;
+ }
+
+ /**
+ * Get the total number of elements in the queue
+ *
+ * @return integer
+ */
+ public function count()
+ {
+ return $this->count;
+ }
+
+ /**
+ * Get the current element in the queue
+ *
+ * @return mixed
+ */
+ public function current()
+ {
+ switch ($this->extractFlag) {
+ case self::EXTR_DATA:
+ return current($this->values[$this->maxPriority]);
+ case self::EXTR_PRIORITY:
+ return $this->maxPriority;
+ case self::EXTR_BOTH:
+ return [
+ 'data' => current($this->values[$this->maxPriority]),
+ 'priority' => $this->maxPriority
+ ];
+ }
+ }
+
+ /**
+ * Get the index of the current element in the queue
+ *
+ * @return integer
+ */
+ public function key()
+ {
+ return $this->index;
+ }
+
+ /**
+ * Set the iterator pointer to the next element in the queue
+ * removing the previous element
+ */
+ protected function nextAndRemove()
+ {
+ if (false === next($this->values[$this->maxPriority])) {
+ unset($this->priorities[$this->maxPriority]);
+ unset($this->values[$this->maxPriority]);
+ $this->maxPriority = empty($this->priorities) ? 0 : max($this->priorities);
+ $this->subIndex = -1;
+ }
+ ++$this->index;
+ ++$this->subIndex;
+ --$this->count;
+ }
+
+ /**
+ * Set the iterator pointer to the next element in the queue
+ * without removing the previous element
+ */
+ public function next()
+ {
+ if (false === next($this->values[$this->maxPriority])) {
+ unset($this->subPriorities[$this->maxPriority]);
+ reset($this->values[$this->maxPriority]);
+ $this->maxPriority = empty($this->subPriorities) ? 0 : max($this->subPriorities);
+ $this->subIndex = -1;
+ }
+ ++$this->index;
+ ++$this->subIndex;
+ }
+
+ /**
+ * Check if the current iterator is valid
+ *
+ * @return boolean
+ */
+ public function valid()
+ {
+ return isset($this->values[$this->maxPriority]);
+ }
+
+ /**
+ * Rewind the current iterator
+ */
+ public function rewind()
+ {
+ $this->subPriorities = $this->priorities;
+ $this->maxPriority = empty($this->priorities) ? 0 : max($this->priorities);
+ $this->index = 0;
+ $this->subIndex = 0;
+ }
+
+ /**
+ * Serialize to an array
+ *
+ * Array will be priority => data pairs
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $array = [];
+ foreach (clone $this as $item) {
+ $array[] = $item;
+ }
+ return $array;
+ }
+
+ /**
+ * Serialize
+ *
+ * @return string
+ */
+ public function serialize()
+ {
+ $clone = clone $this;
+ $clone->setExtractFlags(self::EXTR_BOTH);
+
+ $data = [];
+ foreach ($clone as $item) {
+ $data[] = $item;
+ }
+
+ return serialize($data);
+ }
+
+ /**
+ * Deserialize
+ *
+ * @param string $data
+ * @return void
+ */
+ public function unserialize($data)
+ {
+ foreach (unserialize($data) as $item) {
+ $this->insert($item['data'], $item['priority']);
+ }
+ }
+
+ /**
+ * Set the extract flag
+ *
+ * @param integer $flag
+ */
+ public function setExtractFlags($flag)
+ {
+ switch ($flag) {
+ case self::EXTR_DATA:
+ case self::EXTR_PRIORITY:
+ case self::EXTR_BOTH:
+ $this->extractFlag = $flag;
+ break;
+ default:
+ throw new Exception\InvalidArgumentException("The extract flag specified is not valid");
+ }
+ }
+
+ /**
+ * Check if the queue is empty
+ *
+ * @return boolean
+ */
+ public function isEmpty()
+ {
+ return empty($this->values);
+ }
+
+ /**
+ * Does the queue contain the given datum?
+ *
+ * @param mixed $datum
+ * @return bool
+ */
+ public function contains($datum)
+ {
+ foreach ($this->values as $values) {
+ if (in_array($datum, $values)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Does the queue have an item with the given priority?
+ *
+ * @param int $priority
+ * @return bool
+ */
+ public function hasPriority($priority)
+ {
+ return isset($this->values[$priority]);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+/**
+ * Wrapper for glob with fallback if GLOB_BRACE is not available.
+ */
+abstract class Glob
+{
+ /**#@+
+ * Glob constants.
+ */
+ const GLOB_MARK = 0x01;
+ const GLOB_NOSORT = 0x02;
+ const GLOB_NOCHECK = 0x04;
+ const GLOB_NOESCAPE = 0x08;
+ const GLOB_BRACE = 0x10;
+ const GLOB_ONLYDIR = 0x20;
+ const GLOB_ERR = 0x40;
+ /**#@-*/
+
+ /**
+ * Find pathnames matching a pattern.
+ *
+ * @see http://docs.php.net/glob
+ * @param string $pattern
+ * @param int $flags
+ * @param bool $forceFallback
+ * @return array
+ * @throws Exception\RuntimeException
+ */
+ public static function glob($pattern, $flags = 0, $forceFallback = false)
+ {
+ if (!defined('GLOB_BRACE') || $forceFallback) {
+ return static::fallbackGlob($pattern, $flags);
+ }
+
+ return static::systemGlob($pattern, $flags);
+ }
+
+ /**
+ * Use the glob function provided by the system.
+ *
+ * @param string $pattern
+ * @param int $flags
+ * @return array
+ * @throws Exception\RuntimeException
+ */
+ protected static function systemGlob($pattern, $flags)
+ {
+ if ($flags) {
+ $flagMap = [
+ self::GLOB_MARK => GLOB_MARK,
+ self::GLOB_NOSORT => GLOB_NOSORT,
+ self::GLOB_NOCHECK => GLOB_NOCHECK,
+ self::GLOB_NOESCAPE => GLOB_NOESCAPE,
+ self::GLOB_BRACE => defined('GLOB_BRACE') ? GLOB_BRACE : 0,
+ self::GLOB_ONLYDIR => GLOB_ONLYDIR,
+ self::GLOB_ERR => GLOB_ERR,
+ ];
+
+ $globFlags = 0;
+
+ foreach ($flagMap as $internalFlag => $globFlag) {
+ if ($flags & $internalFlag) {
+ $globFlags |= $globFlag;
+ }
+ }
+ } else {
+ $globFlags = 0;
+ }
+
+ ErrorHandler::start();
+ $res = glob($pattern, $globFlags);
+ $err = ErrorHandler::stop();
+ if ($res === false) {
+ throw new Exception\RuntimeException("glob('{$pattern}', {$globFlags}) failed", 0, $err);
+ }
+ return $res;
+ }
+
+ /**
+ * Expand braces manually, then use the system glob.
+ *
+ * @param string $pattern
+ * @param int $flags
+ * @return array
+ * @throws Exception\RuntimeException
+ */
+ protected static function fallbackGlob($pattern, $flags)
+ {
+ if (!$flags & self::GLOB_BRACE) {
+ return static::systemGlob($pattern, $flags);
+ }
+
+ $flags &= ~self::GLOB_BRACE;
+ $length = strlen($pattern);
+ $paths = [];
+
+ if ($flags & self::GLOB_NOESCAPE) {
+ $begin = strpos($pattern, '{');
+ } else {
+ $begin = 0;
+
+ while (true) {
+ if ($begin === $length) {
+ $begin = false;
+ break;
+ } elseif ($pattern[$begin] === '\\' && ($begin + 1) < $length) {
+ $begin++;
+ } elseif ($pattern[$begin] === '{') {
+ break;
+ }
+
+ $begin++;
+ }
+ }
+
+ if ($begin === false) {
+ return static::systemGlob($pattern, $flags);
+ }
+
+ $next = static::nextBraceSub($pattern, $begin + 1, $flags);
+
+ if ($next === null) {
+ return static::systemGlob($pattern, $flags);
+ }
+
+ $rest = $next;
+
+ while ($pattern[$rest] !== '}') {
+ $rest = static::nextBraceSub($pattern, $rest + 1, $flags);
+
+ if ($rest === null) {
+ return static::systemGlob($pattern, $flags);
+ }
+ }
+
+ $p = $begin + 1;
+
+ while (true) {
+ $subPattern = substr($pattern, 0, $begin)
+ . substr($pattern, $p, $next - $p)
+ . substr($pattern, $rest + 1);
+
+ $result = static::fallbackGlob($subPattern, $flags | self::GLOB_BRACE);
+
+ if ($result) {
+ $paths = array_merge($paths, $result);
+ }
+
+ if ($pattern[$next] === '}') {
+ break;
+ }
+
+ $p = $next + 1;
+ $next = static::nextBraceSub($pattern, $p, $flags);
+ }
+
+ return array_unique($paths);
+ }
+
+ /**
+ * Find the end of the sub-pattern in a brace expression.
+ *
+ * @param string $pattern
+ * @param int $begin
+ * @param int $flags
+ * @return int|null
+ */
+ protected static function nextBraceSub($pattern, $begin, $flags)
+ {
+ $length = strlen($pattern);
+ $depth = 0;
+ $current = $begin;
+
+ while ($current < $length) {
+ if (!$flags & self::GLOB_NOESCAPE && $pattern[$current] === '\\') {
+ if (++$current === $length) {
+ break;
+ }
+
+ $current++;
+ } else {
+ if (($pattern[$current] === '}' && $depth-- === 0) || ($pattern[$current] === ',' && $depth === 0)) {
+ break;
+ } elseif ($pattern[$current++] === '{') {
+ $depth++;
+ }
+ }
+ }
+
+ return ($current < $length ? $current : null);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Guard;
+
+/**
+ * An aggregate for all guard traits
+ */
+trait AllGuardsTrait
+{
+ use ArrayOrTraversableGuardTrait;
+ use EmptyGuardTrait;
+ use NullGuardTrait;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Guard;
+
+use Traversable;
+
+/**
+ * Provide a guard method for array or Traversable data
+ */
+trait ArrayOrTraversableGuardTrait
+{
+ /**
+ * Verifies that the data is an array or Traversable
+ *
+ * @param mixed $data the data to verify
+ * @param string $dataName the data name
+ * @param string $exceptionClass FQCN for the exception
+ * @throws \Exception
+ */
+ protected function guardForArrayOrTraversable(
+ $data,
+ $dataName = 'Argument',
+ $exceptionClass = 'Zend\Stdlib\Exception\InvalidArgumentException'
+ ) {
+ if (!is_array($data) && !($data instanceof Traversable)) {
+ $message = sprintf(
+ "%s must be an array or Traversable, [%s] given",
+ $dataName,
+ is_object($data) ? get_class($data) : gettype($data)
+ );
+ throw new $exceptionClass($message);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Guard;
+
+/**
+ * Provide a guard method against empty data
+ */
+trait EmptyGuardTrait
+{
+ /**
+ * Verify that the data is not empty
+ *
+ * @param mixed $data the data to verify
+ * @param string $dataName the data name
+ * @param string $exceptionClass FQCN for the exception
+ * @throws \Exception
+ */
+ protected function guardAgainstEmpty(
+ $data,
+ $dataName = 'Argument',
+ $exceptionClass = 'Zend\Stdlib\Exception\InvalidArgumentException'
+ ) {
+ if (empty($data)) {
+ $message = sprintf('%s cannot be empty', $dataName);
+ throw new $exceptionClass($message);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Guard;
+
+use Traversable;
+
+/**
+ * Static guard helper class
+ *
+ * Bridges the gap for allowing refactoring until traits can be used by default.
+ *
+ * @deprecated
+ */
+abstract class GuardUtils
+{
+ const DEFAULT_EXCEPTION_CLASS = 'Zend\Stdlib\Exception\InvalidArgumentException';
+
+ /**
+ * Verifies that the data is an array or Traversable
+ *
+ * @param mixed $data the data to verify
+ * @param string $dataName the data name
+ * @param string $exceptionClass FQCN for the exception
+ * @throws \Exception
+ */
+ public static function guardForArrayOrTraversable(
+ $data,
+ $dataName = 'Argument',
+ $exceptionClass = self::DEFAULT_EXCEPTION_CLASS
+ ) {
+ if (!is_array($data) && !($data instanceof Traversable)) {
+ $message = sprintf(
+ '%s must be an array or Traversable, [%s] given',
+ $dataName,
+ is_object($data) ? get_class($data) : gettype($data)
+ );
+ throw new $exceptionClass($message);
+ }
+ }
+
+ /**
+ * Verify that the data is not empty
+ *
+ * @param mixed $data the data to verify
+ * @param string $dataName the data name
+ * @param string $exceptionClass FQCN for the exception
+ * @throws \Exception
+ */
+ public static function guardAgainstEmpty(
+ $data,
+ $dataName = 'Argument',
+ $exceptionClass = self::DEFAULT_EXCEPTION_CLASS
+ ) {
+ if (empty($data)) {
+ $message = sprintf('%s cannot be empty', $dataName);
+ throw new $exceptionClass($message);
+ }
+ }
+
+ /**
+ * Verify that the data is not null
+ *
+ * @param mixed $data the data to verify
+ * @param string $dataName the data name
+ * @param string $exceptionClass FQCN for the exception
+ * @throws \Exception
+ */
+ public static function guardAgainstNull(
+ $data,
+ $dataName = 'Argument',
+ $exceptionClass = self::DEFAULT_EXCEPTION_CLASS
+ ) {
+ if (null === $data) {
+ $message = sprintf('%s cannot be null', $dataName);
+ throw new $exceptionClass($message);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Guard;
+
+/**
+ * Provide a guard method against null data
+ */
+trait NullGuardTrait
+{
+ /**
+ * Verify that the data is not null
+ *
+ * @param mixed $data the data to verify
+ * @param string $dataName the data name
+ * @param string $exceptionClass FQCN for the exception
+ * @throws \Exception
+ */
+ protected function guardAgainstNull(
+ $data,
+ $dataName = 'Argument',
+ $exceptionClass = 'Zend\Stdlib\Exception\InvalidArgumentException'
+ ) {
+ if (null === $data) {
+ $message = sprintf('%s cannot be null', $dataName);
+ throw new $exceptionClass($message);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\AbstractHydrator as BaseAbstractHydrator;
+
+/**
+ * @deprecated Use Zend\Hydrator\AbstractHydrator from zendframework/zend-hydrator instead.
+ */
+abstract class AbstractHydrator extends BaseAbstractHydrator implements HydratorInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Aggregate;
+
+use Zend\Hydrator\Aggregate\AggregateHydrator as BaseAggregateHydrator;
+use Zend\Stdlib\Hydrator\HydratorInterface;
+
+/**
+ * Aggregate hydrator that composes multiple hydrators via events
+ *
+ * @deprecated Use Zend\Hydrator\Aggregate\AggregateHydrator from zendframework/zend-hydrator instead.
+ */
+class AggregateHydrator extends BaseAggregateHydrator implements HydratorInterface
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function extract($object)
+ {
+ $event = new ExtractEvent($this, $object);
+
+ $this->getEventManager()->triggerEvent($event);
+
+ return $event->getExtractedData();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function hydrate(array $data, $object)
+ {
+ $event = new HydrateEvent($this, $object, $data);
+
+ $this->getEventManager()->triggerEvent($event);
+
+ return $event->getHydratedObject();
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Aggregate;
+
+use Zend\Hydrator\Aggregate\ExtractEvent as BaseExtractEvent;
+
+/**
+ * Event triggered when the {@see \Zend\Stdlib\Hydrator\Aggregate\AggregateHydrator} extracts
+ * data from an object
+ *
+ * @deprecated Use Zend\Hydrator\Aggregate\ExtractEvent from zendframework/zend-hydrator instead.
+ */
+class ExtractEvent extends BaseExtractEvent
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Aggregate;
+
+use Zend\Hydrator\Aggregate\HydrateEvent as BaseHydrateEvent;
+
+/**
+ * Event triggered when the {@see \Zend\Stdlib\Hydrator\Aggregate\AggregateHydrator} hydrates
+ * data into an object
+ *
+ * @deprecated Use Zend\Hydrator\Aggregate\HydrateEvent from zendframework/zend-hydrator instead.
+ */
+class HydrateEvent extends BaseHydrateEvent
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Aggregate;
+
+use Zend\Hydrator\Aggregate\HydratorListener as BaseHydratorListener;
+
+/**
+ * Aggregate listener wrapping around a hydrator. Listens
+ * to {@see \Zend\Stdlib\Hydrator\Aggregate::EVENT_HYDRATE} and
+ * {@see \Zend\Stdlib\Hydrator\Aggregate::EVENT_EXTRACT}
+ *
+ * @deprecated Use Zend\Hydrator\Aggregate\HydratorListener from zendframework/zend-hydrator instead.
+ */
+class HydratorListener extends BaseHydratorListener
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\ArraySerializable as BaseArraySerializable;
+
+/**
+ * @deprecated Use Zend\Hydrator\ArraySerializable from zendframework/zend-hydrator instead.
+ */
+class ArraySerializable extends BaseArraySerializable implements HydratorInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\ClassMethods as BaseClassMethods;
+
+/**
+ * @deprecated Use Zend\Hydrator\ClassMethods from zendframework/zend-hydrator instead.
+ */
+class ClassMethods extends BaseClassMethods implements HydratorInterface, HydratorOptionsInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\DelegatingHydrator as BaseDelegatingHydrator;
+
+/**
+ * @deprecated Use Zend\Hydrator\DelegatingHydrator from zendframework/zend-hydrator instead.
+ */
+class DelegatingHydrator extends BaseDelegatingHydrator implements HydratorInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\ServiceManager\FactoryInterface;
+use Zend\ServiceManager\ServiceLocatorInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\DelegatingHydratorFactory from zendframework/zend-hydrator instead.
+ */
+class DelegatingHydratorFactory implements FactoryInterface
+{
+ public function createService(ServiceLocatorInterface $serviceLocator)
+ {
+ // Assume that this factory is registered with the HydratorManager,
+ // and just pass it directly on.
+ return new DelegatingHydrator($serviceLocator);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+namespace Zend\Stdlib\Hydrator\Filter;
+
+use Zend\Hydrator\Filter\FilterComposite as BaseFilterComposite;
+
+/**
+ * @deprecated Use Zend\Hydrator\Filter\FilterComposite from zendframework/zend-hydrator instead.
+ */
+class FilterComposite extends BaseFilterComposite implements FilterInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+namespace Zend\Stdlib\Hydrator\Filter;
+
+use Zend\Hydrator\Filter\FilterInterface as BaseFilterInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\Filter\FilterInterface from zendframework/zend-hydrator instead.
+ */
+interface FilterInterface extends BaseFilterInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+namespace Zend\Stdlib\Hydrator\Filter;
+
+use Zend\Hydrator\Filter\FilterProviderInterface as BaseFilterProviderInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\Filter\FilterProviderInterface from zendframework/zend-hydrator instead.
+ */
+interface FilterProviderInterface extends BaseFilterProviderInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+namespace Zend\Stdlib\Hydrator\Filter;
+
+use Zend\Hydrator\Filter\GetFilter as BaseGetFilter;
+
+/**
+ * @deprecated Use Zend\Hydrator\Filter\GetFilter from zendframework/zend-hydrator instead.
+ */
+class GetFilter extends BaseGetFilter implements FilterInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+namespace Zend\Stdlib\Hydrator\Filter;
+
+use Zend\Hydrator\Filter\HasFilter as BaseHasFilter;
+
+/**
+ * @deprecated Use Zend\Hydrator\Filter\HasFilter from zendframework/zend-hydrator instead.
+ */
+class HasFilter extends BaseHasFilter implements FilterInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+namespace Zend\Stdlib\Hydrator\Filter;
+
+use Zend\Hydrator\Filter\IsFilter as BaseIsFilter;
+
+/**
+ * @deprecated Use Zend\Hydrator\Filter\IsFilter from zendframework/zend-hydrator instead.
+ */
+class IsFilter extends BaseIsFilter implements FilterInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+namespace Zend\Stdlib\Hydrator\Filter;
+
+use Zend\Hydrator\Filter\MethodMatchFilter as BaseMethodMatchFilter;
+
+/**
+ * @deprecated Use Zend\Hydrator\Filter\MethodMatchFilter from zendframework/zend-hydrator instead.
+ */
+class MethodMatchFilter extends BaseMethodMatchFilter implements FilterInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Filter;
+
+use Zend\Hydrator\Filter\NumberOfParameterFilter as BaseNumberOfParameterFilter;
+
+/**
+ * @deprecated Use Zend\Hydrator\Filter\NumberOfParameterFilter from zendframework/zend-hydrator instead.
+ */
+class NumberOfParameterFilter extends BaseNumberOfParameterFilter implements FilterInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+namespace Zend\Stdlib\Hydrator\Filter;
+
+use Zend\Hydrator\Filter\OptionalParametersFilter as BaseOptionalParametersFilter;
+
+/**
+ * Filter that includes methods which have no parameters or only optional parameters
+ *
+ * @deprecated Use Zend\Hydrator\Filter\OptionalParametersFilter from zendframework/zend-hydrator instead.
+ */
+class OptionalParametersFilter extends BaseOptionalParametersFilter implements FilterInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\FilterEnabledInterface as BaseFilterEnabledInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\FilterEnabledInterface from zendframework/zend-hydrator instead.
+ */
+interface FilterEnabledInterface extends BaseFilterEnabledInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\HydrationInterface as BaseHydrationInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\HydrationInterface from zendframework/zend-hydrator instead.
+ */
+interface HydrationInterface extends BaseHydrationInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\HydratorAwareInterface as BaseHydratorAwareInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\HydratorAwareInterface from zendframework/zend-hydrator instead.
+ */
+interface HydratorAwareInterface extends BaseHydratorAwareInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\HydratorAwareTrait as BaseHydratorAwareTrait;
+
+/**
+ * @deprecated Use Zend\Hydrator\HydratorAwareTrait from zendframework/zend-hydrator instead.
+ */
+trait HydratorAwareTrait
+{
+ use BaseHydratorAwareTrait;
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Stdlib\Extractor\ExtractionInterface;
+use Zend\Hydrator\HydratorInterface as BaseHydratorInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\HydratorInterface from zendframework/zend-hydrator instead.
+ */
+interface HydratorInterface extends BaseHydratorInterface, HydrationInterface, ExtractionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\HydratorOptionsInterface as BaseHydratorOptionsInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\HydratorOptionsInterface from zendframework/zend-hydrator instead.
+ */
+interface HydratorOptionsInterface extends BaseHydratorOptionsInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\HydratorPluginManager as BaseHydratorPluginManager;
+
+/**
+ * Plugin manager implementation for hydrators.
+ *
+ * Enforces that adapters retrieved are instances of HydratorInterface
+ *
+ * @deprecated Use Zend\Hydrator\HydratorPluginManager from zendframework/zend-hydrator instead.
+ */
+class HydratorPluginManager extends BaseHydratorPluginManager
+{
+ /**
+ * Default aliases
+ *
+ * @var array
+ */
+ protected $aliases = [
+ 'delegatinghydrator' => 'Zend\Stdlib\Hydrator\DelegatingHydrator',
+ ];
+
+ /**
+ * Default set of adapters
+ *
+ * @var array
+ */
+ protected $invokableClasses = [
+ 'arrayserializable' => 'Zend\Stdlib\Hydrator\ArraySerializable',
+ 'classmethods' => 'Zend\Stdlib\Hydrator\ClassMethods',
+ 'objectproperty' => 'Zend\Stdlib\Hydrator\ObjectProperty',
+ 'reflection' => 'Zend\Stdlib\Hydrator\Reflection'
+ ];
+
+ /**
+ * Default factory-based adapters
+ *
+ * @var array
+ */
+ protected $factories = [
+ 'Zend\Stdlib\Hydrator\DelegatingHydrator' => 'Zend\Stdlib\Hydrator\DelegatingHydratorFactory',
+ 'zendstdlibhydratordelegatinghydrator' => 'Zend\Stdlib\Hydrator\DelegatingHydratorFactory',
+ ];
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Iterator;
+
+use Zend\Hydrator\Iterator\HydratingArrayIterator as BaseHydratingArrayIterator;
+
+/**
+ * @deprecated Use Zend\Hydrator\Iterator\HydratingArrayIterator from zendframework/zend-hydrator instead.
+ */
+class HydratingArrayIterator extends BaseHydratingArrayIterator implements HydratingIteratorInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Iterator;
+
+use Zend\Hydrator\Iterator\HydratingIteratorInterface as BaseHydratingIteratorInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\Iterator\HydratingIteratorInterface from zendframework/zend-hydrator instead.
+ */
+interface HydratingIteratorInterface extends BaseHydratingIteratorInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Iterator;
+
+use Zend\Hydrator\Iterator\HydratingIteratorIterator as BaseHydratingIteratorIterator;
+
+/**
+ * @deprecated Use Zend\Hydrator\Iterator\HydratingIteratorIterator from zendframework/zend-hydrator instead.
+ */
+class HydratingIteratorIterator extends BaseHydratingIteratorIterator implements HydratingIteratorInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\NamingStrategy;
+
+use Zend\Hydrator\NamingStrategy\ArrayMapNamingStrategy as BaseArrayMapNamingStrategy;
+
+/**
+ * @deprecated Use Zend\Hydrator\NamingStrategy\ArrayMapNamingStrategy from zendframework/zend-hydrator instead.
+ */
+class ArrayMapNamingStrategy extends BaseArrayMapNamingStrategy implements NamingStrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\NamingStrategy;
+
+use Zend\Hydrator\NamingStrategy\CompositeNamingStrategy as BaseCompositeNamingStrategy;
+
+/**
+ * @deprecated Use Zend\Hydrator\NamingStrategy\CompositeNamingStrategy from zendframework/zend-hydrator instead.
+ */
+class CompositeNamingStrategy extends BaseCompositeNamingStrategy implements NamingStrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\NamingStrategy;
+
+use Zend\Hydrator\NamingStrategy\IdentityNamingStrategy as BaseIdentityNamingStrategy;
+
+/**
+ * @deprecated Use Zend\Hydrator\NamingStrategy\IdentityNamingStrategy from zendframework/zend-hydrator instead.
+ */
+class IdentityNamingStrategy extends BaseIdentityNamingStrategy implements NamingStrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\NamingStrategy;
+
+use Zend\Hydrator\NamingStrategy\MapNamingStrategy as BaseMapNamingStrategy;
+
+/**
+ * @deprecated Use Zend\Hydrator\NamingStrategy\MapNamingStrategy from zendframework/zend-hydrator instead.
+ */
+class MapNamingStrategy extends BaseMapNamingStrategy implements NamingStrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\NamingStrategy;
+
+use Zend\Hydrator\NamingStrategy\NamingStrategyInterface as BaseNamingStrategyInterface;
+
+/**
+ * Allow property extraction / hydration for hydrator
+ *
+ * @deprecated Use Zend\Hydrator\NamingStrategy\NamingStrategyInterface from zendframework/zend-hydrator instead.
+ */
+interface NamingStrategyInterface extends BaseNamingStrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\NamingStrategy;
+
+use Zend\Hydrator\NamingStrategy\UnderscoreNamingStrategy as BaseUnderscoreNamingStrategy;
+
+/**
+ * @deprecated Use Zend\Hydrator\NamingStrategy\UnderscoreNamingStrategy from zendframework/zend-hydrator instead.
+ */
+class UnderscoreNamingStrategy extends BaseUnderscoreNamingStrategy implements NamingStrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\NamingStrategyEnabledInterface as BaseNamingStrategyEnabledInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\NamingStrategy\NamingStrategyEnabledInterface from zendframework/zend-hydrator instead.
+ */
+interface NamingStrategyEnabledInterface extends BaseNamingStrategyEnabledInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\ObjectProperty as BaseObjectProperty;
+
+/**
+ * @deprecated Use Zend\Hydrator\ObjectProperty from zendframework/zend-hydrator instead.
+ */
+class ObjectProperty extends BaseObjectProperty implements HydratorInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\Reflection as BaseReflection;
+
+/**
+ * @deprecated Use Zend\Hydrator\Reflection from zendframework/zend-hydrator instead.
+ */
+class Reflection extends BaseReflection implements HydratorInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Strategy;
+
+use Zend\Hydrator\Strategy\BooleanStrategy as BaseBooleanStrategy;
+
+/**
+ * This Strategy extracts and hydrates int and string values to Boolean values
+ *
+ * @deprecated Use Zend\Hydrator\Strategy\BooleanStrategy from zendframework/zend-hydrator instead.
+ */
+class BooleanStrategy extends BaseBooleanStrategy implements StrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Strategy;
+
+use Zend\Hydrator\Strategy\ClosureStrategy as BaseClosureStrategy;
+
+/**
+ * @deprecated Use Zend\Hydrator\Strategy\ClosureStrategy from zendframework/zend-hydrator instead.
+ */
+class ClosureStrategy extends BaseClosureStrategy implements StrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Strategy;
+
+use Zend\Hydrator\Strategy\DateTimeFormatterStrategy as BaseDateTimeFormatterStrategy;
+
+/**
+ * @deprecated Use Zend\Hydrator\Strategy\DateTimeFormatterStrategy from zendframework/zend-hydrator instead.
+ */
+class DateTimeFormatterStrategy extends BaseDateTimeFormatterStrategy implements StrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Strategy;
+
+use Zend\Hydrator\Strategy\DefaultStrategy as BaseDefaultStrategy;
+
+/**
+ * @deprecated Use Zend\Hydrator\Strategy\DefaultStrategy from zendframework/zend-hydrator instead.
+ */
+class DefaultStrategy extends BaseDefaultStrategy implements StrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Strategy\Exception;
+
+use Zend\Hydrator\Strategy\Exception;
+
+/**
+ * @deprecated Use Zend\Hydrator\Strategy\Exception\ExceptionInterface from zendframework/zend-hydrator instead.
+ */
+interface ExceptionInterface extends Exception\ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Strategy\Exception;
+
+use Zend\Hydrator\Strategy\Exception\InvalidArgumentException as BaseInvalidArgumentException;
+
+/**
+ * @deprecated Use Zend\Hydrator\Strategy\Exception\InvalidArgumentException from zendframework/zend-hydrator instead.
+ */
+class InvalidArgumentException extends BaseInvalidArgumentException implements ExceptionInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Strategy;
+
+use Zend\Hydrator\Strategy\ExplodeStrategy as BaseExplodeStrategy;
+
+/**
+ * @deprecated Use Zend\Hydrator\Strategy\ExplodeStrategy from zendframework/zend-hydrator instead.
+ */
+class ExplodeStrategy extends BaseExplodeStrategy implements StrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Strategy;
+
+use Zend\Hydrator\Strategy\SerializableStrategy as BaseSerializableStrategy;
+
+/**
+ * @deprecated Use Zend\Hydrator\Strategy\SerializableStrategy from zendframework/zend-hydrator instead.
+ */
+class SerializableStrategy extends BaseSerializableStrategy implements StrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Strategy;
+
+use Zend\Hydrator\Strategy\StrategyChain as BaseStrategyChain;
+
+/**
+ * @deprecated Use Zend\Hydrator\Strategy\StrategyChain from zendframework/zend-hydrator instead.
+ */
+class StrategyChain extends BaseStrategyChain implements StrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator\Strategy;
+
+use Zend\Hydrator\Strategy\StrategyInterface as BaseStrategyInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\Strategy\StrategyInterface from zendframework/zend-hydrator instead.
+ */
+interface StrategyInterface extends BaseStrategyInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\Hydrator;
+
+use Zend\Hydrator\StrategyEnabledInterface as BaseStrategyEnabledInterface;
+
+/**
+ * @deprecated Use Zend\Hydrator\Strategy\StrategyEnabledInterface from zendframework/zend-hydrator instead.
+ */
+interface StrategyEnabledInterface extends BaseStrategyEnabledInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+/**
+ * Interface to allow objects to have initialization logic
+ */
+interface InitializableInterface
+{
+ /**
+ * Init an object
+ *
+ * @return void
+ */
+ public function init();
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+interface JsonSerializable extends \JsonSerializable
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use Traversable;
+
+class Message implements MessageInterface
+{
+ /**
+ * @var array
+ */
+ protected $metadata = [];
+
+ /**
+ * @var string
+ */
+ protected $content = '';
+
+ /**
+ * Set message metadata
+ *
+ * Non-destructive setting of message metadata; always adds to the metadata, never overwrites
+ * the entire metadata container.
+ *
+ * @param string|int|array|Traversable $spec
+ * @param mixed $value
+ * @throws Exception\InvalidArgumentException
+ * @return Message
+ */
+ public function setMetadata($spec, $value = null)
+ {
+ if (is_scalar($spec)) {
+ $this->metadata[$spec] = $value;
+ return $this;
+ }
+ if (!is_array($spec) && !$spec instanceof Traversable) {
+ throw new Exception\InvalidArgumentException(sprintf(
+ 'Expected a string, array, or Traversable argument in first position; received "%s"',
+ (is_object($spec) ? get_class($spec) : gettype($spec))
+ ));
+ }
+ foreach ($spec as $key => $value) {
+ $this->metadata[$key] = $value;
+ }
+ return $this;
+ }
+
+ /**
+ * Retrieve all metadata or a single metadatum as specified by key
+ *
+ * @param null|string|int $key
+ * @param null|mixed $default
+ * @throws Exception\InvalidArgumentException
+ * @return mixed
+ */
+ public function getMetadata($key = null, $default = null)
+ {
+ if (null === $key) {
+ return $this->metadata;
+ }
+
+ if (!is_scalar($key)) {
+ throw new Exception\InvalidArgumentException('Non-scalar argument provided for key');
+ }
+
+ if (array_key_exists($key, $this->metadata)) {
+ return $this->metadata[$key];
+ }
+
+ return $default;
+ }
+
+ /**
+ * Set message content
+ *
+ * @param mixed $value
+ * @return Message
+ */
+ public function setContent($value)
+ {
+ $this->content = $value;
+ return $this;
+ }
+
+ /**
+ * Get message content
+ *
+ * @return mixed
+ */
+ public function getContent()
+ {
+ return $this->content;
+ }
+
+ /**
+ * @return string
+ */
+ public function toString()
+ {
+ $request = '';
+ foreach ($this->getMetadata() as $key => $value) {
+ $request .= sprintf(
+ "%s: %s\r\n",
+ (string) $key,
+ (string) $value
+ );
+ }
+ $request .= "\r\n" . $this->getContent();
+ return $request;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+interface MessageInterface
+{
+ /**
+ * Set metadata
+ *
+ * @param string|int|array|\Traversable $spec
+ * @param mixed $value
+ */
+ public function setMetadata($spec, $value = null);
+
+ /**
+ * Get metadata
+ *
+ * @param null|string|int $key
+ * @return mixed
+ */
+ public function getMetadata($key = null);
+
+ /**
+ * Set content
+ *
+ * @param mixed $content
+ * @return mixed
+ */
+ public function setContent($content);
+
+ /**
+ * Get content
+ *
+ * @return mixed
+ */
+ public function getContent();
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+interface ParameterObjectInterface
+{
+ /**
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function __set($key, $value);
+
+ /**
+ * @param string $key
+ * @return mixed
+ */
+ public function __get($key);
+
+ /**
+ * @param string $key
+ * @return bool
+ */
+ public function __isset($key);
+
+ /**
+ * @param string $key
+ * @return void
+ */
+ public function __unset($key);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use ArrayObject as PhpArrayObject;
+
+class Parameters extends PhpArrayObject implements ParametersInterface
+{
+ /**
+ * Constructor
+ *
+ * Enforces that we have an array, and enforces parameter access to array
+ * elements.
+ *
+ * @param array $values
+ */
+ public function __construct(array $values = null)
+ {
+ if (null === $values) {
+ $values = [];
+ }
+ parent::__construct($values, ArrayObject::ARRAY_AS_PROPS);
+ }
+
+ /**
+ * Populate from native PHP array
+ *
+ * @param array $values
+ * @return void
+ */
+ public function fromArray(array $values)
+ {
+ $this->exchangeArray($values);
+ }
+
+ /**
+ * Populate from query string
+ *
+ * @param string $string
+ * @return void
+ */
+ public function fromString($string)
+ {
+ $array = [];
+ parse_str($string, $array);
+ $this->fromArray($array);
+ }
+
+ /**
+ * Serialize to native PHP array
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return $this->getArrayCopy();
+ }
+
+ /**
+ * Serialize to query string
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ return http_build_query($this);
+ }
+
+ /**
+ * Retrieve by key
+ *
+ * Returns null if the key does not exist.
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function offsetGet($name)
+ {
+ if ($this->offsetExists($name)) {
+ return parent::offsetGet($name);
+ }
+ return;
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $default optional default value
+ * @return mixed
+ */
+ public function get($name, $default = null)
+ {
+ if ($this->offsetExists($name)) {
+ return parent::offsetGet($name);
+ }
+ return $default;
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $value
+ * @return Parameters
+ */
+ public function set($name, $value)
+ {
+ $this[$name] = $value;
+ return $this;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use ArrayAccess;
+use Countable;
+use Serializable;
+use Traversable;
+
+/*
+ * Basically, an ArrayObject. You could simply define something like:
+ * class QueryParams extends ArrayObject implements Parameters {}
+ * and have 90% of the functionality
+ */
+interface ParametersInterface extends ArrayAccess, Countable, Serializable, Traversable
+{
+ /**
+ * Constructor
+ *
+ * @param array $values
+ */
+ public function __construct(array $values = null);
+
+ /**
+ * From array
+ *
+ * Allow deserialization from standard array
+ *
+ * @param array $values
+ * @return mixed
+ */
+ public function fromArray(array $values);
+
+ /**
+ * From string
+ *
+ * Allow deserialization from raw body; e.g., for PUT requests
+ *
+ * @param $string
+ * @return mixed
+ */
+ public function fromString($string);
+
+ /**
+ * To array
+ *
+ * Allow serialization back to standard array
+ *
+ * @return mixed
+ */
+ public function toArray();
+
+ /**
+ * To string
+ *
+ * Allow serialization to query format; e.g., for PUT or POST requests
+ *
+ * @return mixed
+ */
+ public function toString();
+
+ /**
+ * Get
+ *
+ * @param string $name
+ * @param mixed|null $default
+ * @return mixed
+ */
+ public function get($name, $default = null);
+
+ /**
+ * Set
+ *
+ * @param string $name
+ * @param mixed $value
+ * @return ParametersInterface
+ */
+ public function set($name, $value);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use Countable;
+use Iterator;
+
+class PriorityList implements Iterator, Countable
+{
+ const EXTR_DATA = 0x00000001;
+ const EXTR_PRIORITY = 0x00000002;
+ const EXTR_BOTH = 0x00000003;
+ /**
+ * Internal list of all items.
+ *
+ * @var array[]
+ */
+ protected $items = [];
+
+ /**
+ * Serial assigned to items to preserve LIFO.
+ *
+ * @var int
+ */
+ protected $serial = 0;
+
+ /**
+ * Serial order mode
+ * @var integer
+ */
+ protected $isLIFO = 1;
+
+ /**
+ * Internal counter to avoid usage of count().
+ *
+ * @var int
+ */
+ protected $count = 0;
+
+ /**
+ * Whether the list was already sorted.
+ *
+ * @var bool
+ */
+ protected $sorted = false;
+
+ /**
+ * Insert a new item.
+ *
+ * @param string $name
+ * @param mixed $value
+ * @param int $priority
+ *
+ * @return void
+ */
+ public function insert($name, $value, $priority = 0)
+ {
+ if (!isset($this->items[$name])) {
+ $this->count++;
+ }
+
+ $this->sorted = false;
+
+ $this->items[$name] = [
+ 'data' => $value,
+ 'priority' => (int) $priority,
+ 'serial' => $this->serial++,
+ ];
+ }
+
+ /**
+ * @param string $name
+ * @param int $priority
+ *
+ * @return $this
+ *
+ * @throws \Exception
+ */
+ public function setPriority($name, $priority)
+ {
+ if (!isset($this->items[$name])) {
+ throw new \Exception("item $name not found");
+ }
+
+ $this->items[$name]['priority'] = (int) $priority;
+ $this->sorted = false;
+
+ return $this;
+ }
+
+ /**
+ * Remove a item.
+ *
+ * @param string $name
+ * @return void
+ */
+ public function remove($name)
+ {
+ if (isset($this->items[$name])) {
+ $this->count--;
+ }
+
+ unset($this->items[$name]);
+ }
+
+ /**
+ * Remove all items.
+ *
+ * @return void
+ */
+ public function clear()
+ {
+ $this->items = [];
+ $this->serial = 0;
+ $this->count = 0;
+ $this->sorted = false;
+ }
+
+ /**
+ * Get a item.
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function get($name)
+ {
+ if (!isset($this->items[$name])) {
+ return;
+ }
+
+ return $this->items[$name]['data'];
+ }
+
+ /**
+ * Sort all items.
+ *
+ * @return void
+ */
+ protected function sort()
+ {
+ if (!$this->sorted) {
+ uasort($this->items, [$this, 'compare']);
+ $this->sorted = true;
+ }
+ }
+
+ /**
+ * Compare the priority of two items.
+ *
+ * @param array $item1,
+ * @param array $item2
+ * @return int
+ */
+ protected function compare(array $item1, array $item2)
+ {
+ return ($item1['priority'] === $item2['priority'])
+ ? ($item1['serial'] > $item2['serial'] ? -1 : 1) * $this->isLIFO
+ : ($item1['priority'] > $item2['priority'] ? -1 : 1);
+ }
+
+ /**
+ * Get/Set serial order mode
+ *
+ * @param bool|null $flag
+ *
+ * @return bool
+ */
+ public function isLIFO($flag = null)
+ {
+ if ($flag !== null) {
+ $isLifo = $flag === true ? 1 : -1;
+
+ if ($isLifo !== $this->isLIFO) {
+ $this->isLIFO = $isLifo;
+ $this->sorted = false;
+ }
+ }
+
+ return 1 === $this->isLIFO;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function rewind()
+ {
+ $this->sort();
+ reset($this->items);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function current()
+ {
+ $this->sorted || $this->sort();
+ $node = current($this->items);
+
+ return $node ? $node['data'] : false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function key()
+ {
+ $this->sorted || $this->sort();
+ return key($this->items);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function next()
+ {
+ $node = next($this->items);
+
+ return $node ? $node['data'] : false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function valid()
+ {
+ return current($this->items) !== false;
+ }
+
+ /**
+ * @return self
+ */
+ public function getIterator()
+ {
+ return clone $this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function count()
+ {
+ return $this->count;
+ }
+
+ /**
+ * Return list as array
+ *
+ * @param int $flag
+ *
+ * @return array
+ */
+ public function toArray($flag = self::EXTR_DATA)
+ {
+ $this->sort();
+
+ if ($flag == self::EXTR_BOTH) {
+ return $this->items;
+ }
+
+ return array_map(
+ function ($item) use ($flag) {
+ return ($flag == PriorityList::EXTR_PRIORITY) ? $item['priority'] : $item['data'];
+ },
+ $this->items
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use Countable;
+use IteratorAggregate;
+use Serializable;
+
+/**
+ * Re-usable, serializable priority queue implementation
+ *
+ * SplPriorityQueue acts as a heap; on iteration, each item is removed from the
+ * queue. If you wish to re-use such a queue, you need to clone it first. This
+ * makes for some interesting issues if you wish to delete items from the queue,
+ * or, as already stated, iterate over it multiple times.
+ *
+ * This class aggregates items for the queue itself, but also composes an
+ * "inner" iterator in the form of an SplPriorityQueue object for performing
+ * the actual iteration.
+ */
+class PriorityQueue implements Countable, IteratorAggregate, Serializable
+{
+ const EXTR_DATA = 0x00000001;
+ const EXTR_PRIORITY = 0x00000002;
+ const EXTR_BOTH = 0x00000003;
+
+ /**
+ * Inner queue class to use for iteration
+ * @var string
+ */
+ protected $queueClass = 'Zend\Stdlib\SplPriorityQueue';
+
+ /**
+ * Actual items aggregated in the priority queue. Each item is an array
+ * with keys "data" and "priority".
+ * @var array
+ */
+ protected $items = [];
+
+ /**
+ * Inner queue object
+ * @var SplPriorityQueue
+ */
+ protected $queue;
+
+ /**
+ * Insert an item into the queue
+ *
+ * Priority defaults to 1 (low priority) if none provided.
+ *
+ * @param mixed $data
+ * @param int $priority
+ * @return PriorityQueue
+ */
+ public function insert($data, $priority = 1)
+ {
+ $priority = (int) $priority;
+ $this->items[] = [
+ 'data' => $data,
+ 'priority' => $priority,
+ ];
+ $this->getQueue()->insert($data, $priority);
+ return $this;
+ }
+
+ /**
+ * Remove an item from the queue
+ *
+ * This is different than {@link extract()}; its purpose is to dequeue an
+ * item.
+ *
+ * This operation is potentially expensive, as it requires
+ * re-initialization and re-population of the inner queue.
+ *
+ * Note: this removes the first item matching the provided item found. If
+ * the same item has been added multiple times, it will not remove other
+ * instances.
+ *
+ * @param mixed $datum
+ * @return bool False if the item was not found, true otherwise.
+ */
+ public function remove($datum)
+ {
+ $found = false;
+ foreach ($this->items as $key => $item) {
+ if ($item['data'] === $datum) {
+ $found = true;
+ break;
+ }
+ }
+ if ($found) {
+ unset($this->items[$key]);
+ $this->queue = null;
+
+ if (!$this->isEmpty()) {
+ $queue = $this->getQueue();
+ foreach ($this->items as $item) {
+ $queue->insert($item['data'], $item['priority']);
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Is the queue empty?
+ *
+ * @return bool
+ */
+ public function isEmpty()
+ {
+ return (0 === $this->count());
+ }
+
+ /**
+ * How many items are in the queue?
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->items);
+ }
+
+ /**
+ * Peek at the top node in the queue, based on priority.
+ *
+ * @return mixed
+ */
+ public function top()
+ {
+ return $this->getIterator()->top();
+ }
+
+ /**
+ * Extract a node from the inner queue and sift up
+ *
+ * @return mixed
+ */
+ public function extract()
+ {
+ return $this->getQueue()->extract();
+ }
+
+ /**
+ * Retrieve the inner iterator
+ *
+ * SplPriorityQueue acts as a heap, which typically implies that as items
+ * are iterated, they are also removed. This does not work for situations
+ * where the queue may be iterated multiple times. As such, this class
+ * aggregates the values, and also injects an SplPriorityQueue. This method
+ * retrieves the inner queue object, and clones it for purposes of
+ * iteration.
+ *
+ * @return SplPriorityQueue
+ */
+ public function getIterator()
+ {
+ $queue = $this->getQueue();
+ return clone $queue;
+ }
+
+ /**
+ * Serialize the data structure
+ *
+ * @return string
+ */
+ public function serialize()
+ {
+ return serialize($this->items);
+ }
+
+ /**
+ * Unserialize a string into a PriorityQueue object
+ *
+ * Serialization format is compatible with {@link Zend\Stdlib\SplPriorityQueue}
+ *
+ * @param string $data
+ * @return void
+ */
+ public function unserialize($data)
+ {
+ foreach (unserialize($data) as $item) {
+ $this->insert($item['data'], $item['priority']);
+ }
+ }
+
+ /**
+ * Serialize to an array
+ *
+ * By default, returns only the item data, and in the order registered (not
+ * sorted). You may provide one of the EXTR_* flags as an argument, allowing
+ * the ability to return priorities or both data and priority.
+ *
+ * @param int $flag
+ * @return array
+ */
+ public function toArray($flag = self::EXTR_DATA)
+ {
+ switch ($flag) {
+ case self::EXTR_BOTH:
+ return $this->items;
+ case self::EXTR_PRIORITY:
+ return array_map(function ($item) {
+ return $item['priority'];
+ }, $this->items);
+ case self::EXTR_DATA:
+ default:
+ return array_map(function ($item) {
+ return $item['data'];
+ }, $this->items);
+ }
+ }
+
+ /**
+ * Specify the internal queue class
+ *
+ * Please see {@link getIterator()} for details on the necessity of an
+ * internal queue class. The class provided should extend SplPriorityQueue.
+ *
+ * @param string $class
+ * @return PriorityQueue
+ */
+ public function setInternalQueueClass($class)
+ {
+ $this->queueClass = (string) $class;
+ return $this;
+ }
+
+ /**
+ * Does the queue contain the given datum?
+ *
+ * @param mixed $datum
+ * @return bool
+ */
+ public function contains($datum)
+ {
+ foreach ($this->items as $item) {
+ if ($item['data'] === $datum) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Does the queue have an item with the given priority?
+ *
+ * @param int $priority
+ * @return bool
+ */
+ public function hasPriority($priority)
+ {
+ foreach ($this->items as $item) {
+ if ($item['priority'] === $priority) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get the inner priority queue instance
+ *
+ * @throws Exception\DomainException
+ * @return SplPriorityQueue
+ */
+ protected function getQueue()
+ {
+ if (null === $this->queue) {
+ $this->queue = new $this->queueClass();
+ if (!$this->queue instanceof \SplPriorityQueue) {
+ throw new Exception\DomainException(sprintf(
+ 'PriorityQueue expects an internal queue of type SplPriorityQueue; received "%s"',
+ get_class($this->queue)
+ ));
+ }
+ }
+ return $this->queue;
+ }
+
+ /**
+ * Add support for deep cloning
+ *
+ * @return void
+ */
+ public function __clone()
+ {
+ if (null !== $this->queue) {
+ $this->queue = clone $this->queue;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+class Request extends Message implements RequestInterface
+{
+ // generic request implementation
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+interface RequestInterface extends MessageInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+class Response extends Message implements ResponseInterface
+{
+ // generic response implementation
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+interface ResponseInterface extends MessageInterface
+{
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use Serializable;
+
+/**
+ * Serializable version of SplPriorityQueue
+ *
+ * Also, provides predictable heap order for datums added with the same priority
+ * (i.e., they will be emitted in the same order they are enqueued).
+ */
+class SplPriorityQueue extends \SplPriorityQueue implements Serializable
+{
+ /**
+ * @var int Seed used to ensure queue order for items of the same priority
+ */
+ protected $serial = PHP_INT_MAX;
+
+ /**
+ * Insert a value with a given priority
+ *
+ * Utilizes {@var $serial} to ensure that values of equal priority are
+ * emitted in the same order in which they are inserted.
+ *
+ * @param mixed $datum
+ * @param mixed $priority
+ * @return void
+ */
+ public function insert($datum, $priority)
+ {
+ if (!is_array($priority)) {
+ $priority = [$priority, $this->serial--];
+ }
+ parent::insert($datum, $priority);
+ }
+
+ /**
+ * Serialize to an array
+ *
+ * Array will be priority => data pairs
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $array = [];
+ foreach (clone $this as $item) {
+ $array[] = $item;
+ }
+ return $array;
+ }
+
+ /**
+ * Serialize
+ *
+ * @return string
+ */
+ public function serialize()
+ {
+ $clone = clone $this;
+ $clone->setExtractFlags(self::EXTR_BOTH);
+
+ $data = [];
+ foreach ($clone as $item) {
+ $data[] = $item;
+ }
+
+ return serialize($data);
+ }
+
+ /**
+ * Deserialize
+ *
+ * @param string $data
+ * @return void
+ */
+ public function unserialize($data)
+ {
+ foreach (unserialize($data) as $item) {
+ $this->insert($item['data'], $item['priority']);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use Serializable;
+
+/**
+ * Serializable version of SplQueue
+ */
+class SplQueue extends \SplQueue implements Serializable
+{
+ /**
+ * Return an array representing the queue
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $array = [];
+ foreach ($this as $item) {
+ $array[] = $item;
+ }
+ return $array;
+ }
+
+ /**
+ * Serialize
+ *
+ * @return string
+ */
+ public function serialize()
+ {
+ return serialize($this->toArray());
+ }
+
+ /**
+ * Unserialize
+ *
+ * @param string $data
+ * @return void
+ */
+ public function unserialize($data)
+ {
+ foreach (unserialize($data) as $item) {
+ $this->push($item);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use Serializable;
+
+/**
+ * Serializable version of SplStack
+ */
+class SplStack extends \SplStack implements Serializable
+{
+ /**
+ * Serialize to an array representing the stack
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $array = [];
+ foreach ($this as $item) {
+ $array[] = $item;
+ }
+ return $array;
+ }
+
+ /**
+ * Serialize
+ *
+ * @return string
+ */
+ public function serialize()
+ {
+ return serialize($this->toArray());
+ }
+
+ /**
+ * Unserialize
+ *
+ * @param string $data
+ * @return void
+ */
+ public function unserialize($data)
+ {
+ foreach (unserialize($data) as $item) {
+ $this->unshift($item);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib;
+
+use Zend\Stdlib\StringWrapper\StringWrapperInterface;
+
+/**
+ * Utility class for handling strings of different character encodings
+ * using available PHP extensions.
+ *
+ * Declared abstract, as we have no need for instantiation.
+ */
+abstract class StringUtils
+{
+ /**
+ * Ordered list of registered string wrapper instances
+ *
+ * @var StringWrapperInterface[]
+ */
+ protected static $wrapperRegistry = null;
+
+ /**
+ * A list of known single-byte character encodings (upper-case)
+ *
+ * @var string[]
+ */
+ protected static $singleByteEncodings = [
+ 'ASCII', '7BIT', '8BIT',
+ 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', 'ISO-8859-5',
+ 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', 'ISO-8859-10',
+ 'ISO-8859-11', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16',
+ 'CP-1251', 'CP-1252',
+ // TODO
+ ];
+
+ /**
+ * Is PCRE compiled with Unicode support?
+ *
+ * @var bool
+ **/
+ protected static $hasPcreUnicodeSupport = null;
+
+ /**
+ * Get registered wrapper classes
+ *
+ * @return string[]
+ */
+ public static function getRegisteredWrappers()
+ {
+ if (static::$wrapperRegistry === null) {
+ static::$wrapperRegistry = [];
+
+ if (extension_loaded('intl')) {
+ static::$wrapperRegistry[] = 'Zend\Stdlib\StringWrapper\Intl';
+ }
+
+ if (extension_loaded('mbstring')) {
+ static::$wrapperRegistry[] = 'Zend\Stdlib\StringWrapper\MbString';
+ }
+
+ if (extension_loaded('iconv')) {
+ static::$wrapperRegistry[] = 'Zend\Stdlib\StringWrapper\Iconv';
+ }
+
+ static::$wrapperRegistry[] = 'Zend\Stdlib\StringWrapper\Native';
+ }
+
+ return static::$wrapperRegistry;
+ }
+
+ /**
+ * Register a string wrapper class
+ *
+ * @param string $wrapper
+ * @return void
+ */
+ public static function registerWrapper($wrapper)
+ {
+ $wrapper = (string) $wrapper;
+ if (!in_array($wrapper, static::$wrapperRegistry, true)) {
+ static::$wrapperRegistry[] = $wrapper;
+ }
+ }
+
+ /**
+ * Unregister a string wrapper class
+ *
+ * @param string $wrapper
+ * @return void
+ */
+ public static function unregisterWrapper($wrapper)
+ {
+ $index = array_search((string) $wrapper, static::$wrapperRegistry, true);
+ if ($index !== false) {
+ unset(static::$wrapperRegistry[$index]);
+ }
+ }
+
+ /**
+ * Reset all registered wrappers so the default wrappers will be used
+ *
+ * @return void
+ */
+ public static function resetRegisteredWrappers()
+ {
+ static::$wrapperRegistry = null;
+ }
+
+ /**
+ * Get the first string wrapper supporting the given character encoding
+ * and supports to convert into the given convert encoding.
+ *
+ * @param string $encoding Character encoding to support
+ * @param string|null $convertEncoding OPTIONAL character encoding to convert in
+ * @return StringWrapperInterface
+ * @throws Exception\RuntimeException If no wrapper supports given character encodings
+ */
+ public static function getWrapper($encoding = 'UTF-8', $convertEncoding = null)
+ {
+ foreach (static::getRegisteredWrappers() as $wrapperClass) {
+ if ($wrapperClass::isSupported($encoding, $convertEncoding)) {
+ $wrapper = new $wrapperClass($encoding, $convertEncoding);
+ $wrapper->setEncoding($encoding, $convertEncoding);
+ return $wrapper;
+ }
+ }
+
+ throw new Exception\RuntimeException(
+ 'No wrapper found supporting "' . $encoding . '"'
+ . (($convertEncoding !== null) ? ' and "' . $convertEncoding . '"' : '')
+ );
+ }
+
+ /**
+ * Get a list of all known single-byte character encodings
+ *
+ * @return string[]
+ */
+ public static function getSingleByteEncodings()
+ {
+ return static::$singleByteEncodings;
+ }
+
+ /**
+ * Check if a given encoding is a known single-byte character encoding
+ *
+ * @param string $encoding
+ * @return bool
+ */
+ public static function isSingleByteEncoding($encoding)
+ {
+ return in_array(strtoupper($encoding), static::$singleByteEncodings);
+ }
+
+ /**
+ * Check if a given string is valid UTF-8 encoded
+ *
+ * @param string $str
+ * @return bool
+ */
+ public static function isValidUtf8($str)
+ {
+ return is_string($str) && ($str === '' || preg_match('/^./su', $str) == 1);
+ }
+
+ /**
+ * Is PCRE compiled with Unicode support?
+ *
+ * @return bool
+ */
+ public static function hasPcreUnicodeSupport()
+ {
+ if (static::$hasPcreUnicodeSupport === null) {
+ ErrorHandler::start();
+ static::$hasPcreUnicodeSupport = defined('PREG_BAD_UTF8_OFFSET_ERROR') && preg_match('/\pL/u', 'a') == 1;
+ ErrorHandler::stop();
+ }
+ return static::$hasPcreUnicodeSupport;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\StringWrapper;
+
+use Zend\Stdlib\Exception;
+use Zend\Stdlib\StringUtils;
+
+abstract class AbstractStringWrapper implements StringWrapperInterface
+{
+ /**
+ * The character encoding working on
+ * @var string|null
+ */
+ protected $encoding = 'UTF-8';
+
+ /**
+ * An optionally character encoding to convert to
+ * @var string|null
+ */
+ protected $convertEncoding;
+
+ /**
+ * Check if the given character encoding is supported by this wrapper
+ * and the character encoding to convert to is also supported.
+ *
+ * @param string $encoding
+ * @param string|null $convertEncoding
+ * @return bool
+ */
+ public static function isSupported($encoding, $convertEncoding = null)
+ {
+ $supportedEncodings = static::getSupportedEncodings();
+
+ if (!in_array(strtoupper($encoding), $supportedEncodings)) {
+ return false;
+ }
+
+ if ($convertEncoding !== null && !in_array(strtoupper($convertEncoding), $supportedEncodings)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Set character encoding working with and convert to
+ *
+ * @param string $encoding The character encoding to work with
+ * @param string|null $convertEncoding The character encoding to convert to
+ * @return StringWrapperInterface
+ */
+ public function setEncoding($encoding, $convertEncoding = null)
+ {
+ $supportedEncodings = static::getSupportedEncodings();
+
+ $encodingUpper = strtoupper($encoding);
+ if (!in_array($encodingUpper, $supportedEncodings)) {
+ throw new Exception\InvalidArgumentException(
+ 'Wrapper doesn\'t support character encoding "' . $encoding . '"'
+ );
+ }
+
+ if ($convertEncoding !== null) {
+ $convertEncodingUpper = strtoupper($convertEncoding);
+ if (!in_array($convertEncodingUpper, $supportedEncodings)) {
+ throw new Exception\InvalidArgumentException(
+ 'Wrapper doesn\'t support character encoding "' . $convertEncoding . '"'
+ );
+ }
+
+ $this->convertEncoding = $convertEncodingUpper;
+ } else {
+ $this->convertEncoding = null;
+ }
+ $this->encoding = $encodingUpper;
+
+ return $this;
+ }
+
+ /**
+ * Get the defined character encoding to work with
+ *
+ * @return string
+ * @throws Exception\LogicException If no encoding was defined
+ */
+ public function getEncoding()
+ {
+ return $this->encoding;
+ }
+
+ /**
+ * Get the defined character encoding to convert to
+ *
+ * @return string|null
+ */
+ public function getConvertEncoding()
+ {
+ return $this->convertEncoding;
+ }
+
+ /**
+ * Convert a string from defined character encoding to the defined convert encoding
+ *
+ * @param string $str
+ * @param bool $reverse
+ * @return string|false
+ */
+ public function convert($str, $reverse = false)
+ {
+ $encoding = $this->getEncoding();
+ $convertEncoding = $this->getConvertEncoding();
+ if ($convertEncoding === null) {
+ throw new Exception\LogicException(
+ 'No convert encoding defined'
+ );
+ }
+
+ if ($encoding === $convertEncoding) {
+ return $str;
+ }
+
+ $from = $reverse ? $convertEncoding : $encoding;
+ $to = $reverse ? $encoding : $convertEncoding;
+ throw new Exception\RuntimeException(sprintf(
+ 'Converting from "%s" to "%s" isn\'t supported by this string wrapper',
+ $from,
+ $to
+ ));
+ }
+
+ /**
+ * Wraps a string to a given number of characters
+ *
+ * @param string $string
+ * @param int $width
+ * @param string $break
+ * @param bool $cut
+ * @return string|false
+ */
+ public function wordWrap($string, $width = 75, $break = "\n", $cut = false)
+ {
+ $string = (string) $string;
+ if ($string === '') {
+ return '';
+ }
+
+ $break = (string) $break;
+ if ($break === '') {
+ throw new Exception\InvalidArgumentException('Break string cannot be empty');
+ }
+
+ $width = (int) $width;
+ if ($width === 0 && $cut) {
+ throw new Exception\InvalidArgumentException('Cannot force cut when width is zero');
+ }
+
+ if (StringUtils::isSingleByteEncoding($this->getEncoding())) {
+ return wordwrap($string, $width, $break, $cut);
+ }
+
+ $stringWidth = $this->strlen($string);
+ $breakWidth = $this->strlen($break);
+
+ $result = '';
+ $lastStart = $lastSpace = 0;
+
+ for ($current = 0; $current < $stringWidth; $current++) {
+ $char = $this->substr($string, $current, 1);
+
+ $possibleBreak = $char;
+ if ($breakWidth !== 1) {
+ $possibleBreak = $this->substr($string, $current, $breakWidth);
+ }
+
+ if ($possibleBreak === $break) {
+ $result .= $this->substr($string, $lastStart, $current - $lastStart + $breakWidth);
+ $current += $breakWidth - 1;
+ $lastStart = $lastSpace = $current + 1;
+ continue;
+ }
+
+ if ($char === ' ') {
+ if ($current - $lastStart >= $width) {
+ $result .= $this->substr($string, $lastStart, $current - $lastStart) . $break;
+ $lastStart = $current + 1;
+ }
+
+ $lastSpace = $current;
+ continue;
+ }
+
+ if ($current - $lastStart >= $width && $cut && $lastStart >= $lastSpace) {
+ $result .= $this->substr($string, $lastStart, $current - $lastStart) . $break;
+ $lastStart = $lastSpace = $current;
+ continue;
+ }
+
+ if ($current - $lastStart >= $width && $lastStart < $lastSpace) {
+ $result .= $this->substr($string, $lastStart, $lastSpace - $lastStart) . $break;
+ $lastStart = $lastSpace = $lastSpace + 1;
+ continue;
+ }
+ }
+
+ if ($lastStart !== $current) {
+ $result .= $this->substr($string, $lastStart, $current - $lastStart);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Pad a string to a certain length with another string
+ *
+ * @param string $input
+ * @param int $padLength
+ * @param string $padString
+ * @param int $padType
+ * @return string
+ */
+ public function strPad($input, $padLength, $padString = ' ', $padType = STR_PAD_RIGHT)
+ {
+ if (StringUtils::isSingleByteEncoding($this->getEncoding())) {
+ return str_pad($input, $padLength, $padString, $padType);
+ }
+
+ $lengthOfPadding = $padLength - $this->strlen($input);
+ if ($lengthOfPadding <= 0) {
+ return $input;
+ }
+
+ $padStringLength = $this->strlen($padString);
+ if ($padStringLength === 0) {
+ return $input;
+ }
+
+ $repeatCount = floor($lengthOfPadding / $padStringLength);
+
+ if ($padType === STR_PAD_BOTH) {
+ $repeatCountLeft = $repeatCountRight = ($repeatCount - $repeatCount % 2) / 2;
+
+ $lastStringLength = $lengthOfPadding - 2 * $repeatCountLeft * $padStringLength;
+ $lastStringLeftLength = $lastStringRightLength = floor($lastStringLength / 2);
+ $lastStringRightLength += $lastStringLength % 2;
+
+ $lastStringLeft = $this->substr($padString, 0, $lastStringLeftLength);
+ $lastStringRight = $this->substr($padString, 0, $lastStringRightLength);
+
+ return str_repeat($padString, $repeatCountLeft) . $lastStringLeft
+ . $input
+ . str_repeat($padString, $repeatCountRight) . $lastStringRight;
+ }
+
+ $lastString = $this->substr($padString, 0, $lengthOfPadding % $padStringLength);
+
+ if ($padType === STR_PAD_LEFT) {
+ return str_repeat($padString, $repeatCount) . $lastString . $input;
+ }
+
+ return $input . str_repeat($padString, $repeatCount) . $lastString;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\StringWrapper;
+
+use Zend\Stdlib\Exception;
+
+class Iconv extends AbstractStringWrapper
+{
+ /**
+ * List of supported character sets (upper case)
+ *
+ * @var string[]
+ * @link http://www.gnu.org/software/libiconv/
+ */
+ protected static $encodings = [
+ // European languages
+ 'ASCII',
+ 'ISO-8859-1',
+ 'ISO-8859-2',
+ 'ISO-8859-3',
+ 'ISO-8859-4',
+ 'ISO-8859-5',
+ 'ISO-8859-7',
+ 'ISO-8859-9',
+ 'ISO-8859-10',
+ 'ISO-8859-13',
+ 'ISO-8859-14',
+ 'ISO-8859-15',
+ 'ISO-8859-16',
+ 'KOI8-R',
+ 'KOI8-U',
+ 'KOI8-RU',
+ 'CP1250',
+ 'CP1251',
+ 'CP1252',
+ 'CP1253',
+ 'CP1254',
+ 'CP1257',
+ 'CP850',
+ 'CP866',
+ 'CP1131',
+ 'MACROMAN',
+ 'MACCENTRALEUROPE',
+ 'MACICELAND',
+ 'MACCROATIAN',
+ 'MACROMANIA',
+ 'MACCYRILLIC',
+ 'MACUKRAINE',
+ 'MACGREEK',
+ 'MACTURKISH',
+ 'MACINTOSH',
+
+ // Semitic languages
+ 'ISO-8859-6',
+ 'ISO-8859-8',
+ 'CP1255',
+ 'CP1256',
+ 'CP862',
+ 'MACHEBREW',
+ 'MACARABIC',
+
+ // Japanese
+ 'EUC-JP',
+ 'SHIFT_JIS',
+ 'CP932',
+ 'ISO-2022-JP',
+ 'ISO-2022-JP-2',
+ 'ISO-2022-JP-1',
+
+ // Chinese
+ 'EUC-CN',
+ 'HZ',
+ 'GBK',
+ 'CP936',
+ 'GB18030',
+ 'EUC-TW',
+ 'BIG5',
+ 'CP950',
+ 'BIG5-HKSCS',
+ 'BIG5-HKSCS:2004',
+ 'BIG5-HKSCS:2001',
+ 'BIG5-HKSCS:1999',
+ 'ISO-2022-CN',
+ 'ISO-2022-CN-EXT',
+
+ // Korean
+ 'EUC-KR',
+ 'CP949',
+ 'ISO-2022-KR',
+ 'JOHAB',
+
+ // Armenian
+ 'ARMSCII-8',
+
+ // Georgian
+ 'GEORGIAN-ACADEMY',
+ 'GEORGIAN-PS',
+
+ // Tajik
+ 'KOI8-T',
+
+ // Kazakh
+ 'PT154',
+ 'RK1048',
+
+ // Thai
+ 'ISO-8859-11',
+ 'TIS-620',
+ 'CP874',
+ 'MACTHAI',
+
+ // Laotian
+ 'MULELAO-1',
+ 'CP1133',
+
+ // Vietnamese
+ 'VISCII',
+ 'TCVN',
+ 'CP1258',
+
+ // Platform specifics
+ 'HP-ROMAN8',
+ 'NEXTSTEP',
+
+ // Full Unicode
+ 'UTF-8',
+ 'UCS-2',
+ 'UCS-2BE',
+ 'UCS-2LE',
+ 'UCS-4',
+ 'UCS-4BE',
+ 'UCS-4LE',
+ 'UTF-16',
+ 'UTF-16BE',
+ 'UTF-16LE',
+ 'UTF-32',
+ 'UTF-32BE',
+ 'UTF-32LE',
+ 'UTF-7',
+ 'C99',
+ 'JAVA',
+
+ /* Commented out because that's internal encodings not existing in real world
+ // Full Unicode, in terms of uint16_t or uint32_t (with machine dependent endianness and alignment)
+ 'UCS-2-INTERNAL',
+ 'UCS-4-INTERNAL',
+
+ // Locale dependent, in terms of `char' or `wchar_t' (with machine dependent endianness and alignment,
+ // and with OS and locale dependent semantics)
+ 'char',
+ 'wchar_t',
+ '', // The empty encoding name is equivalent to "char": it denotes the locale dependent character encoding.
+ */
+
+ // When configured with the option --enable-extra-encodings,
+ // it also provides support for a few extra encodings:
+
+ // European languages
+ 'CP437',
+ 'CP737',
+ 'CP775',
+ 'CP852',
+ 'CP853',
+ 'CP855',
+ 'CP857',
+ 'CP858',
+ 'CP860',
+ 'CP861',
+ 'CP863',
+ 'CP865',
+ 'CP869',
+ 'CP1125',
+
+ // Semitic languages
+ 'CP864',
+
+ // Japanese
+ 'EUC-JISX0213',
+ 'Shift_JISX0213',
+ 'ISO-2022-JP-3',
+
+ // Chinese
+ 'BIG5-2003', // (experimental)
+
+ // Turkmen
+ 'TDS565',
+
+ // Platform specifics
+ 'ATARIST',
+ 'RISCOS-LATIN1',
+ ];
+
+ /**
+ * Get a list of supported character encodings
+ *
+ * @return string[]
+ */
+ public static function getSupportedEncodings()
+ {
+ return static::$encodings;
+ }
+
+ /**
+ * Constructor
+ *
+ * @throws Exception\ExtensionNotLoadedException
+ */
+ public function __construct()
+ {
+ if (!extension_loaded('iconv')) {
+ throw new Exception\ExtensionNotLoadedException(
+ 'PHP extension "iconv" is required for this wrapper'
+ );
+ }
+ }
+
+ /**
+ * Returns the length of the given string
+ *
+ * @param string $str
+ * @return int|false
+ */
+ public function strlen($str)
+ {
+ return iconv_strlen($str, $this->getEncoding());
+ }
+
+ /**
+ * Returns the portion of string specified by the start and length parameters
+ *
+ * @param string $str
+ * @param int $offset
+ * @param int|null $length
+ * @return string|false
+ */
+ public function substr($str, $offset = 0, $length = null)
+ {
+ return iconv_substr($str, $offset, $length, $this->getEncoding());
+ }
+
+ /**
+ * Find the position of the first occurrence of a substring in a string
+ *
+ * @param string $haystack
+ * @param string $needle
+ * @param int $offset
+ * @return int|false
+ */
+ public function strpos($haystack, $needle, $offset = 0)
+ {
+ return iconv_strpos($haystack, $needle, $offset, $this->getEncoding());
+ }
+
+ /**
+ * Convert a string from defined encoding to the defined convert encoding
+ *
+ * @param string $str
+ * @param bool $reverse
+ * @return string|false
+ */
+ public function convert($str, $reverse = false)
+ {
+ $encoding = $this->getEncoding();
+ $convertEncoding = $this->getConvertEncoding();
+ if ($convertEncoding === null) {
+ throw new Exception\LogicException(
+ 'No convert encoding defined'
+ );
+ }
+
+ if ($encoding === $convertEncoding) {
+ return $str;
+ }
+
+ $fromEncoding = $reverse ? $convertEncoding : $encoding;
+ $toEncoding = $reverse ? $encoding : $convertEncoding;
+
+ // automatically add "//IGNORE" to not stop converting on invalid characters
+ // invalid characters triggers a notice anyway
+ return iconv($fromEncoding, $toEncoding . '//IGNORE', $str);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\StringWrapper;
+
+use Zend\Stdlib\Exception;
+
+class Intl extends AbstractStringWrapper
+{
+ /**
+ * List of supported character sets (upper case)
+ *
+ * @var string[]
+ */
+ protected static $encodings = ['UTF-8'];
+
+ /**
+ * Get a list of supported character encodings
+ *
+ * @return string[]
+ */
+ public static function getSupportedEncodings()
+ {
+ return static::$encodings;
+ }
+
+ /**
+ * Constructor
+ *
+ * @throws Exception\ExtensionNotLoadedException
+ */
+ public function __construct()
+ {
+ if (!extension_loaded('intl')) {
+ throw new Exception\ExtensionNotLoadedException(
+ 'PHP extension "intl" is required for this wrapper'
+ );
+ }
+ }
+
+ /**
+ * Returns the length of the given string
+ *
+ * @param string $str
+ * @return int|false
+ */
+ public function strlen($str)
+ {
+ return grapheme_strlen($str);
+ }
+
+ /**
+ * Returns the portion of string specified by the start and length parameters
+ *
+ * @param string $str
+ * @param int $offset
+ * @param int|null $length
+ * @return string|false
+ */
+ public function substr($str, $offset = 0, $length = null)
+ {
+ // Due fix of PHP #62759 The third argument returns an empty string if is 0 or null.
+ if ($length !== null) {
+ return grapheme_substr($str, $offset, $length);
+ }
+
+ return grapheme_substr($str, $offset);
+ }
+
+ /**
+ * Find the position of the first occurrence of a substring in a string
+ *
+ * @param string $haystack
+ * @param string $needle
+ * @param int $offset
+ * @return int|false
+ */
+ public function strpos($haystack, $needle, $offset = 0)
+ {
+ return grapheme_strpos($haystack, $needle, $offset);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\StringWrapper;
+
+use Zend\Stdlib\Exception;
+
+class MbString extends AbstractStringWrapper
+{
+ /**
+ * List of supported character sets (upper case)
+ *
+ * @var null|string[]
+ * @link http://php.net/manual/mbstring.supported-encodings.php
+ */
+ protected static $encodings = null;
+
+ /**
+ * Get a list of supported character encodings
+ *
+ * @return string[]
+ */
+ public static function getSupportedEncodings()
+ {
+ if (static::$encodings === null) {
+ static::$encodings = array_map('strtoupper', mb_list_encodings());
+
+ // FIXME: Converting € (UTF-8) to ISO-8859-16 gives a wrong result
+ $indexIso885916 = array_search('ISO-8859-16', static::$encodings, true);
+ if ($indexIso885916 !== false) {
+ unset(static::$encodings[$indexIso885916]);
+ }
+ }
+
+ return static::$encodings;
+ }
+
+ /**
+ * Constructor
+ *
+ * @throws Exception\ExtensionNotLoadedException
+ */
+ public function __construct()
+ {
+ if (!extension_loaded('mbstring')) {
+ throw new Exception\ExtensionNotLoadedException(
+ 'PHP extension "mbstring" is required for this wrapper'
+ );
+ }
+ }
+
+ /**
+ * Returns the length of the given string
+ *
+ * @param string $str
+ * @return int|false
+ */
+ public function strlen($str)
+ {
+ return mb_strlen($str, $this->getEncoding());
+ }
+
+ /**
+ * Returns the portion of string specified by the start and length parameters
+ *
+ * @param string $str
+ * @param int $offset
+ * @param int|null $length
+ * @return string|false
+ */
+ public function substr($str, $offset = 0, $length = null)
+ {
+ return mb_substr($str, $offset, $length, $this->getEncoding());
+ }
+
+ /**
+ * Find the position of the first occurrence of a substring in a string
+ *
+ * @param string $haystack
+ * @param string $needle
+ * @param int $offset
+ * @return int|false
+ */
+ public function strpos($haystack, $needle, $offset = 0)
+ {
+ return mb_strpos($haystack, $needle, $offset, $this->getEncoding());
+ }
+
+ /**
+ * Convert a string from defined encoding to the defined convert encoding
+ *
+ * @param string $str
+ * @param bool $reverse
+ * @return string|false
+ */
+ public function convert($str, $reverse = false)
+ {
+ $encoding = $this->getEncoding();
+ $convertEncoding = $this->getConvertEncoding();
+
+ if ($convertEncoding === null) {
+ throw new Exception\LogicException(
+ 'No convert encoding defined'
+ );
+ }
+
+ if ($encoding === $convertEncoding) {
+ return $str;
+ }
+
+ $fromEncoding = $reverse ? $convertEncoding : $encoding;
+ $toEncoding = $reverse ? $encoding : $convertEncoding;
+ return mb_convert_encoding($str, $toEncoding, $fromEncoding);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\StringWrapper;
+
+use Zend\Stdlib\Exception;
+use Zend\Stdlib\StringUtils;
+
+class Native extends AbstractStringWrapper
+{
+ /**
+ * The character encoding working on
+ * (overwritten to change defaut encoding)
+ *
+ * @var string
+ */
+ protected $encoding = 'ASCII';
+
+ /**
+ * Check if the given character encoding is supported by this wrapper
+ * and the character encoding to convert to is also supported.
+ *
+ * @param string $encoding
+ * @param string|null $convertEncoding
+ * @return bool
+ */
+ public static function isSupported($encoding, $convertEncoding = null)
+ {
+ $encodingUpper = strtoupper($encoding);
+ $supportedEncodings = static::getSupportedEncodings();
+
+ if (!in_array($encodingUpper, $supportedEncodings)) {
+ return false;
+ }
+
+ // This adapter doesn't support to convert between encodings
+ if ($convertEncoding !== null && $encodingUpper !== strtoupper($convertEncoding)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Get a list of supported character encodings
+ *
+ * @return string[]
+ */
+ public static function getSupportedEncodings()
+ {
+ return StringUtils::getSingleByteEncodings();
+ }
+
+ /**
+ * Set character encoding working with and convert to
+ *
+ * @param string $encoding The character encoding to work with
+ * @param string|null $convertEncoding The character encoding to convert to
+ * @return StringWrapperInterface
+ */
+ public function setEncoding($encoding, $convertEncoding = null)
+ {
+ $supportedEncodings = static::getSupportedEncodings();
+
+ $encodingUpper = strtoupper($encoding);
+ if (!in_array($encodingUpper, $supportedEncodings)) {
+ throw new Exception\InvalidArgumentException(
+ 'Wrapper doesn\'t support character encoding "' . $encoding . '"'
+ );
+ }
+
+ if ($encodingUpper !== strtoupper($convertEncoding)) {
+ $this->convertEncoding = $encodingUpper;
+ }
+
+ if ($convertEncoding !== null) {
+ if ($encodingUpper !== strtoupper($convertEncoding)) {
+ throw new Exception\InvalidArgumentException(
+ 'Wrapper doesn\'t support to convert between character encodings'
+ );
+ }
+
+ $this->convertEncoding = $encodingUpper;
+ } else {
+ $this->convertEncoding = null;
+ }
+ $this->encoding = $encodingUpper;
+
+ return $this;
+ }
+
+ /**
+ * Returns the length of the given string
+ *
+ * @param string $str
+ * @return int|false
+ */
+ public function strlen($str)
+ {
+ return strlen($str);
+ }
+
+ /**
+ * Returns the portion of string specified by the start and length parameters
+ *
+ * @param string $str
+ * @param int $offset
+ * @param int|null $length
+ * @return string|false
+ */
+ public function substr($str, $offset = 0, $length = null)
+ {
+ return substr($str, $offset, $length);
+ }
+
+ /**
+ * Find the position of the first occurrence of a substring in a string
+ *
+ * @param string $haystack
+ * @param string $needle
+ * @param int $offset
+ * @return int|false
+ */
+ public function strpos($haystack, $needle, $offset = 0)
+ {
+ return strpos($haystack, $needle, $offset);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace Zend\Stdlib\StringWrapper;
+
+interface StringWrapperInterface
+{
+ /**
+ * Check if the given character encoding is supported by this wrapper
+ * and the character encoding to convert to is also supported.
+ *
+ * @param string $encoding
+ * @param string|null $convertEncoding
+ */
+ public static function isSupported($encoding, $convertEncoding = null);
+
+ /**
+ * Get a list of supported character encodings
+ *
+ * @return string[]
+ */
+ public static function getSupportedEncodings();
+
+ /**
+ * Set character encoding working with and convert to
+ *
+ * @param string $encoding The character encoding to work with
+ * @param string|null $convertEncoding The character encoding to convert to
+ * @return StringWrapperInterface
+ */
+ public function setEncoding($encoding, $convertEncoding = null);
+
+ /**
+ * Get the defined character encoding to work with (upper case)
+ *
+ * @return string
+ */
+ public function getEncoding();
+
+ /**
+ * Get the defined character encoding to convert to (upper case)
+ *
+ * @return string|null
+ */
+ public function getConvertEncoding();
+
+ /**
+ * Returns the length of the given string
+ *
+ * @param string $str
+ * @return int|false
+ */
+ public function strlen($str);
+
+ /**
+ * Returns the portion of string specified by the start and length parameters
+ *
+ * @param string $str
+ * @param int $offset
+ * @param int|null $length
+ * @return string|false
+ */
+ public function substr($str, $offset = 0, $length = null);
+
+ /**
+ * Find the position of the first occurrence of a substring in a string
+ *
+ * @param string $haystack
+ * @param string $needle
+ * @param int $offset
+ * @return int|false
+ */
+ public function strpos($haystack, $needle, $offset = 0);
+
+ /**
+ * Convert a string from defined encoding to the defined convert encoding
+ *
+ * @param string $str
+ * @param bool $reverse
+ * @return string|false
+ */
+ public function convert($str, $reverse = false);
+
+ /**
+ * Wraps a string to a given number of characters
+ *
+ * @param string $str
+ * @param int $width
+ * @param string $break
+ * @param bool $cut
+ * @return string
+ */
+ public function wordWrap($str, $width = 75, $break = "\n", $cut = false);
+
+ /**
+ * Pad a string to a certain length with another string
+ *
+ * @param string $input
+ * @param int $padLength
+ * @param string $padString
+ * @param int $padType
+ * @return string
+ */
+ public function strPad($input, $padLength, $padString = ' ', $padType = STR_PAD_RIGHT);
+}
--- /dev/null
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @deprecated
+ */
+
+/**
+ * Legacy purposes only, to prevent code that references it from breaking.
+ */
+trigger_error('Polyfill autoload support (file library/Zend/Stdlib/compatibility/autoload.php) is no longer necessary; please remove your require statement referencing this file', E_USER_DEPRECATED);