Service actions are responsible for handling what behaviours occur during a request.
Drest comes with a number of default service actions that are triggered unless a custom action is specified on the @Drest\Route annotation. The default action is determined on the HTTP verb used, and whether the matched route is a collection or element endpoint (ie user vs users).
All default behaviours operate directly on doctrine’s entity manager. Pull requests [GET] have their data fetched using doctrine’s array hydration for speed. This means that it’s the persisted data that is exposed to your endpoint. So any any tranformations / augmentations you may have written into lifecycle events on your entities will not be executed. If you need to manipulate the data from it’s persisted state before sending to the user you may have to create your own custom service action.
Error handling..
@Drest\Route(
name="get_user",
routePattern="/user/:id",
verbs={"GET"}
)
@Drest\Route(
name="get_users",
routePattern="/users",
verbs={"GET"},
collection=true
)
@Drest\Route(
name="post_user",
routePattern="/user",
verbs={"POST"}
)
@Drest\Route(
name="update_user",
routePattern="/user/:id",
verbs={"PUT", "PATCH"}
)
@Drest\Route(
name="delete_user",
routePattern="/user/:id",
verbs={"DELETE"}
)
@Drest\Route(
name="delete_user",
routePattern="/users",
verbs={"DELETE"},
collection=true
)
You very easily build your own service actions by extending the \Drest\Service\Action\AbstractAction class. You must then implement the method execute().
There are a number of objects at your disposal. You can use the entity manger to start constructing queries, inspect the request, manipulate the response object and more.
namespace Action;
class Custom extends \Drest\Service\Action\AbstractAction
{
public function execute()
{
// Get the Doctrine Entity Manager (Doctrine\ORM\EntityManager)
$this->service->getEntityManager();
// Get Drest Manager (Drest\Manager)
$this->service->getDrestManager();
// Get the request object (Drest\Request)
$this->service->getRequest();
// Get the response object (Drest\Response)
$this->service->getResponse();
// Get the route that was matched (Drest\Mapping\RouteMetaData)
$this->service->getMatchedRoute();
// Get the representation type that's required - XML / JSON (Drest\Representation\AbstractRepresentation)
$this->service->getRepresentation();
// .. execute my own logic, return a custom result set ..
return ResultSet::create(array('name' => 'lee', 'email' => 'lee@somedomain.com'), 'user');
}
}
Once you’ve created your class you simply need to register it on the service action registry when setting up your drest manager. Note that you must use the fully qualified class name of your entity class (include namespace).
$customAction = new Action\Custom()
$actionRegistry = new Drest\Service\Action\Registry();
$actionRegistry->register(
$customAction,
['Entities\User::get_user']
);
$drestManager = \Drest\Manager::create($emr, $drestConfig, $evm, $actionRegistry);
// Alternatively you can register / unregister service actions at any point using the drest manager
// Remove this action and all routes that are registered to use it
$drestManager->getServiceActionRegistry()->unregisterByAction($customAction);
// Remove any registered action for this route
$drestManager->getServiceActionRegistry()->unregisterByRoute('Entities\User::get_user');
Even though you could directly manipulate the response object, if the execute method returns an object of type \Drest\Query\ResultSet then this is automatically written to the document body in requested representation. Any other return types are ignored.
When creating a custom pull action [GET] you may still want to adhere to the expose filtering that you set up, or the client has requested. On the matched route object will be a pre-determined expose array which you’ll need to apply to your query builder instance.
This can be done using the method registerExpose($exposeArray, $queryBuilder, $doctrineORMMetaData).
$classMetaData = $this->getMatchedRoute()->getClassMetaData();
$elementName = $classMetaData->getEntityAlias();
// Note this will return the default entity manager.
$em = $this->getEntityManager();
$qb = $this->registerExpose(
$this->getMatchedRoute()->getExpose(),
$em->createQueryBuilder()->from($classMetaData->getClassName(), $elementName),
$em->getClassMetadata($classMetaData->getClassName())
);
The example above will fetch the default entity manager that was registered with \Drest\EntityManagerRegistry. If you have multiple entity managers or connection resources within your application then you can retrieve the one you require like so:
$this->getEntityManagerRegistry()->getManager({name you registered it with})
For PUT/PATCH/POST requests that have a handle function registered then you may want to trigger this from your service action. To so this simply pass in your entity object instance into the runHandle($entity) method. If a handle isn’t registered, nothing will be called.
// this can be either an newly created instance of the entity object,
// or one fetched through the doctrine entity manager using "ORM\Query::HYDRATE_OBJECT"
$this->runHandle($object);
Note: The default “postElement” action will instantiate an instance of your entity, be sure not to mix behaviours in a handle method that should go into __construct().