-
-
Notifications
You must be signed in to change notification settings - Fork 848
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
Order filter. #43
Order filter. #43
Conversation
|
||
/** | ||
* @param array $properties List of property names on which the filter will be enabled/disabled. | ||
* @param boolean $type If true properties are passed as a whitelist and as a blacklist otherwise. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really like that behaviour. I would prefer just having $whiteList
and $blackList
as parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you copy the behavior of the new Filter API instead (to preserve consistency): if $properties
is null
, can be filtered on all filters, else it's a whitelist (I don't like blacklists because they are error-prone, you always miss to update the list when refactoring).
Warning1: this is a really painful thing, we shouldn't accept it. @dunglas is there anything in the Hydra specification about it ? Warning2: in my opinion, for sure properties have to be checked, and errors have to be sent to user ! Moreover, that case of multiple filters is quite useful and may be used a lot. |
About warning 1: The Hydra spec is very flexible and doesn't cover such details: http://www.hydra-cg.com/spec/latest/core/#templated-links We must take a design decision about filters. Solution 1 The current one. Everything as root queries like:
Pro:
Con:
Solution 2 Mimic the StrongLoop API:
Pro:
Con:
As solution 1 is the current implementation ( About warning 2: It was a voluntary choice to ignore to ignore invalid query parameters for reasons similar of those explained here: http://stackoverflow.com/questions/15947074/extra-query-parameters-in-the-rest-api-url |
StrongLoop approach is better in my opinion because it is more consistent. You may have different kind of parameters besides filters, and with it you know where to look at without any risk of conflict aside for the filter keyword. Still, StrongLoop works differently: there API by default have lots of filter for instance including embedded relations or where filters on a property of a related entity. This Bundle favor a more strict API exposed to the client. The main problem of the current approach is that it uses as much keywords as special filters. As of now there only the order filter and pages so it's not that much of a problem. So IMO if you deem there will be not much filter such as this one, solution1 is fine. If you fear that they may be more in the future, solution2. Solution 3: don't choose and add an option to use solution2 instead of solution1 with solution1 as default. I do not have the code right know but I guess It would be just the way of retrieving the filters which would change and that would let the current filters unchanged. |
Solution 3 will make maintaining the bundle harder (2 different system to maintain).
|
ping @dunglas and @sroze: update of the PR. I have some issues with the Behat tests but it's really weird because they run fine on local but not on Travis. That being said I Behat tests do not pass anyway. If I do Expected response: {
"@context": "/contexts/Dummy",
"@id": "/dummies",
"@type": "hydra:PagedCollection",
"hydra:nextPage": "/dummies?page=2",
"hydra:totalItems": 30,
"hydra:itemsPerPage": 3,
"hydra:firstPage": "/dummies",
"hydra:lastPage": "/dummies?page=10",
"hydra:member": [...]
} Actual response: {
"@context": "\/contexts\/Dummy",
"@id": "\/dummies?order[id]=asc",
"@type": "hydra:PagedCollection",
"hydra:nextPage": "\/dummies?order%5Bid%5D=asc&page=2",
"hydra:totalItems": 30,
"hydra:itemsPerPage": 3,
"hydra:firstPage": "\/dummies?order%5Bid%5D=asc",
"hydra:lastPage": "\/dummies?order%5Bid%5D=asc&page=10",
"hydra:member": [...]
} |
The actual response looks OK to me. See #57 (the old behavior was incorrect). |
@@ -23,7 +23,8 @@ | |||
"doctrine/inflector": "~1.0", | |||
"doctrine/doctrine-bundle": "~1.2", | |||
"dunglas/php-property-info": "~0.2", | |||
"phpdocumentor/reflection": "^1.0.7" | |||
"phpdocumentor/reflection": "^1.0.7", | |||
"phpunit/phpunit": "~4.6" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The phpunit dependency should be in the require-dev
section.
Okay if you say so, looks ugly though :( |
@@ -0,0 +1,109 @@ | |||
<?php |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add the license header please?
The reason is easy to understand: the return of |
use Symfony\Component\HttpFoundation\Request; | ||
|
||
/** | ||
* Test class for @see Dunglas\ApiBundle\Doctrine\Orm\OrderFilter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Must be {@see TheClass}
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually found the proper annotation: it's @coversDefaultClass
and @covers
. I will change that tomorrow.
Yes it makes sense, but kind of unexpected because I was used to the old one. It's just personal but I find |
], | ||
'SELECT o FROM Dunglas\ApiBundle\Tests\Behat\TestBundle\Entity\Dummy o' | ||
], | ||
// Unkown property unabled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo (enabled?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unabled
in the comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
urg indeed
Thanks for your hard work @theofidry I hope we can merge this one soon. Just some issues left and some doc needed :) |
|
Is the PHPUnit test good? I was not really happy with it when I did it and felt like I missed few things that should be done here. |
IMO using Behat here make more sense and specing the class with PHPSpec instead of PHPUnit would be a better approach must now that you've wrote the test, we can keep it. A test is better than no test :) |
{ | ||
$metadata = $queryBuilder->getEntityManager()->getClassMetadata($resource->getEntityClass()); | ||
$fieldNames = $metadata->getFieldNames(); | ||
$filterList = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way I retrieve $fieldNames
is incorrect or at least getClassMetadata
is quoted as @internal
. Wouldn't it be better to use ReflectionClass
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note for myself: remove unused variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest injecting the manager instead: https://github.com/dunglas/DunglasApiBundle/blob/master/Doctrine/Orm/Filter.php#L167
Maybe can you add an abstract
BaseFilter
class to share logic between Filter
and OrderFilter
classes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gladly.
ping @dunglas could you give it a look again? There is still the |
The main remaining problem IMO is that the API of yout OrderFilter is not coherent with the one of SearchFilter (the second one only has a "all" and "whitelist" mode). |
Is that really an issue? Sure at first it may sound inconsistent, but I hardly see any practical use of a blacklist for a search filter since you have to declare the strategy of the enabled properties anyway. On the contrary the blacklist may come handy when you just want to disable only one or two properties. Only keeping the whitelist would require to keep the list of properties async which may be a pain. |
@dunglas Ok ready for merge :) |
Thank you @theofidry |
Hi @dunglas and @sroze , as promised the order filter rebased!
I added Behat features and modified fixtures to properly test my order filter.
Syntax
The URL query syntax is the same as before:
With
property
the name of the property on which the ordering is done, and the ordering value is case insensitive.Of course it is possible to add multiple ordering filters and in this case the order will be done in the order of declaration.
Warning1
Issue:
Update: Problem ignored. If there is any conflict the user can easily override the filter.
Warning2
Issue:
Update: By default if the property does not exists, it is silently ignored even if has been declared in the configuration.
Declaration
The declaration is done as the following:
Which will enable the ordering filter for the properties
id
andname
.Blacklisting properties
Instead of declaring the list on which we enable the order filter, it is also possible to defined which properties on which the order filter is not enabled. In this case all property with a valid value and not in the blacklist may be passed. The declaration is done by adding the boolean value
false
to the arguments:As you can guess the boolean value is set to
true
by default.Code change/remarks
OrderFilter
OrderFilter
is done in a protected functionapplyFilter()
. This way, if the user use another pattern for URL querying, he can change the way to retrieve values from it without having to change how the filters works, which I guess will be the main reason for which one will override this filter.TODO