diff --git a/docs/07. Cookbook.md b/docs/07. Cookbook.md index 72f80c0..4a6786e 100644 --- a/docs/07. Cookbook.md +++ b/docs/07. Cookbook.md @@ -229,6 +229,64 @@ Then, define specific routes in your config files: > Please note the priority parameter. This is used so that those routes are actually evaluated BEFORE any REST routes. +## How to call custom repository methods? + +ZfrRest uses the Doctrine Criteria API to automatically traverses the route hierarchy, and matching the sub-paths. While +very powerful and flexible (it can work either in ORM or ODM), it lacks advanced features like joins or fancy filtering +like full text filtering or geospatial filtering. For cases like that or for very performance sensitive queries that +cannot be done using the criteria API, the best solution is to use custom repositories with hand-written DQL (or even +SQL). + +ZfrRest does not provide any way to do that automatically, but it can be done very easily. Let's imagine that you want +to filter FourSquare "check-ins" by geolocation. Here is your controller (we assume mapping and routes are properly +defined): + +```php +use ZfrRest\Mvc\Controller\AbstractRestfulController; + +class CheckInListController extends AbstractRestfulController +{ + public function get(Selectable $checkIns) + { + $latitude = $this->params()->fromQuery('latitude'); + $longitude = $this->params()->fromQuery('longitude'); + + // What to do? + } +} +``` + +ZfrRest has properly routed the request to the right controller, and as for any ZfrRest controllers, you receive the +checkins as a parameter. A nice side-effect of Criteria API is that, at this point, the query *has not been done* to +the database, which gives us a chance to use our custom service: + +```php +use ZfrRest\Mvc\Controller\AbstractRestfulController; + +class CheckInListController extends AbstractRestfulController +{ + protected $checkInService; + + public function __construct(CheckInService $checkInService) + { + $this->checkInService = $checkInService; + } + + public function get(Selectable $checkIns) + { + $latitude = $this->params()->fromQuery('latitude'); + $longitude = $this->params()->fromQuery('longitude'); + + // The service can in turn call an optimized query from the repository + $checkIns = $this->checkInService->getByCoordinates($latitude, $longitude); + + return $this->resourceModel($checkIns); + } +} +``` + +Your service can either returns a Collection or a Paginator, the resource renderer will take care of that for you! + ## Tuning ZfrRest for production For maximum performance, here are a few best practices: @@ -244,6 +302,10 @@ change the cache option to use something like APC: ] ``` +### Using cache + +We need to wait Doctrine 2.5 for that. But I promise, that will be truly awesome. + ### Navigation * Continue to [the **Mapping reference**](/docs/08. Mapping reference.md) diff --git a/docs/README.md b/docs/README.md index 7eb92b7..26f7dc2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -30,22 +30,22 @@ If you are looking for some information that is not listed in the documentation, 5. [Configuring input filters based on context](/docs/04. Controllers.md#configuring-input-filters-based-on-context) 5. [Built-in listeners](/docs/05. Built-in listeners.md) - 1. [CreateResourceModelListener](/docs/05. Built-in listeners.md) - 2. [HttpExceptionListener](/docs/05. Built-in listeners.md) - 3. [HttpMethodOverrideListener](/docs/05. Built-in listeners.md) + 1. [HttpExceptionListener](/docs/05. Built-in listeners.md#httpexceptionlistener) + 2. [HttpMethodOverrideListener](/docs/05. Built-in listeners.md#httpmethodoverridelistener) 6. [View layer](/docs/06. View layer.md) - 1. [Customizing output](/docs/06. View layer.md) + 1. [The DefaultResourceRenderer](/docs/06. View layer.md#the-defaultresourcerenderer) + 1. [Creating a custom renderer](/docs/06. View layer.md#creating-a-custom-renderer) 7. [Cookbook](/docs/07. Cookbook.md) - 1. [How to implement the OPTIONS method?](/docs/07. Cookbook.md) - 2. [How to customize the payload?](/docs/07. Cookbook.md) - 3. [How to specify a custom hydrator?](/docs/07. Cookbook.md) - 4. [How to specify a custom input filter?](/docs/07. Cookbook.md) - 5. [How to filter a collection using query params?](/docs/07. Cookbook.md) - 6. [How to serialize custom data that do not belong to the entity?](/docs/07. Cookbook.md) - 7. [How to deal with actions?](/docs/07. Cookbook.md) - 8. [Tuning ZfrRest for production](/docs/07. Cookbook.md) + 1. [How to implement the OPTIONS method?](/docs/07. Cookbook.md#how-to-implement-the-options-method) + 2. [How to customize the payload?](/docs/07. Cookbook.md#how-to-customize-the-payload-like-removing-specific-fields) + 3. [How to specify a custom input filter?](/docs/07. Cookbook.md#how-to-specify-a-custom-input-filter) + 4. [How to filter a collection using query params?](/docs/07. Cookbook.md#how-to-filter-a-collection-using-query-params) + 5. [How to serialize custom data that do not belong to the entity?](/docs/07. Cookbook.md#how-to-serialize-custom-data-that-do-not-belong-to-the-entity) + 6. [How to deal with actions?](/docs/07. Cookbook.md#how-to-deal-with-actions) + 7. [How to call custom repository methods?](/docs/07. Cookbook.md#how-to-call-custom-repository-methods) + 8. [Tuning ZfrRest for production](/docs/07. Cookbook.md#tuning-zfrrest-for-production) 8. [Mapping reference](/docs/08. Mapping reference.md) 1. [Annotations](/docs/08. Mapping reference.md)