ResourcesΒΆ
In order to perist resources or retrieve resources to represent, PhlyRestfully
uses a PhlyRestfully\Resource
instance. This class simply triggers an event
based on the operation requested; you, as a developer, provide and attach
listeners to those events to do the actual work.
PhlyRestfully\Resource
defines the following events, with the following
event parameters:
Event name | Parameters |
---|---|
create |
|
update |
|
replaceList |
|
patch |
|
delete |
|
deleteList |
|
fetch |
|
fetchAll | |
Event listeners receive an instance of PhlyRestfully\ResourceEvent
, which
also composes the route matches and query parameters from the request. You may
retrieve them from the event instance using the following methods:
getQueryParams()
(returns aZend\Stdlib\Parameters
instance)getRouteMatch()
(returns aZend\Mvc\Router\RouteMatch
instance)getQueryParam($name, $default = null)
getRouteParam($name, $default = null)
Within your listeners, you have the option of throwing an exception in order to
raise an ApiProblem
response. The following maps events to the special
exceptions you can raise; all exceptions are in the PhlyRestfully\Exception
namespace, except where globally qualified:
Event name | Parameters |
---|---|
create | CreationException |
update | UpdateException |
replaceList | UpdateException |
patch | PatchException |
delete | \Exception |
deleteList | \Exception |
fetch | \Exception |
fetchAll | \Exception |
Additionally, if you throw any exception implementing
PhlyRestfully\Exception\ProblemExceptionInterface
, it can be used to seed an
ApiProblem
instance with the appropriate information. Such an exception
needs to define the following methods:
- getAdditionalDetails(), which should return a string or array.
- getDescribedBy(), which should return a URI for the “describedBy” field.
- getTitle(), which should return a string for the “title” field.
The exception code and message will be used for the “httpStatus” and “detail”, respectively.
The CreationException
, UpdateException
, and PatchException
types all
inherit from DomainException
, which implements the
ProblemExceptionInterface
.
As a quick example, let’s look at two listeners, one that listens on the
create
event, and another on the fetch
event, in order to see how we
might handle them.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | // listener on "create"
function ($e) {
$data = $e->getParam('data');
// Assume an ActiveRecord-like pattern here for simplicity
$user = User::factory($data);
if (!$user->isValid()) {
$ex = new CreationException('New user failed validation', 400);
$ex->setAdditionalDetails($user->getMessages());
$ex->setDescibedBy('http://example.org/api/errors/user-validation');
$ex->setTitle('Validation error');
throw $ex;
}
$user->persist();
return $user;
}
// listener on "fetch"
function ($e) {
$id = $e->getParam('id');
// Assume an ActiveRecord-like pattern here for simplicity
$user = User::fetch($id);
if (!$user) {
$ex = new DomainException('User not found', 404);
$ex->setDescibedBy('http://example.org/api/errors/user-not-found');
$ex->setTitle('User not found');
throw $ex;
}
return $user;
}
|
Typically, you will create a Zend\EventManager\ListenerAggregateInterface
implementation that will contain all of your listeners, so that you can also
compose in other classes such as data mappers, a service layer, etc. Read about
listener aggregates in the ZF2 documentation
if you are unfamiliar with them.
In a later section, I will show you how to wire your listener aggregate to a resource and resource controller.