From ed4e440390dd8c937557ea84ed38d9d6291fb596 Mon Sep 17 00:00:00 2001 From: Dmitry Vapelnik Date: Wed, 28 Jan 2015 11:06:45 +0200 Subject: [PATCH 1/4] new filters added and documented --- README.md | 33 +++++++++++++ src/RestController.php | 108 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 138 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7ebb875..42609cc 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,39 @@ You need to give the path to the `RAML` file describing your API. You can find a Then, browse your new API REST on the url defined in the `baseUrl` configuration of your `RAML` api file. +## Using request parameters + +You can specify some get request parameters. For example: + +Request param | Description | Type / Example | Default +--------------|--------------|--------------|-------------- +`_start` | specify start bound of selection | `number` | `0` +`_end` | specify end bound of selection | `number` |`20` +`_sort` | specify key ordering | `string` | +`_sortDir` | specify order direction | `ASC`, `DESC` | `ASC` +`_fields` | specify comma separated set of fields in result set | `string` | `*` +`_strongFilter[]` | specify conjunction filter like a ````id` = 8 AND `post_id` = 2``` as request params array | `array` | +`_searchOr[]` | specify search disjunction filter like a ````title` LIKE '%foo%' OR `post` LIKE '%bar%'``` | `array` | +`_searchAnd[]` | specify search conjunction filter like a ````title` LIKE '%foo%' AND `post` LIKE '%bar%'``` | `array` | + +You can combine one of `_strongFilter[]`, `_searchOr[]`, `_searchAnd[]` with `_sort`, `_sortDir`, `_fields`, `_start` and `_end` params + +#### Warning! +You should use **only** one filer from +`_strongFilter[]`, `_searchOr[]`, `_searchAnd[]` or you will get an HTTP error `400 Bad request`. + +### Query string examples + +Query string | Description +-------------|------------ +`/posts?_start=10&_and=15` | you will receive a list from 10 till 15 position from result set +`/posts?_sort=title&_sortDir=DESC` | you will receive a list sorted by `title` descending +`/posts?_fields=id,title` | you will receive a list with `id` and `title` field in response +`/posts?_strongFilter[id]=8&_strongFilter[title]=foo` | you will receive a list of items where ````id` = 8 AND `title` = 'foo'``` +`/posts?_searchOr[title]=foo&_searchOr[body]=bar` | you will receive a list of items where ````title` LIKE '%foo%' OR `body` LIKE '%bar%'``` +`/posts?_searchAnd[title]=foo&_searchAnd[body]=bar` | you will receive a list of items where ````title` LIKE '%foo%' AND `body` LIKE '%bar%'``` +`/posts?_searchAnd[title]=foo&_searchOr[body]=bar` | you will receive HTTP error `400 Bad request` + ## Tests Run the tests suite with the following commands: diff --git a/src/RestController.php b/src/RestController.php index e1faa27..97e1e92 100644 --- a/src/RestController.php +++ b/src/RestController.php @@ -25,11 +25,113 @@ public function homeAction($availableRoutes) public function getListAction($objectType, Request $request) { + // Prepare-prefixes + $strongFilterKeyPrefix = 'strong_filter_'; + $searchOrKeyPrefix = 'search_or_'; + $searchAndKeyPrefix = 'search_and_'; + $queryBuilder = $this->dbal ->createQueryBuilder() - ->select('o.*') - ->from($objectType, 'o') - ; + ->from($objectType, 'o'); + + $filterNames = array( + '_strongFilter', + '_searchOr', + '_searchAnd', + ); + + // Fetching filters from request + $filters = array_combine( + $filterNames, + array_map( + function ($filter) use ($request) { + return $request->query->get($filter); + }, + $filterNames + ) + ); + + // Throw expression when count of filters in request greater then one + $count = array_reduce( + $filters, + function ($carry, $item) { + return $carry + ($item !== null); + }, + 0 + ); + if ($count > 1) { + return new JsonResponse( + array( + 'status' => 'ERROR', + 'status_code' => 400, + 'message' => 'You should use only one type of filters per request', + ), 400 + ); + } + + // Return only assigned fields + $fields = $request->query->get('_fields'); + $queryBuilder->select( + $fields ? preg_replace('/([^,]+)/', 'o.$1', $fields) : 'o.*' + ); + + // Strong filter implementing + // o.f1 = 'val1' AND o.f2 = 'val2' ... + if ($filters['_strongFilter']) { + $queryBuilder + ->where( + implode( + ' and ', + array_map( + function ($item) use ($strongFilterKeyPrefix) { + return "{$item} = :{$strongFilterKeyPrefix}{$item}"; + }, + array_keys($filters['_strongFilter']) + ) + ) + ) + ->setParameters( + array_combine( + array_map( + function ($key) use ($strongFilterKeyPrefix) { + return $strongFilterKeyPrefix . $key; + }, + array_keys($filters['_strongFilter']) + ), + $filters['_strongFilter'] + ) + ); + } + + // Searching with OR: + // o.f1 LIKE '%val1%' OR o.f2 LIKE '%val2%' + if ($filters['_searchOr']) { + foreach ($filters['_searchOr'] as $key => $value) { + $queryBuilder + ->orWhere( + $queryBuilder->expr()->like( + $key, + ":" . $searchOrKeyPrefix . $key + ) + ) + ->setParameter($searchOrKeyPrefix . $key, "%{$value}%"); + } + } + + // Searching with AND: + // o.f1 LIKE '%val1%' AND o.f2 LIKE '%val2%' + if ($filters['_searchAnd']) { + foreach ($filters['_searchAnd'] as $key => $value) { + $queryBuilder + ->andWhere( + $queryBuilder->expr()->like( + $key, + ":" . $searchAndKeyPrefix . $key + ) + ) + ->setParameter($searchAndKeyPrefix . $key, "%{$value}%"); + } + } if ($sort = $request->query->get('_sort')) { $queryBuilder->orderBy($sort, $request->query->get('_sortDir', 'ASC')); From e0985f6ebdb7e6cbe84a10357b14064c5c4543a2 Mon Sep 17 00:00:00 2001 From: Dmitry Vapelnik Date: Mon, 2 Feb 2015 10:51:33 +0200 Subject: [PATCH 2/4] new filters added and documented --- README.md | 2 ++ src/RestController.php | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/README.md b/README.md index 42609cc..f588d53 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ Request param | Description | Type / Example | Default `_strongFilter[]` | specify conjunction filter like a ````id` = 8 AND `post_id` = 2``` as request params array | `array` | `_searchOr[]` | specify search disjunction filter like a ````title` LIKE '%foo%' OR `post` LIKE '%bar%'``` | `array` | `_searchAnd[]` | specify search conjunction filter like a ````title` LIKE '%foo%' AND `post` LIKE '%bar%'``` | `array` | +`_group` | set group part | `string` | You can combine one of `_strongFilter[]`, `_searchOr[]`, `_searchAnd[]` with `_sort`, `_sortDir`, `_fields`, `_start` and `_end` params @@ -68,6 +69,7 @@ Query string | Description `/posts?_strongFilter[id]=8&_strongFilter[title]=foo` | you will receive a list of items where ````id` = 8 AND `title` = 'foo'``` `/posts?_searchOr[title]=foo&_searchOr[body]=bar` | you will receive a list of items where ````title` LIKE '%foo%' OR `body` LIKE '%bar%'``` `/posts?_searchAnd[title]=foo&_searchAnd[body]=bar` | you will receive a list of items where ````title` LIKE '%foo%' AND `body` LIKE '%bar%'``` +`/posts?_group=title` | should use for request distinct values of column instead `/posts?_searchAnd[title]=foo&_searchOr[body]=bar` | you will receive HTTP error `400 Bad request` ## Tests diff --git a/src/RestController.php b/src/RestController.php index 97e1e92..db02773 100644 --- a/src/RestController.php +++ b/src/RestController.php @@ -133,6 +133,10 @@ function ($key) use ($strongFilterKeyPrefix) { } } + if ($group = $request->query->get('_group')) { + $queryBuilder->groupBy($group); + } + if ($sort = $request->query->get('_sort')) { $queryBuilder->orderBy($sort, $request->query->get('_sortDir', 'ASC')); } From 747cb080e456771bc787c540bccc40a04ba8caa1 Mon Sep 17 00:00:00 2001 From: Dmitry Vapelnik Date: Tue, 3 Feb 2015 10:14:16 +0200 Subject: [PATCH 3/4] mistake with "_end" param and typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f588d53..ec7c773 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ You can specify some get request parameters. For example: Request param | Description | Type / Example | Default --------------|--------------|--------------|-------------- `_start` | specify start bound of selection | `number` | `0` -`_end` | specify end bound of selection | `number` |`20` +`_end` | specify **length** of selection | `number` |`20` `_sort` | specify key ordering | `string` | `_sortDir` | specify order direction | `ASC`, `DESC` | `ASC` `_fields` | specify comma separated set of fields in result set | `string` | `*` @@ -63,7 +63,7 @@ You should use **only** one filer from Query string | Description -------------|------------ -`/posts?_start=10&_and=15` | you will receive a list from 10 till 15 position from result set +`/posts?_start=10&_end=15` | you will receive a 15 posts from 10 position as result set `/posts?_sort=title&_sortDir=DESC` | you will receive a list sorted by `title` descending `/posts?_fields=id,title` | you will receive a list with `id` and `title` field in response `/posts?_strongFilter[id]=8&_strongFilter[title]=foo` | you will receive a list of items where ````id` = 8 AND `title` = 'foo'``` From 091e8e598a12a61ec6e6210cfeac5bbf834c6737 Mon Sep 17 00:00:00 2001 From: Dmitry Vapelnik Date: Wed, 4 Feb 2015 12:32:10 +0200 Subject: [PATCH 4/4] new filter `_strongFilterIn[]` added and documented --- README.md | 6 ++++-- src/RestController.php | 13 +++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ec7c773..bb944a5 100644 --- a/README.md +++ b/README.md @@ -49,15 +49,16 @@ Request param | Description | Type / Example | Default `_sortDir` | specify order direction | `ASC`, `DESC` | `ASC` `_fields` | specify comma separated set of fields in result set | `string` | `*` `_strongFilter[]` | specify conjunction filter like a ````id` = 8 AND `post_id` = 2``` as request params array | `array` | +`_strongFilterIn[]` | specify `IN` condition like a ````id` IN (1,2,3)``` | array | `_searchOr[]` | specify search disjunction filter like a ````title` LIKE '%foo%' OR `post` LIKE '%bar%'``` | `array` | `_searchAnd[]` | specify search conjunction filter like a ````title` LIKE '%foo%' AND `post` LIKE '%bar%'``` | `array` | `_group` | set group part | `string` | -You can combine one of `_strongFilter[]`, `_searchOr[]`, `_searchAnd[]` with `_sort`, `_sortDir`, `_fields`, `_start` and `_end` params +You can combine one of `_strongFilter[]`, `_strongFilterIn[]`, `_searchOr[]`, `_searchAnd[]` with `_sort`, `_sortDir`, `_fields`, `_start` and `_end` params #### Warning! You should use **only** one filer from -`_strongFilter[]`, `_searchOr[]`, `_searchAnd[]` or you will get an HTTP error `400 Bad request`. +`_strongFilter[]`, `_strongFilterIn[]`, `_searchOr[]`, `_searchAnd[]` or you will get an HTTP error `400 Bad request`. ### Query string examples @@ -67,6 +68,7 @@ Query string | Description `/posts?_sort=title&_sortDir=DESC` | you will receive a list sorted by `title` descending `/posts?_fields=id,title` | you will receive a list with `id` and `title` field in response `/posts?_strongFilter[id]=8&_strongFilter[title]=foo` | you will receive a list of items where ````id` = 8 AND `title` = 'foo'``` +`/posts?_strongFilterIn[id]=1,2,3` | you will receive a list of items with `id` in list: `1`, `2`, `3` `/posts?_searchOr[title]=foo&_searchOr[body]=bar` | you will receive a list of items where ````title` LIKE '%foo%' OR `body` LIKE '%bar%'``` `/posts?_searchAnd[title]=foo&_searchAnd[body]=bar` | you will receive a list of items where ````title` LIKE '%foo%' AND `body` LIKE '%bar%'``` `/posts?_group=title` | should use for request distinct values of column instead diff --git a/src/RestController.php b/src/RestController.php index db02773..f42f3c8 100644 --- a/src/RestController.php +++ b/src/RestController.php @@ -36,6 +36,7 @@ public function getListAction($objectType, Request $request) $filterNames = array( '_strongFilter', + '_strongFilterIn', '_searchOr', '_searchAnd', ); @@ -118,6 +119,18 @@ function ($key) use ($strongFilterKeyPrefix) { } } + if ($filters['_strongFilterIn']) { + foreach ($filters['_strongFilterIn'] as $key => $value) { + $queryBuilder + ->andWhere( + $queryBuilder->expr()->in( + $key, + explode(',', $value) + ) + ); + } + } + // Searching with AND: // o.f1 LIKE '%val1%' AND o.f2 LIKE '%val2%' if ($filters['_searchAnd']) {