Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit 157a275

Browse files
committed
Reviewed and edited all documentation
- Edited documentation for content. - Edited documentation for consistency of formatting. - Edited documentation for weasel words. - Re-organized documentation. - Converted documentation to mkdocs.
1 parent 1801f70 commit 157a275

25 files changed

+3586
-3331
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
nbproject
99
doc/html/
1010
tmp/
11+
zf-mkdoc-theme/
1112

1213
clover.xml
1314
composer.lock

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ The MVC layer is built on top of the following components:
2121

2222

2323
- File issues at https://github.com/zendframework/zend-mvc/issues
24-
- Documentation is at http://framework.zend.com/manual/current/en/index.html#zend-mvc
24+
- Documentation is at https://zendframework.github.io/zend-mvc/

doc/book/controllers.md

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
# Available Controllers
2+
3+
Controllers in zend-mvc are objects implementing `Zend\Stdlib\DispatchableInterface`.
4+
That interface describes a single method:
5+
6+
```php
7+
use Zend\Stdlib\DispatchableInterface;
8+
use Zend\Stdlib\RequestInterface as Request;
9+
use Zend\Stdlib\ResponseInterface as Response;
10+
11+
class Foo implements DispatchableInterface
12+
{
13+
public function dispatch(Request $request, Response $response = null)
14+
{
15+
// ... do something, and preferably return a Response ...
16+
}
17+
}
18+
```
19+
20+
While the pattern is straight-forward, chances are you don't want to implement
21+
custom dispatch logic for every controller, particularly as it's not unusual or
22+
uncommon for a single controller to handle several related types of requests.
23+
24+
To provide convenience, zend-mvc also defines several interfaces that, when
25+
implemented, can provide controllers with additional capabilities.
26+
27+
## Common Interfaces Used With Controllers
28+
29+
### InjectApplicationEvent
30+
31+
The `Zend\Mvc\InjectApplicationEventInterface` hints to the `Application`
32+
instance that it should inject its `MvcEvent` into the controller itself. Why
33+
would this be useful?
34+
35+
Recall that the `MvcEvent` composes a number of objects: the `Request` and
36+
`Response`, naturally, but also the router, the route matches (a `RouteMatch`
37+
instance), and potentially the "result" of dispatching.
38+
39+
A controller that has the `MvcEvent` injected, then, can retrieve or inject
40+
these. As an example:
41+
42+
```php
43+
$matches = $this->getEvent()->getRouteMatch();
44+
$id = $matches->getParam('id', false);
45+
if (! $id) {
46+
$response = $this->getResponse();
47+
$response->setStatusCode(500);
48+
$this->getEvent()->setResult('Invalid identifier; cannot complete request');
49+
return;
50+
}
51+
```
52+
53+
The `InjectApplicationEventInterface` defines two methods:
54+
55+
```php
56+
public function setEvent(Zend\EventManager\EventInterface $event);
57+
public function getEvent();
58+
```
59+
60+
### ServiceLocatorAware
61+
62+
In most cases, you should define your controllers such that dependencies are
63+
injected by the application's `ServiceManager`, via either constructor arguments
64+
or setter methods.
65+
66+
However, occasionally you may have objects you wish to use in your controller
67+
that are only valid for certain code paths. Examples include forms, paginators,
68+
navigation, etc. In these cases, you may decide that it doesn't make sense to
69+
inject those objects every time the controller is used.
70+
71+
The `ServiceLocatorAwareInterface` interface hints to the `ServiceManager` that it should inject
72+
itself into the controller. It defines two simple methods:
73+
74+
```php
75+
use Zend\ServiceManager\ServiceLocatorInterface;
76+
use Zend\ServiceManager\ServiceLocatorAwareInterface;
77+
78+
public function setServiceLocator(ServiceLocatorInterface $serviceLocator);
79+
public function getServiceLocator();
80+
```
81+
82+
> #### ServiceLocatorInterface is deprecated
83+
>
84+
> `ServiceLocatorAwareInterface` [was removed from zend-servicemanager v3.0](http://zendframework.github.io/zend-servicemanager/migration/#miscellaneous-interfaces-traits-and-classes),
85+
> and, as such, starting in zend-mvc 2.7.0, the `AbstractController`
86+
> implementation no longer implements the interface, though it implements the
87+
> methods the interface defines; this allows forwards compatibility with
88+
> zend-servicemanager v3.
89+
>
90+
> However, also starting with the zend-mvc 2.7.0 release, `ServiceLocatorAwareInterface`
91+
> usage is deprecated. We recommend injecting dependencies explicitly instead of
92+
> pulling them from a composed `ServiceManager` instance.
93+
>
94+
> In cases where an object will not be used in all code paths, we recommend
95+
> splitting into discrete controllers, or using [lazy services](http://zendframework.github.io/zend-servicemanager/lazy-services/).
96+
97+
### EventManagerAware
98+
99+
Typically, it's nice to be able to tie into a controller's workflow without
100+
needing to extend it or hardcode behavior into it. The solution for this is to
101+
use the `EventManager`.
102+
103+
You can hint to the `ServiceManager` that you want an `EventManager` injected by
104+
implementing the interface `EventManagerAwareInterface`, which tells the
105+
`ServiceManager` to inject an `EventManager`.
106+
107+
To do this, you define two methods. The first, a setter, should also set any
108+
`SharedEventManager` identifiers you want to listen on, and the second, a getter,
109+
should return the composed `EventManager` instance.
110+
111+
```php
112+
use Zend\EventManager\EventManagerAwareInterface;
113+
use Zend\EventManager\EventManagerInterface;
114+
115+
public function setEventManager(EventManagerInterface $events);
116+
public function getEventManager();
117+
```
118+
119+
### Controller Plugins
120+
121+
Code re-use is a common goal for developers. Another common goal is convenience.
122+
However, this is often difficult to achieve cleanly in abstract, general
123+
systems.
124+
125+
Within your controllers, you'll often find yourself repeating tasks from one
126+
controller to another. Some common examples:
127+
128+
- Generating URLs.
129+
- Redirecting.
130+
- Setting and retrieving flash messages (self-expiring session messages).
131+
- Invoking and dispatching additional controllers.
132+
133+
To facilitate these actions while also making them available to alternate
134+
controller implementations, we've created a `PluginManager` implementation for
135+
the controller layer, `Zend\Mvc\Controller\PluginManager`, building on the
136+
`Zend\ServiceManager\AbstractPluginManager` functionality. To utilize it,
137+
implement the `setPluginManager(PluginManager $plugins)` method, and set up your
138+
code to use the controller-specific implementation by default:
139+
140+
```php
141+
use Zend\Mvc\Controller\PluginManager;
142+
143+
public function setPluginManager(PluginManager $plugins)
144+
{
145+
$this->plugins = $plugins;
146+
$this->plugins->setController($this);
147+
148+
return $this;
149+
}
150+
151+
public function getPluginManager()
152+
{
153+
if (!$this->plugins) {
154+
$this->setPluginManager(new PluginManager());
155+
}
156+
157+
return $this->plugins;
158+
}
159+
160+
public function plugin($name, array $options = null)
161+
{
162+
return $this->getPluginManager()->get($name, $options);
163+
}
164+
```
165+
166+
## AbstractActionController
167+
168+
Implementing each of the above interfaces is a lesson in redundancy; you won't
169+
often want to do it. As such, we've developed abstract, base controllers you
170+
can extend to get started.
171+
172+
The first is `Zend\Mvc\Controller\AbstractActionController`. This controller
173+
implements each of the above interfaces, and uses the following assumptions:
174+
175+
- An "action" parameter is expected in the `RouteMatch` object composed in the
176+
attached `MvcEvent`. If none is found, a `notFoundAction()` is invoked.
177+
- The "action" parameter is converted to a camelCased format and appended with
178+
the word "Action" to create a method name. As examples: "foo" maps to
179+
`fooAction`, "foo-bar" or "foo.bar" or "foo\_bar" to `fooBarAction`. The
180+
controller then checks to see if that method exists. If not, the
181+
`notFoundAction()` method is invoked; otherwise, the discovered method is
182+
called.
183+
- The results of executing the given action method are injected into the
184+
`MvcEvent`'s "result" property (via `setResult()`, and accessible via
185+
`getResult()`).
186+
187+
Essentially, a route mapping to an `AbstractActionController` needs to return
188+
both the "controller" and "action" keys in its matches.
189+
190+
Creation of action controllers looks like the following example:
191+
192+
```php
193+
namespace Foo\Controller;
194+
195+
use Zend\Mvc\Controller\AbstractActionController;
196+
197+
class BarController extends AbstractActionController
198+
{
199+
public function bazAction()
200+
{
201+
return ['title' => __METHOD__];
202+
}
203+
204+
public function batAction()
205+
{
206+
return ['title' => __METHOD__];
207+
}
208+
}
209+
```
210+
211+
### Interfaces and Collaborators
212+
213+
`AbstractActionController` implements each of the following interfaces:
214+
215+
- `Zend\Stdlib\DispatchableInterface`
216+
- `Zend\Mvc\InjectApplicationEventInterface`
217+
- `Zend\ServiceManager\ServiceLocatorAwareInterface` (starting with zend-mvc
218+
2.7.0, only the methods defined by the interface, not the interface itself)
219+
- `Zend\EventManager\EventManagerAwareInterface`
220+
221+
The composed `EventManager` will be configured to listen on the following contexts:
222+
223+
- `Zend\Stdlib\DispatchableInterface`
224+
- `Zend\Mvc\Controller\AbstractActionController`
225+
- `Zend\Mvc\Controller\AbstractController`
226+
227+
Additionally, if you extend the class, it will listen on the name of the
228+
extending class.
229+
230+
## AbstractRestfulController
231+
232+
`Zend\Mvc\Controller\AbstractRestfulController` provides a native RESTful
233+
implementation that maps HTTP request methods to controller methods, using the
234+
following matrix:
235+
236+
- **GET** maps to either `get()` or `getList()`, depending on whether or not an
237+
"id" parameter is found in the route matches. If one is, it is passed as an
238+
argument to `get()`; if not, `getList()` is invoked. In the former case, you
239+
should provide a representation of the given entity with that identification;
240+
in the latter, you should provide a list of entities.
241+
- **POST** maps to `create()`. That method expects a `$data` argument, usually
242+
the `$_POST` superglobal array. The data should be used to create a new
243+
entity, and the response should typically be an HTTP 201 response with the
244+
Location header indicating the URI of the newly created entity and the
245+
response body providing the representation.
246+
- **PUT** maps to `update()`, and requires that an "id" parameter exists in the
247+
route matches; that value is passed as an argument to the method. It should
248+
attempt to update the given entity, and, if successful, return either a 200 or
249+
202 response status, as well as the representation of the entity.
250+
- **DELETE** maps to `delete()`, and requires that an "id" parameter exists in
251+
the route matches; that value is passed as an argument to the method. It
252+
should attempt to delete the given entity, and, if successful, return either a
253+
200 or 204 response status.
254+
255+
Additionally, you can map "action" methods to the `AbstractRestfulController`,
256+
just as you would in the `AbstractActionController`; these methods will be
257+
suffixed with "Action", differentiating them from the RESTful methods listed
258+
above. This allows you to perform such actions as providing forms used to submit
259+
to the various RESTful methods, or to add RPC methods to your RESTful API.
260+
261+
### Interfaces and Collaborators
262+
263+
`AbstractRestfulController` implements each of the following interfaces:
264+
265+
- `Zend\Stdlib\DispatchableInterface`
266+
- `Zend\Mvc\InjectApplicationEventInterface`
267+
- `Zend\ServiceManager\ServiceLocatorAwareInterface` (starting with zend-mvc
268+
2.7.0, only the methods defined by the interface, not the interface itself)
269+
- `Zend\EventManager\EventManagerAwareInterface`
270+
271+
The composed `EventManager` will be configured to listen on the following contexts:
272+
273+
- `Zend\Stdlib\DispatchableInterface`
274+
- `Zend\Mvc\Controller\AbstractRestfulController`
275+
- `Zend\Mvc\Controller\AbstractController`
276+
277+
Additionally, if you extend the class, it will listen on the name of the
278+
extending class.
279+
280+
## AbstractConsoleController
281+
282+
`Zend\Mvc\Controller\AbstractConsoleController` extends from [AbstractActionController](#abstractactioncontroller)
283+
and provides the following functionality:
284+
285+
- The method `setConsole(Zend\Console\Adapter\AdapterInterface $console)` allows
286+
injecting a console adapter representing the current console environment. By
287+
default, the `ControllerManager` will inject this for you as part of
288+
controller instantiation.
289+
- The method `getConsole()` allows you to retrieve the current console adapter
290+
instance, allowing you to retrieve console capabilities and generate console
291+
output.
292+
- The `dispatch()` method will throw an exception if invoked in a non-console
293+
environment, ensuring that you do not need to do any checks within your action
294+
methods for the environment.
295+
296+
### Interfaces and Collaborators
297+
298+
`AbstractRestfulController` implements each of the following interfaces:
299+
300+
- `Zend\Stdlib\DispatchableInterface`
301+
- `Zend\Mvc\InjectApplicationEventInterface`
302+
- `Zend\ServiceManager\ServiceLocatorAwareInterface` (starting with zend-mvc
303+
2.7.0, only the methods defined by the interface, not the interface itself)
304+
- `Zend\EventManager\EventManagerAwareInterface`
305+
306+
The composed `EventManager` will be configured to listen on the following contexts:
307+
308+
- `Zend\Stdlib\DispatchableInterface`
309+
- `Zend\Mvc\Controller\AbstractConsoleController`
310+
- `Zend\Mvc\Controller\AbstractActionController`
311+
- `Zend\Mvc\Controller\AbstractController`
312+
313+
Additionally, if you extend the class, it will listen on the name of the
314+
extending class.

0 commit comments

Comments
 (0)