Update documentation

This commit is contained in:
PJ Dietz 2015-06-13 18:21:30 -04:00
parent 45379ab241
commit fa6fb124ad
3 changed files with 46 additions and 55 deletions

View File

@ -3,7 +3,7 @@ Dependency Injection
WellRESTed strives to play nicely with other code and not force developers into using any specific libraries or frameworks. As such, WellRESTed does not provide a dependency injection container, nor does it require you to use a specific container (or any).
This section describes a handful of ways of making the dependency container of your choice available to middleware with WellRESTed.
This section describes a handful of ways of making dependencies available to middleware.
Request Attribute
^^^^^^^^^^^^^^^^^
@ -28,84 +28,75 @@ When the server dispatches middleware, the middleware will be able to read the c
// It's a super cool dependency container!
}
Callables
^^^^^^^^^
.. note::
Another approach is to use callables that return ``MiddlewareInterface`` instances when you assign middleware. This approach provides an opportunity to pass the container into the middleware's constructor.
This approach is technically more of a `service locator`_ pattern. It's easy to implement, and it allows you the most flexibility in how you assign middleware.
It has some drawbacks as well, though. For example, your middleware is now dependent on your container, and describing which items needs to be **in** the container provides its own challenge.
If your interested in a truer dependency injection approach, read on to the next section where we look at registering middleware factories.
Middleware Factories
^^^^^^^^^^^^^^^^^^^^
Another approach is to use a factory function that returns middleware, usually in the form of a ``MiddlewareInterface`` instance. This approach provides the opportunity to pass dependencies to your middleware's constructor, while still delaying instantiation until the middleware is used.
Imagine a middleware ``FooHandler`` that depends on a ``BarInterface``, and ``BazInterface``.
.. code-block:: php
Class CatHandler implements WellRESTed\MiddlewareInterface
Class FooHandler implements WellRESTed\MiddlewareInterface
{
private $container;
private $bar;
private $baz;
public function __construct($container)
public function __construct(BarInterface $bar, BazInterface $bar)
{
$this->container = $container;
$this->bar = $bar;
$this->baz = $baz;
}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next);
{
// Do something with the $this->container, and make a response.
// Do something with the bar and baz and update the response.
// ...
return $response;
}
}
When you add the middleware to the server or register it with a router, use a callable that passes container into the constructor.
When you add the middleware to the server or register it with a router, you can use a callable that passes appropriate instances into the constructor.
.. code-block:: php
$container = new MySuperCoolDependencyContainer();
$catHandler = function () use ($container) {
return new CatHandler($container);
// Assume $bar and $baz exist in this scope.
$fooHandlerFactory = function () use ($bar, $bar) {
return new FooHandler($bar, $baz);
}
$server = new Server();
$server->add(
$server->createRoute()
->register("GET", "/cats/{cat}", $catHandler)
->register("GET", "/foo/{id}", $fooHandlerFactory)
);
$server->respond();
For extra fun, store the callable that provides the handler in the container. Here's an example using Pimple_).
You can combine this approach with a dependency container. Here's an example using Pimple_).
.. code-block:: php
$c = new Pimple\Container();
$c["catHandler"] = $c->protect(function () use ($c) {
return new CatHandler($c);
$c["bar"] = /* Return a BarInterface */
$c["baz"] = /* Return a BazInterface */
$c["fooHandler"] = $c->protect(function () use ($c) {
return new FooHandler($c["bar"], $c["baz"]);
});
$server = new Server();
$server->add(
$server->createRoute()
->register("GET", "/cats/{cat}", $c["catHandler"])
);
$server->respond();
Combined
^^^^^^^^
Of course these two approaches are not mutually exclusive. You can even obtain your server from the container as well, for good measure.
.. code-block:: php
$c = new Pimple\Container();
$c["server"] = function ($c) {
return new Server(["container" => $c);
};
$c["catHandler"] = $c->protect(function () use ($c) {
return new CatHandler($c);
});
$server = $c["server"];
$server->add(
$server->createRoute()
->register("GET", "/cats/{cat}", $c["catHandler"])
->register("GET", "/foo/{id}", $c["fooHandler"])
);
$server->respond();
.. _Pimple: http://pimple.sensiolabs.org
.. _service locator: https://en.wikipedia.org/wiki/Service_locator_pattern

View File

@ -1,7 +1,7 @@
Extending and Customizing
=========================
WellRESTed is designed with customization in mind. This section will describe some common scenarios for customization, starting with using middleware that implements a different interface.
WellRESTed is designed with customization in mind. This section describes some common scenarios for customization, starting with using middleware that implements a different interface.
Custom Middleware
-----------------

View File

@ -80,7 +80,7 @@ Middleware can be a callable (as in the `Getting Started`_) or an implementation
Using Middleware
^^^^^^^^^^^^^^^^
Methods that accept middleware (e.g., ``Server::add``, ``Router::register``) allow you to provide middleware in a number of ways. For example, when you can provide a callable, a string containing a class name, an instance, or even an array containing a sequence of middleware.
Methods that accept middleware (e.g., ``Server::add``, ``Router::register``) allow you to provide middleware in a number of ways. For example, you can provide a string containing a class name, a middleware callable, a factory callable, or even an array containing a sequence of middleware.
Fully Qualified Class Name (FQCN)
---------------------------------
@ -93,8 +93,8 @@ Assume your Web service has an autoloadable class named ``Webservice\Widgets\Wid
The class is not loaded, and no instances are created, until the route is matched and dispatched. Even for a router with 100 routes, no middleware registered by string name is loaded, except for the one that matches the request.
Callable Provider
-----------------
Factory Callable
----------------
You can also use a callable to instantiate and return a ``MiddlewareInterface`` instance or middleware callable.
@ -104,14 +104,14 @@ You can also use a callable to instantiate and return a ``MiddlewareInterface``
return new \Webservice\Widgets\WidgetHandler();
});
This still delays instantiation, but gives you some added flexibility. For example, you could define middleware that receives some configuration upon construction.
This still delays instantiation, but gives you some added flexibility. For example, you could define middleware that receives some dependencies upon construction.
.. code-block:: php
$container = new MySuperCoolDependencyContainer();
$router->add("GET,PUT,DELETE", "/widgets/{id}", function () use ($container) {
return new \Webservice\Widgets\WidgetHandler($container);
return new \Webservice\Widgets\WidgetHandler($container["foo"], $container["baz"]);
});
This is one approach to `dependency injection`_.
@ -130,10 +130,7 @@ Use a middleware callable directly.
return $next($request, $response);
});
Instance
--------
You can also provide pass an instance directly as middleware.
Because ``WellRESTed\MiddlewareInterface`` has an ``__invoke`` method, implementing instances are also middleware callables. Assuming ``WidgetHandler`` implements ``MiddelewareInterface``, you can do this:
.. code-block:: php
@ -141,7 +138,7 @@ You can also provide pass an instance directly as middleware.
.. warning::
This is simple, but has a significant disadvantage over the other options because each middleware used this way will be loaded and instantiated, even though only one middleware will actually be used for a given request-response cycle. You may find this approach useful for testing, but avoid if for production code.
This is simple, but has a significant disadvantage over the other options because each middleware used this way will be loaded and instantiated, even if it's not needed for a given request-response cycle. You may find this approach useful for testing, but avoid if for production code.
Array
-----
@ -200,14 +197,17 @@ We can add authorization for just the ``/widgets/{id}`` endpoint like this:
.. code-block:: php
$router->register("GET,PUT,DELETE", "/widgets/{id}", [
$server = new \WellRESTed\Server();
$server->add($server->createRouter()
->register("GET,PUT,DELETE", "/widgets/{id}", [
'Webservice\Authorization',
'Webservice\Widgets\WidgetHandler'
]);
])
->respond();
Or, if you wanted to use the authorization for the entire service, you can add it to the ``Server`` in front of the ``Router``.
.. code-block:: php
.. code-block:: php
$server = new \WellRESTed\Server();
$server