Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/filters #100

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open

Feature/filters #100

wants to merge 15 commits into from

Conversation

srottem
Copy link

@srottem srottem commented Sep 18, 2016

Hi Nil,

Let me try this again: I've been working up a filtering scheme that uses RQL in the filter request parameter to populate the eloquent query used by the controller index method with where clauses. For example, the request string could contain something like the following:

filter=and(or(and(like(name,b_),ne(name,bob),like(name,a_)),eq(size,10))

There are other ways of expressing this using RQL, but this will do for an example. At the moment I'm supporting all the standard scalar checks (eq, gt, ge, lt, le, ne) as well as null checks, array checks (in, out) and the logical 'and' and 'or' operators in groups (not is unsupported because I can't figure out how to map it to an Eloquent query builder).

The implementation I've thrown together is using the xiag-ag/rql-parser (https://github.com/xiag-ag/rql-parser) to parse the content of the filter parameter passed on in the request string and then uses a class I've added named EloquentNodeVisitor to add where clauses to the eloquent query builder.

My implementation does kind of break your approach to handling the filter parameter (based, I assume on the recommendation on the jsonapi website) since I want to have a single RQL filter rather than a filter per field. Since the current implementation of your json-api package exposes the filter through the Request->getFilters and this always returns an array it posed an issue with obtaining the RQL and still getting correctly formed links in the response. As a workaround the JsonApiController now converts the result from getFilters to a string or a null - it might be better to change this in the json-api package instead but I didn't know whether this approach made sense to you so I've just hacked it for now.

Let me know if you want anything further clarified.

Symon.

@@ -136,6 +136,18 @@ public function getOrdersByEmployee($id)
$sorting = $apiRequest->getSort();
$included = $apiRequest->getIncludedRelationships();
$filters = $apiRequest->getFilters();

//HACK: JsonAPI is specifying this as an array but it should be a string at this point for RQL processing.
switch(count($filters)){

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Spaces must be used to indent lines; tabs are not allowed
  • Expected 1 space after SWITCH keyword; 0 found
  • Expected 1 space after closing parenthesis; found 0


//HACK: JsonAPI is specifying this as an array but it should be a string at this point for RQL processing.
switch(count($filters)){
case 0:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed

//HACK: JsonAPI is specifying this as an array but it should be a string at this point for RQL processing.
switch(count($filters)){
case 0:
$filters = null;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed

switch(count($filters)){
case 0:
$filters = null;
break;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed

case 0:
$filters = null;
break;
case 1:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed

$filters = null;
break;
case 1:
$filters = $filters[0];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed

break;
case 1:
$filters = $filters[0];
break;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed

case 1:
$filters = $filters[0];
break;
default:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed

$filters = $filters[0];
break;
default:
throw new \Exception('Only a single filter is supported at present.');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed

break;
default:
throw new \Exception('Only a single filter is supported at present.');
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitespace found at end of line


public function getRequiredProperties()
{
return [];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed


public function getRequiredProperties()
{
return [];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed


public function testListActionCanFilter()
{
$this->call('GET', 'http://localhost/employees?filter=ne(a,b)');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed

public function testListActionCanFilter()
{
$this->call('GET', 'http://localhost/employees?filter=ne(a,b)');
$response = $this->response;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed

$this->call('GET', 'http://localhost/employees?filter=ne(a,b)');
$response = $this->response;

$this->assertEquals(200, $response->getStatusCode());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed

$response = $this->response;

$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('application/vnd.api+json', $response->headers->get('Content-type'));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed


$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('application/vnd.api+json', $response->headers->get('Content-type'));
$this->assertContains('&filter=ne(a,b)', $response->getContent());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces must be used to indent lines; tabs are not allowed

@srottem
Copy link
Author

srottem commented Sep 18, 2016

Oh, and I forgot to mention that the 'like' operator is also supported using RQL glob syntax.

…t\QueryBuilder in order to potentially support more possible calls. Also reorganized logical node handling to facilitate future implementation of 'not()' RQL clause.
throw new \Exception('Only a single filter is supported at present.');
}

$resource = new ListResource($this->serializer, $page, $fields, $sorting, $included, urlencode($filters));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitespace found at end of line

@@ -45,10 +47,11 @@ public function index()
$fields = $apiRequest->getFields();
$sorting = $apiRequest->getSort();
$included = $apiRequest->getIncludedRelationships();
$filters = $apiRequest->getFilters();
$filters = $apiRequest->getRawFilter();
Copy link
Author

@srottem srottem Sep 24, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getRawFilter has been implemented on a modified version of the php-json-api package that I've rolled which returns the entire and unmodified text of the filter parameter in the URL. The method uses the $_SERVER['QUERY_STRING'] value to obtain the value as the ServerRequestInterface object's getQueryParams() method has run the values through urldecode which makes returning original filters provided by the user in URLs generated by the controller near impossible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants