diff --git a/.gitignore b/.gitignore index 78ee4855c..f146c8613 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ nbproject doc/html/ tmp/ +zf-mkdoc-theme/ clover.xml composer.lock diff --git a/.travis.yml b/.travis.yml index c3d3d1abf..24681d89b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,8 @@ branches: cache: directories: - $HOME/.composer/cache + - $HOME/.local + - zf-mkdoc-theme env: global: @@ -17,6 +19,11 @@ env: - HYDRATOR_VERSION="^2.1" - SERVICE_MANAGER_VERSION="^3.0.3" - STDLIB_VERSION="^3.0" + - SITE_URL: https://zendframework.github.io/zend-mvc + - GH_USER_NAME: "Matthew Weier O'Phinney" + - GH_USER_EMAIL: matthew@weierophinney.net + - GH_REF: github.com/zendframework/zend-mvc.git + - secure: "naVln9sqGUKWRbe3qlbtcw9Ink0qXmP6iU8A0IAScpuYOeGkDF9ripkCWytjJb+sZFOpjbwwV5spoaWRied1A10P6f8GRMAPJ1xEa0Pm7JE5iCoijUdiC2FJlv0Xd79ir5xAKb4mvyAGxRDgCYXVGYnszGLQYyfaTJ9hVlRQw6N3hcWWUADXxV4Z7Akp5XN6mo52ZRwAXJNmJliyDC4INC1AE2Y8hMbD4SjIetsO7VYBBiOYJhd/9ir7ETlbvt7npEil7KKZP0Y8lanTU2coKESut4b0vE9Vxq6znoK6jrV3xULuZOU6xe3Di8roIAFaR/neeX/blfuvgYCP4lM/ed+CaSD56aFIGizyP0gLB7xrNooBttFh0JV69/8Iu5G7dbZ3nw6gc0cXDvnl9aHpsInAlGbJShlJR9JY1OqxhewgNVA9cWTs2IekdY5Zz/be+elXjYIWkM+3ig6Lw41uaE4AwKp+MdQeyhp4snUIJZeXpdRYsmPDbYI3xTPFDc3bbYgypasox+jLQB0QXY5HKUrlaKdZiY6s1rMHTRnFLLybUlxbPIM1J/rMHPjs0YRgABtVPUsXpNKkY08pkk0cfvxAKTMGP7SmN3P/cSUeWvNNInCUjCnYWSqcqcp25QoIy9BTF4gKjwoCRPfIgzj3jd0qOoRkYx2HuWZVA5+q8SM=" matrix: fast_finish: true @@ -33,6 +40,8 @@ matrix: - php: 5.6 env: - EXECUTE_TEST_COVERALLS=true + - DEPLOY_DOCS="$(if [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then echo -n 'true' ; else echo -n 'false' ; fi)" + - PATH="$HOME/.local/bin:$PATH" - php: 5.6 env: - EVENT_MANAGER_VERSION="^2.6.2" @@ -73,6 +82,10 @@ script: - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then ./vendor/bin/phpunit --coverage-clover clover.xml ; fi - if [[ $EXECUTE_TEST_COVERALLS != 'true' ]]; then ./vendor/bin/phpunit ; fi - if [[ $EXECUTE_CS_CHECK == 'true' ]]; then ./vendor/bin/php-cs-fixer fix -v --diff --dry-run ; fi + - if [[ $DEPLOY_DOCS == "true" && "$TRAVIS_TEST_RESULT" == "0" ]]; then wget -O theme-installer.sh "https://raw.githubusercontent.com/zendframework/zf-mkdoc-theme/master/theme-installer.sh" ; chmod 755 theme-installer.sh ; ./theme-installer.sh ; fi + +after_success: + - if [[ $DEPLOY_DOCS == "true" ]]; then echo "Preparing to build and deploy documentation" ; ./zf-mkdoc-theme/deploy.sh ; echo "Completed deploying documentation" ; fi after_script: - if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then ./vendor/bin/coveralls ; fi diff --git a/README.md b/README.md index 43fb1f07b..5c241247c 100644 --- a/README.md +++ b/README.md @@ -21,4 +21,4 @@ The MVC layer is built on top of the following components: - File issues at https://github.com/zendframework/zend-mvc/issues -- Documentation is at http://framework.zend.com/manual/current/en/index.html#zend-mvc +- Documentation is at https://zendframework.github.io/zend-mvc/ diff --git a/doc/book/controllers.md b/doc/book/controllers.md new file mode 100644 index 000000000..7bd14befc --- /dev/null +++ b/doc/book/controllers.md @@ -0,0 +1,314 @@ +# Available Controllers + +Controllers in zend-mvc are objects implementing `Zend\Stdlib\DispatchableInterface`. +That interface describes a single method: + +```php +use Zend\Stdlib\DispatchableInterface; +use Zend\Stdlib\RequestInterface as Request; +use Zend\Stdlib\ResponseInterface as Response; + +class Foo implements DispatchableInterface +{ + public function dispatch(Request $request, Response $response = null) + { + // ... do something, and preferably return a Response ... + } +} +``` + +While the pattern is straight-forward, chances are you don't want to implement +custom dispatch logic for every controller, particularly as it's not unusual or +uncommon for a single controller to handle several related types of requests. + +To provide convenience, zend-mvc also defines several interfaces that, when +implemented, can provide controllers with additional capabilities. + +## Common Interfaces Used With Controllers + +### InjectApplicationEvent + +The `Zend\Mvc\InjectApplicationEventInterface` hints to the `Application` +instance that it should inject its `MvcEvent` into the controller itself. Why +would this be useful? + +Recall that the `MvcEvent` composes a number of objects: the `Request` and +`Response`, naturally, but also the router, the route matches (a `RouteMatch` +instance), and potentially the "result" of dispatching. + +A controller that has the `MvcEvent` injected, then, can retrieve or inject +these. As an example: + +```php +$matches = $this->getEvent()->getRouteMatch(); +$id = $matches->getParam('id', false); +if (! $id) { + $response = $this->getResponse(); + $response->setStatusCode(500); + $this->getEvent()->setResult('Invalid identifier; cannot complete request'); + return; +} +``` + +The `InjectApplicationEventInterface` defines two methods: + +```php +public function setEvent(Zend\EventManager\EventInterface $event); +public function getEvent(); +``` + +### ServiceLocatorAware + +In most cases, you should define your controllers such that dependencies are +injected by the application's `ServiceManager`, via either constructor arguments +or setter methods. + +However, occasionally you may have objects you wish to use in your controller +that are only valid for certain code paths. Examples include forms, paginators, +navigation, etc. In these cases, you may decide that it doesn't make sense to +inject those objects every time the controller is used. + +The `ServiceLocatorAwareInterface` interface hints to the `ServiceManager` that it should inject +itself into the controller. It defines two simple methods: + +```php +use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\ServiceLocatorAwareInterface; + +public function setServiceLocator(ServiceLocatorInterface $serviceLocator); +public function getServiceLocator(); +``` + +> #### ServiceLocatorInterface is deprecated +> +> `ServiceLocatorAwareInterface` [was removed from zend-servicemanager v3.0](http://zendframework.github.io/zend-servicemanager/migration/#miscellaneous-interfaces-traits-and-classes), +> and, as such, starting in zend-mvc 2.7.0, the `AbstractController` +> implementation no longer implements the interface, though it implements the +> methods the interface defines; this allows forwards compatibility with +> zend-servicemanager v3. +> +> However, also starting with the zend-mvc 2.7.0 release, `ServiceLocatorAwareInterface` +> usage is deprecated. We recommend injecting dependencies explicitly instead of +> pulling them from a composed `ServiceManager` instance. +> +> In cases where an object will not be used in all code paths, we recommend +> splitting into discrete controllers, or using [lazy services](http://zendframework.github.io/zend-servicemanager/lazy-services/). + +### EventManagerAware + +Typically, it's nice to be able to tie into a controller's workflow without +needing to extend it or hardcode behavior into it. The solution for this is to +use the `EventManager`. + +You can hint to the `ServiceManager` that you want an `EventManager` injected by +implementing the interface `EventManagerAwareInterface`, which tells the +`ServiceManager` to inject an `EventManager`. + +To do this, you define two methods. The first, a setter, should also set any +`SharedEventManager` identifiers you want to listen on, and the second, a getter, +should return the composed `EventManager` instance. + +```php +use Zend\EventManager\EventManagerAwareInterface; +use Zend\EventManager\EventManagerInterface; + +public function setEventManager(EventManagerInterface $events); +public function getEventManager(); +``` + +### Controller Plugins + +Code re-use is a common goal for developers. Another common goal is convenience. +However, this is often difficult to achieve cleanly in abstract, general +systems. + +Within your controllers, you'll often find yourself repeating tasks from one +controller to another. Some common examples: + +- Generating URLs. +- Redirecting. +- Setting and retrieving flash messages (self-expiring session messages). +- Invoking and dispatching additional controllers. + +To facilitate these actions while also making them available to alternate +controller implementations, we've created a `PluginManager` implementation for +the controller layer, `Zend\Mvc\Controller\PluginManager`, building on the +`Zend\ServiceManager\AbstractPluginManager` functionality. To utilize it, +implement the `setPluginManager(PluginManager $plugins)` method, and set up your +code to use the controller-specific implementation by default: + +```php +use Zend\Mvc\Controller\PluginManager; + +public function setPluginManager(PluginManager $plugins) +{ + $this->plugins = $plugins; + $this->plugins->setController($this); + + return $this; +} + +public function getPluginManager() +{ + if (!$this->plugins) { + $this->setPluginManager(new PluginManager()); + } + + return $this->plugins; +} + +public function plugin($name, array $options = null) +{ + return $this->getPluginManager()->get($name, $options); +} +``` + +## AbstractActionController + +Implementing each of the above interfaces is a lesson in redundancy; you won't +often want to do it. As such, we've developed abstract, base controllers you +can extend to get started. + +The first is `Zend\Mvc\Controller\AbstractActionController`. This controller +implements each of the above interfaces, and uses the following assumptions: + +- An "action" parameter is expected in the `RouteMatch` object composed in the + attached `MvcEvent`. If none is found, a `notFoundAction()` is invoked. +- The "action" parameter is converted to a camelCased format and appended with + the word "Action" to create a method name. As examples: "foo" maps to + `fooAction`, "foo-bar" or "foo.bar" or "foo\_bar" to `fooBarAction`. The + controller then checks to see if that method exists. If not, the + `notFoundAction()` method is invoked; otherwise, the discovered method is + called. +- The results of executing the given action method are injected into the + `MvcEvent`'s "result" property (via `setResult()`, and accessible via + `getResult()`). + +Essentially, a route mapping to an `AbstractActionController` needs to return +both the "controller" and "action" keys in its matches. + +Creation of action controllers looks like the following example: + +```php +namespace Foo\Controller; + +use Zend\Mvc\Controller\AbstractActionController; + +class BarController extends AbstractActionController +{ + public function bazAction() + { + return ['title' => __METHOD__]; + } + + public function batAction() + { + return ['title' => __METHOD__]; + } +} +``` + +### Interfaces and Collaborators + +`AbstractActionController` implements each of the following interfaces: + +- `Zend\Stdlib\DispatchableInterface` +- `Zend\Mvc\InjectApplicationEventInterface` +- `Zend\ServiceManager\ServiceLocatorAwareInterface` (starting with zend-mvc + 2.7.0, only the methods defined by the interface, not the interface itself) +- `Zend\EventManager\EventManagerAwareInterface` + +The composed `EventManager` will be configured to listen on the following contexts: + +- `Zend\Stdlib\DispatchableInterface` +- `Zend\Mvc\Controller\AbstractActionController` +- `Zend\Mvc\Controller\AbstractController` + +Additionally, if you extend the class, it will listen on the name of the +extending class. + +## AbstractRestfulController + +`Zend\Mvc\Controller\AbstractRestfulController` provides a native RESTful +implementation that maps HTTP request methods to controller methods, using the +following matrix: + +- **GET** maps to either `get()` or `getList()`, depending on whether or not an + "id" parameter is found in the route matches. If one is, it is passed as an + argument to `get()`; if not, `getList()` is invoked. In the former case, you + should provide a representation of the given entity with that identification; + in the latter, you should provide a list of entities. +- **POST** maps to `create()`. That method expects a `$data` argument, usually + the `$_POST` superglobal array. The data should be used to create a new + entity, and the response should typically be an HTTP 201 response with the + Location header indicating the URI of the newly created entity and the + response body providing the representation. +- **PUT** maps to `update()`, and requires that an "id" parameter exists in the + route matches; that value is passed as an argument to the method. It should + attempt to update the given entity, and, if successful, return either a 200 or + 202 response status, as well as the representation of the entity. +- **DELETE** maps to `delete()`, and requires that an "id" parameter exists in + the route matches; that value is passed as an argument to the method. It + should attempt to delete the given entity, and, if successful, return either a + 200 or 204 response status. + +Additionally, you can map "action" methods to the `AbstractRestfulController`, +just as you would in the `AbstractActionController`; these methods will be +suffixed with "Action", differentiating them from the RESTful methods listed +above. This allows you to perform such actions as providing forms used to submit +to the various RESTful methods, or to add RPC methods to your RESTful API. + +### Interfaces and Collaborators + +`AbstractRestfulController` implements each of the following interfaces: + +- `Zend\Stdlib\DispatchableInterface` +- `Zend\Mvc\InjectApplicationEventInterface` +- `Zend\ServiceManager\ServiceLocatorAwareInterface` (starting with zend-mvc + 2.7.0, only the methods defined by the interface, not the interface itself) +- `Zend\EventManager\EventManagerAwareInterface` + +The composed `EventManager` will be configured to listen on the following contexts: + +- `Zend\Stdlib\DispatchableInterface` +- `Zend\Mvc\Controller\AbstractRestfulController` +- `Zend\Mvc\Controller\AbstractController` + +Additionally, if you extend the class, it will listen on the name of the +extending class. + +## AbstractConsoleController + +`Zend\Mvc\Controller\AbstractConsoleController` extends from [AbstractActionController](#abstractactioncontroller) +and provides the following functionality: + +- The method `setConsole(Zend\Console\Adapter\AdapterInterface $console)` allows + injecting a console adapter representing the current console environment. By + default, the `ControllerManager` will inject this for you as part of + controller instantiation. +- The method `getConsole()` allows you to retrieve the current console adapter + instance, allowing you to retrieve console capabilities and generate console + output. +- The `dispatch()` method will throw an exception if invoked in a non-console + environment, ensuring that you do not need to do any checks within your action + methods for the environment. + +### Interfaces and Collaborators + +`AbstractRestfulController` implements each of the following interfaces: + +- `Zend\Stdlib\DispatchableInterface` +- `Zend\Mvc\InjectApplicationEventInterface` +- `Zend\ServiceManager\ServiceLocatorAwareInterface` (starting with zend-mvc + 2.7.0, only the methods defined by the interface, not the interface itself) +- `Zend\EventManager\EventManagerAwareInterface` + +The composed `EventManager` will be configured to listen on the following contexts: + +- `Zend\Stdlib\DispatchableInterface` +- `Zend\Mvc\Controller\AbstractConsoleController` +- `Zend\Mvc\Controller\AbstractActionController` +- `Zend\Mvc\Controller\AbstractController` + +Additionally, if you extend the class, it will listen on the name of the +extending class. diff --git a/doc/book/examples.md b/doc/book/examples.md new file mode 100644 index 000000000..48aa6b5af --- /dev/null +++ b/doc/book/examples.md @@ -0,0 +1,117 @@ +# Examples + +## Controllers + +### Accessing the Request and Response + +When using one of the abstract controller implementations, the request and +response object are composed directly into the controller as soon as +`dispatch()` is called. You may access them as follows: + +```php +// Using explicit accessor methods +$request = $this->getRequest(); +$response = $this->getResponse(); + +// Using direct property access +$request = $this->request; +$response = $this->response; +``` + +Additionally, if your controller implements `InjectApplicationEventInterface` +(as all shipped abstract controllers do), you can access these objects from the +attached `MvcEvent`: + +```php +$event = $this->getEvent(); +$request = $event->getRequest(); +$response = $event->getResponse(); +``` + +The above can be useful when composing event listeners into your controller. + +### Accessing routing parameters + +The parameters returned when routing completes are wrapped in a +`Zend\Mvc\Router\RouteMatch` object. This object is detailed in the section on +[Routing](routing.md). + +Within your controller, if you implement `InjectApplicationEventInterface` (as +all shipped abstract controllers do), you can access this object from the +attached `MvcEvent`: + +```php +$event = $this->getEvent(); +$matches = $event->getRouteMatch(); +``` + +Once you have the `RouteMatch` object, you can pull parameters from it. + +The same can be done using the [Params plugin](plugins.md#params-plugin). + +### Returning early + +You can short-circuit execution of the application at any point by returning a +`Response` from your controller or any event. When such a value is discovered, +it halts further execution of the event manager, bubbling up to the +`Application` instance, where it is immediately returned. + +As an example, the `Redirect` plugin returns a `Response`, which can be returned +immediately so as to complete the request as quickly as possible. Other use +cases might be for returning JSON or XML results from web service endpoints, +returning "401 Unauthorized" results, etc. + +## Bootstrapping + +### Registering module-specific listeners + +You may want module-specific listeners; these allow you to introduce +authorization, logging, caching, or other concerns into your application. + +Each `Module` class can have an optional `onBootstrap()` method. This method is +used for module-specific configuration, and is the ideal location to setup event +listeners for you module. The `onBootstrap()` method is called for **every** +module on **every** page request and should **only** be used for performing +**lightweight** tasks such as registering event listeners. + +The base `Application` class shipped with the framework has an `EventManager` +associated with it, and once the modules are initialized, it triggers the +[bootstrap](mvc-event.md#mvceventevent_bootstrap-bootstrap) event, which +provides a `getApplication()` method on the event. + +One way to accomplish module-specific listeners is to listen to that event, and +register listeners at that time. As an example: + +```php +namespace SomeCustomModule; + +class Module +{ + /** + * @param \Zend\Mvc\MvcEvent $e The MvcEvent instance + * @return void + */ + public function onBootstrap($e) + { + $application = $e->getApplication(); + $config = $application->getConfig(); + $view = $application->getServiceManager()->get('ViewHelperManager'); + // You must have these keys in you application config + $view->headTitle($config['view']['base_title']); + + // This is your custom listener + $listener = new Listeners\ViewListener(); + $listener->setView($view); + $listener->attach($application->getEventManager()); + } +} +``` + +The above demonstrates several things. First, it demonstrates a listener on the +application's [bootstrap](mvc-event.md#mvceventevent_bootstrap-bootstrap) event +(the `onBootstrap()` method). Second, it demonstrates that listener, and how it +can be used to register listeners with the application. It grabs the +`Application` instance; from the `Application`, it is able to grab the attached +service manager and configuration. These are then used to retrieve the view, +configure some helpers, and then register a listener aggregate with the +application event manager. diff --git a/doc/book/index.html b/doc/book/index.html new file mode 100644 index 000000000..1bd278447 --- /dev/null +++ b/doc/book/index.html @@ -0,0 +1,10 @@ +
Zend Framework's event-driven MVC layer, including MVC Applications, Controllers, and Plugins.
+ +$ composer require zendframework/zend-mvc
+
+ test/
+ phpunit.xml
+ bootstrap.php
+ /
+
+ view/
+ /
+ /
+ <.phtml files>
+```
+
+Since a module acts as a namespace, the module root directory should be that
+namespace. This namespace could also include a vendor prefix of sorts. As an
+example a module centered around "User" functionality delivered by Zend might be
+named "ZendUser", and this is also what the module root directory will be named.
+
+> ### Source and test code organization
+>
+> The above details a [PSR-0](http://www.php-fig.org/psr/psr-0/) structure for
+> the source and test code directories. You can also use
+> [PSR-4](http://www.php-fig.org/psr/psr-4/) so long as you have setup
+> autoloading correctly to do so.
+
+The `Module.php` file directly under the module root directory will be in the
+module namespace shown below.
+
+```php
+namespace ZendUser;
+
+class Module
+{
+}
+```
+
+> ### Module class location
+>
+> If you have an autoloader defined, such as detailed later around the various
+> `autoload_*.php` files or using Composer's [autoloading features](https://getcomposer.org/doc/01-basic-usage.md#autoloading),
+> then your `Module.php` file can be co-located with your source code.
+>
+> Our current recommendation is to define autoloading for your
+> application-specific modules via Composer.
+
+When an `init()` method is defined, this method will be triggered by a
+zend-modulemanager listener when it loads the module class, and passed a
+`ModuleManager` instance by default. This allows you to perform tasks such as
+setting up module-specific event listeners. But be cautious, the `init()` method
+is called for **every** module on **every** page request and should **only** be
+used for performing **lightweight** tasks such as registering event listeners.
+Similarly, an `onBootstrap()` method (which accepts an `MvcEvent` instance) may
+be defined; it is also triggered for every page request, and should be used for
+lightweight tasks as well.
+
+The three `autoload_*.php` files are not required, but recommended if you are
+not using Composer to provide autoloading for your module. They provide the
+following:
+
+ File | Description
+-------------------------|------------
+ `autoload_classmap.php` | Should return an array classmap of class name/filename pairs (with the filenames resolved via the `__DIR__` magic constant).
+ `autoload_function.php` | Should return a PHP callback that can be passed to `spl_autoload_register()`. Typically, this callback should utilize the map returned by `autoload_classmap.php.`
+ `autoload_register.php` | should register a PHP callback (is typically returned by `autoload_function.php` with `spl_autoload_register()`.
+
+The point of these three files is to provide reasonable default mechanisms for autoloading the
+classes contained in the module, thus providing a trivial way to consume the module without
+requiring zend-modulemanager (e.g., for use outside a ZF2 application).
+
+The `config` directory should contain any module-specific configuration. These
+files may be in any format zend-config supports. We recommend naming the main
+configuration `module.config.` (e.g., for PHP-based configuration,
+`module.config.php`). Typically, you will create configuration for the router as
+well as for the service manager.
+
+The `src` directory should be a [PSR-0](http://www.php-fig.org/psr/psr-0/) or
+[PSR-4](http://www.php-fig.org/psr/psr-4/) compliant directory structure with
+your module's source code.
+
+The `test` directory should contain your unit tests. Typically, these are written using
+[PHPUnit](http://phpunit.de).
+
+The `public` directory can be used for assets that you may want to expose in
+your application's document root. These might include images, CSS files,
+JavaScript files, etc. How these are exposed is left to the developer.
+
+The `view` directory contains view scripts related to your controllers.
+
+## Bootstrapping an Application
+
+The `Application` has seven basic dependencies.
+
+- **configuration**, usually an array or object implementing `Traversable`.
+- **ServiceManager** instance.
+- **EventManager** instance, which, by default, is pulled from the
+ `ServiceManager`, by the service name "EventManager".
+- **SharedEventManager** instance, which, by default, is pulled from the
+ `ServiceManager`, by the service name "SharedEventManager"; this is injected
+ into the `EventManager` instance, and then pushed into every new
+ `EventManager` instance created.
+- **ModuleManager** instance, which, by default, is pulled from the
+ `ServiceManager`, by the service name "ModuleManager".
+- **Request** instance, which, by default, is pulled from the `ServiceManager`,
+ by the service name "Request".
+- **Response** instance, which, by default, is pulled from the `ServiceManager`,
+ by the service name "Response".
+
+These may be satisfied at instantiation:
+
+```php
+use Zend\EventManager\EventManager;
+use Zend\EventManager\SharedEventManager;
+use Zend\Http\PhpEnvironment;
+use Zend\ModuleManager\ModuleManager;
+use Zend\Mvc\Application;
+use Zend\ServiceManager\ServiceManager;
+
+$config = include 'config/application.config.php';
+
+$serviceManager = new ServiceManager();
+$serviceManager->setService('SharedEventManager', new SharedEventManager());
+$serviceManager->setService('ModuleManager', new ModuleManager($config));
+$serviceManager->setService('Request', new PhpEnvironment\Request());
+$serviceManager->setService('Response', new PhpEnvironment\Response());
+$serviceManager->setFactory('EventManager', function ($serviceManager) {
+ $eventManager = new EventManager();
+ $eventManager->setSharedManager($serviceManager->get('SharedEventManager');
+ return $eventManager;
+});
+$serviceManager->setShared('EventManager', false);
+
+$application = new Application($config, $serviceManager);
+```
+
+Once you've done this, there are two additional actions you can take. The first is to "bootstrap"
+the application. In the default implementation, this does the following:
+
+- Attaches the default route listener (`Zend\Mvc\RouteListener`).
+- Attaches the middleware dispatch listener (`Zend\Mvc\MiddlewareListener`)
+ (v2.7.0 and up).
+- Attaches the default dispatch listener (`Zend\Mvc\DispatchListener`).
+- Attaches the `ViewManager` listener (`Zend\Mvc\View\ViewManager`).
+- Creates the `MvcEvent`, and injects it with the application, request, and
+ response; it also retrieves the router (`Zend\Mvc\Router\Http\TreeRouteStack`)
+ at this time and attaches it to the event.
+- Triggers the "bootstrap" event.
+
+If you do not want these actions, or want to provide alternatives, you can do so by extending the
+`Application` class and/or manually coding what actions you want to occur.
+
+The second action you can take with the configured `Application` is to `run()`
+it. Calling this method performs the following:
+
+- it triggers the "route" event,
+- followed by the "dispatch" event, and, depending on execution,
+- the "render" event
+
+When done, it triggers the "finish" event, and then returns the response
+instance. If an error occurs during either the "route" or "dispatch" event, a
+"dispatch.error" event is triggered as well.
+
+This is a lot to remember in order to bootstrap the application; in fact, we haven't covered all the
+services available by default yet. You can greatly simplify things by using the default
+`ServiceManager` configuration shipped with the MVC.
+
+```php
+use Zend\Loader\AutoloaderFactory;
+use Zend\Mvc\Service\ServiceManagerConfig;
+use Zend\ServiceManager\ServiceManager;
+
+// setup autoloader
+AutoloaderFactory::factory();
+
+// get application stack configuration
+$configuration = include 'config/application.config.php';
+
+// setup service manager
+$serviceManager = new ServiceManager(new ServiceManagerConfig());
+$serviceManager->setService('ApplicationConfig', $configuration);
+
+// load modules -- which will provide services, configuration, and more
+$serviceManager->get('ModuleManager')->loadModules();
+
+// bootstrap and run application
+$application = $serviceManager->get('Application');
+$application->bootstrap();
+$application->run();
+```
+
+You can make this even simpler by using the `init()` method of the
+`Application`. This is a static method for quick and easy initialization of the
+`Application` instance.
+
+```php
+use Zend\Loader\AutoloaderFactory;
+use Zend\Mvc\Application;
+use Zend\Mvc\Service\ServiceManagerConfig;
+use Zend\ServiceManager\ServiceManager;
+
+// setup autoloader
+AutoloaderFactory::factory();
+
+// get application stack configuration
+$configuration = include 'config/application.config.php';
+
+// The init() method does something very similar with the previous example.
+Application::init($configuration)->run();
+```
+
+The `init()` does the following:
+
+- Grabs the application configuration and pulls from the `service_manager` key,
+ creating a `ServiceManager` instance with it and with the default services
+ shipped with zend-mvc;
+- Creates a service named `ApplicationConfig` with the application configuration array;
+- Grabs the `ModuleManager` service and loads the modules;
+- `bootstrap()`s the `Application` and returns its instance.
+
+> ### ApplicationConfig service
+>
+> If you use the `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` and `Zend\EventManager\EventManagerInterface`
+>
+> All other services are configured after module loading, thus can be overridden
+> by modules.
+
+You'll note that you have a great amount of control over the workflow. Using the
+`ServiceManager`, you have fine-grained control over what services are
+available, how they are instantiated, and what dependencies are injected into
+them. Using the `EventManager`'s priority system, you can intercept any of the
+application events ("bootstrap", "route", "dispatch", "dispatch.error",
+"render", and "finish") anywhere during execution, allowing you to craft your
+own application workflows as needed.
+
+## Bootstrapping a Modular Application
+
+While the previous approach largely works, where does the configuration come
+from? When we create a modular application, the assumption will be that it's
+from the modules themselves. How do we get that information and aggregate it,
+then?
+
+The answer is via zend-modulemanager. This component allows you to specify what
+modules the application will use; it then locates each module and initializes
+it. Module classes can tie into various listeners in order to provide
+configuration, services, listeners, and more to the application. Sounds
+complicated? It's not.
+
+### Configuring the Module Manager
+
+The first step is configuring the module manager. Inform the module manager
+which modules to load, and potentially provide configuration for the module
+listeners.
+
+Remember the `application.config.php` from earlier? We're going to provide some
+configuration.
+
+```php
+ array(
+ /* ... */
+ ),
+ 'module_listener_options' => array(
+ 'module_paths' => array(
+ './module',
+ './vendor',
+ ),
+ ),
+);
+```
+
+As we add modules to the system, we'll add items to the `modules` array.
+
+Each `Module` class that has configuration it wants the `Application` to know
+about should define a `getConfig()` method. That method should return an array
+or `Traversable` object such as a `Zend\Config\Config` instance. As an example:
+
+```php
+namespace ZendUser;
+
+class Module
+{
+ public function getConfig()
+ {
+ return include __DIR__ . '/config/module.config.php'
+ }
+}
+```
+
+There are a number of other methods you can define for tasks ranging from
+providing autoloader configuration, to providing services to the
+`ServiceManager`, to listening to the bootstrap event. The
+[ModuleManager documentation](http:/framework.zend.com/manual/current/en/modules/zend.module-manager.intro.html)
+goes into more detail on these.
+
+## Conclusion
+
+zend-mvc is incredibly flexible, offering an opt-in, easy to create modular
+infrastructure, as well as the ability to craft your own application workflows
+via the `ServiceManager` and `EventManager`. The `ModuleManager` is a
+lightweight and simple approach to enforcing a modular architecture that
+encourages clean separation of concerns and code re-use.
diff --git a/doc/book/middleware.md b/doc/book/middleware.md
new file mode 100644
index 000000000..7e31eb10d
--- /dev/null
+++ b/doc/book/middleware.md
@@ -0,0 +1,108 @@
+# Dispatching PSR-7 Middleware
+
+[PSR-7](http://www.php-fig.org/psr/psr-7/) defines interfaces for HTTP messages,
+and is now being adopted by many frameworks; Zend Framework itself offers a
+parallel microframework targeting PSR-7 with [Expressive](https://zendframework.github.io/zend-expressive).
+What if you want to dispatch PSR-7 middleware from zend-mvc?
+
+zend-mvc currently uses [zend-http](https://github.com/zendframework/zend-http)
+for its HTTP transport layer, and the objects it defines are not compatible with
+PSR-7, meaning the basic MVC layer does not and cannot make use of PSR-7
+currently.
+
+However, starting with version 2.7.0, zend-mvc offers
+`Zend\Mvc\MiddlewareListener`. This [dispatch](mvc-event.md#mvceventevent_dispatch-dispatch)
+listener listens prior to the default `DispatchListener`, and executes if the
+route matches contain a "middleware" parameter, and the service that resolves to
+is callable. When those conditions are met, it uses the [PSR-7 bridge](https://github.com/zendframework/zend-psr7bridge)
+to convert the zend-http request and response objects into PSR-7 instances, and
+then invokes the middleware.
+
+## Mapping routes to middleware
+
+The first step is to map a route to PSR-7 middleware. This looks like any other
+[routing](routing.md) configuration, with one small change: instead of providing
+a "controller" in the routing defaults, you provide "middleware":
+
+```php
+// Via configuration:
+return [
+ 'router' =>
+ 'routes' => [
+ 'home' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => '/',
+ 'defaults' => [
+ 'middleware' => 'Application\Middleware\IndexMiddleware',
+ ],
+ ],
+ ],
+ ],
+ ],
+];
+
+// Manually:
+$route = Literal::factory([
+ 'route' => '/',
+ 'defaults' => [
+ 'middleware' => 'Application\Middleware\IndexMiddleware',
+ ],
+]);
+```
+
+Middleware may be provided as PHP callables, or as service names.
+
+> ### No action required
+>
+> Unlike action controllers, middleware typically is single purpose, and, as
+> such, does require a default `action` parameter.
+
+## Middleware services
+
+In a normal zend-mvc dispatch cycle, controllers are pulled from a dedicated
+`ControllerManager`. Middleware, however, are pulled from the application
+service manager.
+
+Middleware retrieved *must* be PHP callables. The `MiddlewareListener` will
+create an error response if non-callable middleware is indicated.
+
+## Writing middleware
+
+When dispatching middleware, the `MiddlewareListener` calls it with two
+arguments, the PSR-7 request and response, respectively. As such, your
+middleware signature should look like the following:
+
+```php
+namespace Application\Middleware;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+class IndexMiddleware
+{
+ public function __invoke(ServerRequestInterface $request, ResponseInterface $response)
+ {
+ // do some work
+ }
+}
+```
+
+From there, you can pull information from the composed request, and manipulate
+the response.
+
+> ### Routing parameters
+>
+> At the time of the 2.7.0 release, route match parameters are not yet injected
+> into the PSR-7 `ServerRequest` instance, and are thus not available as request
+> attributes..
+
+## Middleware return values
+
+Ideally, your middleware should return a PSR-7 response. When it does, it is
+converted back to a zend-http response and returned by the `MiddlewareListener`,
+causing the application to short-circuit and return the response immediately.
+
+You can, however, return arbitrary values. If you do, the result is pushed into
+the `MvcEvent` as the event result, allowing later dispatch listeners to
+manipulate the results.
diff --git a/doc/book/migration.md b/doc/book/migration.md
index bcf6b4cae..c147293cd 100644
--- a/doc/book/migration.md
+++ b/doc/book/migration.md
@@ -1,8 +1,15 @@
# Migration Guide
-This is a guide for migration from version 2 to version 3 of zend-mvc.
+## Upgrading to 2.7
-## Application
+### Middleware
+
+zend-mvc now registers `Zend\Mvc\MiddlewareListener` as a dispatch listener at
+a priority higher than `Zend\Mvc\DispatchListener`, allowing dispatch of
+[PSR-7](http://www.php-fig.org/psr/psr-7/) middleware. Read the
+[middleware chapter](middleware.md) for details on how to use this new feature.
+
+### Application
The constructor signature of `Zend\Mvc\Application` has changed. Previously, it
was:
@@ -14,31 +21,36 @@ __construct($configuration, ServiceManager $serviceManager)
and internally, it pulled the services `EventManager`, `Request`, and `Response`
from the provided `$serviceManager` during initialization.
-The new constructor signature is:
+The new constructor signature provides optional arguments for injecting the
+event manager, request, and response:
```php
__construct(
$configuration,
ServiceManager $serviceManager,
- EventManager $events,
- RequestInterface $request,
- ResponseInterface $response
+ EventManager $events = null,
+ RequestInterface $request = null,
+ ResponseInterface $response = null
)
```
-making all dependencies explicit. The factory
-`Zend\Mvc\Service\ApplicationFactory` was updated to follow the new signature.
+This change makes all dependencies explicit. Starting in v3.0, the new arguments
+will be *required*.
+
+The factory `Zend\Mvc\Service\ApplicationFactory` was updated to follow the new
+signature.
This change should only affect users who are manually instantiating the
`Application` instance.
-## EventManager initializer and ControllerManager event manager injection
+### EventManagerAware initializers
zend-mvc provides two mechanisms for injecting event managers into
`EventManagerAware` objects. One is the "EventManagerAwareInitializer"
-registered in `Zend\Mvc\Service\ServiceManagerConfig`, and the other is internal
-logic in `Zend\Mvc\Controller\ControllerManager`. In both cases, the logic was
-updated due to changes in the v3 version of zend-eventmanager.
+registered in `Zend\Mvc\Service\ServiceManagerConfig`, and the other is the
+`Zend\Mvc\Controller\ControllerManager::injectEventManager()` initializer. In
+both cases, the logic was updated to be forwards compatible with
+zend-eventmanager v3.
Previously each would check if the instance's `getEventManager()` method
returned an event manager instance, and, if so, inject the shared event manager:
@@ -67,3 +79,27 @@ pulled does not have a shared manager composed.
This likely will not cause regressions in existing code, but may be something to
be aware of if you were previously depending on lazy-loaded event manager
state.
+
+### ServiceLocatorAware initializers
+
+zend-servicemanager v3.0 removes `Zend\ServiceManager\ServiceLocatorAwareInterface`.
+Since zend-mvc provides initializers around that interface, they needed updates
+to allow both forwards compatibility with zend-servicemanager v3 as well as
+backwards compatibility with existing applications.
+
+This was accomplished in two ways:
+
+- The abstract controller implementations no longer implement
+ `ServiceLocatorAwareInterface`, but continue to define the methods that the
+ interface defines (namely `setServiceLocator()` and `getServiceLocator()`.
+- The initializers registered by `Zend\Mvc\Service\ServiceManagerConfig` and
+ `Zend\Mvc\Controller\ControllerManager` now use duck-typing to determine if
+ an instance requires container injection; if so it will do so.
+
+However, we also maintain that service locator injection is an anti-pattern;
+dependencies should be injected directly into instances instead. As such,
+starting in 2.7.0, we now emit a deprecation notice any time an instance is
+injected by one of these initializers, and we plan to remove the initializers
+for version 3.0. The deprecation notice includes the name of the class, to help
+you identify what instances you will need to update before the zend-mvc v3
+release.
diff --git a/doc/book/mvc-event.md b/doc/book/mvc-event.md
new file mode 100644
index 000000000..f488c7998
--- /dev/null
+++ b/doc/book/mvc-event.md
@@ -0,0 +1,287 @@
+# The MvcEvent
+
+zend-mvc defines and utilizes a custom `Zend\EventManager\Event` implementation,
+`Zend\Mvc\MvcEvent`. This event is created during `Zend\Mvc\Application::bootstrap()`
+and is passed when triggering all application events. Additionally, if your
+controllers implement the `Zend\Mvc\InjectApplicationEventInterface`, `MvcEvent`
+will be injected into those controllers.
+
+The `MvcEvent` adds accessors and mutators for the following:
+
+- `Application` object.
+- `Request` object.
+- `Response` object.
+- `Router` object.
+- `RouteMatch` object.
+- Result - usually the result of dispatching a controller.
+- `ViewModel` object, typically representing the layout view model.
+
+The methods it defines are:
+
+- `setApplication($application)`
+- `getApplication()`
+- `setRequest($request)`
+- `getRequest()`
+- `setResponse($response)`
+- `getResponse()`
+- `setRouter($router)`
+- `getRouter()`
+- `setRouteMatch($routeMatch)`
+- `getRouteMatch()`
+- `setResult($result)`
+- `getResult()`
+- `setViewModel($viewModel)`
+- `getViewModel()`
+- `isError()`
+- `setError()`
+- `getError()`
+- `getController()`
+- `setController($name)`
+- `getControllerClass()`
+- `setControllerClass($class)`
+
+The `Application`, `Request`, `Response`, `Router`, and `ViewModel` are all
+injected during the `bootstrap` event. Following the `route` event, it will be
+injected also with the `RouteMatch` object encapsulating the results of routing.
+
+Since this object is passed around throughout the MVC, it is a common location
+for retrieving the results of routing, the router, and the request and response
+objects. Additionally, we encourage setting the results of execution in the
+event, to allow event listeners to introspect them and utilize them within their
+execution. As an example, the results could be passed into a view renderer.
+
+## Order of events
+
+The following events are triggered, in the following order:
+
+Name | Constant | Description
+-----------------|----------------------------------|------------
+`bootstrap` | `MvcEvent::EVENT_BOOTSTRAP` | Bootstrap the application by creating the ViewManager.
+`route` | `MvcEvent::EVENT_ROUTE` | Perform routing (or route-related actions).
+`dispatch` | `MvcEvent::EVENT_DISPATCH` | Dispatch the matched route to a controller/action.
+`dispatch.error` | `MvcEvent::EVENT_DISPATCH_ERROR` | Event triggered in case of a problem during dispatch process (e.g., unknown controller).
+`render` | `MvcEvent::EVENT_RENDER` | Prepare the data and delegate the rendering to the view layer.
+`render.error` | `MvcEvent::EVENT_RENDER_ERROR` | Event triggered in case of a problem during the render process (e.g., no renderer found).
+`finish` | `MvcEvent::EVENT_FINISH` | Perform tasks once everything else is done.
+
+The following sections provide more detail on each event.
+
+## `MvcEvent::EVENT_BOOTSTRAP` ("bootstrap")
+
+### Listeners
+
+The following classes listen to this event (sorted from higher priority to lower
+priority):
+
+Class | Priority | Method Called | Triggers | Description
+---------------------------------|---------:|---------------|----------|------------
+`Zend\Mvc\View\Http\ViewManager` | 10000 | `onBootstrap` | none | Prepares the view layer (instantiate a `Zend\Mvc\View\Http\ViewManager`).
+
+### Triggered By
+
+This event is triggered by the following classes:
+
+Class | In Method
+-----------------------|----------
+`Zend\Mvc\Application` | `bootstrap`
+
+## `MvcEvent::EVENT_ROUTE` ("route")
+
+### Listeners
+
+The following classes listen to this event (sorted from higher priority to lower
+priority):
+
+Class | Priority | Method Called | Triggers | Description
+-------------------------------|---------:|---------------|----------|------------
+`Zend\Mvc\ModuleRouteListener` | 1 | `onRoute` | none | Determines if the module namespace should be prepended to the controller name. This is the case if the route match contains a parameter key matching the `MODULE_NAMESPACE` constant.
+`Zend\Mvc\RouteListener` | 1 | `onRoute` | `MvcEvent::EVENT_DISPATCH_ERROR` (if no route is matched) | Tries to match the request to the router and return a `RouteMatch` object.
+
+### Triggered By
+
+This event is triggered by the following classes:
+
+Class | In Method | Description
+-----------------------|-----------|------------
+`Zend\Mvc\Application` | `run` | Uses a short circuit callback that allows halting propagation of the event if an error is raised during routing.
+
+## `MvcEvent::EVENT_DISPATCH` ("dispatch")
+
+### Listeners
+
+The following classes listen to this event (sorted from higher priority to lower
+priority):
+
+#### Console context only
+
+The following listeners are only attached in a console context:
+
+Class | Priority | Method Called | Description
+---------------------------------------------------------|---------:|-----------------------------|------------
+`Zend\Mvc\View\Console\InjectNamedConsoleParamsListener` | 1000 | `injectNamedParams` | Merge all params (route match params and params in the command), and add them to the `Request` object.
+`Zend\Mvc\View\Console\CreateViewModelListener` | -80 | `createViewModelFromArray` | If the controller action returns an associative array, this listener casts it to a `ConsoleModel` object.
+`Zend\Mvc\View\Console\CreateViewModelListener` | -80 | `createViewModelFromString` | If the controller action returns a string, this listener casts it to a `ConsoleModel` object.
+`Zend\Mvc\View\Console\CreateViewModelListener` | -80 | `createViewModelFromNull` | If the controller action returns null, this listener casts it to a `ConsoleModel` object.
+`Zend\Mvc\View\Console\InjectViewModelListener` | -100 | `injectViewModel` | Inserts the `ViewModel` (in this case, a `ConsoleModel`) and adds it to the MvcEvent object. It either (a) adds it as a child to the default, composed view model, or (b) replaces it if the result is marked as terminal.
+
+#### HTTP context only
+
+The following listeners are only attached in an HTTP context:
+
+Class | Priority | Method Called | Description
+---------------------------------------------|---------:|----------------------------|------------
+`Zend\Mvc\View\Http\CreateViewModelListener` | -80 | `createViewModelFromArray` | If the controller action returns an associative array, this listener casts it to a `ViewModel` object.
+`Zend\Mvc\View\Http\CreateViewModelListener` | -80 | `createViewModelFromNull` | If the controller action returns null, this listener casts it to a `ViewModel` object.
+`Zend\Mvc\View\Http\RouteNotFoundStrategy` | -90 | `prepareNotFoundViewModel` | Creates and return a 404 `ViewModel`.
+`Zend\Mvc\View\Http\InjectTemplateListener` | -90 | `injectTemplate` | Injects a template into the view model, if none present. Template name is derived from the controller found in the route match, and, optionally, the action, if present.
+`Zend\Mvc\View\Http\InjectViewModelListener` | -100 | `injectViewModel` | Inserts the `ViewModel` (in this case, a `ViewModel`) and adds it to the `MvcEvent` object. It either (a) adds it as a child to the default, composed view model, or (b) replaces it if the result is marked as terminable.
+
+#### All contexts
+
+The following listeners are attached for all contexts (sorted from higher
+priority to lower priority):
+
+Class | Priority | Method Called | Triggers | Description
+------------------------------|---------:|---------------|----------|------------
+`Zend\Mvc\MiddlewareListener` | 1 | `onDispatch` | `MvcEvent::EVENT_DISPATCH_ERROR` (if an exception is raised during dispatch processes) | Load and dispatch the matched PSR-7 middleware from the service manager (and throws various exceptions if it does not).
+`Zend\Mvc\DispatchListener` | 1 | `onDispatch` | `MvcEvent::EVENT_DISPATCH_ERROR` (if an exception is raised during dispatch processes) | Load and dispatch the matched controller from the service manager (and throws various exceptions if it does not).
+`Zend\Mvc\AbstractController` | 1 | `onDispatch` | none | The `onDispatch` method of the `AbstractController` is an abstract method. In `AbstractActionController`, for instance, it calls the action method.
+
+### Triggered By
+
+This event is triggered by the following classes:
+
+Class | In Method | Description
+-----------------------------------------|-------------|------------
+`Zend\Mvc\Application` | `run` | Uses a short circuit callback to halt propagation of the event if an error is raised during routing.
+`Zend\Mvc\Controller\AbstractController` | `dispatch` | If a listener returns a `Response` object, it halts propagation. Note: every `AbstractController` listens to this event and executes the `onDispatch` method when it is triggered.
+
+## `MvcEvent::EVENT_DISPATCH_ERROR` ("dispatch.error")
+
+### Listeners
+
+The following classes listen to this event (sorted from higher priority to lower
+priority):
+
+#### Console context only
+
+The following listeners are only attached in a console context:
+
+Class | Priority | Method Called | Description
+------------------------------------------------|---------:|-----------------------------|------------
+`Zend\Mvc\View\Console\RouteNotFoundStrategy` | 1 | `handleRouteNotFoundError ` | 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.
+`Zend\Mvc\View\Console\ExceptionStrategy` | 1 | `prepareExceptionViewModel` | Create an exception view model, and sets the status code to 404.
+`Zend\Mvc\View\Console\InjectViewModelListener` | -100 | `injectViewModel` | Inserts the `ViewModel` (in this case, a `ConsoleModel`) and adds it to the `MvcEvent` object. It either (a) adds it as a child to the default, composed view model, or (b) replaces it if the result is marked as terminable.
+
+#### HTTP context only
+
+The following listeners are only attached in an HTTP context:
+
+Class | Priority | Method Called | Description
+---------------------------------------------|---------:|-----------------------------|------------
+`Zend\Mvc\View\Http\RouteNotFoundStrategy` | 1 | `detectNotFoundError` | 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.
+`Zend\Mvc\View\Http\RouteNotFoundStrategy` | 1 | `prepareNotFoundViewModel` | Create and return a 404 view model.
+`Zend\Mvc\View\Http\ExceptionStrategy` | 1 | `prepareExceptionViewModel` | Create an exception view model and set the status code to 404.
+`Zend\Mvc\View\Http\InjectViewModelListener` | -100 | `injectViewModel` | Inserts the `ViewModel` (in this case, a `ViewModel`) and adds it to the MvcEvent object. It either (a) adds it as a child to the default, composed view model, or (b) replaces it if the result is marked as terminable.
+
+#### All contexts
+
+The following listeners are attached for all contexts:
+
+Class | Priority | Method Called | Description
+----------------------------|---------:|----------------------|------------
+`Zend\Mvc\DispatchListener` | 1 | `reportMonitorEvent` | Used for monitoring when Zend Server is used.
+
+### Triggered By
+
+Class | In Method
+------------------------------|----------
+`Zend\Mvc\MiddlewareListener` | `onDispatch`
+`Zend\Mvc\DispatchListener` | `onDispatch`
+`Zend\Mvc\DispatchListener` | `marshallControllerNotFoundEvent`
+`Zend\Mvc\DispatchListener` | `marshallBadControllerEvent`
+
+## `MvcEvent::EVENT_RENDER` ("render")
+
+### Listeners
+
+The following classes listen to this event (sorted from higher priority to lower
+priority):
+
+#### Console context only
+
+The following listeners are only attached in a console context:
+
+Class | Priority | Method Called | Description
+-------------------------------------------------|---------:|---------------|------------
+`Zend\Mvc\View\Console\DefaultRenderingStrategy` | -10000 | `render` | Render the view.
+
+#### HTTP context only
+
+The following listeners are only attached in an HTTP context:
+
+Class | Priority | Method Called | Description
+----------------------------------------------|---------:|---------------|------------
+`Zend\Mvc\View\Http\DefaultRenderingStrategy` | -10000 | `render` | Render the view.
+
+### Triggered By
+
+This event is triggered by the following classes:
+
+Class | In Method | Description
+-----------------------|-------------------|------------
+`Zend\Mvc\Application` | `completeRequest` | This event is triggered just before the `MvcEvent::FINISH` event.
+
+## `MvcEvent::EVENT_RENDER_ERROR` ("render.error")
+
+### Listeners
+
+The following classes listen to this event (sorted from higher priority to lower
+priority):
+
+#### Console context only
+
+The following listeners are only attached in a console context:
+
+Class | Priority | Method Called | Description
+------------------------------------------------|---------:|-----------------------------|------------
+`Zend\Mvc\View\Console\ExceptionStrategy` | 1 | `prepareExceptionViewModel` | Create an exception view model and set the status code to 404.
+`Zend\Mvc\View\Console\InjectViewModelListener` | -100 | `injectViewModel` | Inserts the `ViewModel` (in this case, a `ConsoleModel`) and adds it to the `MvcEvent` object. It either (a) adds it as a child to the default, composed view model, or (b) replaces it if the result is marked as terminable.
+
+#### HTTP context only
+
+The following listeners are only attached in an HTTP context:
+
+Class | Priority | Method Called | Description
+------------------------------------------------|---------:|-----------------------------|------------
+`Zend\Mvc\View\Console\ExceptionStrategy` | 1 | `prepareExceptionViewModel` | Create an exception view model and set the status code to 404.
+`Zend\Mvc\View\Console\InjectViewModelListener` | | |
+
+### Triggered By
+
+This event is triggered by the following classes:
+
+Class | In Method | Description
+----------------------------------------------|-----------|------------
+`Zend\Mvc\View\Http\DefaultRenderingStrategy` | `render` | This event is triggered if an exception is raised during rendering.
+
+## `MvcEvent::EVENT_FINISH` ("finish")
+
+### Listeners
+
+The following classes listen to this event (sorted from higher priority to lower
+priority):
+
+Class | Priority | Method Called | Description
+--------------------------------|---------:|----------------|------------
+`Zend\Mvc\SendResponseListener` | -10000 | `sendResponse` | Triggers the `SendResponseEvent` in order to prepare the response (see the next chapter for more information about `SendResponseEvent`).
+
+### Triggered By
+
+This event is triggered by the following classes:
+
+Class | In Method | Description
+-----------------------|-------------------|------------
+`Zend\Mvc\Application` | `run` | This event is triggered once the `MvcEvent::ROUTE` event returns a correct `ResponseInterface`.
+`Zend\Mvc\Application` | `run` | This event is triggered once the `MvcEvent::DISPATCH` event returns a correct `ResponseInterface`.
+`Zend\Mvc\Application` | `completeRequest` | This event is triggered after `MvcEvent::RENDER` (at this point, the view is already rendered).
diff --git a/doc/book/plugins.md b/doc/book/plugins.md
new file mode 100644
index 000000000..e25b1f84b
--- /dev/null
+++ b/doc/book/plugins.md
@@ -0,0 +1,507 @@
+# Controller Plugins
+
+When using any of the abstract controller implementations shipped with zend-mvc,
+or if you implement the `setPluginManager` method in your custom controllers,
+you have access to a number of pre-built plugins. Additionally, you can register
+your own custom plugins with the manager.
+
+The built-in plugins are:
+
+- [Zend\\Mvc\\Controller\\Plugin\\AcceptableViewModelSelector](#acceptableviewmodelselector-plugin)
+- [Zend\\Mvc\\Controller\\Plugin\\FlashMessenger](#flashmessenger-plugin)
+- [Zend\\Mvc\\Controller\\Plugin\\Forward](#forward-plugin)
+- [Zend\\Mvc\\Controller\\Plugin\\Identity](#identity-plugin)
+- [Zend\\Mvc\\Controller\\Plugin\\Layout](#layout-plugin)
+- [Zend\\Mvc\\Controller\\Plugin\\Params](#params-plugin)
+- [Zend\\Mvc\\Controller\\Plugin\\PostRedirectGet](#postredirectget-plugin)
+- [Zend\\Mvc\\Controller\\Plugin\\FilePostRedirectGet](#file-postredirectget-plugin)
+- [Zend\\Mvc\\Controller\\Plugin\\Redirect](#redirect-plugin)
+- [Zend\\Mvc\\Controller\\Plugin\\Url](#url-plugin)
+
+If your controller implements the `setPluginManager()`, `getPluginManager()` and
+`plugin()` methods, you can access these using their shortname via the `plugin()`
+method:
+
+```php
+$plugin = $this->plugin('url');
+```
+
+For an extra layer of convenience, this shipped abstract controller
+implementations have `__call()` methods defined that allow you to retrieve
+plugins via method calls:
+
+```php
+$plugin = $this->url();
+```
+
+## AcceptableViewModelSelector Plugin
+
+The `AcceptableViewModelSelector` is a helper that can be used to select an
+appropriate view model based on user defined criteria will be tested against the
+Accept header in the request.
+
+As an example:
+
+```php
+use Zend\Mvc\Controller\AbstractActionController;
+use Zend\View\Model\JsonModel;
+
+class SomeController extends AbstractActionController
+{
+ protected $acceptCriteria = [
+ 'Zend\View\Model\JsonModel' => [
+ 'application/json',
+ ],
+ 'Zend\View\Model\FeedModel' => [
+ 'application/rss+xml',
+ ],
+ ];
+
+ public function apiAction()
+ {
+ $viewModel = $this->acceptableViewModelSelector($this->acceptCriteria);
+
+ // Potentially vary execution based on model returned
+ if ($viewModel instanceof JsonModel) {
+ // ...
+ }
+ }
+}
+```
+
+The above would return a standard `Zend\View\Model\ViewModel` instance if the
+criteria is not met, and the specified view model types if the specific criteria
+is met. Rules are matched in order, with the first match "winning."
+
+## FlashMessenger Plugin
+
+The `FlashMessenger` is a plugin designed to create and retrieve self-expiring,
+session-based messages. It exposes a number of methods:
+
+- `setSessionManager(Zend\Session\ManagerInterface $manager) : FlashMessenger`:
+ Allows you to specify an alternate session manager, if desired.
+
+- `getSessionManager() : Zend\Session\ManagerInterface`: Allows you to retrieve
+ the session manager registered.
+
+- `getContainer() : Zend\Session\Container`: Returns the
+ `Zend\Session\Container` instance in which the flash messages are stored.
+
+- `setNamespace(string $namespace = 'default') : FlashMessenger`:
+ Allows you to specify a specific namespace in the container in which to store
+ or from which to retrieve flash messages.
+
+- `getNamespace() : string`: retrieves the name of the flash message namespace.
+
+- `addMessage(string $message) : FlashMessenger`: Allows you to add a message to
+ the current namespace of the session container.
+
+- `hasMessages() : bool`: Lets you determine if there are any flash messages
+ from the current namespace in the session container.
+
+- `getMessages() : array`: Retrieves the flash messages from the current
+ namespace of the session container
+
+- `clearMessages() : bool`: Clears all flash messages in current namespace of
+ the session container. Returns `true` if messages were cleared, `false` if
+ none existed.
+
+- `hasCurrentMessages() : bool`: Indicates whether any messages were added
+ during the current request.
+
+- `getCurrentMessages() : array`: Retrieves any messages added during the
+ current request.
+
+- `clearCurrentMessages() : bool`: Removes any messages added during the current
+ request. Returns `true` if current messages were cleared, `false` if none
+ existed.
+
+- `clearMessagesFromContainer() : bool`: Clear all messages from the container.
+ Returns `true` if any messages were cleared, `false` if none existed.
+
+This plugin also provides four meaningful namespaces, namely: `INFO`, `ERROR`,
+`WARNING`, and `SUCCESS`. The following functions are related to these
+namespaces:
+
+- `addInfoMessage(string $message): FlashMessenger`: Add a message to "info"
+ namespace.
+
+- `hasCurrentInfoMessages() : bool`: Check to see if messages have been added to
+ "info" namespace within this request.
+
+- `addWarningMessage(string $message) : FlashMessenger`: Add a message to
+ "warning" namespace.
+
+- `hasCurrentWarningMessages() : bool`: Check to see if messages have been added
+ to "warning" namespace within this request.
+
+- `addErrorMessage(string $message) : FlashMessenger`: Add a message to "error"
+ namespace.
+
+- `hasCurrentErrorMessages() : bool`: Check to see if messages have been added
+ to "error" namespace within this request.
+
+- `addSuccessMessage(string $message) : FlashMessenger`: Add a message to
+ "success" namespace.
+
+- `hasCurrentSuccessMessages() :bool`: Check to see if messages have been added
+ to "success" namespace within this request.
+
+Additionally, the `FlashMessenger` implements both `IteratorAggregate` and
+`Countable`, allowing you to iterate over and count the flash messages in the
+current namespace within the session container.
+
+### Examples
+
+```php
+public function processAction()
+{
+ // ... do some work ...
+ $this->flashMessenger()->addMessage('You are now logged in.');
+ return $this->redirect()->toRoute('user-success');
+}
+
+public function successAction()
+{
+ $return = ['success' => true];
+ $flashMessenger = $this->flashMessenger();
+ if ($flashMessenger->hasMessages()) {
+ $return['messages'] = $flashMessenger->getMessages();
+ }
+ return $return;
+}
+```
+
+## Forward Plugin
+
+Occasionally, you may want to dispatch additional controllers from within the
+matched controller. For example, you might use this approach to build up
+"widgetized" content. The `Forward` plugin helps enable this.
+
+For the `Forward` plugin to work, the controller calling it must be
+`ServiceLocatorAware`; otherwise, the plugin will be unable to retrieve a
+configured and injected instance of the requested controller.
+
+The plugin exposes a single method, `dispatch()`, which takes two arguments:
+
+- `$name`, the name of the controller to invoke. This may be either the fully
+ qualified class name, or an alias defined and recognized by the
+ `ServiceManager` instance attached to the invoking controller.
+- `$params` is an optional array of parameters with which to seed a `RouteMatch`
+ object for purposes of this specific request. Meaning the parameters will be
+ matched by their key to the routing identifiers in the config (otherwise
+ non-matching keys are ignored)
+
+`Forward` returns the results of dispatching the requested controller; it is up
+to the developer to determine what, if anything, to do with those results. One
+recommendation is to aggregate them in any return value from the invoking
+controller.
+
+As an example:
+
+```php
+$foo = $this->forward()->dispatch('foo', ['action' => 'process']);
+return [
+ 'somekey' => $somevalue,
+ 'foo' => $foo,
+];
+```
+
+## Identity Plugin
+
+The `Identity` plugin allows retrieving the identity from the
+`AuthenticationService`.
+
+For the `Identity` plugin to work, a `Zend\Authentication\AuthenticationService`
+name or alias must be defined and recognized by the `ServiceManager`.
+
+`Identity` returns the identity in the `AuthenticationService` or `null` if no
+identity is available.
+
+As an example:
+
+```php
+public function testAction()
+{
+ if ($user = $this->identity()) {
+ // someone is logged !
+ } else {
+ // not logged in
+ }
+}
+```
+
+When invoked, the `Identity` plugin will look for a service by the name or alias
+`Zend\Authentication\AuthenticationService` in the `ServiceManager`. You can
+provide this service to the `ServiceManager` in a configuration file:
+
+```php
+// In a configuration file...
+use Zend\Authentication\AuthenticationService;
+
+return [
+ 'service_manager' => [
+ 'aliases' => [
+ AuthenticationService::class => 'my_auth_service',
+ ],
+ 'invokables' => [
+ 'my_auth_service' => AuthenticationService::class,
+ ],
+ ],
+];
+```
+
+The `Identity` plugin exposes two methods:
+
+- `setAuthenticationService(AuthenticationService $authenticationService) : void`:
+ Sets the authentication service instance to be used by the plugin.
+
+- `getAuthenticationService() : AuthenticationService`: Retrieves the current
+ authentication service instance if any is attached.
+
+## Layout Plugin
+
+The `Layout` plugin allows changing layout templates from within controller actions.
+
+It exposes a single method, `setTemplate()`, which takes one argument,
+`$template`, the name of the template to set.
+
+As an example:
+
+```php
+$this->layout()->setTemplate('layout/newlayout');
+```
+
+It also implements the `__invoke` magic method, which allows calling the plugin
+as a method call:
+
+```php
+$this->layout('layout/newlayout');
+```
+
+## Params Plugin
+
+The `Params` plugin allows accessing parameters in actions from different sources.
+
+It exposes several methods, one for each parameter source:
+
+- `fromFiles(string $name = null, mixed $default = null): array|ArrayAccess|null`:
+ For retrieving all or one single **file**. If `$name` is null, all files will
+ be returned.
+
+- `fromHeader(string $header = null, mixed $default = null) : null|Zend\Http\Header\HeaderInterface`:
+ For retrieving all or one single **header** parameter. If `$header` is null,
+ all header parameters will be returned.
+
+- `fromPost(string $param = null, mixed $default = null) : mixed`: For
+ retrieving all or one single **post** parameter. If `$param` is null, all post
+ parameters will be returned.
+
+- `fromQuery(string $param = null, mixed $default = null) : mixed`: For
+ retrieving all or one single **query** parameter. If `$param` is null, all
+ query parameters will be returned.
+
+- `fromRoute(string $param = null, mixed $default = null) : mixed`: For
+ retrieving all or one single **route** parameter. If `$param` is null, all
+ route parameters will be returned.
+
+The plugin also implements the `__invoke` magic method, providing a shortcut
+for invoking the `fromRoute` method:
+
+```php
+$this->params()->fromRoute('param', $default);
+// or
+$this->params('param', $default);
+```
+
+## Post/Redirect/Get Plugin
+
+When a user sends a POST request (e.g. after submitting a form), their browser
+will try to protect them from sending the POST again, breaking the back button,
+causing browser warnings and pop-ups, and sometimes reposting the form. Instead,
+when receiving a POST, we should store the data in a session container and
+redirect the user to a GET request.
+
+This plugin can be invoked with two arguments:
+
+- `$redirect`, a string containing the redirect location, which can either be a
+ named route or a URL, based on the contents of the second parameter.
+- `$redirectToUrl`, a boolean that when set to `TRUE`, causes the first
+ parameter to be treated as a URL instead of a route name (this is required
+ when redirecting to a URL instead of a route). This argument defaults to
+ `false`.
+
+When no arguments are provided, the current matched route is used.
+
+### Example Usage
+
+```php
+// Pass in the route/url you want to redirect to after the POST
+$prg = $this->prg('/user/register', true);
+
+if ($prg instanceof \Zend\Http\PhpEnvironment\Response) {
+ // Returned a response to redirect us.
+ return $prg;
+}
+
+if ($prg === false) {
+ // This wasn't a POST request, but there were no params in the flash
+ // messenger; this is probably the first time the form was loaded.
+ return ['form' => $myForm];
+}
+
+// $prg is an array containing the POST params from the previous request
+$form->setData($prg);
+
+// ... your form processing code here
+```
+
+## File Post/Redirect/Get Plugin
+
+While similar to the [Post/Redirect/Get Plugin](#postredirectget-plugin),
+the File PRG Plugin will work for forms with file inputs. The difference is in
+the behavior: The File PRG Plugin will interact directly with your form instance
+and the file inputs, rather than *only* returning the POST params from the
+previous request.
+
+By interacting directly with the form, the File PRG Plugin will turn off any
+file inputs `required` flags for already uploaded files (for a partially valid
+form state), as well as run the file input filters to move the uploaded files
+into a new location (configured by the user).
+
+> ### Files must be relocated on upload
+>
+> You **must** attach a filter for moving the uploaded files to a new location, such as the
+> [RenameUpload Filter](http://zendframework.github.io/zend-filter/file/#renameupload),
+> or else your files will be removed upon the redirect.
+
+This plugin is invoked with three arguments:
+
+- `$form`: the form instance.
+- `$redirect`: (Optional) a string containing the redirect location, which can
+ either be a named route or a URL, based on the contents of the third
+ parameter. If this argument is not provided, it will default to the current
+ matched route.
+- `$redirectToUrl`: (Optional) a boolean that when set to `TRUE`, causes the
+ second parameter to be treated as a URL instead of a route name (this is
+ required when redirecting to a URL instead of a route). This argument defaults
+ to `false`.
+
+### Example Usage
+
+```php
+$myForm = new Zend\Form\Form('my-form');
+$myForm->add([
+ 'type' => 'Zend\Form\Element\File',
+ 'name' => 'file',
+]);
+
+// NOTE: Without a filter to move the file,
+// our files will disappear between the requests
+$myForm->getInputFilter()->getFilterChain()->attach(
+ new Zend\Filter\File\RenameUpload([
+ 'target' => './data/tmpuploads/file',
+ 'randomize' => true,
+ ])
+);
+
+// Pass in the form and optional the route/url you want to redirect to after the POST
+$prg = $this->fileprg($myForm, '/user/profile-pic', true);
+
+if ($prg instanceof \Zend\Http\PhpEnvironment\Response) {
+ // Returned a response to redirect us.
+ return $prg;
+}
+
+if ($prg === false) {
+ // First time the form was loaded.
+ return array('form' => $myForm);
+}
+
+// Form was submitted.
+// $prg is now an array containing the POST params from the previous request,
+// but we don't have to apply it to the form since that has already been done.
+
+// Process the form
+if ($form->isValid()) {
+ // ...Save the form...
+ return $this->redirect()->toRoute('/user/profile-pic/success');
+}
+
+// Form not valid, but file uploads might be valid and uploaded
+$fileErrors = $form->get('file')->getMessages();
+if (empty($fileErrors)) {
+ $tempFile = $form->get('file')->getValue();
+}
+```
+
+## Redirect Plugin
+
+Redirections are quite common operations within applications. If done manually,
+you will need to do the following steps:
+
+- Assemble a url using the router.
+- Create and inject a "Location" header into the `Response` object, pointing to
+ the assembled URL.
+- Set the status code of the `Response` object to one of the 3xx HTTP statuses.
+
+The `Redirect` plugin does this work for you. It offers three methods:
+
+- `toRoute(string $route = null, array $params = array(), array $options = array(), boolean $reuseMatchedParams = false) : Zend\Http\Response`:
+ Redirects to a named route, using the provided `$params` and `$options` to
+ assembled the URL.
+
+- `toUrl(string $url) : Zend\Http\Response`: Simply redirects to the given URL.
+
+- `refresh() : Zend\Http\Response`: Refresh to current route.
+
+In each case, the `Response` object is returned. If you return this immediately,
+you can effectively short-circuit execution of the request.
+
+> ### Requires MvcEvent
+>
+> This plugin requires that the controller invoking it implements
+> `InjectApplicationEventInterface`, and thus has an `MvcEvent` composed, as it
+> retrieves the router from the event object.
+
+As an example:
+
+```php
+return $this->redirect()->toRoute('login-success');
+```
+
+## Url Plugin
+
+You may need to generate URLs from route definitions within your controllers;
+for example, to seed the view, generate headers, etc. While the `MvcEvent`
+object composes the router, doing so manually would require this workflow:
+
+```php
+$router = $this->getEvent()->getRouter();
+$url = $router->assemble($params, ['name' => 'route-name']);
+```
+
+The `Url` helper makes this slightly more convenient:
+
+```php
+$url = $this->url()->fromRoute('route-name', $params);
+```
+
+The `fromRoute()` method is the only public method defined, and is used to
+generate a URL string from the provided parameters. It has the following
+signature:
+
+- `fromRoute(string $route = null, array $params = [], array $options = [], bool $reuseMatchedParams = false): string`, where:
+ - `$name`: the name of the route to use for URL generation.
+ - `$params`: Any parameter substitutions to use with the named route.
+ - `$options`: Options used by the router when generating the URL (e.g., `force_canonical`, `query`, etc.).
+ - `$reuseMatchedParams`: Whether or not to use route match parameters from the
+ current URL when generating the new URL. This will only affect cases where
+ the specified `$name` matches the currently matched route; the default is
+ `true`.
+
+> ### Requires MvcEvent
+>
+> This plugin requires that the controller invoking it implements
+> `InjectApplicationEventInterface`, and thus has an `MvcEvent` composed, as it
+> retrieves the router from the event object.
diff --git a/doc/book/quick-start.md b/doc/book/quick-start.md
new file mode 100644
index 000000000..39055ea36
--- /dev/null
+++ b/doc/book/quick-start.md
@@ -0,0 +1,335 @@
+# Quick Start
+
+Now that you have basic knowledge of applications, modules, and how they are
+each structured, we'll show you the easy way to get started.
+
+## Install the Zend Skeleton Application
+
+The easiest way to get started is to install the skeleton application via
+Composer.
+
+If you have not yet done so, [install Composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx).
+
+Once you have, use the `create-project` command to create a new application:
+
+```bash
+$ git create-project -sdev zendframework/skeleton-application my-application
+```
+
+## Create a New Module
+
+By default, one module is provided with the `ZendSkeletonApplication`, named
+"Application". It provides a controller to handle the "home" page of the
+application, the layout template, and templates for 404 and error pages.
+
+Typically, you will not need to touch this other than to provide an alternate
+entry page for your site and/or alternate error page.
+
+Additional functionality will be provided by creating new modules.
+
+To get you started with modules, we recommend using the `ZendSkeletonModule` as
+a base. Download it from here:
+
+* [ZendSkeletonModule zip package](https://github.com/zendframework/ZendSkeletonModule/zipball/master)
+* [ZendSkeletonModule tarball](https://github.com/zendframework/ZendSkeletonModule/tarball/master)
+
+Deflate the package, and rename the directory "ZendSkeletonModule" to reflect
+the name of the new module you want to create; when done, move the module into
+your new project's `module/` directory.
+
+At this point, it's time to create some functionality.
+
+## Update the Module Class
+
+Let's update the `Module` class. We'll want to make sure the namespace is correct,
+configuration is enabled and returned, and that we setup autoloading on
+initialization. Since we're actively working on this module, the class list will
+be in flux; we probably want to be pretty lenient in our autoloading approach,
+so let's keep it flexible by using the `StandardAutoloader`. Let's begin.
+
+First, let's have `autoload_classmap.php` return an empty array:
+
+```php
+ array(
+ 'template_path_stack' => array(
+ '' => __DIR__ . '/../view'
+ ),
+ ),
+);
+```
+
+Fill in `module-name` with a lowercased, dash-separated version of your module
+name; e.g., "ZendUser" would become "zend-user".
+
+Next, edit the namespace declaration of the `Module.php` file. Replace the
+following line:
+
+```php
+namespace ZendSkeletonModule;
+```
+
+with the namespace you want to use for your application.
+
+Next, rename the directory `src/ZendSkeletonModule` to `src/`,
+and the directory `view/zend-skeleton-module` to `src/`.
+
+At this point, you now have your module configured properly. Let's create a
+controller!
+
+## Create a Controller
+
+Controllers are objects that implement `Zend\Stdlib\DispatchableInterface`. This
+means they need to implement a `dispatch()` method that takes minimally a
+`Request` object as an argument.
+
+In practice, though, this would mean writing logic to branch based on matched
+routing within every controller. As such, we've created several base controller
+classes for you to start with:
+
+- `Zend\Mvc\Controller\AbstractActionController` allows routes to match an
+ "action". When matched, a method named after the action will be called by the
+ controller. As an example, if you had a route that returned "foo" for the
+ "action" key, the "fooAction" method would be invoked.
+- `Zend\Mvc\Controller\AbstractRestfulController` introspects the `Request` to
+ determine what HTTP method was used, and calls a method according to that.
+ - `GET` will call either the `getList()` method, or, if an "id" was matched
+ during routing, the `get()` method (with that identifer value).
+ - `POST` will call the `create()` method, passing in the `$_POST` values.
+ - `PUT` expects an "id" to be matched during routing, and will call the
+ `update()` method, passing in the identifier, and any data found in the raw
+ post body.
+ - `DELETE` expects an "id" to be matched during routing, and will call the
+ `delete()` method.
+- `Zend\Mvc\Controller\AbstractConsoleController` extends from
+ `AbstractActionController`, but provides methods for retrieving the
+ `Zend\Console\Adapter\AdapterInterface` instance, and ensuring that execution
+ fails in non-console environments.
+
+To get started, we'll create a "hello world"-style controller, with a single
+action. First, create the file `HelloController.php` in the directory
+`src//Controller`. Edit it in your favorite text editor or IDE,
+and insert the following contents:
+
+```php
+\Controller;
+
+use Zend\Mvc\Controller\AbstractActionController;
+use Zend\View\Model\ViewModel;
+
+class HelloController extends AbstractActionController
+{
+ public function worldAction()
+ {
+ $message = $this->params()->fromQuery('message', 'foo');
+ return new ViewModel(['message' => $message]);
+ }
+}
+```
+
+So, what are we doing here?
+
+- We're creating an action controller.
+- We're defining an action, "world".
+- We're pulling a message from the query parameters (yes, this is a superbly bad
+ idea in production! Always sanitize your inputs!).
+- We're returning a `ViewModel` with an array of values to be processed later.
+
+We return a `ViewModel`. The view layer will use this when rendering the view,
+pulling variables and the template name from it. By default, you can omit the
+template name, and it will resolve to "lowercase-controller-name/lowercase-action-name".
+However, you can override this to specify something different by calling
+`setTemplate()` on the `ViewModel` instance. Typically, templates will resolve
+to files with a ".phtml" suffix in your module's `view` directory.
+
+So, with that in mind, let's create a view script.
+
+## Create a View Script
+
+Create the directory `view//hello`. Inside that directory, create a
+file named `world.phtml`. Inside that, paste in the following:
+
+```php
+Greetings!
+
+You said "escapeHtml($message) ?>".
+```
+
+That's it. Save the file.
+
+> ### Escaping output
+>
+> What is the method `escapeHtml()`? It's actually a [view helper](http://framework.zend.com/manual/current/en/modules/zend.view.helpers.html),
+> and it's designed to help mitigate XSS attacks. Never trust user input; if you
+> are at all uncertain about the source of a given variable in your view script,
+> escape it using one of the provided escape view helpers depending on the type
+> of data you have.
+
+## View scripts for module names with subnamespaces
+
+As per PSR-0, modules should be named following the rule: `\\*`.
+However, the default controller class to template mapping does not work very
+well with those: it will remove subnamespace.
+
+To address that issue, new mapping rules were introduced with version 2.3.0. To
+maintain backwards compatibility, that mapping is not enabled by default. To
+enable it, you need to add your module namespace to a whitelist in your module
+configuration:
+
+```php
+'view_manager' => array(
+ // Controller namespace to template map
+ // or whitelisting for controller FQCN to template mapping
+ 'controller_map' => array(
+ '' => true,
+ ),
+),
+```
+
+Once you have, you can create the directory `view///hello`. Inside
+that directory, create a file named `world.phtml`. Inside that, paste the
+following:
+
+```php
+Greetings!
+
+You said "escapeHtml($message) ?>".
+```
+
+## Create a Route
+
+Now that we have a controller and a view script, we need to create a route to it.
+
+> ### Default routing
+>
+> `ZendSkeletonModule` ships with a "default route" that will likely get
+> you to this action. That route is defined roughly as
+> `/{module}/{controller}/{action}`, which means that the path
+> `/zend-user/hello/world` will map to `ZendUser\Controller\HelloController::worldAction()`
+> (assuming the module name were `ZendUser`).
+>
+> We're going to create an explicit route in this example, as
+> creating explicit routes is a recommended practice. The application will look for a
+> `Zend\Mvc\Router\RouteStackInterface` instance to setup routing. The default generated router is a
+> `Zend\Mvc\Router\Http\TreeRouteStack`.
+>
+> To use the "default route" functionality, you will need to edit the shipped
+> routing definition in the module's `config/module.config.php`, and replace:
+>
+> - `/module-specific-root` with a module-specific root path.
+> - `ZendSkeletonModule\Controller` with `\Controller`.
+
+Additionally, we need to tell the application we have a controller:
+
+```php
+// module.config.php
+return [
+ 'controllers' => [
+ 'invokables' => [
+ '\Controller\Index' => '\Controller\IndexController',
+ // Do similar for each other controller in your module
+ ],
+ ],
+ // ... other configuration ...
+];
+```
+
+> ### Controller services
+>
+> We inform the application about controllers we expect to have in the
+> application. This is to prevent somebody requesting any service the
+> `ServiceManager` knows about in an attempt to break the application. The
+> dispatcher uses a special, scoped container that will only pull controllers
+> that are specifically registered with it, either as invokable classes or via
+> factories.
+
+Open your `config/module.config.php` file, and modify it to add to the "routes"
+and "controller" parameters so it reads as follows:
+
+```php
+return [
+ 'router' => [
+ 'routes' => [
+ '-hello-world' => [
+ 'type' => 'Literal',
+ 'options' => [
+ 'route' => '/hello/world',
+ 'defaults' => [
+ 'controller' => '\Controller\Hello',
+ 'action' => 'world',
+ ],
+ ],
+ ],
+ ],
+ ],
+ 'controllers' => [
+ 'invokables' => [
+ '\Controller\Hello' => '\Controller\HelloController',
+ ],
+ ],
+ // ... other configuration ...
+];
+```
+
+## Tell the Application About our Module
+
+One problem: we haven't told our application about our new module!
+
+By default, modules are not utilized unless we tell the module manager about them.
+As such, we need to notify the application about them.
+
+Remember the `config/application.config.php` file? Let's modify it to add our
+new module. Once done, it should read as follows:
+
+```php
+ array(
+ 'Application',
+ '',
+ ),
+ 'module_listener_options' => array(
+ 'module_paths' => array(
+ './module',
+ './vendor',
+ ),
+ ),
+);
+```
+
+Replace `` with the namespace of your module.
+
+## Test it Out!
+
+Now we can test things out! Create a new vhost pointing its document root to the `public` directory
+of your application, and fire it up in a browser. You should see the default homepage template of
+ZendSkeletonApplication.
+
+Now alter the location in your URL to append the path "/hello/world", and load the page. You should
+now get the following content:
+
+```html
+Greetings!
+
+You said "foo".
+```
+
+Now alter the location to append "?message=bar" and load the page. You should now get:
+
+```html
+Greetings!
+
+You said "bar".
+```
+
+Congratulations! You've created your first ZF2 MVC module!
diff --git a/doc/book/routing.md b/doc/book/routing.md
new file mode 100644
index 000000000..494001dec
--- /dev/null
+++ b/doc/book/routing.md
@@ -0,0 +1,725 @@
+# Routing
+
+Routing is the act of matching a request to a given controller.
+
+Typically, routing will examine the request URI, and attempt to match the URI
+path segment against provided constraints. If the constraints match, a set of
+"matches" are returned, one of which should be the controller name to execute.
+Routing can utilize other portions of the request URI or environment as well.
+For example, the host or scheme, query parameters, headers, request method, and
+more.
+
+The base unit of routing is a `Route`:
+
+```php
+namespace Zend\Mvc\Router;
+
+use Zend\Stdlib\RequestInterface as Request;
+
+interface RouteInterface
+{
+ public static function factory(array $options = []);
+ public function match(Request $request);
+ public function assemble(array $params = [], array $options = []);
+}
+```
+
+A `Route` accepts a `Request`, and determines if it matches. If so, it returns a
+`RouteMatch` object:
+
+```php
+namespace Zend\Mvc\Router;
+
+class RouteMatch
+{
+ public function __construct(array $params);
+ public function setMatchedRouteName($name);
+ public function getMatchedRouteName();
+ public function setParam($name, $value);
+ public function getParams();
+ public function getParam($name, $default = null);
+}
+```
+
+Typically, when a `Route` matches, it will define one or more parameters. These
+are passed into the `RouteMatch`, and objects may query the `RouteMatch` for
+their values.
+
+```php
+$id = $routeMatch->getParam('id', false);
+if (! $id) {
+ throw new Exception('Required identifier is missing!');
+}
+$entity = $resource->get($id);
+```
+
+Usually you will have multiple routes you wish to test against. In order to
+facilitate this, you will use a route aggregate, usually implementing
+`RouteStack`:
+
+```php
+namespace Zend\Mvc\Router;
+
+interface RouteStackInterface extends RouteInterface
+{
+ public function addRoute($name, $route, $priority = null);
+ public function addRoutes(array $routes);
+ public function removeRoute($name);
+ public function setRoutes(array $routes);
+}
+```
+
+Routes will be queried in a LIFO order, and hence the reason behind the name
+`RouteStack`. zend-mvc provides two implementations of this interface,
+`SimpleRouteStack` and `TreeRouteStack`. In each, you register routes either one
+at a time using `addRoute()`, or in bulk using `addRoutes()`.
+
+```php
+// One at a time:
+$route = Literal::factory([
+ 'route' => '/foo',
+ 'defaults' => [
+ 'controller' => 'foo-index',
+ 'action' => 'index',
+ ],
+]);
+$router->addRoute('foo', $route);
+
+// In bulk:
+$router->addRoutes([
+ // using already instantiated routes:
+ 'foo' => $route,
+
+ // providing configuration to allow lazy-loading routes:
+ 'bar' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => '/bar',
+ 'defaults' => [
+ 'controller' => 'bar-index',
+ 'action' => 'index',
+ ],
+ ],
+ ],
+]);
+```
+
+## Router Types
+
+Two routers are provided, the `SimpleRouteStack` and `TreeRouteStack`. Each
+works with the above interface, but utilize slightly different options and
+execution paths. By default, the zend-mvc uses the `TreeRouteStack` as the
+router.
+
+### SimpleRouteStack
+
+This router takes individual routes that provide their full matching logic in
+one go, and loops through them in LIFO order until a match is found. As such,
+routes that will match most often should be registered last, and least common
+routes first. Additionally, you will need to ensure that routes that potentially
+overlap are registered such that the most specific match will match first (i.e.,
+register later). Alternatively, you can set priorities by giving the priority as
+third parameter to the `addRoute()` method, specifying the priority in the route
+specifications or setting the priority property within a route instance before
+adding it to the route stack.
+
+### TreeRouteStack
+
+`Zend\Mvc\Router\Http\TreeRouteStack` provides the ability to register trees of
+routes, and uses a B-tree algorithm to match routes. As such, you register a
+single route with many children.
+
+A `TreeRouteStack` will consist of the following configuration:
+
+- A base "route", which describes the base match needed, the root of the tree.
+- An optional `route_plugins`, which is a configured
+ `Zend\Mvc\Router\RoutePluginManager` that can lazy-load routes.
+- The option `may_terminate`, which hints to the router that no other segments
+ will follow it.
+- An optional `child_routes` array, which contains additional routes that stem
+ from the base "route" (i.e., build from it). Each child route can itself be a
+ `TreeRouteStack` if desired; in fact, the `Part` route works exactly this way.
+
+When a route matches against a `TreeRouteStack`, the matched parameters from
+each segment of the tree will be returned.
+
+A `TreeRouteStack` can be your sole route for your application, or describe
+particular path segments of the application.
+
+An example of a `TreeRouteStack` is provided in the documentation of the `Part`
+route.
+
+## HTTP Route Types
+
+zend-mvc ships with the following HTTP route types.
+
+### Zend\\Mvc\\Router\\Http\\Hostname
+
+The `Hostname` route attempts to match the hostname registered in the request
+against specific criteria. Typically, this will be in one of the following
+forms:
+
+* `subdomain.domain.tld`
+* `:subdomain.domain.tld`
+
+In the above, the second route would return a "subdomain" key as part of the
+route match.
+
+For any given hostname segment, you may also provide a constraint. As an
+example, if the "subdomain" segment needed to match only if it started with "fw"
+and contained exactly 2 digits following, the following route would be needed:
+
+```php
+$route = Hostname::factory([
+ 'route' => ':subdomain.domain.tld',
+ 'constraints' => [
+ 'subdomain' => 'fw\d{2}',
+ ],
+]);
+```
+
+In the above example, only a "subdomain" key will be returned in the
+`RouteMatch`. If you wanted to also provide other information based on matching,
+or a default value to return for the subdomain, you need to also provide
+defaults.
+
+```php
+$route = Hostname::factory([
+ 'route' => ':subdomain.domain.tld',
+ 'constraints' => [
+ 'subdomain' => 'fw\d{2}',
+ ],
+ 'defaults' => [
+ 'type' => 'json',
+ ],
+]);
+```
+
+When matched, the above will return two keys in the `RouteMatch`, "subdomain"
+and "type".
+
+### Zend\\Mvc\\Router\\Http\\Literal
+
+The `Literal` route is for doing exact matching of the URI path. Configuration
+therefore is solely the path you want to match, and the "defaults", or
+parameters you want returned on a match.
+
+```php
+$route = Literal::factory([
+ 'route' => '/foo',
+ 'defaults' => [
+ 'controller' => 'Application\Controller\IndexController',
+ 'action' => 'foo',
+ ],
+]);
+```
+
+The above route would match a path "/foo", and return the key "action" in the
+`RouteMatch`, with the value "foo".
+
+### Zend\\Mvc\\Router\\Http\\Method
+
+The `Method` route is used to match the HTTP method or 'verb' specified in the
+request (See RFC 2616 Sec. 5.1.1). It can optionally be configured to match
+against multiple methods by providing a comma-separated list of method tokens.
+
+```php
+$route = Method::factory([
+ 'verb' => 'post,put',
+ 'defaults' => [
+ 'controller' => 'Application\Controller\IndexController',
+ 'action' => 'form-submit',
+ ],
+]);
+```
+
+The above route would match an http "POST" or "PUT" request and return a
+`RouteMatch` object containing a key "action" with a value of "form-submit".
+
+### Zend\\Mvc\\Router\\Http\\Part
+
+A `Part` route allows crafting a tree of possible routes based on segments of
+the URI path. It actually extends the `TreeRouteStack`.
+
+`Part` routes are difficult to describe, so we'll simply provide a sample one
+here.
+
+```php
+$route = Part::factory([
+ 'route' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => '/',
+ 'defaults' => [
+ 'controller' => 'Application\Controller\IndexController',
+ 'action' => 'index',
+ ],
+ ],
+ ],
+ 'route_plugins' => $routePlugins,
+ 'may_terminate' => true,
+ 'child_routes' => [
+ 'blog' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => '/blog',
+ 'defaults' => [
+ 'controller' => 'Application\Controller\BlogController',
+ 'action' => 'index',
+ ],
+ ],
+ 'may_terminate' => true,
+ 'child_routes' => [
+ 'rss' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => '/rss',
+ 'defaults' => [
+ 'action' => 'rss',
+ ]
+ ],
+ 'may_terminate' => true,
+ 'child_routes' => [
+ 'subrss' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => '/sub',
+ 'defaults' => [
+ 'action' => 'subrss',
+ ],
+ ],
+ ],
+ ],
+ ],
+ ],
+ ],
+ 'forum' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => 'forum',
+ 'defaults' => [
+ 'controller' => 'Application\Controller\ForumController',
+ 'action' => 'index',
+ ],
+ ],
+ ],
+ ],
+]);
+```
+
+The above would match the following:
+
+- `/` would load the "Index" controller, "index" action.
+- `/blog` would load the "Blog" controller, "index" action.
+- `/blog/rss` would load the "Blog" controller, "rss" action.
+- `/blog/rss/sub` would load the "Blog" controller, "subrss" action.
+- `/forum` would load the "Forum" controller, "index" action.
+
+You may use any route type as a child route of a `Part` route.
+
+> ### Part routes are an implementation detail
+>
+> `Part` routes are not meant to be used directly. When you add definitions for
+> `child_routes` to any route type, that route will become a `Part` route. As
+> already said, describing `Part` routes with words is difficult, so hopefully
+> the additional [examples at the end](#http-routing-examples) will provide
+> further insight.
+
+> ### Route plugins
+>
+> In the above example, the `$routePlugins` is an instance of
+> `Zend\Mvc\Router\RoutePluginManager`, containing essentially the following
+> configuration:
+>
+> ```php
+> $routePlugins = new Zend\Mvc\Router\RoutePluginManager();
+> $plugins = [
+> 'hostname' => 'Zend\Mvc\Router\Http\Hostname',
+> 'literal' => 'Zend\Mvc\Router\Http\Literal',
+> 'part' => 'Zend\Mvc\Router\Http\Part',
+> 'regex' => 'Zend\Mvc\Router\Http\Regex',
+> 'scheme' => 'Zend\Mvc\Router\Http\Scheme',
+> 'segment' => 'Zend\Mvc\Router\Http\Segment',
+> 'wildcard' => 'Zend\Mvc\Router\Http\Wildcard',
+> 'query' => 'Zend\Mvc\Router\Http\Query',
+> 'method' => 'Zend\Mvc\Router\Http\Method',
+> ];
+> foreach ($plugins as $name => $class) {
+> $routePlugins->setInvokableClass($name, $class);
+> }
+> ```
+>
+> When using `Zend\Mvc\Router\Http\TreeRouteStack`, the `RoutePluginManager` is
+> set up by default, and the developer does not need to worry about autoloading
+> of standard HTTP routes.
+
+### Zend\\Mvc\\Router\\Http\\Regex
+
+A `Regex` route utilizes a regular expression to match against the URI path. Any
+valid regular expression is allowed; our recommendation is to use named captures
+for any values you want to return in the `RouteMatch`.
+
+Since regular expression routes are often complex, you must specify a "spec" or
+specification to use when assembling URLs from regex routes. The spec is simply
+a string; replacements are identified using `%keyname%` within the string, with
+the keys coming from either the captured values or named parameters passed to
+the `assemble()` method.
+
+Just like other routes, the `Regex` route can accept "defaults", parameters to
+include in the `RouteMatch` when successfully matched.
+
+```php
+$route = Regex::factory([
+ 'regex' => '/blog/(?[a-zA-Z0-9_-]+)(\.(?(json|html|xml|rss)))?',
+ 'defaults' => [
+ 'controller' => 'Application\Controller\BlogController',
+ 'action' => 'view',
+ 'format' => 'html',
+ ],
+ 'spec' => '/blog/%id%.%format%',
+]);
+```
+
+The above would match `/blog/001-some-blog_slug-here.html`, and return four
+items in the `RouteMatch`, an "id", the "controller", the "action", and the
+"format". When assembling a URL from this route, the "id" and "format" values
+would be used to fill the specification.
+
+### Zend\\Mvc\\Router\\Http\\Scheme
+
+The `Scheme` route matches the URI scheme only, and must be an exact match. As
+such, this route, like the `Literal` route, simply takes what you want to match
+and the "defaults", parameters to return on a match.
+
+```php
+$route = Scheme::factory([
+ 'scheme' => 'https',
+ 'defaults' => [
+ 'https' => true,
+ ],
+]);
+```
+
+The above route would match the "https" scheme, and return the key "https" in
+the `RouteMatch` with a boolean `true` value.
+
+### Zend\\Mvc\\Router\\Http\\Segment
+
+A `Segment` route allows matching any segment of a URI path. Segments are
+denoted using a colon, followed by alphanumeric characters; if a segment is
+optional, it should be surrounded by brackets. As an example, `/:foo[/:bar]`
+would match a `/` followed by text and assign it to the key "foo"; if any
+additional `/` characters are found, any text following the last one will be
+assigned to the key "bar".
+
+The separation between literal and named segments can be anything. For example,
+the above could be done as `/:foo{-}[-:bar]` as well. The `{-}` after the `:foo`
+parameter indicates a set of one or more delimiters, after which matching of the
+parameter itself ends.
+
+Each segment may have constraints associated with it. Each constraint should
+simply be a regular expression expressing the conditions under which that
+segment should match.
+
+Also, as you can in other routes, you may provide defaults to use; these are
+particularly useful when using optional segments.
+
+As a complex example:
+
+```php
+$route = Segment::factory([
+ 'route' => '/:controller[/:action]',
+ 'constraints' => [
+ 'controller' => '[a-zA-Z][a-zA-Z0-9_-]+',
+ 'action' => '[a-zA-Z][a-zA-Z0-9_-]+',
+ ],
+ 'defaults' => [
+ 'controller' => 'Application\Controller\IndexController',
+ 'action' => 'index',
+ ],
+]);
+```
+
+### Zend\\Mvc\\Router\\Http\\Query (Deprecated)
+
+> #### Potential security issue
+>
+> Misuse of this route can lead to potential security issues.
+
+> #### Deprecated
+>
+> This route part is deprecated since you can now add query parameters without a
+> query route.
+
+The `Query` route part allows you to specify and capture query string parameters
+for a given route.
+
+The intention of the `Query` part is that you do not instantiate it in its own
+right, but use it as a child of another route part.
+
+An example of its usage would be:
+
+```php
+$route = Part::factory([
+ 'route' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => 'page',
+ 'defaults' => [],
+ ],
+ ],
+ 'may_terminate' => true,
+ 'route_plugins' => $routePlugins,
+ 'child_routes' => [
+ 'query' => [
+ 'type' => 'Query',
+ 'options' => [
+ 'defaults' => [
+ 'foo' => 'bar',
+ ],
+ ],
+ ],
+ ],
+]);
+```
+
+This then allows you to create query strings using the url view helper.
+
+```php
+$this->url(
+ 'page/query',
+ [
+ 'name' => 'my-test-page',
+ 'format' => 'rss',
+ 'limit' => 10,
+ ]
+);
+```
+
+Per the above example, you must add `/query` (the name we gave to our query
+route segment) to your route name in order to append a query string. If you do
+not specify `/query` in the route name, then no query string will be appended.
+
+Our example "page" route has only one defined parameter of "name"
+(`/page[/:name]`), meaning that the remaining parameters of "format" and "limit"
+will then be appended as a query string.
+
+The output from our example should then be
+`/page/my-test-page?format=rss&limit=10`
+
+### Zend\\Mvc\\Router\\Http\\Wildcard (Deprecated)
+
+> #### Potential security issue
+>
+> Misuse of this route type can lead to potential security issues.
+
+> #### Deprecated
+>
+> This route type is deprecated. Use the `Segment` route type.
+
+The `Wildcard` route type matches all remaining segments of a URI path.
+
+## HTTP Routing Examples
+
+Most of the routing definitions will be done in module configuration files, so
+the following examples will show how to set up routes in config files.
+
+### Simple example with two literal routes
+
+```php
+return [
+ 'router' => [
+ 'routes' => [
+ // Literal route named "home"
+ 'home' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => '/',
+ 'defaults' => [
+ 'controller' => 'Application\Controller\IndexController',
+ 'action' => 'index',
+ ],
+ ],
+ ],
+ // Literal route named "contact"
+ 'contact' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => 'contact',
+ 'defaults' => [
+ 'controller' => 'Application\Controller\ContactController',
+ 'action' => 'form',
+ ],
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+### A complex example with child routes
+
+```php
+return [
+ 'router' => [
+ 'routes' => [
+ // Literal route named "home"
+ 'home' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => '/',
+ 'defaults' => [
+ 'controller' => 'Application\Controller\IndexController',
+ 'action' => 'index',
+ ],
+ ],
+ ],
+ // Literal route named "blog", with child routes
+ 'blog' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => '/blog',
+ 'defaults' => [
+ 'controller' => 'Application\Controller\BlogController',
+ 'action' => 'index',
+ ],
+ ],
+ 'may_terminate' => true,
+ 'child_routes' => [
+ // Segment route for viewing one blog post
+ 'post' => [
+ 'type' => 'segment',
+ 'options' => [
+ 'route' => '/[:slug]',
+ 'constraints' => [
+ 'slug' => '[a-zA-Z0-9_-]+',
+ ],
+ 'defaults' => [
+ 'action' => 'view',
+ ],
+ ],
+ ],
+ // Literal route for viewing blog RSS feed
+ 'rss' => [
+ 'type' => 'literal',
+ 'options' => [
+ 'route' => '/rss',
+ 'defaults' => [
+ 'action' => 'rss',
+ ],
+ ],
+ ],
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+When using child routes, naming of the routes follows the `parent/child`
+pattern, so to use the child routes from the above example:
+
+```php
+echo $this->url('blog'); // gives "/blog"
+echo $this->url('blog/post', ['slug' => 'my-post']); // gives "/blog/my-post"
+echo $this->url('blog/rss'); // gives "/blog/rss"
+```
+
+### An example with multiple Hostnames and subdomains within a single application
+
+```php
+return [
+ 'router' => [
+ 'routes' => [
+ 'modules.zendframework.com' => [
+ 'type' => 'Zend\Mvc\Router\Http\Hostname',
+ 'options' => [
+ 'route' => ':4th.[:3rd.]:2nd.:1st', // domain levels from right to left
+ 'contraints' => [
+ '4th' => 'modules',
+ '3rd' => '.*?', // optional 3rd level domain such as .ci, .dev or .test
+ '2nd' => 'zendframework',
+ '1st' => 'com',
+ ],
+ // Purposely omit default controller and action
+ // to let the child routes control the route match
+ ],
+ // child route controllers may span multiple modules as desired
+ 'child_routes' => [
+ 'index' => [
+ 'type' => 'Zend\Mvc\Router\Http\Literal',
+ 'options' => [
+ 'route' => '/',
+ 'defaults' => [
+ 'controller' => 'Module\Controller\Index',
+ 'action' = > 'index',
+ ],
+ ],
+ 'may_terminate' => true,
+ ],
+ ],
+ ],
+ 'packages.zendframework.com' => [
+ 'type' => 'Zend\Mvc\Router\Http\Hostname',
+ 'options' => [
+ 'route' => ':4th.[:3rd.]:2nd.:1st', // domain levels from right to left
+ 'contraints' => [
+ '4th' => 'packages',
+ '3rd' => '.*?', // optional 3rd level domain such as .ci, .dev or .test
+ '2nd' => 'zendframework',
+ '1st' => 'com',
+ ],
+ // Purposely omit default controller and action
+ // to let the child routes control the route match
+ ],
+ // child route controllers may span multiple modules as desired
+ 'child_routes' => [
+ 'index' => [
+ 'type' => 'Zend\Mvc\Router\Http\Literal',
+ 'options' => [
+ 'route' => '/',
+ 'defaults' => [
+ 'controller' => 'Package\Controller\Index',
+ 'action' = > 'index',
+ ],
+ ],
+ 'may_terminate' => true,
+ ],
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+The above would match the following:
+
+- `modules.zendframework.com` would dispatch the `Index` controller's `index`
+ action of the `Module` module.
+- `modules.ci.zendframework.com` would dispatch the `Index` controller's `index`
+ action of the `Module` module.
+- `packages.zendframework.com` would dispatch the `Index` controller's `index`
+ action of the `Package` module.
+- `packages.dev.zendframework.com` would dispatch the `Index` controller's
+ `index` action of the `Package` module.
+
+The `Url` controller plugin or view helper may be used to generate URLs
+following the above example:
+
+```php
+// reuse the route matched parameters to generate URLs
+echo $this->url('modules.zendframework.com/index', [], [], true);
+echo $this->url('packages.zendframework.com/index', [], [], true);
+```
+
+> ### may_terminate and child_routes placement
+>
+> When defining child routes pay attention that the `may_terminate` and
+> `child_routes` definitions are in same level as the `options` and `type`
+> definitions. A common pitfall is to have those two definitions nested in
+> `options`, which will not result in the desired routes.
+
+## Console Route Types
+
+zend-mvc also allows routing Console based applications; console routes are
+explained in the [zend-console routing documentation](http://zendframework.github.io/zend-console/routes/).
diff --git a/doc/book/send-response-event.md b/doc/book/send-response-event.md
new file mode 100644
index 000000000..fe9d79e52
--- /dev/null
+++ b/doc/book/send-response-event.md
@@ -0,0 +1,33 @@
+# The SendResponse Event
+
+zend-mvc defines and utilizes a custom `Zend\EventManager\Event` for updating
+the response object prior to emitting it, `Zend\Mvc\ResponseSender\SendResponseEvent`.
+The event allows listeners to set response headers and content.
+
+The methods it defines are:
+
+- `setResponse($response)`
+- `getResponse()`
+- `setContentSent()`
+- `contentSent()`
+- `setHeadersSent()`
+- `headersSent()`
+
+## Listeners
+
+Currently, three listeners are listening to this event at different priorities based on which
+listener is used most.
+
+Class | Priority | Method Called | Description
+------------------------------------------------------------ | -------: | ------------- | -----------
+`Zend\Mvc\SendResponseListener\PhpEnvironmentResponseSender` | -1000 | `__invoke` | This is used in HTTP contexts (this is the most often used).
+`Zend\Mvc\SendResponseListener\ConsoleResponseSender` | -2000 | `__invoke` | This is used in console contexts.
+`Zend\Mvc\SendResponseListener\SimpleStreamResponseSender` | -3000 | `__invoke` |
+
+Because each listener has negative priority, adding your own logic to modify the
+`Response` involves adding a new listener without priority (as priority defaults
+to 1); thus, your own listener will execute before any of the defaults.
+
+## Triggered By
+
+This event is executed when the `MvcEvent::FINISH` event is triggered, with a priority of -10000.
diff --git a/doc/book/services.md b/doc/book/services.md
new file mode 100644
index 000000000..1a2e7e776
--- /dev/null
+++ b/doc/book/services.md
@@ -0,0 +1,785 @@
+# Default Services
+
+The default and recommended way to write zend-mvc applications uses a set of
+services defined in the `Zend\Mvc\Service` namespace. This chapter details what
+each of those services are, the classes they represent, and the configuration
+options available.
+
+Many of the services are provided by other components, and the factories and
+abstract factories themselves are defined in the individual components. We will
+cover those factories in this chapter, however, as usage is generally the same
+between each.
+
+## Theory of Operation
+
+To allow easy configuration of all the different parts of the MVC system, a
+somewhat complex set of services and their factories has been created. We'll try
+to give a simplified explanation of the process.
+
+When a `Zend\Mvc\Application` is created, a `Zend\ServiceManager\ServiceManager`
+object is created and configured via `Zend\Mvc\Service\ServiceManagerConfig`.
+The `ServiceManagerConfig` gets the configuration from
+`config/application.config.php` (or some other application configuration you
+passed to the `Application` when creating it). From all the service and
+factories provided in the `Zend\Mvc\Service` namespace, `ServiceManagerConfig`
+is responsible of configuring only three: `SharedEventManager`, `EventManager`,
+and `ModuleManager`.
+
+After this, the `Application` fetches the `ModuleManager`. At this point, the
+`ModuleManager` further configures the `ServiceManager` with services and
+factories provided in `Zend\Mvc\Service\ServiceListenerFactory`. This approach
+allows us to keep the main application configuration concise, and to give the
+developer the power to configure different parts of the MVC system from within
+the modules, overriding any default configuration in these MVC services.
+
+## ServiceManager
+
+As a quick review, the following service types may be configured:
+
+- **Invokable services**, which map a service name to a class that has no
+ constructor or a constructor that accepts no arguments.
+- **Factories**, which map a service name to a factory which will create and
+ return an object. A factory receives the service manager as an argument, and
+ may be any PHP callable, or a class or object that implements
+ `Zend\ServiceManager\FactoryInterface`.
+- **Abstract factories**, which are factories that can create any number of
+ named services that share the same instantiation pattern; examples include
+ database adapters, cache adapters, loggers, etc. The factory receives the
+ service manager as an argument, the resolved service name, and the requested
+ service name; it **must** be a class or object implementing
+ `Zend\ServiceManager\AbstractFactoryInterface`. See the section on
+ [abstract factories](http://zendframework.github.io/zend-servicemanager/configuring-the-service-manager/#abstract-factories)
+ for configuration information.
+- **Aliases**, which alias one service name to another. Aliases can also
+ reference other aliases.
+- **Initializers**, which receive the newly created instance and the service
+ manager, and which can be used to perform additional initialization tasks. The
+ most common use case is to test the instance against specific "Aware"
+ interfaces, and, if matching, inject them with the appropriate service.
+- **Delegators**, which typically *decorate* retrieval of a service to either
+ substitute an alternate service, decorate the created service, or perform
+ pre/post initialization tasks when creating a service.
+- **Lazy services**, which are decorators for services with expensive
+ initialization; the service manager essentially returns a proxy service that
+ defers initialization until the first call is made to the service.
+- **Plugin managers**, which are specialized service managers used to manage
+ objects that are of a related type, such as view helpers, controller plugins,
+ controllers, etc. Plugin managers accept configuration just like service
+ managers, and as such can compose each of the service types listed above.
+ They are also `ServiceLocatorAware`, and will be injected with the application
+ service manager instance, giving factories and abstract factories access to
+ application-level services when needed. See the heading
+ [Plugin managers](#plugin-managers) for a list of available plugin managers.
+
+The application service manager is referenced directly during bootstrapping, and has the following
+services configured out of the box.
+
+### Invokable services
+
+- `DispatchListener`, mapping to `Zend\Mvc\DispatchListener`.
+- `Zend\Mvc\MiddlewareListener`.
+- `RouteListener`, mapping to `Zend\Mvc\RouteListener`.
+- `SendResponseListener`, mapping to `Zend\Mvc\SendResponseListener`.
+- `SharedEventManager`, mapping to `Zend\EventManager\SharedEventManager`.
+
+### Factories
+
+- `Application`, mapping to `Zend\Mvc\Service\ApplicationFactory`.
+
+- `Config`, mapping to `Zend\Mvc\Service\ConfigFactory`. Internally, this
+ pulls the `ModuleManager` service, calls its `loadModules()` method, and
+ retrieves the merged configuration from the module event. As such, this
+ service contains the entire, merged application configuration.
+
+- `ControllerManager`, mapping to `Zend\Mvc\Service\ControllerLoaderFactory`.
+ This creates an instance of `Zend\Mvc\Controller\ControllerManager`, passing
+ the service manager instance. Additionally, it uses the
+ `DiStrictAbstractServiceFactory` service, effectively allowing you to fall
+ back to DI in order to retrieve your controllers. If you want to use
+ `Zend\Di` to retrieve your controllers, you must white-list them in your DI
+ configuration under the `allowed_controllers` key (otherwise, they will just
+ be ignored). The `ControllerManager` provides initializers for the
+ following:
+
+ - If the controller implements `Zend\ServiceManager\ServiceLocatorAwareInterface`
+ (or the methods it defines), an instance of the `ServiceManager` will be
+ injected into it.
+
+ - If the controller implements `Zend\EventManager\EventManagerAwareInterface`,
+ an instance of the `EventManager` will be injected into it.
+
+ - Finally, an initializer will inject it with the `ControllerPluginManager`
+ service, as long as the `setPluginManager` method is implemented.
+
+- `ControllerPluginManager`, mapping to
+ `Zend\Mvc\Service\ControllerPluginManagerFactory`. This instantiates the
+ `Zend\Mvc\Controller\PluginManager` instance, passing it the service manager
+ instance. It also uses the `DiAbstractServiceFactory` service, effectively
+ allowing you to fall back to DI in order to retrieve your [controller plugins](controller-plugins.md).
+ It registers a set of default controller plugins, and contains an
+ initializer for injecting plugins with the current controller.
+
+- `ConsoleAdapter`, mapping to `Zend\Mvc\Service\ConsoleAdapterFactory`. This
+ grabs the `Config` service, pulls from the `console` key, and do the
+ following:
+
+ - If the `adapter` subkey is present, it is used to get the adapter
+ instance, otherwise, `Zend\Console\Console::detectBestAdapter()` will be
+ called to configure an adapter instance.
+
+ - If the `charset` subkey is present, the value is used to set the adapter
+ charset.
+
+- `ConsoleRouter`, mapping to `Zend\Mvc\Service\ConsoleRouterFactory`. This
+ grabs the `Config` service, and pulls from the `console` key and `router`
+ subkey, configuring a `Zend\Mvc\Router\Console\SimpleRouteStack` instance.
+
+- `ConsoleViewManager`, mapping to `Zend\Mvc\Service\ConsoleViewManagerFactory`.
+ This creates and returns an instance of `Zend\Mvc\View\Console\ViewManager`,
+ which in turn registers and initializes a number of console-specific view
+ services.
+
+- `DependencyInjector`, mapping to `Zend\Mvc\Service\DiFactory`. This pulls
+ the `Config` service, and looks for a "di" key; if found, that value is used
+ to configure a new `Zend\Di\Di` instance.
+
+- `DiAbstractServiceFactory`, mapping to
+ `Zend\Mvc\Service\DiAbstractServiceFactoryFactory`. This creates an instance
+ of `Zend\ServiceManager\Di\DiAbstractServiceFactory` injecting the `Di`
+ service instance. That instance is attached to the service manager as an
+ abstract factory, effectively enabling DI as a fallback for providing
+ services.
+
+- `DiServiceInitializer`, mapping to `Zend\Mvc\Service\DiServiceInitializerFactory`.
+ This creates an instance of `Zend\ServiceManager\Di\DiServiceInitializer`
+ injecting the `Di` service and the service manager itself.
+
+- `DiStrictAbstractServiceFactory`, mapping to `Zend\Mvc\Service\DiStrictAbstractServiceFactoryFactory`.
+ This creates an instance of `Zend\Mvc\Service\DiStrictAbstractServiceFactoryFactory`,
+ injecting the `Di` service instance.
+
+- `EventManager`, mapping to `Zend\Mvc\Service\EventManagerFactory`. This
+ factory returns a *discrete* instance of `Zend\EventManager\EventManager` on
+ each request. This service is not shared by default, allowing the ability to
+ have an `EventManager` per service, with a shared `SharedEventManager`
+ injected in each.
+
+- `FilterManager`, mapping to `Zend\Mvc\Service\FilterManagerFactory`. This
+ instantiates the `Zend\Filter\FilterPluginManager` instance, passing it the
+ service manager instance; this is used to manage filters for [filter chains](http://zendframework.github.io/zend-filter/filter-chains/).
+ It also uses the `DiAbstractServiceFactory` service, effectively allowing
+ you to fall back to DI in order to retrieve filters.
+
+- `FormElementManager`, mapping to `Zend\Mvc\Service\FormElementManagerFactory`.
+ This instantiates the `Zend\Form\FormElementManager` instance, passing it
+ the service manager instance; this is used to manage [form elements](http://framework.zend.com/manual/current/en/zend.form.elements.intro.html).
+ It also uses the `DiAbstractServiceFactory` service, effectively allowing
+ you to fall back to DI in order to retrieve form elements.
+
+- `HttpRouter`, mapping to `Zend\Mvc\Service\HttpRouterFactory`. This grabs
+ the `Config` service, and pulls from the `router` key, configuring a
+ `Zend\Mvc\Router\Http\TreeRouteStack` instance.
+
+- `HttpViewManager`, mapping to `Zend\Mvc\Service\HttpViewManagerFactory`.
+ This creates and returns an instance of `Zend\Mvc\View\Http\ViewManager`,
+ which in turn registers and initializes a number of HTTP-specific view
+ services.
+
+- `HydratorManager`, mapping to `Zend\Mvc\Service\HydratorManagerFactory`.
+ This creates and returns an instance of `Zend\Stdlib\Hydrator\HydratorPluginManager`,
+ which can be used to manage and persist hydrator instances.
+
+- `InputFilterManager`, mapping to `Zend\Mvc\Service\InputFilterManagerFactory`.
+ This creates and returns an instance of `Zend\InputFilter\InputFilterPluginManager`,
+ which can be used to manage and persist input filter instances.
+
+- `ModuleManager`, mapping to `Zend\Mvc\Service\ModuleManagerFactory`. This is
+ perhaps the most complex factory in the MVC stack. It expects that an
+ `ApplicationConfig` service has been injected, with keys for
+ `module_listener_options` and `modules`; see the quick start for samples.
+ It creates an instance of `Zend\ModuleManager\Listener\DefaultListenerAggregate`,
+ using the `module_listener_options` retrieved. It then checks if a service
+ with the name `ServiceListener` exists; if not, it sets a factory with that
+ name mapping to `Zend\Mvc\Service\ServiceListenerFactory`. A bunch of
+ service listeners will be added to the `ServiceListener`, like listeners for
+ the `getServiceConfig`, `getControllerConfig`, `getControllerPluginConfig`,
+ and `getViewHelperConfig` module methods. Next, it retrieves the
+ `EventManager` service, and attaches the above listeners. It instantiates a
+ `Zend\ModuleManager\ModuleEvent` instance, setting the "ServiceManager"
+ parameter to the service manager object. Finally, it instantiates a
+ `Zend\ModuleManager\ModuleManager` instance, and injects the `EventManager`
+ and `ModuleEvent`.
+
+- `MvcTranslator`, mapping to `Zend\Mvc\Service\TranslatorServiceFactory`, and
+ returning an instance of `Zend\Mvc\I18n\Translator`, which extends
+ `Zend\I18n\Translator\Translator` and implements `Zend\Validator\Translator\TranslatorInterface`,
+ allowing the instance to be used anywhere a translator may be required in
+ the framework.
+
+- `PaginatorPluginManager`, mapping to `Zend\Mvc\Service\PaginatorPluginManagerFactory`.
+ This instantiates the `Zend\Paginator\AdapterPluginManager` instance,
+ passing it the service manager instance. This is used to manage
+ [paginator adapters](http://framework.zend.com/manual/current/en/zend.paginator.usage.paginating.adapters.html).
+ It also uses the `DiAbstractServiceFactory` service, effectively allowing
+ you to fall back to DI in order to retrieve paginator adapters.
+
+- `Request`, mapping to `Zend\Mvc\Service\RequestFactory`. The factory is used
+ to create and return a request instance, according to the current
+ environment. If the current environment is a console environment, it will
+ create a `Zend\Console\Request`; otherwise, for HTTP environments, it
+ creates a `Zend\Http\PhpEnvironment\Request`.
+
+- `Response`, mapping to `Zend\Mvc\Service\ResponseFactory`. The factory is
+ used to create and return a response instance, according to the current
+ environment. If the current environment is a console environment, it will
+ create a `Zend\Console\Response`; otherwise, for HTTP environments, it
+ creates a `Zend\Http\PhpEnvironment\Response`.
+
+- `Router`, mapping to `Zend\Mvc\Service\RouterFactory`. If in a console
+ enviroment, it proxies to the `ConsoleRouter` service; otherwise, it proxies
+ to the `HttpRouter` service.
+
+- `RoutePluginManager`, mapping to `Zend\Mvc\Service\RoutePluginManagerFactory`.
+ This instantiates the `Zend\Mvc\Router\RoutePluginManager` instance, passing
+ it the service manager instance; this is used to manage [route types](routing.md#http-route-types).
+ It also uses the `DiAbstractServiceFactory` service, effectively allowing
+ you to fall back to DI in order to retrieve route types.
+
+- `SerializerAdapterManager`, mapping to `Zend\Mvc\Service\SerializerAdapterPluginManagerFactory`,
+ which returns an instance of `Zend\Serializer\AdapterPluginManager`. This is
+ a plugin manager for managing serializer adapter instances.
+
+- `ServiceListener`, mapping to `Zend\Mvc\Service\ServiceListenerFactory`. The
+ factory is used to instantiate the `ServiceListener`, while allowing easy
+ extending. It checks if a service with the name `ServiceListenerInterface`
+ exists, which must implement `Zend\ModuleManager\Listener\ServiceListenerInterface`,
+ before instantiating the default `ServiceListener`.
+ In addition to this, it retrieves the `ApplicationConfig` and looks for the
+ `service_listener_options` key. This allows you to register own listeners
+ for module methods and configuration keys to create an own service manager;
+ see the [application configuration options](#application-configuration-options) for samples.
+
+- `ValidatorManager`, mapping to `Zend\Mvc\Service\ValidatorManagerFactory`.
+ This instantiates the `Zend\Validator\ValidatorPluginManager` instance,
+ passing it the service manager instance. This is used to manage
+ [validators](http://framework.zend.com/manual/current/en/zend.validator.set.html).
+ It also uses the `DiAbstractServiceFactory` service, effectively allowing
+ you to fall back to DI in order to retrieve validators.
+
+- `ViewFeedRenderer`, mapping to `Zend\Mvc\Service\ViewFeedRendererFactory`,
+ which returns an instance of `Zend\View\Renderer\FeedRenderer`, used to
+ render feeds.
+
+- `ViewFeedStrategy`, mapping to `Zend\Mvc\Service\ViewFeedStrategyFactory`,
+ which returns an instance of `Zend\View\Strategy\FeedStrategy`, used to
+ select the `ViewFeedRenderer` given the appropriate criteria.
+
+- `ViewHelperManager`, mapping to `Zend\Mvc\Service\ViewHelperManagerFactory`,
+ which returns an instance of `Zend\View\HelperManager`. This is a plugin
+ manager for managing view helper instances.
+
+- `ViewJsonRenderer`, mapping to `Zend\Mvc\Service\ViewJsonRendererFactory`,
+ which returns an instance of `Zend\View\Renderer\JsonRenderer`, used to
+ render JSON structures.
+
+- `ViewJsonStrategy`, mapping to `Zend\Mvc\Service\ViewJsonStrategyFactory`,
+ which returns an instance of `Zend\View\Strategy\JsonStrategy`, used to
+ select the `ViewJsonRenderer` given the appropriate criteria.
+
+- `ViewManager`, mapping to `Zend\Mvc\Service\ViewManagerFactory`. The factory
+ is used to create and return a view manager, according to the current
+ environment. If the current environment is a console environment, it will
+ create a `Zend\Mvc\View\Console\ViewManager`; otherwise, for HTTP
+ environments, it returns a `Zend\Mvc\View\Http\ViewManager`.
+
+- `ViewResolver`, mapping to `Zend\Mvc\Service\ViewResolverFactory`, which
+ creates and returns the aggregate view resolver. It also attaches the
+ `ViewTemplateMapResolver` and `ViewTemplatePathStack` services to it.
+
+- `ViewTemplateMapResolver`, mapping to `Zend\Mvc\Service\ViewTemplateMapResolverFactory`,
+ which creates, configures and returns the `Zend\View\Resolver\TemplateMapResolver`.
+
+- `ViewTemplatePathStack`, mapping to `Zend\Mvc\Service\ViewTemplatePathStackFactory`,
+ which creates, configures and returns the `Zend\View\Resolver\TemplatePathStack`.
+
+### Abstract factories
+
+- `Zend\Cache\Service\StorageCacheAbstractServiceFactory` (opt-in; registered
+ by default in the skeleton application).
+- `Zend\Db\Adapter\AdapterAbstractServiceFactory` (opt-in).
+- `Zend\Form\FormAbstractServiceFactory` is registered by default.
+- `Zend\Log\LoggerAbstractServiceFactory` (opt-in; registered by default in the skeleton application).
+
+### Aliases
+
+- `Configuration`, mapping to the `Config` service.
+- `Console`, mapping to the `ConsoleAdapter` service.
+- `Di`, mapping to the `DependencyInjector` service.
+- `MiddlewareListener`, mapping to the `Zend\Mvc\MiddlewareListener` service.
+- `Zend\Di\LocatorInterface`, mapping to the `DependencyInjector` service.
+- `Zend\EventManager\EventManagerInterface`, mapping to the `EventManager`
+ service. This is mainly to ensure that when falling through to DI, classes
+ are still injected via the `ServiceManager`.
+- `Zend\Mvc\Controller\PluginManager`, mapping to the
+ `ControllerPluginManager` service. This is mainly to ensure that when
+ falling through to DI, classes are still injected via the `ServiceManager`.
+- `Zend\View\Resolver\TemplateMapResolver`, mapping to the
+ `ViewTemplateMapResolver` service.
+- `Zend\View\Resolver\TemplatePathStack`, mapping to the
+ `ViewTemplatePathStack` service.
+- `Zend\View\Resolver\AggregateResolver`, mapping to the `ViewResolver` service.
+- `Zend\View\Resolver\ResolverInterface`, mapping to the `ViewResolver` service.
+
+### Initializers
+
+- For objects that implement `Zend\EventManager\EventManagerAwareInterface`,
+ the `EventManager` service will be retrieved and injected. This service is
+ **not** shared, though each instance it creates is injected with a shared
+ instance of `SharedEventManager`.
+
+- For objects that implement `Zend\ServiceManager\ServiceLocatorAwareInterface`
+ (or the methods it defines), the `ServiceManager` will inject itself into
+ the object.
+
+- The `ServiceManager` registers itself as the `ServiceManager` service, and
+ aliases itself to the class names `Zend\ServiceManager\ServiceLocatorInterface`
+ and `Zend\ServiceManager\ServiceManager`.
+
+## Abstract Factories
+
+As noted in the previous section, Zend Framework provides a number of abstract
+service factories by default. Each is noted below, along with sample
+configuration.
+
+In each instance, the abstract factory looks for a top-level configuration key,
+consisting of key/value pairs where the key is the service name, and the value
+is the configuration to use to create the given service.
+
+### Zend\\Cache\\Service\\StorageCacheAbstractServiceFactory
+
+This abstract factory is opt-in, but registered by default in the skeleton application. It uses the
+top-level configuration key "caches".
+
+```php
+return [
+ 'caches' => [
+ 'Cache\Transient' => [
+ 'adapter' => 'redis',
+ 'ttl' => 60,
+ 'plugins' => [
+ 'exception_handler' => [
+ 'throw_exceptions' => false,
+ ],
+ ],
+ ],
+ 'Cache\Persistence' => [
+ 'adapter' => 'filesystem',
+ 'ttl' => 86400,
+ ],
+ ],
+];
+```
+
+See the [cache documentation](https://zendframework.github.io/zend-cache/storage/adapter/)
+for more configuration options.
+
+### Zend\\Db\\Adapter\\AdapterAbstractServiceFactory
+
+This abstract factory is opt-in. It uses the top-level configuration key "db",
+with a subkey "adapters".
+
+```php
+return [
+ 'db' => ['adapters' => [
+ 'Db\ReadOnly' => [
+ 'driver' => 'Pdo_Sqlite',
+ 'database' => 'data/db/users.db',
+ ],
+ 'Db\Writeable' => [
+ 'driver' => 'Mysqli',
+ 'database' => 'users',
+ 'username' => 'developer',
+ 'password' => 'developer_password',
+ ],
+ ]],
+];
+```
+
+See the [DB adapter documentation](http://framework.zend.com/manual/current/en/zend.db.adapter.html)
+for more configuration options.
+
+### Zend\\Form\\FormAbstractServiceFactory
+
+This abstract factory is registered by default. It uses the top-level
+configuration key "forms". It makes use of the `FilterManager`,
+`FormElementManager`, `HydratorManager`, `InputFilterManager`, and
+`ValidatorManager` plugin managers in order to allow instantiation and creation
+of form objects and all related objects in the form hierarchy.
+
+```php
+return [
+ 'forms' => [
+ 'Form\Foo' => [
+ 'hydrator' => 'ObjectProperty',
+ 'type' => 'Zend\Form\Form',
+ 'elements' => [
+ [
+ 'spec' => [
+ 'type' => 'Zend\Form\Element\Email',
+ 'name' => 'email',
+ 'options' => [
+ 'label' => 'Your email address',
+ ],
+ ],
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+Form configuration follows the same configuration you would use with a form
+factory; the primary difference is that all plugin managers have already been
+injected for you, allowing you the possibility of custom objects or
+substitutions.
+
+See the [form factory documentation](http://framework.zend.com/manual/current/en/zend.form.quick-start.factory.html)
+for more configuration options.
+
+### Zend\\Log\\LoggerAbstractServiceFactory
+
+This abstract factory is opt-in, but registered by default in the skeleton
+application. It uses the top-level configuration key "log".
+
+```php
+return [
+ 'log' => [
+ 'Log\App' => [
+ 'writers' => [
+ [
+ 'name' => 'stream',
+ 'priority' => 1000,
+ 'options' => [
+ 'stream' => 'data/logs/app.log',
+ ],
+ ],
+ ],
+ ],
+ ],
+];
+```
+
+See the [log documentation](https://zendframework.github.io/zend-log/intro/)
+for more configuration options.
+
+## Plugin Managers
+
+The following plugin managers are configured by default:
+
+- **ControllerManager**, corresponding to `Zend\Mvc\Controller\ControllerManager`,
+ and used to manage controller instances.
+- **ControllerPluginManager**, corresponding to `Zend\Mvc\Controller\PluginManager`,
+ and used to manage controller plugin instances.
+- **FilterManager**, corresponding to `Zend\Filter\FilterPluginManager`, and
+ used to manage filter instances.
+- **FormElementManager**, corresponding to `Zend\Form\FormElementManager`, and
+ used to manage instances of form elements and fieldsets.
+- **HydratorManager**, corresponding to `Zend\Stdlib\Hydrator\HydratorPluginManager`,
+ and used to manage hydrator instances.
+- **InputFilterManager**, corresponding to `Zend\InputFilter\InputFilterPluginManager`,
+ and used to manage input filter instances.
+- **RoutePluginManager**, corresponding to `Zend\Mvc\Router\RoutePluginManager`,
+ and used to manage route instances.
+- **SerializerAdapterManager**, corresponding to `Zend\Serializer\AdapterPluginManager`,
+ and used to manage serializer instances.
+- **ValidatorManager**, corresponding to `Zend\Validator\ValidatorPluginManager`,
+ and used to manage validator instances.
+- **ViewHelperManager**, corresponding to `Zend\View\HelperPluginManager`, and
+ used to manage view helper instances.
+
+As noted in the previous section, all plugin managers share the same
+configuration and service types as the standard service manager; they are simply
+scoped, and only allow instances of certain types to be created or registered.
+Default types available are listed in the documentation for each component.
+
+## ViewManager
+
+The View layer within zend-mvc consists of a large number of collaborators and
+event listeners. As such, `Zend\Mvc\View\ViewManager` was created to handle
+creation of the various objects, as well as wiring them together and
+establishing event listeners.
+
+The `ViewManager` itself is an event listener on the `bootstrap` event. It
+retrieves the `ServiceManager` from the `Application` object, as well as its
+composed `EventManager`.
+
+Configuration for all members of the `ViewManager` fall under the `view_manager`
+configuration key, and expect values as noted below. The following services are
+created and managed by the `ViewManager`:
+
+- `ViewHelperManager`, representing and aliased to `Zend\View\HelperPluginManager`.
+ It is seeded with the `ServiceManager`. Created via the
+ `Zend\Mvc\Service\ViewHelperManagerFactory`.
+
+ - The `Router` service is retrieved, and injected into the `Url` helper.
+
+ - If the `base_path` key is present, it is used to inject the `BasePath` view
+ helper; otherwise, the `Request` service is retrieved, and the value of its
+ `getBasePath()` method is used.
+
+ - If the `base_path_console` key is present, it is used to inject the
+ `BasePath` view helper for console requests; otherwise, the `Request`
+ service is retrieved, and the value of its `getBasePath()` method is used.
+ This can be useful for sending urls in emails via a cronjob.
+
+ - If the `doctype` key is present, it will be used to set the value of the
+ `Doctype` view helper.
+
+- `ViewTemplateMapResolver`, representing and aliased to
+ `Zend\View\Resolver\TemplateMapResolver`. If a `template_map` key is present,
+ it will be used to seed the template map.
+
+- `ViewTemplatePathStack`, representing and aliased to
+ `Zend\View\Resolver\TemplatePathStack`.
+
+ - If a `template_path_stack` key is present, it will be used to seed the
+ stack.
+
+ - If a `default_template_suffix` key is present, it will be used as the
+ default suffix for template scripts resolving.
+
+- `ViewResolver`, representing and aliased to `Zend\View\Resolver\AggregateResolver`
+ and `Zend\View\Resolver\ResolverInterface`. It is seeded with the
+ `ViewTemplateMapResolver` and `ViewTemplatePathStack` services as resolvers.
+
+- `ViewRenderer`, representing and aliased to `Zend\View\Renderer\PhpRenderer`
+ and `Zend\View\Renderer\RendererInterface`. It is seeded with the
+ `ViewResolver` and `ViewHelperManager` services. Additionally, the `ViewModel`
+ helper gets seeded with the `ViewModel` as its root (layout) model.
+
+- `ViewPhpRendererStrategy`, representing and aliased to
+ `Zend\View\Strategy\PhpRendererStrategy`. It gets seeded with the
+ `ViewRenderer` service.
+
+- `View`, representing and aliased to `Zend\View\View`. It gets seeded with the
+ `EventManager` service, and attaches the `ViewPhpRendererStrategy` as an
+ aggregate listener.
+
+- `DefaultRenderingStrategy`, representing and aliased to
+ `Zend\Mvc\View\DefaultRenderingStrategy`. If the `layout` key is present, it
+ is used to seed the strategy's layout template. It is seeded with the `View`
+ service.
+
+- `ExceptionStrategy`, representing and aliased to `Zend\Mvc\View\ExceptionStrategy`.
+ If the `display_exceptions` or `exception_template` keys are present, they are
+ used to configure the strategy.
+
+- `RouteNotFoundStrategy`, representing and aliased to `Zend\Mvc\View\RouteNotFoundStrategy`
+ and `404Strategy`. If the `display_not_found_reason` or `not_found_template`
+ keys are present, they are used to configure the strategy.
+
+- `ViewModel`. In this case, no service is registered; the `ViewModel` is
+ retrieved from the `MvcEvent` and injected with the layout template name.
+
+The `ViewManager` also creates several other listeners, but does not expose them
+as services; these include `Zend\Mvc\View\CreateViewModelListener`,
+`Zend\Mvc\View\InjectTemplateListener`, and `Zend\Mvc\View\InjectViewModelListener`.
+These, along with `RouteNotFoundStrategy`, `ExceptionStrategy`, and
+`DefaultRenderingStrategy` are attached as listeners either to the application
+`EventManager` instance or the `SharedEventManager` instance.
+
+Finally, if you have a `strategies` key in your configuration, the `ViewManager`
+will loop over these and attach them in order to the `View` service as
+listeners, at a priority of 100 (allowing them to execute before the
+`DefaultRenderingStrategy`).
+
+## Application Configuration Options
+
+The following options may be used to provide initial configuration for the
+`ServiceManager`, `ModuleManager`, and `Application` instances, allowing them to
+then find and aggregate the configuration used for the `Config` service, which
+is intended for configuring all other objects in the system. These configuration
+directives go to the `config/application.config.php` file.
+
+```php
+ [
+ ],
+
+ // These are various options for the listeners attached to the ModuleManager
+ 'module_listener_options' => [
+ // This should be an array of paths in which modules reside.
+ // If a string key is provided, the listener will consider that a module
+ // namespace, the value of that key the specific path to that module's
+ // Module class.
+ 'module_paths' => [
+ ],
+
+ // An array of paths from which to glob configuration files after
+ // modules are loaded. These effectively override configuration
+ // provided by modules themselves. Paths may use GLOB_BRACE notation.
+ 'config_glob_paths' => [
+ ],
+
+ // Whether or not to enable a configuration cache.
+ // If enabled, the merged configuration will be cached and used in
+ // subsequent requests.
+ 'config_cache_enabled' => $booleanValue,
+
+ // The key used to create the configuration cache file name.
+ 'config_cache_key' => $stringKey,
+
+ // Whether or not to enable a module class map cache.
+ // If enabled, creates a module class map cache which will be used
+ // by in future requests, to reduce the autoloading process.
+ 'module_map_cache_enabled' => $booleanValue,
+
+ // The key used to create the class map cache file name.
+ 'module_map_cache_key' => $stringKey,
+
+ // The path in which to cache merged configuration.
+ 'cache_dir' => $stringPath,
+
+ // Whether or not to enable modules dependency checking.
+ // Enabled by default, prevents usage of modules that depend on other modules
+ // that weren't loaded.
+ 'check_dependencies' => $booleanValue,
+ ],
+
+ // Used to create an own service manager. May contain one or more child arrays.
+ 'service_listener_options' => [
+ [
+ 'service_manager' => $stringServiceManagerName,
+ 'config_key' => $stringConfigKey,
+ 'interface' => $stringOptionalInterface,
+ 'method' => $stringRequiredMethodName,
+ ],
+ ]
+
+ // Initial configuration with which to seed the ServiceManager.
+ // Should be compatible with Zend\ServiceManager\Config.
+ 'service_manager' => [
+ ],
+];
+```
+
+For an example, see the
+[ZendSkeletonApplication configuration file](https://github.com/zendframework/ZendSkeletonApplication/blob/master/config/application.config.php).
+
+## Default Configuration Options
+
+The following options are available when using the default services configured
+by the `ServiceManagerConfig` and `ViewManager`.
+
+These configuration directives can go to the `config/autoload/{{,*.}global,{,*.}local}.php`
+files, or in the `module//config/module.config.php` configuration
+files. The merging of these configuration files is done by the `ModuleManager`.
+It first merges each module's `module.config.php` file, and then the files in
+`config/autoload` (first the `*.global.php` and then the `*.local.php` files).
+The order of the merge is relevant so you can override a module's configuration
+with your application configuration. If you have both a `config/autoload/my.global.config.php`
+and `config/autoload/my.local.config.php`, the local configuration file
+overrides the global configuration.
+
+> ### Do not commit local configuration
+>
+> Local configuration files are intended to keep sensitive information, such as
+> database credentials, and as such, it is highly recommended to keep these
+> local configuration files out of your VCS. The `ZendSkeletonApplication`'s
+> `config/autoload/.gitignore` file ignores `*.local.php` files by default.
+
+```php
+ [
+ // Map of controller "name" to class
+ // This should be used if you do not need to inject any dependencies
+ // in your controller
+ 'invokables' => [
+ ],
+
+ // Map of controller "name" to factory for creating controller instance
+ // You may provide either the class name of a factory, or a PHP callback.
+ 'factories' => [
+ ],
+ ],
+
+ // The following are used to configure controller plugin loader
+ // Should be compatible with Zend\ServiceManager\Config.
+ 'controller_plugins' => [
+ ],
+
+ // The following are used to configure view helper manager
+ // Should be compatible with Zend\ServiceManager\Config.
+ 'view_helpers' => [
+ ],
+
+ // The following is used to configure a Zend\Di\Di instance.
+ // The array should be in a format that Zend\Di\Config can understand.
+ 'di' => [
+ ],
+
+ // Configuration for the Router service
+ // Can contain any router configuration, but typically will always define
+ // the routes for the application. See the router documentation for details
+ // on route configuration.
+ 'router' => [
+ 'routes' => [
+ ],
+ ],
+
+ // ViewManager configuration
+ 'view_manager' => [
+ // Base URL path to the application
+ 'base_path' => $stringBasePath,
+
+ // Doctype with which to seed the Doctype helper
+ 'doctype' => $doctypeHelperConstantString, // e.g. HTML5, XHTML1
+
+ // TemplateMapResolver configuration
+ // template/path pairs
+ 'template_map' => [
+ ],
+
+ // TemplatePathStack configuration
+ // module/view script path pairs
+ 'template_path_stack' => [
+ ],
+ // Default suffix to use when resolving template scripts, if none, 'phtml' is used
+ 'default_template_suffix' => $templateSuffix, // e.g. 'php'
+
+ // Controller namespace to template map
+ // or whitelisting for controller FQCN to template mapping
+ 'controller_map' => [
+ ],
+
+ // Layout template name
+ 'layout' => $layoutTemplateName, // e.g. 'layout/layout'
+
+ // ExceptionStrategy configuration
+ 'display_exceptions' => $bool, // display exceptions in template
+ 'exception_template' => $stringTemplateName, // e.g. 'error'
+
+ // RouteNotFoundStrategy configuration
+ 'display_not_found_reason' => $bool, // display 404 reason in template
+ 'not_found_template' => $stringTemplateName, // e.g. '404'
+
+ // Additional strategies to attach
+ // These should be class names or service names of View strategy classes
+ // that act as ListenerAggregates. They will be attached at priority 100,
+ // in the order registered.
+ 'strategies' => [
+ 'ViewJsonStrategy', // register JSON renderer strategy
+ 'ViewFeedStrategy', // register Feed renderer strategy
+ ],
+ ],
+];
+```
+
+For an example, see the
+[Application module configuration file](https://github.com/zendframework/ZendSkeletonApplication/blob/master/module/Application/config/module.config.php)
+in the ZendSkeletonApplication.
diff --git a/doc/book/zend.mvc.controllers.md b/doc/book/zend.mvc.controllers.md
deleted file mode 100644
index 8e80a3f0d..000000000
--- a/doc/book/zend.mvc.controllers.md
+++ /dev/null
@@ -1,243 +0,0 @@
-# Available Controllers
-
-Controllers in the MVC layer simply need to be objects implementing
-`Zend\Stdlib\DispatchableInterface`. That interface describes a single method:
-
-```php
-use Zend\Stdlib\DispatchableInterface;
-use Zend\Stdlib\RequestInterface as Request;
-use Zend\Stdlib\ResponseInterface as Response;
-
-class Foo implements DispatchableInterface
-{
- public function dispatch(Request $request, Response $response = null)
- {
- // ... do something, and preferably return a Response ...
- }
-}
-```
-
-While this pattern is simple enough, chances are you don't want to implement custom dispatch logic
-for every controller (particularly as it's not unusual or uncommon for a single controller to handle
-several related types of requests).
-
-The MVC also defines several interfaces that, when implemented, can provide controllers with
-additional capabilities.
-
-## Common Interfaces Used With Controllers
-
-### InjectApplicationEvent
-
-The `Zend\Mvc\InjectApplicationEventInterface` hints to the `Application` instance that it should
-inject its `MvcEvent` into the controller itself. Why would this be useful?
-
-Recall that the `MvcEvent` composes a number of objects: the `Request` and `Response`, naturally,
-but also the router, the route matches (a `RouteMatch` instance), and potentially the "result" of
-dispatching.
-
-A controller that has the `MvcEvent` injected, then, can retrieve or inject these. As an example:
-
-```php
-$matches = $this->getEvent()->getRouteMatch();
-$id = $matches->getParam('id', false);
-if (!$id) {
- $response = $this->getResponse();
- $response->setStatusCode(500);
- $this->getEvent()->setResult('Invalid identifier; cannot complete request');
- return;
-}
-```
-
-The `InjectApplicationEventInterface` defines simply two methods:
-
-```php
-public function setEvent(Zend\EventManager\EventInterface $event);
-public function getEvent();
-```
-
-### ServiceLocatorAware
-
-In most cases, you should define your controllers such that dependencies are injected by the
-application's `ServiceManager`, via either constructor arguments or setter methods.
-
-However, occasionally you may have objects you wish to use in your controller that are only valid
-for certain code paths. Examples include forms, paginators, navigation, etc. In these cases, you may
-decide that it doesn't make sense to inject those objects every time the controller is used.
-
-The `ServiceLocatorAwareInterface` interface hints to the `ServiceManager` that it should inject
-itself into the controller. It defines two simple methods:
-
-```php
-use Zend\ServiceManager\ServiceLocatorInterface;
-use Zend\ServiceManager\ServiceLocatorAwareInterface;
-
-public function setServiceLocator(ServiceLocatorInterface $serviceLocator);
-public function getServiceLocator();
-```
-
-### EventManagerAware
-
-Typically, it's nice to be able to tie into a controller's workflow without needing to extend it or
-hardcode behavior into it. The solution for this at the framework level is to use the
-`EventManager`.
-
-You can hint to the `ServiceManager` that you want an `EventManager` injected by implementing the
-interface `EventManagerAwareInterface`, which tells the `ServiceManager` to inject an
-`EventManager`.
-
-You define two methods. The first, a setter, should also set any `EventManager` identifiers you want
-to listen on, and the second, a getter, should simply return the composed `EventManager` instance.
-
-```php
-use Zend\EventManager\EventManagerAwareInterface;
-use Zend\EventManager\EventManagerInterface;
-
-public function setEventManager(EventManagerInterface $events);
-public function getEventManager();
-```
-
-### Controller Plugins
-
-Code re-use is a common goal for developers. Another common goal is convenience. However, this is
-often difficult to achieve cleanly in abstract, general systems.
-
-Within your controllers, you'll often find yourself repeating tasks from one controller to another.
-Some common examples:
-
-- Generating URLs
-- Redirecting
-- Setting and retrieving flash messages (self-expiring session messages)
-- Invoking and dispatching additional controllers
-
-To facilitate these actions while also making them available to alternate controller
-implementations, we've created a `PluginManager` implementation for the controller layer,
-`Zend\Mvc\Controller\PluginManager`, building on the `Zend\ServiceManager\AbstractPluginManager`
-functionality. To utilize it, you simply need to implement the `setPluginManager(PluginManager
-$plugins)` method, and set up your code to use the controller-specific implementation by default:
-
-```php
-use Zend\Mvc\Controller\PluginManager;
-
-public function setPluginManager(PluginManager $plugins)
-{
- $this->plugins = $plugins;
- $this->plugins->setController($this);
-
- return $this;
-}
-
-public function getPluginManager()
-{
- if (!$this->plugins) {
- $this->setPluginManager(new PluginManager());
- }
-
- return $this->plugins;
-}
-
-public function plugin($name, array $options = null)
-{
- return $this->getPluginManager()->get($name, $options);
-}
-```
-
-## The AbstractActionController
-
-Implementing each of the above interfaces is a lesson in redundancy; you won't often want to do it.
-As such, we've developed two abstract, base controllers you can extend to get started.
-
-The first is `Zend\Mvc\Controller\AbstractActionController`. This controller implements each of the
-above interfaces, and uses the following assumptions:
-
-- An "action" parameter is expected in the `RouteMatch` object composed in the attached `MvcEvent`.
-If none is found, a `notFoundAction()` is invoked.
-- The "action" parameter is converted to a camelCased format and appended with the word "Action" to
-create a method name. As examples: "foo" maps to "fooAction", "foo-bar" or "foo.bar" or "foo\_bar"
-to "fooBarAction". The controller then checks to see if that method exists. If not, the
-`notFoundAction()` method is invoked; otherwise, the discovered method is called.
-- The results of executing the given action method are injected into the `MvcEvent`'s "result"
-property (via `setResult()`, and accessible via `getResult()`).
-
-Essentially, a route mapping to an `AbstractActionController` needs to return both "controller" and
-"action" keys in its matches.
-
-Creation of action controllers is then reasonably trivial:
-
-```php
-namespace Foo\Controller;
-
-use Zend\Mvc\Controller\AbstractActionController;
-
-class BarController extends AbstractActionController
-{
- public function bazAction()
- {
- return array('title' => __METHOD__);
- }
-
- public function batAction()
- {
- return array('title' => __METHOD__);
- }
-}
-```
-
-### Interfaces and Collaborators
-
-`AbstractActionController` implements each of the following interfaces:
-
-- `Zend\Stdlib\DispatchableInterface`
-- `Zend\Mvc\InjectApplicationEventInterface`
-- `Zend\ServiceManager\ServiceLocatorAwareInterface`
-- `Zend\EventManager\EventManagerAwareInterface`
-
-The composed `EventManager` will be configured to listen on the following contexts:
-
-- `Zend\Stdlib\DispatchableInterface`
-- `Zend\Mvc\Controller\AbstractActionController`
-- `Zend\Mvc\Controller\AbstractController`
-
-Additionally, if you extend the class, it will listen on the extending class's name.
-
-## The AbstractRestfulController
-
-The second abstract controller ZF2 provides is `Zend\Mvc\Controller\AbstractRestfulController`. This
-controller provides a native RESTful implementation that simply maps HTTP request methods to
-controller methods, using the following matrix:
-
-- **GET** maps to either `get()` or `getList()`, depending on whether or not an "id" parameter is
-found in the route matches. If one is, it is passed as an argument to `get()`; if not, `getList()`
-is invoked. In the former case, you should provide a representation of the given entity with that
-identification; in the latter, you should provide a list of entities.
-- **POST** maps to `create()`. That method expects a `$data` argument, usually the `$_POST`
-superglobal array. The data should be used to create a new entity, and the response should typically
-be an HTTP 201 response with the Location header indicating the URI of the newly created entity and
-the response body providing the representation.
-- **PUT** maps to `update()`, and requires that an "id" parameter exists in the route matches; that
-value is passed as an argument to the method. It should attempt to update the given entity, and, if
-successful, return either a 200 or 202 response status, as well as the representation of the entity.
-- **DELETE** maps to `delete()`, and requires that an "id" parameter exists in the route matches;
-that value is passed as an argument to the method. It should attempt to delete the given entity,
-and, if successful, return either a 200 or 204 response status.
-
-Additionally, you can map "action" methods to the `AbstractRestfulController`, just as you would in
-the `AbstractActionController`; these methods will be suffixed with "Action", differentiating them
-from the RESTful methods listed above. This allows you to perform such actions as providing forms
-used to submit to the various RESTful methods, or to add RPC methods to your RESTful API.
-
-### Interfaces and Collaborators
-
-`AbstractRestfulController` implements each of the following interfaces:
-
-- `Zend\Stdlib\DispatchableInterface`
-- `Zend\Mvc\InjectApplicationEventInterface`
-- `Zend\ServiceManager\ServiceLocatorAwareInterface`
-- `Zend\EventManager\EventManagerAwareInterface`
-
-The composed `EventManager` will be configured to listen on the following contexts:
-
-- `Zend\Stdlib\DispatchableInterface`
-- `Zend\Mvc\Controller\AbstractRestfulController`
-- `Zend\Mvc\Controller\AbstractController`
-
-Additionally, if you extend the class, it will listen on the extending class's name.
diff --git a/doc/book/zend.mvc.examples.md b/doc/book/zend.mvc.examples.md
deleted file mode 100644
index 52837742c..000000000
--- a/doc/book/zend.mvc.examples.md
+++ /dev/null
@@ -1,111 +0,0 @@
-# Examples
-
-## Controllers
-
-### Accessing the Request and Response
-
-When using `AbstractActionController` or `AbstractRestfulController`, the request and response
-object are composed directly into the controller as soon as `dispatch()` is called. You may access
-them in the following ways:
-
-```php
-// Using explicit accessor methods
-$request = $this->getRequest();
-$response = $this->getResponse();
-
-// Using direct property access
-$request = $this->request;
-$response = $this->response;
-```
-
-Additionally, if your controller implements `InjectApplicationEventInterface` (as both
-`AbstractActionController` and `AbstractRestfulController` do), you can access these objects from
-the attached `MvcEvent`:
-
-```php
-$event = $this->getEvent();
-$request = $event->getRequest();
-$response = $event->getResponse();
-```
-
-The above can be useful when composing event listeners into your controller.
-
-### Accessing routing parameters
-
-The parameters returned when routing completes are wrapped in a `Zend\Mvc\Router\RouteMatch` object.
-This object is detailed in the section on \[Routing\](zend.mvc.routing).
-
-Within your controller, if you implement `InjectApplicationEventInterface` (as both
-`AbstractActionController` and `AbstractRestfulController` do), you can access this object from the
-attached `MvcEvent`:
-
-```php
-$event = $this->getEvent();
-$matches = $event->getRouteMatch();
-```
-
-Once you have the `RouteMatch` object, you can pull parameters from it.
-
-The same can be done using the Params plugin<zend.mvc.controller-plugins.params>.
-
-### Returning early
-
-You can effectively short-circuit execution of the application at any point by returning a
-`Response` from your controller or any event. When such a value is discovered, it halts further
-execution of the event manager, bubbling up to the `Application` instance, where it is immediately
-returned.
-
-As an example, the `Redirect` plugin returns a `Response`, which can be returned immediately so as
-to complete the request as quickly as possible. Other use cases might be for returning JSON or XML
-results from web service endpoints, returning "401 Unauthorized" results, etc.
-
-## Bootstrapping
-
-### Registering module-specific listeners
-
-Often you may want module-specific listeners. As an example, this would be a simple and effective
-way to introduce authorization, logging, or caching into your application.
-
-Each `Module` class can have an optional `onBootstrap()` method. Typically, you'll do
-module-specific configuration here, or setup event listeners for you module here. The
-`onBootstrap()` method is called for **every** module on **every** page request and should **only**
-be used for performing **lightweight** tasks such as registering event listeners.
-
-The base `Application` class shipped with the framework has an `EventManager` associated with it,
-and once the modules are initialized, it triggers the \[bootstrap\](zend.mvc.mvc-event.bootstrap)
-event, with a `getApplication()` method on the event.
-
-So, one way to accomplish module-specific listeners is to listen to that event, and register
-listeners at that time. As an example:
-
-```php
-namespace SomeCustomModule;
-
-class Module
-{
- /**
- * @param \Zend\Mvc\MvcEvent $e The MvcEvent instance
- * @return void
- */
- public function onBootstrap($e)
- {
- $application = $e->getApplication();
- $config = $application->getConfig();
- $view = $application->getServiceManager()->get('ViewHelperManager');
- // You must have these keys in you application config
- $view->headTitle($config['view']['base_title']);
-
- // This is your custom listener
- $listener = new Listeners\ViewListener();
- $listener->setView($view);
- $application->getEventManager()->attachAggregate($listener);
- }
-}
-```
-
-The above demonstrates several things. First, it demonstrates a listener on the application's
-\[bootstrap\](zend.mvc.mvc-event.bootstrap) event (the `onBootstrap()` method). Second, it
-demonstrates that listener, and how it can be used to register listeners with the application. It
-grabs the `Application` instance; from the `Application`, it is able to grab the attached service
-manager and configuration. These are then used to retrieve the view, configure some helpers, and
-then register a listener aggregate with the application event manager.
diff --git a/doc/book/zend.mvc.intro.md b/doc/book/zend.mvc.intro.md
deleted file mode 100644
index a3e260131..000000000
--- a/doc/book/zend.mvc.intro.md
+++ /dev/null
@@ -1,349 +0,0 @@
-# Introduction to the MVC Layer
-
-`Zend\Mvc` is a brand new MVC implementation designed from the ground up for Zend Framework 2,
-focusing on performance and flexibility.
-
-The MVC layer is built on top of the following components:
-
-- `Zend\ServiceManager` - Zend Framework provides a set of default service definitions set up at
-`Zend\Mvc\Service`. The `ServiceManager` creates and configures your application instance and
-workflow.
-- `Zend\EventManager` - The MVC is event driven. This component is used everywhere from initial
-bootstrapping of the application, through returning response and request calls, to setting and
-retrieving routes and matched routes, as well as render views.
-- `Zend\Http` - specifically the request and response objects, used within:
-- `Zend\Stdlib\DispatchableInterface`. All "controllers" are simply dispatchable objects.
-
-Within the MVC layer, several sub-components are exposed:
-
-- `Zend\Mvc\Router` contains classes pertaining to routing a request. In other words, it matches the
-request to its respective controller (or dispatchable).
-- `Zend\Http\PhpEnvironment` provides a set of decorators for the HTTP `Request` and `Response`
-objects that ensure the request is injected with the current environment (including query
-parameters, POST parameters, HTTP headers, etc.)
-- `Zend\Mvc\Controller`, a set of abstract "controller" classes with basic responsibilities such as
-event wiring, action dispatching, etc.
-- `Zend\Mvc\Service` provides a set of `ServiceManager` factories and definitions for the default
-application workflow.
-- `Zend\Mvc\View` provides default wiring for renderer selection, view script resolution, helper
-registration, and more; additionally, it provides a number of listeners that tie into the MVC
-workflow, providing features such as automated template name resolution, automated view model
-creation and injection, and more.
-
-The gateway to the MVC is the
-[Zend\\Mvc\\Application](https://github.com/zendframework/zf2/blob/master/library/Zend/Mvc/Application.php)
-object (referred to as `Application` henceforth). Its primary responsibilities are to **bootstrap**
-resources, **route** the request, and to retrieve and **dispatch** the controller matched during
-routing. Once accomplished, it will **render** the view, and **finish** the request, returning and
-sending the response.
-
-## Basic Application Structure
-
-The basic application structure follows:
-
- application_root/
- config/
- application.config.php
- autoload/
- global.php
- local.php
- // etc.
- data/
- module/
- vendor/
- public/
- .htaccess
- index.php
- init_autoloader.php
-
-The `public/index.php` marshalls all user requests to your website, retrieving an array of
-configuration located in `config/application.config.php`. On return, it `run()`s the `Application`,
-processing the request and returning a response to the user.
-
-The `config` directory as described above contains configuration used by the `Zend\ModuleManager` to
-load modules and merge configuration (e.g., database configuration and credentials); we will detail
-this more later.
-
-The `vendor` sub-directory should contain any third-party modules or libraries on which your
-application depends. This might include Zend Framework, custom libraries from your organization, or
-other third-party libraries from other projects. Libraries and modules placed in the `vendor`
-sub-directory should not be modified from their original, distributed state.
-
-Finally, the `module` directory will contain one or more modules delivering your application's
-functionality.
-
-Let's now turn to modules, as they are the basic units of a web application.
-
-## Basic Module Structure
-
-A module may contain anything: PHP code, including MVC functionality; library code; view scripts;
-and/or or public assets such as images, CSS, and JavaScript. The only requirement -- and even this
-is optional -- is that a module acts as a PHP namespace and that it contains a `Module.php` class
-under that namespace. This class is eventually consumed by `Zend\ModuleManager` to perform a number
-of tasks.
-
-The recommended module structure follows:
-
- module_root/
- Module.php
- autoload_classmap.php
- autoload_function.php
- autoload_register.php
- config/
- module.config.php
- public/
- images/
- css/
- js/
- src/
- /
-
- test/
- phpunit.xml
- bootstrap.php
- /
-
- view/
- /
- /
- <.phtml files>
-
-Since a module acts as a namespace, the module root directory should be that namespace. This
-namespace could also include a vendor prefix of sorts. As an example a module centered around "User"
-functionality delivered by Zend might be named "ZendUser", and this is also what the module root
-directory will be named.
-
-The `Module.php` file directly under the module root directory will be in the module namespace shown
-below.
-
-```php
-namespace ZendUser;
-
-class Module
-{
-}
-```
-
-When an `init()` method is defined, this method will be triggered by a `Zend\ModuleManager` listener
-when it loads the module class, and passed an instance of the manager by default. This allows you to
-perform tasks such as setting up module-specific event listeners. But be cautious, the `init()`
-method is called for **every** module on **every** page request and should **only** be used for
-performing **lightweight** tasks such as registering event listeners. Similarly, an `onBootstrap()`
-method (which accepts an `MvcEvent` instance) may be defined; it is also triggered for every page
-request, and should be used for lightweight tasks as well.
-
-The three `autoload_*.php` files are not required, but recommended. They provide the following:
-
-The point of these three files is to provide reasonable default mechanisms for autoloading the
-classes contained in the module, thus providing a trivial way to consume the module without
-requiring `Zend\ModuleManager` (e.g., for use outside a ZF2 application).
-
-The `config` directory should contain any module-specific configuration. These files may be in any
-format `Zend\Config` supports. We recommend naming the main configuration "module.format", and for
-PHP-based configuration, "module.config.php". Typically, you will create configuration for the
-router as well as for the dependency injector.
-
-The `src` directory should be a [PSR-0 compliant directory
-structure](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) with your
-module's source code. Typically, you should at least have one sub-directory named after your module
-namespace; however, you can ship code from multiple namespaces if desired.
-
-The `test` directory should contain your unit tests. Typically, these are written using
-[PHPUnit](http://phpunit.de), and contain artifacts related to its configuration (e.g.,
-`phpunit.xml`, `bootstrap.php`).
-
-The `public` directory can be used for assets that you may want to expose in your application's
-document root. These might include images, CSS files, JavaScript files, etc. How these are exposed
-is left to the developer.
-
-The `view` directory contains view scripts related to your controllers.
-
-## Bootstrapping an Application
-
-The `Application` has six basic dependencies.
-
-- **configuration**, usually an array or object implementing `Traversable`.
-- **ServiceManager** instance.
-- **EventManager** instance, which, by default, is pulled from the `ServiceManager`, by the service
-name "EventManager".
-- **ModuleManager** instance, which, by default, is pulled from the `ServiceManager`, by the service
-name "ModuleManager".
-- **Request** instance, which, by default, is pulled from the `ServiceManager`, by the service name
-"Request".
-- **Response** instance, which, by default, is pulled from the `ServiceManager`, by the service name
-"Response".
-
-These may be satisfied at instantiation:
-
-```php
-use Zend\EventManager\EventManager;
-use Zend\Http\PhpEnvironment;
-use Zend\ModuleManager\ModuleManager;
-use Zend\Mvc\Application;
-use Zend\ServiceManager\ServiceManager;
-
-$config = include 'config/application.config.php';
-
-$serviceManager = new ServiceManager();
-$serviceManager->setService('EventManager', new EventManager());
-$serviceManager->setService('ModuleManager', new ModuleManager($config));
-$serviceManager->setService('Request', new PhpEnvironment\Request());
-$serviceManager->setService('Response', new PhpEnvironment\Response());
-
-$application = new Application($config, $serviceManager);
-```
-
-Once you've done this, there are two additional actions you can take. The first is to "bootstrap"
-the application. In the default implementation, this does the following:
-
-- Attaches the default route listener (`Zend\Mvc\RouteListener`).
-- Attaches the default dispatch listener (`Zend\Mvc\DispatchListener`).
-- Attaches the `ViewManager` listener (`Zend\Mvc\View\ViewManager`).
-- Creates the `MvcEvent`, and injects it with the application, request, and response; it also
-retrieves the router (`Zend\Mvc\Router\Http\TreeRouteStack`) at this time and attaches it to the
-event.
-- Triggers the "bootstrap" event.
-
-If you do not want these actions, or want to provide alternatives, you can do so by extending the
-`Application` class and/or simply coding what actions you want to occur.
-
-The second action you can take with the configured `Application` is to `run()` it. Calling this
-method simply does the following: it triggers the "route" event, followed by the "dispatch" event,
-and, depending on execution, the "render" event; when done, it triggers the "finish" event, and then
-returns the response instance. If an error occurs during either the "route" or "dispatch" event, a
-"dispatch.error" event is triggered as well.
-
-This is a lot to remember in order to bootstrap the application; in fact, we haven't covered all the
-services available by default yet. You can greatly simplify things by using the default
-`ServiceManager` configuration shipped with the MVC.
-
-```php
-use Zend\Loader\AutoloaderFactory;
-use Zend\Mvc\Service\ServiceManagerConfig;
-use Zend\ServiceManager\ServiceManager;
-
-// setup autoloader
-AutoloaderFactory::factory();
-
-// get application stack configuration
-$configuration = include 'config/application.config.php';
-
-// setup service manager
-$serviceManager = new ServiceManager(new ServiceManagerConfig());
-$serviceManager->setService('ApplicationConfig', $configuration);
-
-// load modules -- which will provide services, configuration, and more
-$serviceManager->get('ModuleManager')->loadModules();
-
-// bootstrap and run application
-$application = $serviceManager->get('Application');
-$application->bootstrap();
-$application->run();
-```
-
-You can make this even simpler by using the `init()` method of the `Application`. This is a static
-method for quick and easy initialization of the Application.
-
-```php
-use Zend\Loader\AutoloaderFactory;
-use Zend\Mvc\Application;
-use Zend\Mvc\Service\ServiceManagerConfig;
-use Zend\ServiceManager\ServiceManager;
-
-// setup autoloader
-AutoloaderFactory::factory();
-
-// get application stack configuration
-$configuration = include 'config/application.config.php';
-
-// The init() method does something very similar with the previous example.
-Application::init($configuration)->run();
-```
-
-The `init()` method will basically do the following:
-- Grabs the application configuration and pulls from the `service_manager` key, creating a
-`ServiceManager`
- instance with it and with the default services shipped with `Zend\Mvc`;
-
-- Create a service named `ApplicationConfig` with the application configuration array;
-- Grabs the `ModuleManager` service and load the modules;
-- `bootstrap()`s the `Application` and returns its instance;
-
-> ## Note
-If you use the `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.
-
-You'll note that you have a great amount of control over the workflow. Using the `ServiceManager`,
-you have fine-grained control over what services are available, how they are instantiated, and what
-dependencies are injected into them. Using the `EventManager`'s priority system, you can intercept
-any of the application events ("bootstrap", "route", "dispatch", "dispatch.error", "render", and
-"finish") anywhere during execution, allowing you to craft your own application workflows as needed.
-
-## Bootstrapping a Modular Application
-
-While the previous approach largely works, where does the configuration come from? When we create a
-modular application, the assumption will be that it's from the modules themselves. How do we get
-that information and aggregate it, then?
-
-The answer is via `Zend\ModuleManager\ModuleManager`. This component allows you to specify where
-modules exist. Then, it will locate each module and initialize it. Module classes can tie into
-various listeners on the `ModuleManager` in order to provide configuration, services, listeners, and
-more to the application. Sounds complicated? It's not.
-
-### Configuring the Module Manager
-
-The first step is configuring the module manager. Simply inform the module manager which modules to
-load, and potentially provide configuration for the module listeners.
-
-Remember the `application.config.php` from earlier? We're going to provide some configuration.
-
-```php
- array(
- /* ... */
- ),
- 'module_listener_options' => array(
- 'module_paths' => array(
- './module',
- './vendor',
- ),
- ),
-);
-```
-
-As we add modules to the system, we'll add items to the `modules` array.
-
-Each `Module` class that has configuration it wants the `Application` to know about should define a
-`getConfig()` method. That method should return an array or `Traversable` object such as
-`Zend\Config\Config`. As an example:
-
-```php
-namespace ZendUser;
-
-class Module
-{
- public function getConfig()
- {
- return include __DIR__ . '/config/module.config.php'
- }
-}
-```
-
-There are a number of other methods you can define for tasks ranging from providing autoloader
-configuration, to providing services to the `ServiceManager`, to listening to the bootstrap event.
-The ModuleManager
-documentation <zend.module-manager.intro> goes into more detail on these.
-
-## Conclusion
-
-The ZF2 MVC layer is incredibly flexible, offering an opt-in, easy to create modular infrastructure,
-as well as the ability to craft your own application workflows via the `ServiceManager` and
-`EventManager`. The `ModuleManager` is a lightweight and simple approach to enforcing a modular
-architecture that encourages clean separation of concerns and code re-use.
diff --git a/doc/book/zend.mvc.mvc-event.md b/doc/book/zend.mvc.mvc-event.md
deleted file mode 100644
index cae39559e..000000000
--- a/doc/book/zend.mvc.mvc-event.md
+++ /dev/null
@@ -1,170 +0,0 @@
-# The MvcEvent
-
-The MVC layer of Zend Framework 2 incorporates and utilizes a custom `Zend\EventManager\Event`
-implementation -`Zend\Mvc\MvcEvent`. This event is created during
-`Zend\Mvc\Application::bootstrap()` and is passed directly to all the events that method triggers.
-Additionally, if your controllers implement the `Zend\Mvc\InjectApplicationEventInterface`,
-`MvcEvent` will be injected into those controllers.
-
-The `MvcEvent` adds accessors and mutators for the following:
-
-- `Application` object.
-- `Request` object.
-- `Response` object.
-- `Router` object.
-- `RouteMatch` object.
-- Result - usually the result of dispatching a controller.
-- `ViewModel` object, typically representing the layout view model.
-
-The methods it defines are:
-
-- `setApplication($application)`
-- `getApplication()`
-- `setRequest($request)`
-- `getRequest()`
-- `setResponse($response)`
-- `getResponse()`
-- `setRouter($router)`
-- `getRouter()`
-- `setRouteMatch($routeMatch)`
-- `getRouteMatch()`
-- `setResult($result)`
-- `getResult()`
-- `setViewModel($viewModel)`
-- `getViewModel()`
-- `isError()`
-- `setError()`
-- `getError()`
-- `getController()`
-- `setController($name)`
-- `getControllerClass()`
-- `setControllerClass($class)`
-
-The `Application`, `Request`, `Response`, `Router`, and `ViewModel` are all injected during the
-`bootstrap` event. Following the `route` event, it will be injected also with the `RouteMatch`
-object encapsulating the results of routing.
-
-Since this object is passed around throughout the MVC, it is a common location for retrieving the
-results of routing, the router, and the request and response objects. Additionally, we encourage
-setting the results of execution in the event, to allow event listeners to introspect them and
-utilize them within their execution. As an example, the results could be passed into a view
-renderer.
-
-## Order of events
-
-The following events are triggered, in the following order:
-
-Those events are extensively describe in the following sections.
-
-## MvcEvent::EVENT\_BOOTSTRAP
-
-### Listeners
-
-The following classes are listening to this event (they are sorted from higher priority to lower
-priority):
-
-### Triggerers
-
-This event is triggered by the following classes:
-
-## MvcEvent::EVENT\_ROUTE
-
-### Listeners
-
-The following classes are listening to this event (they are sorted from higher priority to lower
-priority):
-
-### Triggerers
-
-This event is triggered by the following classes:
-
-## MvcEvent::EVENT\_DISPATCH
-
-### Listeners
-
-The following classes are listening to this event (they are sorted from higher priority to lower
-priority):
-
-#### Console context only
-
-Those listeners are only attached in a Console context:
-
-#### Http context only
-
-Those listeners are only attached in a Http context:
-
-#### All contexts
-
-Those listeners are attached for both contexts:
-
-### Triggerers
-
-This event is triggered by the following classes:
-
-## MvcEvent::EVENT\_DISPATCH\_ERROR
-
-### Listeners
-
-The following classes are listening to this event (they are sorted from higher priority to lower
-priority):
-
-#### Console context only
-
-#### Http context only
-
-Those listeners are only attached in a Http context:
-
-#### All contexts
-
-Those listeners are attached for both contexts:
-
-### Triggerers
-
-## MvcEvent::EVENT\_RENDER
-
-### Listeners
-
-The following classes are listening to this event (they are sorted from higher priority to lower
-priority):
-
-#### Console context only
-
-Those listeners are only attached in a Console context:
-
-#### Http context only
-
-Those listeners are only attached in a Http context:
-
-### Triggerers
-
-This event is triggered by the following classes:
-
-## MvcEvent::EVENT\_RENDER\_ERROR
-
-### Listeners
-
-The following classes are listening to this event (they are sorted from higher priority to lower
-priority):
-
-#### Console context only
-
-Those listeners are only attached in a Console context:
-
-#### Http context only
-
-Those listeners are only attached in a Http context:
-
-### Triggerers
-
-This event is triggered by the following classes:
-
-## MvcEvent::EVENT\_FINISH
-
-### Listeners
-
-The following classes are listening to this event (they are sorted from higher priority to lower
-priority):
-
-### Triggerers
-
-This event is triggered by the following classes:
diff --git a/doc/book/zend.mvc.plugins.md b/doc/book/zend.mvc.plugins.md
deleted file mode 100644
index 1c4fb229a..000000000
--- a/doc/book/zend.mvc.plugins.md
+++ /dev/null
@@ -1,545 +0,0 @@
-# Controller Plugins
-
-When using the `AbstractActionController` or `AbstractRestfulController`, or if you implement the
-`setPluginManager` method in your custom controllers, you have access to a number of pre-built
-plugins. Additionally, you can register your own custom plugins with the manager.
-
-The built-in plugins are:
-
--
-\[Zend\\Mvc\\Controller\\Plugin\\AcceptableViewModelSelector\](zend.mvc.controller-plugins.acceptableviewmodelselector)
-- \[Zend\\Mvc\\Controller\\Plugin\\FlashMessenger\](zend.mvc.controller-plugins.flashmessenger)
-- \[Zend\\Mvc\\Controller\\Plugin\\Forward\](zend.mvc.controller-plugins.forward)
-- \[Zend\\Mvc\\Controller\\Plugin\\Identity\](zend.mvc.controller-plugins.identity)
-- \[Zend\\Mvc\\Controller\\Plugin\\Layout\](zend.mvc.controller-plugins.layout)
-- \[Zend\\Mvc\\Controller\\Plugin\\Params\](zend.mvc.controller-plugins.params)
-- \[Zend\\Mvc\\Controller\\Plugin\\PostRedirectGet\](zend.mvc.controller-plugins.postredirectget)
-- \[Zend\\Mvc\\Controller\\Plugin\\Redirect\](zend.mvc.controller-plugins.redirect)
-- \[Zend\\Mvc\\Controller\\Plugin\\Url\](zend.mvc.controller-plugins.url)
-
-If your controller implements the `setPluginManager`, `getPluginManager` and `plugin` methods, you
-can access these using their shortname via the `plugin()` method:
-
-```php
-$plugin = $this->plugin('url');
-```
-
-For an extra layer of convenience, both `AbstractActionController` and `AbstractRestfulController`
-have `__call()` implementations that allow you to retrieve plugins via method calls:
-
-```php
-$plugin = $this->url();
-```
-
-## AcceptableViewModelSelector Plugin
-
-The `AcceptableViewModelSelector` is a helper that can be used to select an appropriate view model
-based on user defined criteria will be tested against the Accept header in the request.
-
-As an example:
-
-```php
-use Zend\Mvc\Controller\AbstractActionController;
-use Zend\View\Model\JsonModel;
-
-class SomeController extends AbstractActionController
-{
- protected $acceptCriteria = array(
- 'Zend\View\Model\JsonModel' => array(
- 'application/json',
- ),
- 'Zend\View\Model\FeedModel' => array(
- 'application/rss+xml',
- ),
- );
-
- public function apiAction()
- {
- $viewModel = $this->acceptableViewModelSelector($this->acceptCriteria);
-
- // Potentially vary execution based on model returned
- if ($viewModel instanceof JsonModel) {
- // ...
- }
- }
-}
-```
-
-The above would return a standard `Zend\View\Model\ViewModel` instance if the criteria is not met,
-and the specified view model types if the specific criteria is met. Rules are matched in order, with
-the first match "winning."
-
-## FlashMessenger Plugin
-
-The `FlashMessenger` is a plugin designed to create and retrieve self-expiring, session-based
-messages. It exposes a number of methods:
-
-setSessionManager(Zend\\Session\\ManagerInterface $manager)
-
-> Allows you to specify an alternate session manager, if desired.
-rtype
-`Zend\Mvc\Controller\Plugin\FlashMessenger`
-getSessionManager()
-
-> Allows you to retrieve the session manager registered.
-rtype
-`Zend\Session\ManagerInterface`
-getContainer()
-
-> Returns the `Zend\Session\Container` instance in which the flash messages are stored.
-rtype
-`Zend\Session\Container`
-setNamespace(string $namespace = 'default')
-
-> Allows you to specify a specific namespace in the container in which to store or from which to
-retrieve flash messages.
-rtype
-`Zend\Mvc\Controller\Plugin\FlashMessenger`
-- `getNamespace()` retrieves the name of the flash message namespace.
-
-getNamespace()
-
-> Retrieves the name of the flash message namespace.
-rtype
-`string`
-addMessage(string $message)
-
-> Allows you to add a message to the current namespace of the session container.
-rtype
-`Zend\Mvc\Controller\Plugin\FlashMessenger`
-hasMessages()
-
-> Lets you determine if there are any flash messages from the current namespace in the session
-container.
-rtype
-`boolean`
-getMessages()
-
-> Retrieves the flash messages from the current namespace of the session container
-rtype
-`array`
-clearMessages()
-
-> Clears all flash messages in current namespace of the session container. Returns `true` if
-messages were cleared, `false` if none existed.
-rtype
-`boolean`
-hasCurrentMessages()
-
-> Indicates whether any messages were added during the current request.
-rtype
-`boolean`
-getCurrentMessages()
-
-> Retrieves any messages added during the current request.
-rtype
-`array`
-clearCurrentMessages()
-
-> Removes any messages added during the current request. Returns `true` if current messages were
-cleared, `false` if none existed.
-rtype
-`boolean`
-clearMessagesFromContainer()
-
-> Clear all messages from the container. Returns `true` if any messages were cleared, `false` if
-none existed.
-rtype
-`boolean`
-This plugin also provides four meaningful namespaces, namely: INFO, ERROR, WARNING, SUCCESS. The
-following functions are related to these namespaces:
-
-addInfoMessage()
-
-> Add a message to "info" namespace
-
-> rtype
-`Zend\Mvc\Controller\Plugin\FlashMessenger`
-hasCurrentInfoMessages()
-
-> Check to see if messages have been added to "info" namespace within this request
-
-> rtype
-`boolean`
-addWarningMessage()
-
-> Add a message to "warning" namespace
-
-> rtype
-`Zend\Mvc\Controller\Plugin\FlashMessenger`
-hasCurrentWarningMessages()
-
-> Check to see if messages have been added to "warning" namespace within this request
-
-> rtype
-`boolean`
-addErrorMessage()
-
-> Add a message to "error" namespace
-
-> rtype
-`Zend\Mvc\Controller\Plugin\FlashMessenger`
-hasCurrentErrorMessages()
-
-> Check to see if messages have been added to "error" namespace within this request
-
-> rtype
-`boolean`
-addSuccessMessage()
-
-> Add a message to "success" namespace
-
-> rtype
-`Zend\Mvc\Controller\Plugin\FlashMessenger`
-hasCurrentSuccessMessages()
-
-> Check to see if messages have been added to "success" namespace within this request
-
-> rtype
-`boolean`
-Additionally, the `FlashMessenger` implements both `IteratorAggregate` and `Countable`, allowing you
-to iterate over and count the flash messages in the current namespace within the session container.
-
-**Examples**
-
-```php
-public function processAction()
-{
- // ... do some work ...
- $this->flashMessenger()->addMessage('You are now logged in.');
- return $this->redirect()->toRoute('user-success');
-}
-
-public function successAction()
-{
- $return = array('success' => true);
- $flashMessenger = $this->flashMessenger();
- if ($flashMessenger->hasMessages()) {
- $return['messages'] = $flashMessenger->getMessages();
- }
- return $return;
-}
-```
-
-## Forward Plugin
-
-Occasionally, you may want to dispatch additional controllers from within the matched controller --
-for instance, you might use this approach to build up "widgetized" content. The `Forward` plugin
-helps enable this.
-
-For the `Forward` plugin to work, the controller calling it must be `ServiceLocatorAware`;
-otherwise, the plugin will be unable to retrieve a configured and injected instance of the requested
-controller.
-
-The plugin exposes a single method, `dispatch()`, which takes two arguments:
-
-- `$name`, the name of the controller to invoke. This may be either the fully qualified class name,
-or an alias defined and recognized by the `ServiceManager` instance attached to the invoking
-controller.
-- `$params` is an optional array of parameters with which to seed a `RouteMatch` object for purposes
-of this specific request. Meaning the parameters will be matched by their key to the routing
-identifiers in the config (otherwise non-matching keys are ignored)
-
-`Forward` returns the results of dispatching the requested controller; it is up to the developer to
-determine what, if anything, to do with those results. One recommendation is to aggregate them in
-any return value from the invoking controller.
-
-As an example:
-
-```php
-$foo = $this->forward()->dispatch('foo', array('action' => 'process'));
-return array(
- 'somekey' => $somevalue,
- 'foo' => $foo,
-);
-```
-
-## Identity Plugin
-
-The `Identity` plugin allows for getting the identity from the `AuthenticationService`.
-
-For the `Identity` plugin to work, a `Zend\Authentication\AuthenticationService` name or alias must
-be defined and recognized by the `ServiceManager`.
-
-`Identity` returns the identity in the `AuthenticationService` or null if no identity is available.
-
-As an example:
-
-```php
-public function testAction()
-{
- if ($user = $this->identity()) {
- // someone is logged !
- } else {
- // not logged in
- }
-}
-```
-
-When invoked, the `Identity` plugin will look for a service by the name or alias
-`Zend\Authentication\AuthenticationService` in the `ServiceManager`. You can provide this service to
-the `ServiceManager` in a configuration file:
-
-```php
-// In a configuration file...
-return array(
- 'service_manager' => array(
- 'aliases' => array(
- 'Zend\Authentication\AuthenticationService' => 'my_auth_service',
- ),
- 'invokables' => array(
- 'my_auth_service' => 'Zend\Authentication\AuthenticationService',
- ),
- ),
-);
-```
-
-The `Identity` plugin exposes two methods:
-
-setAuthenticationService(Zend\\Authentication\\AuthenticationService $authenticationService)
-
-> Sets the authentication service instance to be used by the plugin.
-rtype
-`void`
-getAuthenticationService()
-
-> Retrieves the current authentication service instance if any is attached.
-rtype
-`Zend\Authentication\AuthenticationService`
-## Layout Plugin
-
-The `Layout` plugin allows for changing layout templates from within controller actions.
-
-It exposes a single method, `setTemplate()`, which takes one argument:
-
-- `$template`, the name of the template to set.
-
-As an example:
-
-```php
-$this->layout()->setTemplate('layout/newlayout');
-```
-
-It also implements the `__invoke` magic method, which allows for even easier setting of the
-template:
-
-```php
-$this->layout('layout/newlayout');
-```
-
-## Params Plugin
-
-The `Params` plugin allows for accessing parameters in actions from different sources.
-
-It exposes several methods, one for each parameter source:
-
-fromFiles(string $name = null, mixed $default = null)
-
-> For retrieving all or one single **file**. If `$name` is null, all files will be returned.
-rtype
-`array|ArrayAccess|null`
-fromHeader(string $header = null, mixed $default = null)
-
-> For retrieving all or one single **header** parameter. If `$header` is null, all header parameters
-will be returned.
-rtype
-`null|Zend\Http\Header\HeaderInterface`
-fromPost(string $param = null, mixed $default = null)
-
-> For retrieving all or one single **post** parameter. If `$param` is null, all post parameters will
-be returned.
-rtype
-`mixed`
-fromQuery(string $param = null, mixed $default = null)
-
-> For retrieving all or one single **query** parameter. If `$param` is null, all query parameters
-will be returned.
-rtype
-`mixed`
-fromRoute(string $param = null, mixed $default = null)
-
-> For retrieving all or one single **route** parameter. If `$param` is null, all route parameters
-will be returned.
-rtype
-`mixed`
-It also implements the `__invoke` magic method, which allows for short circuiting to the `fromRoute`
-method:
-
-```php
-$this->params()->fromRoute('param', $default);
-// or
-$this->params('param', $default);
-```
-
-## Post/Redirect/Get Plugin
-
-When a user sends a POST request (e.g. after submitting a form), their browser will try to protect
-them from sending the POST again, breaking the back button, causing browser warnings and pop-ups,
-and sometimes reposting the form. Instead, when receiving a POST, we should store the data in a
-session container and redirect the user to a GET request.
-
-This plugin can be invoked with two arguments:
-
-- `$redirect`, a string containing the redirect location which can either be a named route or a URL,
-based on the contents of the second parameter.
-- `$redirectToUrl`, a boolean that when set to TRUE, causes the first parameter to be treated as a
-URL instead of a route name (this is required when redirecting to a URL instead of a route). This
-argument defaults to false.
-
-When no arguments are provided, the current matched route is used.
-
-**Example Usage**
-
-```php
-// Pass in the route/url you want to redirect to after the POST
-$prg = $this->prg('/user/register', true);
-
-if ($prg instanceof \Zend\Http\PhpEnvironment\Response) {
- // returned a response to redirect us
- return $prg;
-} elseif ($prg === false) {
- // this wasn't a POST request, but there were no params in the flash messenger
- // probably this is the first time the form was loaded
- return array('form' => $myForm);
-}
-
-// $prg is an array containing the POST params from the previous request
-$form->setData($prg);
-
-// ... your form processing code here
-```
-
-## File Post/Redirect/Get Plugin
-
-While similar to the standard \[Post/Redirect/Get
-Plugin\](zend.mvc.controller-plugins.postredirectget), the File PRG Plugin will work for forms with
-file inputs. The difference is in the behavior: The File PRG Plugin will interact directly with your
-form instance and the file inputs, rather than *only* returning the POST params from the previous
-request.
-
-By interacting directly with the form, the File PRG Plugin will turn off any file inputs' `required`
-flags for already uploaded files (for a partially valid form state), as well as run the file input
-filters to move the uploaded files into a new location (configured by the user).
-
-> ## Warning
-You **must** attach a Filter for moving the uploaded files to a new location, such as the
-\[RenameUpload Filter\](zend.filter.file.rename-upload), or else your files will be removed upon the
-redirect.
-
-This plugin can be invoked with three arguments:
-
-- `$form`: the form instance.
-- `$redirect`: (Optional) a string containing the redirect location which can either be a named
-route or a URL, based on the contents of the third parameter. If this argument is not provided, it
-will default to the current matched route.
-- `$redirectToUrl`: (Optional) a boolean that when set to TRUE, causes the second parameter to be
-treated as a URL instead of a route name (this is required when redirecting to a URL instead of a
-route). This argument defaults to false.
-
-**Example Usage**
-
-```php
-$myForm = new Zend\Form\Form('my-form');
-$myForm->add(array(
- 'type' => 'Zend\Form\Element\File',
- 'name' => 'file',
-));
-// NOTE: Without a filter to move the file,
-// our files will disappear between the requests
-$myForm->getInputFilter()->getFilterChain()->attach(
- new Zend\Filter\File\RenameUpload(array(
- 'target' => './data/tmpuploads/file',
- 'randomize' => true,
- ))
-);
-
-// Pass in the form and optional the route/url you want to redirect to after the POST
-$prg = $this->fileprg($myForm, '/user/profile-pic', true);
-
-if ($prg instanceof \Zend\Http\PhpEnvironment\Response) {
- // Returned a response to redirect us
- return $prg;
-} elseif ($prg === false) {
- // First time the form was loaded
- return array('form' => $myForm);
-}
-
-// Form was submitted.
-// $prg is now an array containing the POST params from the previous request,
-// but we don't have to apply it to the form since that has already been done.
-
-// Process the form
-if ($form->isValid()) {
- // ...Save the form...
- return $this->redirect()->toRoute('/user/profile-pic/success');
-} else {
- // Form not valid, but file uploads might be valid and uploaded
- $fileErrors = $form->get('file')->getMessages();
- if (empty($fileErrors)) {
- $tempFile = $form->get('file')->getValue();
- }
-}
-```
-
-## Redirect Plugin
-
-Redirections are quite common operations within applications. If done manually, you will need to do
-the following steps:
-
-- Assemble a url using the router
-- Create and inject a "Location" header into the `Response` object, pointing to the assembled URL
-- Set the status code of the `Response` object to one of the 3xx HTTP statuses.
-
-The `Redirect` plugin does this work for you. It offers three methods:
-
-toRoute(string $route = null, array $params = array(), array $options = array(), boolean
-$reuseMatchedParams = false)
-
-> Redirects to a named route, using the provided `$params` and `$options` to assembled the URL.
-rtype
-`Zend\Http\Response`
-toUrl(string $url)
-
-> Simply redirects to the given URL.
-rtype
-`Zend\Http\Response`
-refresh()
-
-> Refresh to current route
-rtype
-`Zend\Http\Response`
-In each case, the `Response` object is returned. If you return this immediately, you can effectively
-short-circuit execution of the request.
-
-> ## Note
-This plugin requires that the controller invoking it implements `InjectApplicationEventInterface`,
-and thus has an `MvcEvent` composed, as it retrieves the router from the event object.
-
-As an example:
-
-```php
-return $this->redirect()->toRoute('login-success');
-```
-
-## Url Plugin
-
-Often you may want to generate URLs from route definitions within your controllers -- in order to
-seed the view, generate headers, etc. While the `MvcEvent` object composes the router, doing so
-manually would require this workflow:
-
-```php
-$router = $this->getEvent()->getRouter();
-$url = $router->assemble($params, array('name' => 'route-name'));
-```
-
-The `Url` helper makes this slightly more convenient:
-
-```php
-$url = $this->url()->fromRoute('route-name', $params);
-```
-
-The `fromRoute()` method is the only public method defined, and has the following signature:
-
-> ## Note
-This plugin requires that the controller invoking it implements `InjectApplicationEventInterface`,
-and thus has an `MvcEvent` composed, as it retrieves the router from the event object.
diff --git a/doc/book/zend.mvc.quick-start.md b/doc/book/zend.mvc.quick-start.md
deleted file mode 100644
index b4aa2c32f..000000000
--- a/doc/book/zend.mvc.quick-start.md
+++ /dev/null
@@ -1,382 +0,0 @@
-# Quick Start
-
-Now that you have basic knowledge of applications, modules, and how they are each structured, we'll
-show you the easy way to get started.
-
-## Install the Zend Skeleton Application
-
-The easiest way to get started is to grab the sample application and module repositories. This can
-be done in the following ways.
-
-### Using Composer
-
-Simply clone the `ZendSkeletonApplication` repository:
-
-```php
-prompt> git clone git://github.com/zendframework/ZendSkeletonApplication.git my-application
-```
-
-Then run [Composer](http://getcomposer.org/)'s `install` command to install the ZF library and any
-other configured dependencies:
-
-```php
-prompt> php ./composer.phar install
-```
-
-### Using Git
-
-Simply clone the `ZendSkeletonApplication` repository, using the `--recursive` option, which will
-also grab ZF.
-
-```php
-prompt> git clone --recursive git://github.com/zendframework/ZendSkeletonApplication.git
-my-application
-```
-
-### Manual Installation
-
-- Download a tarball of the `ZendSkeletonApplication` repository:
-- Zip:
-- Tarball:
-- Deflate the archive you selected and rename the parent directory according to your project needs;
-we use "my-application" throughout this document.
-- Install Zend Framework, and either have its library on your PHP `include_path`, symlink the
-library into your project's "library", or install it directly into your application using Pyrus.
-
-## Create a New Module
-
-By default, one module is provided with the `ZendSkeletonApplication`, named "Application". It
-simply provides a controller to handle the "home" page of the application, the layout template, and
-templates for 404 and error pages.
-
-Typically, you will not need to touch this other than to provide an alternate entry page for your
-site and/or alternate error page.
-
-Additional functionality will be provided by creating new modules.
-
-To get you started with modules, we recommend using the `ZendSkeletonModule` as a base. Download it
-from here:
-
-- Zip:
-- Tarball:
-
-Deflate the package, and rename the directory "ZendSkeletonModule" to reflect the name of the new
-module you want to create; when done, move the module into your new project's `module/` directory.
-
-At this point, it's time to create some functionality.
-
-## Update the Module Class
-
-Let's update the module class. We'll want to make sure the namespace is correct, configuration is
-enabled and returned, and that we setup autoloading on initialization. Since we're actively working
-on this module, the class list will be in flux, we probably want to be pretty lenient in our
-autoloading approach, so let's keep it flexible by using the `StandardAutoloader`. Let's begin.
-
-First, let's have `autoload_classmap.php` return an empty array:
-
-```php
- array(
- 'template_path_stack' => array(
- '' => __DIR__ . '/../view'
- ),
- ),
-);
-```
-
-Fill in "module-name" with a lowercased, dash-separated version of your module name -- e.g.,
-"ZendUser" would become "zend-user".
-
-Next, edit the `Module.php` file to read as follows:
-
-```php
-namespace ;
-
-use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
-use Zend\ModuleManager\Feature\ConfigProviderInterface;
-
-class Module implements AutoloaderProviderInterface, ConfigProviderInterface
-{
- public function getAutoloaderConfig()
- {
- return array(
- 'Zend\Loader\ClassMapAutoloader' => array(
- __DIR__ . '/autoload_classmap.php',
- ),
- 'Zend\Loader\StandardAutoloader' => array(
- 'namespaces' => array(
- __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
- ),
- ),
- );
- }
-
- public function getConfig()
- {
- return include __DIR__ . '/config/module.config.php';
- }
-}
-```
-
-At this point, you now have your module configured properly. Let's create a controller!
-
-## Create a Controller
-
-Controllers are simply objects that implement `Zend\Stdlib\DispatchableInterface`. This means they
-need to implement a `dispatch()` method that takes minimally a `Request` object as an argument.
-
-In practice, though, this would mean writing logic to branch based on matched routing within every
-controller. As such, we've created two base controller classes for you to start with:
-
-- `Zend\Mvc\Controller\AbstractActionController` allows routes to match an "action". When matched, a
-method named after the action will be called by the controller. As an example, if you had a route
-that returned "foo" for the "action" key, the "fooAction" method would be invoked.
-- `Zend\Mvc\Controller\AbstractRestfulController` introspects the `Request` to determine what HTTP
-method was used, and calls a method according to that.
-- `GET` will call either the `getList()` method, or, if an "id" was matched during routing, the
-`get()` method (with that identifer value).
-- `POST` will call the `create()` method, passing in the `$_POST` values.
-- `PUT` expects an "id" to be matched during routing, and will call the `update()` method, passing
-in the identifier, and any data found in the raw post body.
-- `DELETE` expects an "id" to be matched during routing, and will call the `delete()` method.
-
-To get started, we'll simply create a "hello world"-style controller, with a single action. First,
-create the directory `src//Controller`, and then create the file `HelloController.php`
-inside it. Edit it in your favorite text editor or IDE, and insert the following contents:
-
-```php
-\Controller;
-
-use Zend\Mvc\Controller\AbstractActionController;
-use Zend\View\Model\ViewModel;
-
-class HelloController extends AbstractActionController
-{
- public function worldAction()
- {
- $message = $this->params()->fromQuery('message', 'foo');
- return new ViewModel(array('message' => $message));
- }
-}
-```
-
-So, what are we doing here?
-
-- We're creating an action controller.
-- We're defining an action, "world".
-- We're pulling a message from the query parameters (yes, this is a superbly bad idea in production!
-Always sanitize your inputs!).
-- We're returning a ViewModel with an array of values to be processed later.
-
-We return a `ViewModel`. The view layer will use this when rendering the view, pulling variables and
-the template name from it. By default, you can omit the template name, and it will resolve to
-"lowercase-controller-name/lowercase-action-name". However, you can override this to specify
-something different by calling `setTemplate()` on the `ViewModel` instance. Typically, templates
-will resolve to files with a ".phtml" suffix in your module's `view` directory.
-
-So, with that in mind, let's create a view script.
-
-## Create a View Script
-
-Create the directory `view//hello`. Inside that directory, create a file named
-`world.phtml`. Inside that, paste in the following:
-
-```php
-Greetings!
-
-You said "escapeHtml($message) ?>".
-```
-
-That's it. Save the file.
-
-> ## Note
-What is the method `escapeHtml()`? It's actually a \[view helper\](zend.view.helpers), and it's
-designed to help mitigate *XSS* attacks. Never trust user input; if you are at all uncertain about
-the source of a given variable in your view script, escape it using one of the \[provided escape
-view helper\](zend.view.helpers) depending on the type of data you have.
-
-## View scripts for module names with subnamespaces
-
-As per PSR-0, module should be named following this rule: `\\(\)*` Default
-controller class to template mapping does not work very well with those: it will remove
-subnamespace.
-
-To address that issue new mapping was introduced since 2.3.0. To maintain backwards compatibility
-that mapping is not enabled by default. To enable it, you need to add your module namespace to
-whitelist in your module config:
-
-```php
-'view_manager' => array(
- // Controller namespace to template map
- // or whitelisting for controller FQCN to template mapping
- 'controller_map' => array(
- '' => true,
- ),
-),
-```
-
-Now, create the directory `view///hello`. Inside that directory, create a file named
-`world.phtml`. Inside that, paste in the following:
-
-```php
-Greetings!
-
-You said "escapeHtml($message) ?>".
-```
-
-## Create a Route
-
-Now that we have a controller and a view script, we need to create a route to it.
-
-> ## Note
-`ZendSkeletonApplication` ships with a "default route" that will likely get you to this action. That
-route basically expects "/{module}/{controller}/{action}", which allows you to specify this:
-"/zend-user/hello/world". We're going to create a route here mainly for illustration purposes, as
-creating explicit routes is a recommended practice. The application will look for a
-`Zend\Mvc\Router\RouteStack` instance to setup routing. The default generated router is a
-`Zend\Mvc\Router\Http\TreeRouteStack`.
-To use the "default route" functionality, you will need to have the following route definition in
-your module. Replace <module-name> with the name of your module.
-```php
-// module.config.php
-return array(
-' ```php
-// module.config.php
-return array(
-'controllers' = array(
-'invokables' = array(
-' ## Note
-We inform the application about controllers we expect to have in the application. This is to prevent
-somebody requesting any service the `ServiceManager` knows about in an attempt to break the
-application. The dispatcher uses a special, scoped container that will only pull controllers that
-are specifically registered with it, either as invokable classes or via factories.
-
-Open your `config/module.config.php` file, and modify it to add to the "routes" and "controller"
-parameters so it reads as follows:
-
-```php
-return array(
- 'router' => array(
- 'routes' => array(
- '-hello-world' => array(
- 'type' => 'Literal',
- 'options' => array(
- 'route' => '/hello/world',
- 'defaults' => array(
- 'controller' => '\Controller\Hello',
- 'action' => 'world',
- ),
- ),
- ),
- ),
- ),
- 'controllers' => array(
- 'invokables' => array(
- '\Controller\Hello' => '\Controller\HelloController',
- ),
- ),
- // ... other configuration ...
-);
-```
-
-## Tell the Application About our Module
-
-One problem: we haven't told our application about our new module!
-
-By default, modules are not parsed unless we tell the module manager about them. As such, we need to
-notify the application about them.
-
-Remember the `config/application.config.php` file? Let's modify it to add our new module. Once done,
-it should read as follows:
-
-```php
- array(
- 'Application',
- '',
- ),
- 'module_listener_options' => array(
- 'module_paths' => array(
- './module',
- './vendor',
- ),
- ),
-);
-```
-
-Replace `` with the namespace of your module.
-
-## Test it Out!
-
-Now we can test things out! Create a new vhost pointing its document root to the `public` directory
-of your application, and fire it up in a browser. You should see the default homepage template of
-ZendSkeletonApplication.
-
-Now alter the location in your URL to append the path "/hello/world", and load the page. You should
-now get the following content:
-
-```php
-Greetings!
-
-You said "foo".
-```
-
-Now alter the location to append "?message=bar" and load the page. You should now get:
-
-```php
-Greetings!
-
-You said "bar".
-```
-
-Congratulations! You've created your first ZF2 MVC module!
diff --git a/doc/book/zend.mvc.routing.md b/doc/book/zend.mvc.routing.md
deleted file mode 100644
index 6af73646f..000000000
--- a/doc/book/zend.mvc.routing.md
+++ /dev/null
@@ -1,703 +0,0 @@
-# Routing
-
-Routing is the act of matching a request to a given controller.
-
-Typically, routing will examine the request URI, and attempt to match the URI path segment against
-provided constraints. If the constraints match, a set of "matches" are returned, one of which should
-be the controller name to execute. Routing can utilize other portions of the request URI or
-environment as well -- for example, the host or scheme, query parameters, headers, request method,
-and more.
-
-Routing has been written from the ground up for Zend Framework 2.0. Execution is quite similar, but
-the internal workings are more consistent, performant, and often simpler.
-
-> ## Note
-If you are a developer with knowledge of the routing system in Zend Framework 1.x, you should know
-that some of the old terminology does not apply in Zend Framework 2.x. In the new routing system we
-don't have a router as such, as every route can match and assemble URIs by themselves, which makes
-them routers, too.
-That said, in most cases the developer does not need to worry about this, because Zend Framework 2.x
-will take care of this "under the hood". The work of the router will be done by
-`Zend\Mvc\Router\SimpleRouteStack` or `Zend\Mvc\Router\Http\TreeRouteStack`.
-
-The base unit of routing is a `Route`:
-
-```php
-namespace Zend\Mvc\Router;
-
-use Zend\Stdlib\RequestInterface as Request;
-
-interface RouteInterface
-{
- public static function factory(array $options = array());
- public function match(Request $request);
- public function assemble(array $params = array(), array $options = array());
-}
-```
-
-A `Route` accepts a `Request`, and determines if it matches. If so, it returns a `RouteMatch`
-object:
-
-```php
-namespace Zend\Mvc\Router;
-
-class RouteMatch
-{
- public function __construct(array $params);
- public function setMatchedRouteName($name);
- public function getMatchedRouteName();
- public function setParam($name, $value);
- public function getParams();
- public function getParam($name, $default = null);
-}
-```
-
-Typically, when a `Route` matches, it will define one or more parameters. These are passed into the
-`RouteMatch`, and objects may query the `RouteMatch` for their values.
-
-```php
-$id = $routeMatch->getParam('id', false);
-if (!$id) {
- throw new Exception('Required identifier is missing!');
-}
-$entity = $resource->get($id);
-```
-
-Usually you will have multiple routes you wish to test against. In order to facilitate this, you
-will use a route aggregate, usually implementing `RouteStack`:
-
-```php
-namespace Zend\Mvc\Router;
-
-interface RouteStackInterface extends RouteInterface
-{
- public function addRoute($name, $route, $priority = null);
- public function addRoutes(array $routes);
- public function removeRoute($name);
- public function setRoutes(array $routes);
-}
-```
-
-Typically, routes should be queried in a LIFO order, and hence the reason behind the name
-`RouteStack`. Zend Framework provides two implementations of this interface, `SimpleRouteStack` and
-`TreeRouteStack`. In each, you register routes either one at a time using `addRoute()`, or in bulk
-using `addRoutes()`.
-
-```php
-// One at a time:
-$route = Literal::factory(array(
- 'route' => '/foo',
- 'defaults' => array(
- 'controller' => 'foo-index',
- 'action' => 'index',
- ),
-));
-$router->addRoute('foo', $route);
-
-// In bulk:
-$router->addRoutes(array(
- // using already instantiated routes:
- 'foo' => $route,
-
- // providing configuration to allow lazy-loading routes:
- 'bar' => array(
- 'type' => 'literal',
- 'options' => array(
- 'route' => '/bar',
- 'defaults' => array(
- 'controller' => 'bar-index',
- 'action' => 'index',
- ),
- ),
- ),
-));
-```
-
-## Router Types
-
-Two routers are provided, the `SimpleRouteStack` and `TreeRouteStack`. Each works with the above
-interface, but utilize slightly different options and execution paths. By default, the `Zend\Mvc`
-uses the `TreeRouteStack` as the router.
-
-### SimpleRouteStack
-
-This router simply takes individual routes that provide their full matching logic in one go, and
-loops through them in LIFO order until a match is found. As such, routes that will match most often
-should be registered last, and least common routes first. Additionally, you will need to ensure that
-routes that potentially overlap are registered such that the most specific match will match first
-(i.e., register later). Alternatively, you can set priorities by giving the priority as third
-parameter to the `addRoute()` method, specifying the priority in the route specifications or setting
-the priority property within a route instance before adding it to the route stack.
-
-### TreeRouteStack
-
-`Zend\Mvc\Router\Http\TreeRouteStack` provides the ability to register trees of routes, and will use
-a B-tree algorithm to match routes. As such, you register a single route with many children.
-
-A `TreeRouteStack` will consist of the following configuration:
-
-- A base "route", which describes the base match needed, the root of the tree.
-- An optional "route\_plugins", which is a configured `Zend\Mvc\Router\RoutePluginManager` that can
-lazy-load routes.
-- The option "may\_terminate", which hints to the router that no other segments will follow it.
-- An optional "child\_routes" array, which contains additional routes that stem from the base
-"route" (i.e., build from it). Each child route can itself be a `TreeRouteStack` if desired; in
-fact, the `Part` route works exactly this way.
-
-When a route matches against a `TreeRouteStack`, the matched parameters from each segment of the
-tree will be returned.
-
-A `TreeRouteStack` can be your sole route for your application, or describe particular path segments
-of the application.
-
-An example of a `TreeRouteStack` is provided in the documentation of the `Part` route.
-
-## HTTP Route Types
-
-Zend Framework 2.0 ships with the following HTTP route types.
-
-### Zend\\Mvc\\Router\\Http\\Hostname
-
-The `Hostname` route attempts to match the hostname registered in the request against specific
-criteria. Typically, this will be in one of the following forms:
-
-- "subdomain.domain.tld"
-- ":subdomain.domain.tld"
-
-In the above, the second route would return a "subdomain" key as part of the route match.
-
-For any given hostname segment, you may also provide a constraint. As an example, if the "subdomain"
-segment needed to match only if it started with "fw" and contained exactly 2 digits following, the
-following route would be needed:
-
-```php
-$route = Hostname::factory(array(
- 'route' => ':subdomain.domain.tld',
- 'constraints' => array(
- 'subdomain' => 'fw\d{2}',
- ),
-));
-```
-
-In the above example, only a "subdomain" key will be returned in the `RouteMatch`. If you wanted to
-also provide other information based on matching, or a default value to return for the subdomain,
-you need to also provide defaults.
-
-```php
-$route = Hostname::factory(array(
- 'route' => ':subdomain.domain.tld',
- 'constraints' => array(
- 'subdomain' => 'fw\d{2}',
- ),
- 'defaults' => array(
- 'type' => 'json',
- ),
-));
-```
-
-When matched, the above will return two keys in the `RouteMatch`, "subdomain" and "type".
-
-### Zend\\Mvc\\Router\\Http\\Literal
-
-The `Literal` route is for doing exact matching of the URI path. Configuration therefore is solely
-the path you want to match, and the "defaults", or parameters you want returned on a match.
-
-```php
-$route = Literal::factory(array(
- 'route' => '/foo',
- 'defaults' => array(
- 'controller' => 'Application\Controller\IndexController',
- 'action' => 'foo',
- ),
-));
-```
-
-The above route would match a path "/foo", and return the key "action" in the `RouteMatch`, with the
-value "foo".
-
-### Zend\\Mvc\\Router\\Http\\Method
-
-The `Method` route is used to match the http method or 'verb' specified in the request (See RFC 2616
-Sec. 5.1.1). It can optionally be configured to match against multiple methods by providing a
-comma-separated list of method tokens.
-
-```php
-$route = Method::factory(array(
- 'verb' => 'post,put',
- 'defaults' => array(
- 'controller' => 'Application\Controller\IndexController',
- 'action' => 'form-submit',
- ),
-));
-```
-
-The above route would match an http "POST" or "PUT" request and return a `RouteMatch` object
-containing a key "action" with a value of "form-submit".
-
-### Zend\\Mvc\\Router\\Http\\Part
-
-A `Part` route allows crafting a tree of possible routes based on segments of the URI path. It
-actually extends the `TreeRouteStack`.
-
-`Part` routes are difficult to describe, so we'll simply provide a sample one here.
-
-```php
-$route = Part::factory(array(
- 'route' => array(
- 'type' => 'literal',
- 'options' => array(
- 'route' => '/',
- 'defaults' => array(
- 'controller' => 'Application\Controller\IndexController',
- 'action' => 'index',
- ),
- ),
- ),
- 'route_plugins' => $routePlugins,
- 'may_terminate' => true,
- 'child_routes' => array(
- 'blog' => array(
- 'type' => 'literal',
- 'options' => array(
- 'route' => '/blog',
- 'defaults' => array(
- 'controller' => 'Application\Controller\BlogController',
- 'action' => 'index',
- ),
- ),
- 'may_terminate' => true,
- 'child_routes' => array(
- 'rss' => array(
- 'type' => 'literal',
- 'options' => array(
- 'route' => '/rss',
- 'defaults' => array(
- 'action' => 'rss',
- )
- ),
- 'may_terminate' => true,
- 'child_routes' => array(
- 'subrss' => array(
- 'type' => 'literal',
- 'options' => array(
- 'route' => '/sub',
- 'defaults' => array(
- 'action' => 'subrss',
- ),
- ),
- ),
- ),
- ),
- ),
- ),
- 'forum' => array(
- 'type' => 'literal',
- 'options' => array(
- 'route' => 'forum',
- 'defaults' => array(
- 'controller' => 'Application\Controller\ForumController',
- 'action' => 'index',
- ),
- ),
- ),
- ),
-));
-```
-
-The above would match the following:
-
-- "/" would load the "Index" controller, "index" action.
-- "/blog" would load the "Blog" controller, "index" action.
-- "/blog/rss" would load the "Blog" controller, "rss" action.
-- "/blog/rss/sub" would load the "Blog" controller, "subrss" action.
-- "/forum" would load the "Forum" controller, "index" action.
-
-You may use any route type as a child route of a `Part` route.
-
-> ## Note
-`Part` routes are not meant to be used directly. When you add definitions for `child_routes` to any
-route type, that route will become a `Part` route. As already said, describing `Part` routes with
-words is difficult, so hopefully the additional \[examples at the
-end\](zend.mvc.routing.http-route-types.examples) will provide further insight.
-
-> ## Note
-In the above example, the `$routePlugins` is an instance of `Zend\Mvc\Router\RoutePluginManager`.
-```php
-$routePlugins = new Zend\Mvc\Router\RoutePluginManager();
-$plugins = array(
-'hostname' = 'Zend\Mvc\Router\Http\Hostname',
-'literal' = 'Zend\Mvc\Router\Http\Literal',
-'part' = 'Zend\Mvc\Router\Http\Part',
-'regex' = 'Zend\Mvc\Router\Http\Regex',
-'scheme' = 'Zend\Mvc\Router\Http\Scheme',
-'segment' = 'Zend\Mvc\Router\Http\Segment',
-'wildcard' = 'Zend\Mvc\Router\Http\Wildcard',
-'query' = 'Zend\Mvc\Router\Http\Query',
-'method' = 'Zend\Mvc\Router\Http\Method',
-);
-foreach ($plugins as $name = $class) {
-$routePlugins-setInvokableClass($name, $class);
-}
-```
-When using `Zend\Mvc\Router\Http\TreeRouteStack`, the `RoutePluginManager` is set up by default, and
-the developer does not need to worry about the autoloading of standard HTTP routes.
-
-### Zend\\Mvc\\Router\\Http\\Regex
-
-A `Regex` route utilizes a regular expression to match against the URI path. Any valid regular
-expression is allowed; our recommendation is to use named captures for any values you want to return
-in the `RouteMatch`.
-
-Since regular expression routes are often complex, you must specify a "spec" or specification to use
-when assembling URLs from regex routes. The spec is simply a string; replacements are identified
-using "%keyname%" within the string, with the keys coming from either the captured values or named
-parameters passed to the `assemble()` method.
-
-Just like other routes, the `Regex` route can accept "defaults", parameters to include in the
-`RouteMatch` when successfully matched.
-
-```php
-$route = Regex::factory(array(
- 'regex' => '/blog/(?[a-zA-Z0-9_-]+)(\.(?(json|html|xml|rss)))?',
- 'defaults' => array(
- 'controller' => 'Application\Controller\BlogController',
- 'action' => 'view',
- 'format' => 'html',
- ),
- 'spec' => '/blog/%id%.%format%',
-));
-```
-
-The above would match "/blog/001-some-blog\_slug-here.html", and return four items in the
-`RouteMatch`, an "id", the "controller", the "action", and the "format". When assembling a URL from
-this route, the "id" and "format" values would be used to fill the specification.
-
-### Zend\\Mvc\\Router\\Http\\Scheme
-
-The `Scheme` route matches the URI scheme only, and must be an exact match. As such, this route,
-like the `Literal` route, simply takes what you want to match and the "defaults", parameters to
-return on a match.
-
-```php
-$route = Scheme::factory(array(
- 'scheme' => 'https',
- 'defaults' => array(
- 'https' => true,
- ),
-));
-```
-
-The above route would match the "https" scheme, and return the key "https" in the `RouteMatch` with
-a boolean `true` value.
-
-### Zend\\Mvc\\Router\\Http\\Segment
-
-A `Segment` route allows matching any segment of a URI path. Segments are denoted using a colon,
-followed by alphanumeric characters; if a segment is optional, it should be surrounded by brackets.
-As an example, "/:foo\[/:bar\]" would match a "/" followed by text and assign it to the key "foo";
-if any additional "/" characters are found, any text following the last one will be assigned to the
-key "bar".
-
-The separation between literal and named segments can be anything. For example, the above could be
-done as "/:foo{-}\[-:bar\] as well. The {-} after the :foo parameter indicates a set of one or more
-delimiters, after which matching of the parameter itself ends.
-
-Each segment may have constraints associated with it. Each constraint should simply be a regular
-expression expressing the conditions under which that segment should match.
-
-Also, as you can in other routes, you may provide defaults to use; these are particularly useful
-when using optional segments.
-
-As a complex example:
-
-```php
-$route = Segment::factory(array(
- 'route' => '/:controller[/:action]',
- 'constraints' => array(
- 'controller' => '[a-zA-Z][a-zA-Z0-9_-]+',
- 'action' => '[a-zA-Z][a-zA-Z0-9_-]+',
- ),
- 'defaults' => array(
- 'controller' => 'Application\Controller\IndexController',
- 'action' => 'index',
- ),
-));
-```
-
-### Zend\\Mvc\\Router\\Http\\Query (Deprecated)
-
-> ## Warning
-#### Potential security issue
-A misuse of this route part can lead to a potential security issue.
-
-> ## Note
-#### Deprecated
-This route part is deprecated since you can now add query parameters without a query route.
-
-The `Query` route part allows you to specify and capture query string parameters for a given route.
-
-The intention of the `Query` part is that you do not instantiate it in its own right but to use it
-as a child of another route part.
-
-An example of its usage would be
-
-```php
-$route = Part::factory(array(
- 'route' => array(
- 'type' => 'literal',
- 'options' => array(
- 'route' => 'page',
- 'defaults' => array(
- ),
- ),
- ),
- 'may_terminate' => true,
- 'route_plugins' => $routePlugins,
- 'child_routes' => array(
- 'query' => array(
- 'type' => 'Query',
- 'options' => array(
- 'defaults' => array(
- 'foo' => 'bar',
- ),
- ),
- ),
- ),
-));
-```
-
-As you can see, it's pretty straight forward to specify the query part. This then allows you to
-create query strings using the url view helper.
-
-```php
-$this->url(
- 'page/query',
- array(
- 'name' => 'my-test-page',
- 'format' => 'rss',
- 'limit' => 10,
- )
-);
-```
-
-As you can see above, you must add "/query" to your route name in order to append a query string. If
-you do not specify "/query" in the route name then no query string will be appended.
-
-Our example "page" route has only one defined parameter of "name" ("/page\[/:name\]"), meaning that
-the remaining parameters of "format" and "limit" will then be appended as a query string.
-
-The output from our example should then be "/page/my-test-page?format=rss&limit=10"
-
-### Zend\\Mvc\\Router\\Http\\Wildcard (Deprecated)
-
-> ## Warning
-#### Potential security issue
-A misuse of this route type can lead to a potential security issue.
-
-> ## Note
-#### Deprecated
-This route type is deprecated. Use the `Segment` route type.
-
-The `Wildcard` route type matches all segments of a URI path, like in version 1 of Zend Framework.
-
-## HTTP Routing Examples
-
-Most of the routing definitions will be done in module configuration files, so the following
-examples will show how to set up routes in config files.
-
-**Simple example with two literal routes**
-
-```php
-return array(
- 'router' => array(
- 'routes' => array(
- // Literal route named "home"
- 'home' => array(
- 'type' => 'literal',
- 'options' => array(
- 'route' => '/',
- 'defaults' => array(
- 'controller' => 'Application\Controller\IndexController',
- 'action' => 'index',
- ),
- ),
- ),
- // Literal route named "contact"
- 'contact' => array(
- 'type' => 'literal',
- 'options' => array(
- 'route' => 'contact',
- 'defaults' => array(
- 'controller' => 'Application\Controller\ContactController',
- 'action' => 'form',
- ),
- ),
- ),
- ),
- ),
-);
-```
-
-**A complex example with child routes**
-
-```php
-return array(
- 'router' => array(
- 'routes' => array(
- // Literal route named "home"
- 'home' => array(
- 'type' => 'literal',
- 'options' => array(
- 'route' => '/',
- 'defaults' => array(
- 'controller' => 'Application\Controller\IndexController',
- 'action' => 'index',
- ),
- ),
- ),
- // Literal route named "blog", with child routes
- 'blog' => array(
- 'type' => 'literal',
- 'options' => array(
- 'route' => '/blog',
- 'defaults' => array(
- 'controller' => 'Application\Controller\BlogController',
- 'action' => 'index',
- ),
- ),
- 'may_terminate' => true,
- 'child_routes' => array(
- // Segment route for viewing one blog post
- 'post' => array(
- 'type' => 'segment',
- 'options' => array(
- 'route' => '/[:slug]',
- 'constraints' => array(
- 'slug' => '[a-zA-Z0-9_-]+',
- ),
- 'defaults' => array(
- 'action' => 'view',
- ),
- ),
- ),
- // Literal route for viewing blog RSS feed
- 'rss' => array(
- 'type' => 'literal',
- 'options' => array(
- 'route' => '/rss',
- 'defaults' => array(
- 'action' => 'rss',
- ),
- ),
- ),
- ),
- ),
- ),
- ),
-);
-```
-
-When using child routes, naming of the routes follows the `parent/child` pattern, so to use the
-child routes from the above example:
-
-```php
-echo $this->url('blog'); // gives "/blog"
-echo $this->url('blog/post', array('slug' => 'my-post')); // gives "/blog/my-post"
-echo $this->url('blog/rss'); // gives "/blog/rss"
-```
-
-**An example with multiple Hostnames and subdomains within a single application**
-
-```php
-return array(
- 'router' => array(
- 'routes' => array(
- 'modules.zendframework.com' => array(
- 'type' => 'Zend\Mvc\Router\Http\Hostname',
- 'options' => array(
- 'route' => ':4th.[:3rd.]:2nd.:1st', // domain levels from right to left
- 'contraints' => array(
- '4th' => 'modules',
- '3rd' => '.*?', // optional 3rd level domain such as .ci, .dev or .test
- '2nd' => 'zendframework',
- '1st' => 'com',
- ),
- // Purposely omit default controller and action
- // to let the child routes control the route match
- ),
- // child route controllers may span multiple modules as desired
- 'child_routes' => array(
- 'index' => array(
- 'type' => 'Zend\Mvc\Router\Http\Literal',
- 'options' => array(
- 'route' => '/',
- 'defaults' => array(
- 'controller' => 'Module\Controller\Index',
- 'action' = > 'index',
- ),
- ),
- 'may_terminate' => true,
- ),
- ),
- ),
- 'packages.zendframework.com' => array(
- 'type' => 'Zend\Mvc\Router\Http\Hostname',
- 'options' => array(
- 'route' => ':4th.[:3rd.]:2nd.:1st', // domain levels from right to left
- 'contraints' => array(
- '4th' => 'packages',
- '3rd' => '.*?', // optional 3rd level domain such as .ci, .dev or .test
- '2nd' => 'zendframework',
- '1st' => 'com',
- ),
- // Purposely omit default controller and action
- // to let the child routes control the route match
- ),
- // child route controllers may span multiple modules as desired
- 'child_routes' => array(
- 'index' => array(
- 'type' => 'Zend\Mvc\Router\Http\Literal',
- 'options' => array(
- 'route' => '/',
- 'defaults' => array(
- 'controller' => 'Package\Controller\Index',
- 'action' = > 'index',
- ),
- ),
- 'may_terminate' => true,
- ),
- ),
- ),
- ),
- ),
-);
-```
-
-The above would match the following:
-
-- `modules.zendframework.com` would dispatch the `Index` controller's `index` action of the `Module`
-module.
-- `modules.ci.zendframework.com` would dispatch the `Index` controller's `index` action of the
-`Module` module.
-- `packages.zendframework.com` would dispatch the `Index` controller's `index` action of the
-`Package` module.
-- `packages.dev.zendframework.com` would dispatch the `Index` controller's `index` action of the
-`Package` module.
-
-The `Url` controller plugin or view helper may be used to generate URLs following the above example:
-
-```php
-// reuse the route matched parameters to generate URLs
-echo $this->url('modules.zendframework.com/index', array(), array(), true);
-echo $this->url('packages.zendframework.com/index', array(), array(), true);
-```
-
-> ## Warning
-When defining child routes pay attention that the `may_terminate` and `child_routes` definitions are
-in same level as the `options` and `type` definitions. A common pitfall is to have those two
-definitions nested in `options`, which will not result in the desired routes.
-
-## Console Route Types
-
-Zend Framework 2.0 also comes with routes for writing Console based applications, which is explained
-in the \[Console routes and routing\](zend.console.routes) section.
diff --git a/doc/book/zend.mvc.send-response-event.md b/doc/book/zend.mvc.send-response-event.md
deleted file mode 100644
index 190f3cd95..000000000
--- a/doc/book/zend.mvc.send-response-event.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# The SendResponseEvent
-
-The MVC layer of Zend Framework 2 also incorporates and utilizes a custom `Zend\EventManager\Event`
-implementation located at `Zend\Mvc\ResponseSender\SendResponseEvent`. This event allows listeners
-to update the response object, by setting headers and content.
-
-The methods it defines are:
-
-- `setResponse($response)`
-- `getResponse()`
-- `setContentSent()`
-- `contentSent()`
-- `setHeadersSent()`
-- `headersSent()`
-
-## Listeners
-
-Currently, three listeners are listening to this event at different priorities based on which
-listener is used most.
-
-Because all these listeners have negative priorities, adding your own logic to modify `Response`
-object is easy: just add a new listener without any priority (it will default to 1) and it will
-always be executed first.
-
-## Triggerers
-
-This event is executed when MvcEvent::FINISH event is triggered, with a priority of -10000.
diff --git a/doc/book/zend.mvc.services.md b/doc/book/zend.mvc.services.md
deleted file mode 100644
index d19e74556..000000000
--- a/doc/book/zend.mvc.services.md
+++ /dev/null
@@ -1,660 +0,0 @@
-# Default Services
-
-The default and recommended way to write Zend Framework applications uses a set of services defined
-in the `Zend\Mvc\Service` namespace. This chapter details what each of those services are, the
-classes they represent, and the configuration options available.
-
-Many of the services are provided by other components, and the factories and abstract factories
-themselves are defined in the individual components. We will cover those factories in this chapter,
-however, as usage is generally the same between each.
-
-## Theory of Operation
-
-To allow easy configuration of all the different parts of the MVC system, a somewhat complex set of
-services and their factories has been created. We'll try to give a simplified explanation of the
-process.
-
-When a `Zend\Mvc\Application` is created, a `Zend\ServiceManager\ServiceManager` object is created
-and configured via `Zend\Mvc\Service\ServiceManagerConfig`. The `ServiceManagerConfig` gets the
-configuration from `application.config.php` (or some other application configuration you passed to
-the `Application` when creating it). From all the service and factories provided in the
-`Zend\Mvc\Service` namespace, `ServiceManagerConfig` is responsible of configuring only three:
-`SharedEventManager`, `EventManager`, and `ModuleManager`.
-
-After this, the `Application` calls for the `ModuleManager`. At this point, the `ModuleManager`
-further configures the `ServiceManager` with services and factories provided in
-`Zend\Mvc\Service\ServiceListenerFactory`. This approach allows us to keep the main application
-configuration concise, and to give the developer the power to configure different parts of the MVC
-system from within the modules, overriding any default configuration in these MVC services.
-
-## ServiceManager
-
-As a quick review, the following service types may be configured:
-
-- **Invokable services**, which map a service name to a class that has no constructor or a
-constructor that accepts no arguments.
-- **Factories**, which map a service name to a factory which will create and return an object. A
-factory receives the service manager as an argument, and may be any PHP callable, or a class or
-object that implements `Zend\ServiceManager\FactoryInterface`.
-- **Abstract factories**, which are factories that can create any number of named services that
-share the same instantiation pattern; examples include database adapters, cache adapters, loggers,
-etc. The factory receives the service manager as an argument, the resolved service name, and the
-requested service name; it **must** be a class or object implementing
-`Zend\ServiceManager\AbstractFactoryInterface`. See the section on abstract factories
- <zend.mvc.services.abstract-factories> for configuration information.
-- **Aliases**, which alias one service name to another. Aliases can also reference other aliases.
-- **Initializers**, which receive the newly created instance and the service manager, and which can
-be used to perform additional initialization tasks. The most common use case is to test the instance
-against specific "Aware" interfaces, and, if matching, inject them with the appropriate service.
-- **Plugin managers**, which are specialized service managers used to manage objects that are of a
-related type, such as view helpers, controller plugins, controllers, etc. Plugin managers accept
-configuration just like service managers, and as such can compose invokable services, factories,
-abstract factories, aliases, and initializers. They are also `ServiceLocatorAware`, and will be
-injected with the application service manager instance, giving factories and abstract factories
-access to application-level services when needed. See the heading Plugin managers
- <zend.mvc.services.plugin-managers> for a list of available plugin managers.
-
-The application service manager is referenced directly during bootstrapping, and has the following
-services configured out of the box.
-
-- **Invokable services**
-- `DispatchListener`, mapping to `Zend\Mvc\DispatchListener`.
-- `RouteListener`, mapping to `Zend\Mvc\RouteListener`.
-- `SendResponseListener`, mapping to `Zend\Mvc\SendResponseListener`.
-- `SharedEventManager`, mapping to `Zend\EventManager\SharedEventManager`.
-- **Factories**
-- `Application`, mapping to `Zend\Mvc\Service\ApplicationFactory`.
-- `Config`, mapping to `Zend\Mvc\Service\ConfigFactory`. Internally, this pulls the `ModuleManager`
-service, and calls its `loadModules()` method, and retrieves the merged configuration from the
-module event. As such, this service contains the entire, merged application configuration.
-- `ControllerManager`, mapping to `Zend\Mvc\Service\ControllerLoaderFactory`. This creates an
-instance of `Zend\Mvc\Controller\ControllerManager`, passing the service manager instance.
-
- Additionally, it uses the `DiStrictAbstractServiceFactory` service -- effectively allowing
-you to fall back to DI in order to retrieve your controllers. If you want to use `Zend\Di` to
-retrieve your controllers, you must white-list them in your DI configuration under the
-`allowed_controllers` key (otherwise, they will just be ignored).
-
- The `ControllerManager` will add an initializer that will do the following:
-
- > - If the controller implements the `Zend\ServiceManager\ServiceLocatorAwareInterface`
-interface, an instance of the `ServiceManager` will be injected into it.
- > - If the controller implements the `Zend\EventManager\EventManagerAwareInterface`
-interface, an instance of the `EventManager` will be injected into it.
- > - Finally, an initializer will inject it with the `ControllerPluginManager` service, as
-long as the `setPluginManager` method is implemented.
-
-- `ControllerPluginManager`, mapping to `Zend\Mvc\Service\ControllerPluginManagerFactory`. This
-instantiates the `Zend\Mvc\Controller\PluginManager` instance, passing it the service manager
-instance. It also uses the `DiAbstractServiceFactory` service -- effectively allowing you to fall
-back to DI in order to retrieve your controller plugins
- <zend.mvc.controller-plugins>.
-
- It registers a set of default controller plugins, and contains an initializer for injecting
-plugins with the current controller.
-
-- `ConsoleAdapter`, mapping to `Zend\Mvc\Service\ConsoleAdapterFactory`. This grabs the `Config`
-service, pulls from the `console` key, and do the following:
-- If the `adapter` subkey is present, it is used to get the adapter instance, otherwise,
-`Zend\Console\Console::detectBestAdapter()` will be called to configure an adapter instance.
-- If the `charset` subkey is present, the is used to set the adapter charset.
-- `ConsoleRouter`, mapping to `Zend\Mvc\Service\RouterFactory`. This grabs the `Config` service, and
-pulls from the `console` key and `router` subkey, configuring a
-`Zend\Mvc\Router\Console\SimpleRouteStack` instance.
-- `ConsoleViewManager`, mapping to `Zend\Mvc\Service\ConsoleViewManagerFactory`. This creates and
-returns an instance of `Zend\Mvc\View\Console\ViewManager`, which in turn registers and initializes
-a number of console-specific view services.
-- `DependencyInjector`, mapping to `Zend\Mvc\Service\DiFactory`. This pulls the `Config` service,
-and looks for a "di" key; if found, that value is used to configure a new `Zend\Di\Di` instance.
-- `DiAbstractServiceFactory`, mapping to `Zend\Mvc\Service\DiAbstractServiceFactoryFactory`. This
-creates an instance of `Zend\ServiceManager\Di\DiAbstractServiceFactory` injecting the `Di` service
-instance. That instance is attached to the service manager as an abstract factory -- effectively
-enabling DI as a fallback for providing services.
-- `DiServiceInitializer`, mapping to `Zend\Mvc\Service\DiServiceInitializerFactory`. This creates an
-instance of `Zend\ServiceManager\Di\DiServiceInitializer` injecting the `Di` service and the service
-manager itself.
-- `DiStrictAbstractServiceFactory`, mapping to
-`Zend\Mvc\Service\DiStrictAbstractServiceFactoryFactory`. This creates an instance of
-`Zend\Mvc\Service\DiStrictAbstractServiceFactoryFactory` injecting the `Di` service instance.
-- `EventManager`, mapping to `Zend\Mvc\Service\EventManagerFactory`. This factory returns a new
-instance of `Zend\EventManager\EventManager` on each request. This service is not shared by default,
-allowing the ability to have an `EventManager` per service, with a shared `SharedEventManager`
-injected in each.
-- `FilterManager`, mapping to `Zend\Mvc\Service\FilterManagerFactory`. This instantiates the
-`Zend\Filter\FilterPluginManager` instance, passing it the service manager instance -- this is used
-to manage filters for the \[filter chains\](zend.filter.filter\_chains). It also uses the
-`DiAbstractServiceFactory` service -- effectively allowing you to fall back to DI in order to
-retrieve filters.
-- `FormElementManager`, mapping to `Zend\Mvc\Service\FormElementManagerFactory`. This instantiates
-the `Zend\Form\FormElementManager` instance, passing it the service manager instance -- this is used
-to manage \[form elements\](zend.form.elements.intro). It also uses the `DiAbstractServiceFactory`
-service -- effectively allowing you to fall back to DI in order to retrieve form elements.
-- `HttpRouter`, mapping to `Zend\Mvc\Service\RouterFactory`. This grabs the `Config` service, and
-pulls from the `router` key, configuring a `Zend\Mvc\Router\Http\TreeRouteStack` instance.
-- `HttpViewManager`, mapping to `Zend\Mvc\Service\HttpViewManagerFactory`. This creates and returns
-an instance of `Zend\Mvc\View\Http\ViewManager`, which in turn registers and initializes a number of
-HTTP-specific view services.
-- `HydratorManager`, mapping to `Zend\Mvc\Service\HydratorManagerFactory`. This creates and returns
-an instance of `Zend\Stdlib\Hydrator\HydratorPluginManager`, which can be used to manage and persist
-hydrator instances.
-- `InputFilterManager`, mapping to `Zend\Mvc\Service\InputFilterManagerFactory`. This creates and
-returns an instance of `Zend\InputFilter\InputFilterPluginManager`, which can be used to manage and
-persist input filter instances.
-- `ModuleManager`, mapping to `Zend\Mvc\Service\ModuleManagerFactory`.
-
- This is perhaps the most complex factory in the MVC stack. It expects that an
-`ApplicationConfig` service has been injected, with keys for `module_listener_options` and
-`modules`; see the quick start for samples.
-
- It instantiates an instance of `Zend\ModuleManager\Listener\DefaultListenerAggregate`, using
-the "module\_listener\_options" retrieved. Checks if a service with the name `ServiceListener`
-exists, otherwise it sets a factory with that name mapping to
-`Zend\Mvc\Service\ServiceListenerFactory`. A bunch of service listeners will be added to the
-`ServiceListener`, like listeners for the `getServiceConfig`, `getControllerConfig`,
-`getControllerPluginConfig`, `getViewHelperConfig` module methods.
-
- Next, it retrieves the `EventManager` service, and attaches the above listeners.
-
- It instantiates a `Zend\ModuleManager\ModuleEvent` instance, setting the "ServiceManager"
-parameter to the service manager object.
-
- Finally, it instantiates a `Zend\ModuleManager\ModuleManager` instance, and injects the
-`EventManager` and `ModuleEvent`.
-
-- `MvcTranslator`, mapping to `Zend\Mvc\Service\TranslatorServiceFactory`, and returning an instance
-of `Zend\Mvc\I18n\Translator`, which extends `Zend\I18n\Translator\Translator` and implements
-`Zend\Validator\Translator\TranslatorInterface`, allowing the instance to be used anywhere a
-translator may be required in the framework.
-- `PaginatorPluginManager`, mapping to `Zend\Mvc\Service\PaginatorPluginManagerFactory`. This
-instantiates the `Zend\Paginator\AdapterPluginManager` instance, passing it the service manager
-instance -- this is used to manage paginator adapters
- <zend.paginator.usage.paginating.adapters>. It also uses the
-`DiAbstractServiceFactory` service -- effectively allowing you to fall back to DI in order to
-retrieve paginator adapters.
-- `Request`, mapping to `Zend\Mvc\Service\RequestFactory`. The factory is used to create and return
-a request instance, according to the current environment. If the current environment is `cli`, it
-will create a `Zend\Console\Request`, or a `Zend\Http\PhpEnvironment\Request` if the current
-environment is HTTP.
-- `Response`, mapping to `Zend\Mvc\Service\ResponseFactory`. The factory is used to create and
-return a response instance, according to the current environment. If the current environment is
-`cli`, it will create a `Zend\Console\Response`, or a `Zend\Http\PhpEnvironment\Response` if the
-current environment is HTTP.
-- `Router`, mapping to `Zend\Mvc\Service\RouterFactory`. If in a console enviroment, this will
-behave the same way as the `ConsoleRouter` service, if not, it will behave the same way as
-`HttpRouter` service.
-- `RoutePluginManager`, mapping to `Zend\Mvc\Service\RoutePluginManagerFactory`. This instantiates
-the `Zend\Mvc\Router\RoutePluginManager` instance, passing it the service manager instance -- this
-is used to manage \[route types\](zend.mvc.routing.http-route-types). It also uses the
-`DiAbstractServiceFactory` service -- effectively allowing you to fall back to DI in order to
-retrieve route types.
-- `SerializerAdapterManager`, mapping to `Zend\Mvc\Service\SerializerAdapterPluginManagerFactory`,
-which returns an instance of `Zend\Serializer\AdapterPluginManager`. This is a plugin manager for
-managing serializer adapter instances.
-- `ServiceListener`, mapping to `Zend\Mvc\Service\ServiceListenerFactory`. The factory is used to
-instantiate the `ServiceListener`, while allowing easy extending. It checks if a service with the
-name `ServiceListenerInterface` exists, which must implement
-`Zend\ModuleManager\Listener\ServiceListenerInterface`, before instantiating the default
-`ServiceListener`.
-
- In addition to this, it retrieves the `ApplicationConfig` and looks for the
-`service_listener_options` key. This allows you to register own listeners for module methods and
-configuration keys to create an own service manager; see the application configuration
- options <zend.mvc.services.app-config> for samples.
-
-- `ValidatorManager`, mapping to `Zend\Mvc\Service\ValidatorManagerFactory`. This instantiates the
-`Zend\Validator\ValidatorPluginManager` instance, passing it the service manager instance -- this is
-used to manage \[validators\](zend.validator.set). It also uses the `DiAbstractServiceFactory`
-service -- effectively allowing you to fall back to DI in order to retrieve validators.
-- `ViewFeedRenderer`, mapping to `Zend\Mvc\Service\ViewFeedRendererFactory`, which returns an
-instance of `Zend\View\Renderer\FeedRenderer`, used to render feeds.
-- `ViewFeedStrategy`, mapping to `Zend\Mvc\Service\ViewFeedStrategyFactory`, which returns an
-instance of `Zend\View\Strategy\FeedStrategy`, used to select the `ViewFeedRenderer` given the
-appropriate criteria.
-- `ViewHelperManager`, mapping to `Zend\Mvc\Service\ViewHelperManagerFactory`, which returns an
-instance of `Zend\View\HelperManager`. This is a plugin manager for managing view helper instances.
-- `ViewJsonRenderer`, mapping to `Zend\Mvc\Service\ViewJsonRendererFactory`, which returns an
-instance of `Zend\View\Renderer\JsonRenderer`, used to render JSON structures.
-- `ViewJsonStrategy`, mapping to `Zend\Mvc\Service\ViewJsonStrategyFactory`, which returns an
-instance of `Zend\View\Strategy\JsonStrategy`, used to select the `ViewJsonRenderer` given the
-appropriate criteria.
-- `ViewManager`, mapping to `Zend\Mvc\Service\ViewManagerFactory`. The factory is used to create and
-return a view manager, according to the current environment. If the current environment is `cli`, it
-will create a `Zend\Mvc\View\Console\ViewManager`, or a `Zend\Mvc\View\Http\ViewManager` if the
-current environment is HTTP.
-- `ViewResolver`, mapping to `Zend\Mvc\Service\ViewResolverFactory`, which creates and returns the
-aggregate view resolver. It also attaches the `ViewTemplateMapResolver` and `ViewTemplatePathStack`
-services to it.
-- `ViewTemplateMapResolver`, mapping to `Zend\Mvc\Service\ViewTemplateMapResolverFactory` which
-creates, configures and returns the `Zend\View\Resolver\TemplateMapResolver`.
-- `ViewTemplatePathStack`, mapping to `Zend\Mvc\Service\ViewTemplatePathStackFactory` which creates,
-configures and returns the `Zend\View\Resolver\TemplatePathStack`.
-
-- **Abstract factories**
-- `Zend\Cache\Service\StorageCacheAbstractServiceFactory` (opt-in; registered by default in the
-skeleton application).
-- `Zend\Db\Adapter\AdapterAbstractServiceFactory` (opt-in).
-- `Zend\Form\FormAbstractServiceFactory` is registered by default.
-- `Zend\Log\LoggerAbstractServiceFactory` (opt-in; registered by default in the skeleton
-application).
-- **Aliases**
-- `Configuration`, mapping to the `Config` service.
-- `Console`, mapping to the `ConsoleAdapter` service.
-- `Di`, mapping to the `DependencyInjector` service.
-- `Zend\Di\LocatorInterface`, mapping to the `DependencyInjector` service.
-- `Zend\EventManager\EventManagerInterface`, mapping to the `EventManager` service. This is mainly
-to ensure that when falling through to DI, classes are still injected via the `ServiceManager`.
-- `Zend\Mvc\Controller\PluginManager`, mapping to the `ControllerPluginManager` service. This is
-mainly to ensure that when falling through to DI, classes are still injected via the
-`ServiceManager`.
-- `Zend\View\Resolver\TemplateMapResolver`, mapping to the `ViewTemplateMapResolver` service.
-- `Zend\View\Resolver\TemplatePathStack`, mapping to the `ViewTemplatePathStack` service.
-- `Zend\View\Resolver\AggregateResolver`, mapping to the `ViewResolver` service.
-- `Zend\View\Resolver\ResolverInterface`, mapping to the `ViewResolver` service.
-- **Initializers**
-- For objects that implement `Zend\EventManager\EventManagerAwareInterface`, the `EventManager`
-service will be retrieved and injected. This service is **not** shared, though each instance it
-creates is injected with a shared instance of `SharedEventManager`.
-- For objects that implement `Zend\ServiceManager\ServiceLocatorAwareInterface`, the
-`ServiceManager` will inject itself into the object.
-- The `ServiceManager` registers itself as the `ServiceManager` service, and aliases itself to the
-class names `Zend\ServiceManager\ServiceLocatorInterface` and `Zend\ServiceManager\ServiceManager`.
-
-## Abstract Factories
-
-As noted in the previous section, Zend Framework provides a number of abstract service factories by
-default. Each is noted below, along with sample configuration.
-
-In each instance, the abstract factory looks for a top-level configuration key, consisting of
-key/value pairs where the key is the service name, and the value is the configuration to use to
-create the given service.
-
-### Zend\\Cache\\Service\\StorageCacheAbstractServiceFactory
-
-This abstract factory is opt-in, but registered by default in the skeleton application. It uses the
-top-level configuration key "caches".
-
-```php
-return array(
- 'caches' => array(
- 'Cache\Transient' => array(
- 'adapter' => 'redis',
- 'ttl' => 60,
- 'plugins' => array(
- 'exception_handler' => array(
- 'throw_exceptions' => false,
- ),
- ),
- ),
- 'Cache\Persistence' => array(
- 'adapter' => 'filesystem',
- 'ttl' => 86400,
- ),
- ),
-);
-```
-
-See the \[cache documentation\](zend.cache.storage.adapter) for more configuration options.
-
-### Zend\\Db\\Adapter\\AdapterAbstractServiceFactory
-
-This abstract factory is opt-in. It uses the top-level configuration key "db", with a subkey
-"adapters".
-
-```php
-return array(
- 'db' => array('adapters' => array(
- 'Db\ReadOnly' => array(
- 'driver' => 'Pdo_Sqlite',
- 'database' => 'data/db/users.db',
- ),
- 'Db\Writeable' => array(
- 'driver' => 'Mysqli',
- 'database' => 'users',
- 'username' => 'developer',
- 'password' => 'developer_password',
- ),
- )),
-);
-```
-
-See the \[DB adapter documentation\](zend.db.adapter) for more configuration options.
-
-### Zend\\Form\\FormAbstractServiceFactory
-
-This abstract factory is registered by default. It uses the top-level configuration key "forms". It
-makes use of the `FilterManager`, `FormElementManager`, `HydratorManager`, `InputFilterManager`, and
-`ValidatorManager` plugin managers in order to allow instantiation and creation of form objects and
-all related objects in the form hierarchy.
-
-```php
-return array(
- 'forms' => array(
- 'Form\Foo' => array(
- 'hydrator' => 'ObjectProperty',
- 'type' => 'Zend\Form\Form',
- 'elements' => array(
- array(
- 'spec' => array(
- 'type' => 'Zend\Form\Element\Email',
- 'name' => 'email',
- 'options' => array(
- 'label' => 'Your email address',
- ),
- ),
- ),
- ),
- ),
- ),
-);
-```
-
-Form configuration follows the same configuration you would use with a form factory; the primary
-difference is that all plugin managers have already been injected for you, allowing you the
-possibility of custom objects or substitutions.
-
-See the \[form factory documentation\](zend.form.quick-start.factory) for more configuration
-options.
-
-### Zend\\Log\\LoggerAbstractServiceFactory
-
-This abstract factory is opt-in, but registered by default in the skeleton application. It uses the
-top-level configuration key "log".
-
-```php
-return array(
- 'log' => array(
- 'Log\App' => array(
- 'writers' => array(
- array(
- 'name' => 'stream',
- 'priority' => 1000,
- 'options' => array(
- 'stream' => 'data/logs/app.log',
- ),
- ),
- ),
- ),
- ),
-);
-```
-
-See the \[log documentation\](zend.log.overview) for more configuration options.
-
-## Plugin Managers
-
-The following plugin managers are configured by default:
-
-- **ControllerManager**, corresponding to `Zend\Mvc\Controller\ControllerManager`, and used to
-manage controller instances.
-- **ControllerPluginManager**, corresponding to `Zend\Mvc\Controller\PluginManager`, and used to
-manage controller plugin instances.
-- **FilterManager**, corresponding to `Zend\Filter\FilterPluginManager`, and used to manage filter
-instances.
-- **FormElementManager**, corresponding to `Zend\Form\FormElementManager`, and used to manage
-instances of form elements and fieldsets.
-- **HydratorManager**, corresponding to `Zend\Stdlib\Hydrator\HydratorPluginManager`, and used to
-manage hydrator instances.
-- **InputFilterManager**, corresponding to `Zend\InputFilter\InputFilterPluginManager`, and used to
-manage input filter instances.
-- **RoutePluginManager**, corresponding to `Zend\Mvc\Router\RoutePluginManager`, and used to manage
-route instances.
-- **SerializerAdapterManager**, corresponding to `Zend\Serializer\AdapterPluginManager`, and used to
-manage serializer instances.
-- **ValidatorManager**, corresponding to `Zend\Validator\ValidatorPluginManager`, and used to manage
-validator instances.
-- **ViewHelperManager**, corresponding to `Zend\View\HelperPluginManager`, and used to manage view
-helper instances.
-
-As noted in the previous section, all plugin managers share the same configuration and service types
-as the standard service manager; they are simply scoped, and only allow instances of certain types
-to be created or registered. Default types available are listed in the documentation for each
-component.
-
-## ViewManager
-
-The View layer within `Zend\Mvc` consists of a large number of collaborators and event listeners. As
-such, `Zend\Mvc\View\ViewManager` was created to handle creation of the various objects, as well as
-wiring them together and establishing event listeners.
-
-The `ViewManager` itself is an event listener on the `bootstrap` event. It retrieves the
-`ServiceManager` from the `Application` object, as well as its composed `EventManager`.
-
-Configuration for all members of the `ViewManager` fall under the `view_manager` configuration key,
-and expect values as noted below. The following services are created and managed by the
-`ViewManager`:
-
-- `ViewHelperManager`, representing and aliased to `Zend\View\HelperPluginManager`. It is seeded
-with the `ServiceManager`. Created via the `Zend\Mvc\Service\ViewHelperManagerFactory`.
-- The `Router` service is retrieved, and injected into the `Url` helper.
-- If the `base_path` key is present, it is used to inject the `BasePath` view helper; otherwise, the
-`Request` service is retrieved, and the value of its `getBasePath()` method is used.
-- If the `base_path_console` key is present, it is used to inject the `BasePath` view helper for
-console requests; otherwise, the `Request` service is retrieved, and the value of its
-`getBasePath()` method is used. This can be useful for sending urls in emails via a cronjob.
-- If the `doctype` key is present, it will be used to set the value of the `Doctype` view helper.
-- `ViewTemplateMapResolver`, representing and aliased to `Zend\View\Resolver\TemplateMapResolver`.
-If a `template_map` key is present, it will be used to seed the template map.
-- `ViewTemplatePathStack`, representing and aliased to `Zend\View\Resolver\TemplatePathStack`.
-- If a `template_path_stack` key is present, it will be used to seed the stack.
-- If a `default_template_suffix` key is present, it will be used as the default suffix for template
-scripts resolving.
-- `ViewResolver`, representing and aliased to `Zend\View\Resolver\AggregateResolver` and
-`Zend\View\Resolver\ResolverInterface`. It is seeded with the `ViewTemplateMapResolver` and
-`ViewTemplatePathStack` services as resolvers.
-- `ViewRenderer`, representing and aliased to `Zend\View\Renderer\PhpRenderer` and
-`Zend\View\Renderer\RendererInterface`. It is seeded with the `ViewResolver` and `ViewHelperManager`
-services. Additionally, the `ViewModel` helper gets seeded with the `ViewModel` as its root (layout)
-model.
-- `ViewPhpRendererStrategy`, representing and aliased to `Zend\View\Strategy\PhpRendererStrategy`.
-It gets seeded with the `ViewRenderer` service.
-- `View`, representing and aliased to `Zend\View\View`. It gets seeded with the `EventManager`
-service, and attaches the `ViewPhpRendererStrategy` as an aggregate listener.
-- `DefaultRenderingStrategy`, representing and aliased to `Zend\Mvc\View\DefaultRenderingStrategy`.
-If the `layout` key is present, it is used to seed the strategy's layout template. It is seeded with
-the `View` service.
-- `ExceptionStrategy`, representing and aliased to `Zend\Mvc\View\ExceptionStrategy`. If the
-`display_exceptions` or `exception_template` keys are present, they are used to configure the
-strategy.
-- `RouteNotFoundStrategy`, representing and aliased to `Zend\Mvc\View\RouteNotFoundStrategy` and
-`404Strategy`. If the `display_not_found_reason` or `not_found_template` keys are present, they are
-used to configure the strategy.
-- `ViewModel`. In this case, no service is registered; the `ViewModel` is simply retrieved from the
-`MvcEvent` and injected with the layout template name.
-
-The `ViewManager` also creates several other listeners, but does not expose them as services; these
-include `Zend\Mvc\View\CreateViewModelListener`, `Zend\Mvc\View\InjectTemplateListener`, and
-`Zend\Mvc\View\InjectViewModelListener`. These, along with `RouteNotFoundStrategy`,
-`ExceptionStrategy`, and `DefaultRenderingStrategy` are attached as listeners either to the
-application `EventManager` instance or the `SharedEventManager` instance.
-
-Finally, if you have a `strategies` key in your configuration, the `ViewManager` will loop over
-these and attach them in order to the `View` service as listeners, at a priority of 100 (allowing
-them to execute before the `DefaultRenderingStrategy`).
-
-## Application Configuration Options
-
-The following options may be used to provide initial configuration for the `ServiceManager`,
-`ModuleManager`, and `Application` instances, allowing them to then find and aggregate the
-configuration used for the `Config` service, which is intended for configuring all other objects in
-the system. These configuration directives go to the `config/application.config.php` file.
-
-```php
- array(
- ),
-
- // These are various options for the listeners attached to the ModuleManager
- 'module_listener_options' => array(
- // This should be an array of paths in which modules reside.
- // If a string key is provided, the listener will consider that a module
- // namespace, the value of that key the specific path to that module's
- // Module class.
- 'module_paths' => array(
- ),
-
- // An array of paths from which to glob configuration files after
- // modules are loaded. These effectively override configuration
- // provided by modules themselves. Paths may use GLOB_BRACE notation.
- 'config_glob_paths' => array(
- ),
-
- // Whether or not to enable a configuration cache.
- // If enabled, the merged configuration will be cached and used in
- // subsequent requests.
- 'config_cache_enabled' => $booleanValue,
-
- // The key used to create the configuration cache file name.
- 'config_cache_key' => $stringKey,
-
- // Whether or not to enable a module class map cache.
- // If enabled, creates a module class map cache which will be used
- // by in future requests, to reduce the autoloading process.
- 'module_map_cache_enabled' => $booleanValue,
-
- // The key used to create the class map cache file name.
- 'module_map_cache_key' => $stringKey,
-
- // The path in which to cache merged configuration.
- 'cache_dir' => $stringPath,
-
- // Whether or not to enable modules dependency checking.
- // Enabled by default, prevents usage of modules that depend on other modules
- // that weren't loaded.
- 'check_dependencies' => $booleanValue,
- ),
-
- // Used to create an own service manager. May contain one or more child arrays.
- 'service_listener_options' => array(
- array(
- 'service_manager' => $stringServiceManagerName,
- 'config_key' => $stringConfigKey,
- 'interface' => $stringOptionalInterface,
- 'method' => $stringRequiredMethodName,
- ),
- )
-
- // Initial configuration with which to seed the ServiceManager.
- // Should be compatible with Zend\ServiceManager\Config.
- 'service_manager' => array(
- ),
-);
-```
-
-For an example, see the [ZendSkeletonApplication configuration
-file](https://github.com/zendframework/ZendSkeletonApplication/blob/master/config/application.config.php).
-
-## Default Configuration Options
-
-The following options are available when using the default services configured by the
-`ServiceManagerConfig` and `ViewManager`.
-
-These configuration directives can go to the `config/autoload/{{,*.}global,{,*.}local}.php` files,
-or in the `module//config/module.config.php` configuration files. The merging of these
-configuration files is done by the `ModuleManager`. It first merges each module's
-`module.config.php` file, and then the files in `config/autoload` (first the `*.global.php` and then
-the `*.local.php` files). The order of the merge is relevant so you can override a module's
-configuration with your application configuration. If you have both a
-`config/autoload/my.global.config.php` and `config/autoload/my.local.config.php`, the local
-configuration file overrides the global configuration.
-
-> ## Warning
-Local configuration files are intended to keep sensitive information, such as database credentials,
-and as such, it is highly recommended to keep these local configuration files out of your VCS. The
-`ZendSkeletonApplication`'s `config/autoload/.gitignore` file ignores `*.local.php` files by
-default.
-
-```php
- array(
- // Map of controller "name" to class
- // This should be used if you do not need to inject any dependencies
- // in your controller
- 'invokables' => array(
- ),
-
- // Map of controller "name" to factory for creating controller instance
- // You may provide either the class name of a factory, or a PHP callback.
- 'factories' => array(
- ),
- ),
-
- // The following are used to configure controller plugin loader
- // Should be compatible with Zend\ServiceManager\Config.
- 'controller_plugins' => array(
- ),
-
- // The following are used to configure view helper manager
- // Should be compatible with Zend\ServiceManager\Config.
- 'view_helpers' => array(
- ),
-
- // The following is used to configure a Zend\Di\Di instance.
- // The array should be in a format that Zend\Di\Config can understand.
- 'di' => array(
- ),
-
- // Configuration for the Router service
- // Can contain any router configuration, but typically will always define
- // the routes for the application. See the router documentation for details
- // on route configuration.
- 'router' => array(
- 'routes' => array(
- ),
- ),
-
- // ViewManager configuration
- 'view_manager' => array(
- // Base URL path to the application
- 'base_path' => $stringBasePath,
-
- // Doctype with which to seed the Doctype helper
- 'doctype' => $doctypeHelperConstantString, // e.g. HTML5, XHTML1
-
- // TemplateMapResolver configuration
- // template/path pairs
- 'template_map' => array(
- ),
-
- // TemplatePathStack configuration
- // module/view script path pairs
- 'template_path_stack' => array(
- ),
- // Default suffix to use when resolving template scripts, if none, 'phtml' is used
- 'default_template_suffix' => $templateSuffix, // e.g. 'php'
-
- // Controller namespace to template map
- // or whitelisting for controller FQCN to template mapping
- 'controller_map' => array(
- ),
-
- // Layout template name
- 'layout' => $layoutTemplateName, // e.g. 'layout/layout'
-
- // ExceptionStrategy configuration
- 'display_exceptions' => $bool, // display exceptions in template
- 'exception_template' => $stringTemplateName, // e.g. 'error'
-
- // RouteNotFoundStrategy configuration
- 'display_not_found_reason' => $bool, // display 404 reason in template
- 'not_found_template' => $stringTemplateName, // e.g. '404'
-
- // Additional strategies to attach
- // These should be class names or service names of View strategy classes
- // that act as ListenerAggregates. They will be attached at priority 100,
- // in the order registered.
- 'strategies' => array(
- 'ViewJsonStrategy', // register JSON renderer strategy
- 'ViewFeedStrategy', // register Feed renderer strategy
- ),
- ),
-);
-```
-
-For an example, see the [Application module configuration
-file](https://github.com/zendframework/ZendSkeletonApplication/blob/master/module/Application/config/module.config.php)
-in the ZendSkeletonApplication.
diff --git a/doc/bookdown.json b/doc/bookdown.json
deleted file mode 100644
index 7ea866c20..000000000
--- a/doc/bookdown.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "title": "zend-mvc: MVC application provider",
- "target": "html/",
- "content": [
- "book/zend.mvc.intro.md",
- "book/zend.mvc.quick-start.md",
- "book/zend.mvc.services.md",
- "book/zend.mvc.routing.md",
- "book/zend.mvc.mvc-event.md",
- "book/zend.mvc.send-response-event.md",
- "book/zend.mvc.controllers.md",
- "book/zend.mvc.plugins.md",
- "book/zend.mvc.examples.md",
- {"Migration Guide": "book/migration.md"}
- ]
-}
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 000000000..d2fffe021
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,20 @@
+docs_dir: doc/book
+site_dir: doc/html
+pages:
+ - index.md
+ - Introduction: intro.md
+ - 'Quick Start': quick-start.md
+ - Reference:
+ - 'Default Services': services.md
+ - Routing: routing.md
+ - 'The MVC Event': mvc-event.md
+ - 'The SendResponse Event': send-response-event.md
+ - 'Available Controllers': controllers.md
+ - 'Controller Plugins': plugins.md
+ - Examples: examples.md
+ - 'Dispatching PSR-7 Middleware': middleware.md
+ - 'Migration Guide': migration.md
+site_name: zend-mvc
+site_description: 'zend-mvc: MVC application provider'
+repo_url: 'https://github.com/zendframework/zend-mvc'
+copyright: 'Copyright (c) 2016 Zend Technologies USA Inc.'