partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

commit 9f7bcee50e45a01144fe28ed5616213c0e1e6192
parent fc2d74aac6a6ee6b63cae6d057784ae5e7359fde
Author: Felicitus <felicitus@felicitus.org>
Date:   Mon, 20 Jul 2015 00:13:11 +0200

Added implementation for multiple order by clauses as well as ordering by associations

Diffstat:
Mapp/config/config.yml | 21+++++++++------------
Msrc/PartKeepr/DoctrineReflectionBundle/Filter/AdvancedSearchFilter.php | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/PartKeepr/FrontendBundle/Resources/public/js/Data/HydraProxy.js | 21+--------------------
3 files changed, 104 insertions(+), 34 deletions(-)

diff --git a/app/config/config.yml b/app/config/config.yml @@ -139,9 +139,6 @@ services: - "@annotation_reader" - "@property_accessor" tags: [ { name: "kernel.event_listener", event: "api.pre_update", method: "replaceTemporaryImage" }, { name: "kernel.event_listener", event: "api.pre_create", method: "replaceTemporaryImage" } ] - resource.order_filter: - parent: "api.doctrine.orm.order_filter" - arguments: [ ~ ] # This line can also be omitted resource.distributor: parent: "api.resource" @@ -149,7 +146,7 @@ services: tags: [ { name: "api.resource" } ] calls: - method: "initFilters" - arguments: [ [ "@resource.order_filter" ] ] + arguments: [ [ "@doctrine_reflection_service.search_filter" ] ] - method: "initNormalizationContext" arguments: [ { groups: [ "default" ] } ] - method: "initDenormalizationContext" @@ -162,7 +159,7 @@ services: tags: [ { name: "api.resource" } ] calls: - method: "initFilters" - arguments: [ [ "@resource.order_filter", "@doctrine_reflection_service.search_filter" ] ] + arguments: [ [ "@doctrine_reflection_service.search_filter" ] ] - method: "initNormalizationContext" arguments: [ { groups: [ "default" ] } ] - method: "initDenormalizationContext" @@ -175,7 +172,7 @@ services: tags: [ { name: "api.resource" } ] calls: - method: "initFilters" - arguments: [ [ "@resource.order_filter" ] ] + arguments: [ [ "@doctrine_reflection_service.search_filter" ] ] - method: "initNormalizationContext" arguments: [ { groups: [ "default" ] } ] - method: "initDenormalizationContext" @@ -226,7 +223,7 @@ services: - method: "initItemOperations" arguments: [ [ "@resource.footprint_attachment.item_operation.get", "@resource.footprint_attachment.item_operation.custom_get", "@resource.footprint_attachment.item_operation.custom_get_mime" ] ] - method: "initFilters" - arguments: [ [ "@resource.order_filter" ] ] + arguments: [ [ "@doctrine_reflection_service.search_filter" ] ] - method: "initNormalizationContext" arguments: [ { groups: [ "default" ] } ] - method: "initDenormalizationContext" @@ -285,7 +282,7 @@ services: tags: [ { name: "api.resource" } ] calls: - method: "initFilters" - arguments: [ [ "@resource.order_filter" ] ] + arguments: [ [ "@doctrine_reflection_service.search_filter" ] ] - method: "initNormalizationContext" arguments: [ { groups: [ "default" ] } ] - method: "initDenormalizationContext" @@ -327,7 +324,7 @@ services: - method: "initItemOperations" arguments: [ [ "@resource.manufacturer_ic_logo.item_operation.custom_get", "@resource.manufacturer_ic_logo.item_operation.get", "@resource.manufacturer_ic_logo.item_operation.put" ] ] - method: "initFilters" - arguments: [ [ "@resource.order_filter" ] ] + arguments: [ [ "@doctrine_reflection_service.search_filter" ] ] - method: "initNormalizationContext" arguments: [ { groups: [ "default" ] } ] - method: "initDenormalizationContext" @@ -368,7 +365,7 @@ services: - method: "initItemOperations" arguments: [ [ "@resource.partmeasurementunit.item_operation.custom_put", "@resource.partmeasurementunit.item_operation.get", "@resource.partmeasurementunit.item_operation.put" ] ] - method: "initFilters" - arguments: [ [ "@resource.order_filter", "@doctrine_reflection_service.search_filter" ] ] + arguments: [ [ "@doctrine_reflection_service.search_filter" ] ] - method: "initNormalizationContext" arguments: [ { groups: [ "default" ] } ] - method: "initDenormalizationContext" @@ -382,7 +379,7 @@ services: tags: [ { name: "api.resource" } ] calls: - method: "initFilters" - arguments: [ [ "@resource.order_filter", "@doctrine_reflection_service.search_filter" ] ] + arguments: [ [ "@doctrine_reflection_service.search_filter" ] ] - method: "initNormalizationContext" arguments: [ { groups: [ "default" ] } ] - method: "initDenormalizationContext" @@ -395,7 +392,7 @@ services: tags: [ { name: "api.resource" } ] calls: - method: "initFilters" - arguments: [ [ "@resource.order_filter", "@doctrine_reflection_service.search_filter" ] ] + arguments: [ [ "@doctrine_reflection_service.search_filter" ] ] - method: "initNormalizationContext" arguments: [ { groups: [ "default" ] } ] - method: "initDenormalizationContext" diff --git a/src/PartKeepr/DoctrineReflectionBundle/Filter/AdvancedSearchFilter.php b/src/PartKeepr/DoctrineReflectionBundle/Filter/AdvancedSearchFilter.php @@ -93,7 +93,9 @@ class AdvancedSearchFilter extends AbstractFilter $metadata = $this->getClassMetadata($resource); $fieldNames = array_flip($metadata->getFieldNames()); - $filters = $this->extractProperties($request); + $properties = $this->extractProperties($request); + $filters = $properties["filters"]; + $sorters = $properties["sorters"]; foreach ($filters as $filter) { if (isset($fieldNames[$filter["property"]]) && $filter["association"] === null) { @@ -115,6 +117,15 @@ class AdvancedSearchFilter extends AbstractFilter ); } } + + foreach ($sorters as $sorter) { + if ($sorter["association"] !== null) { + // Pull in associations + $this->addJoins($queryBuilder, $sorter); + } + + $this->applyOrderByExpression($queryBuilder, $sorter); + } } /** @@ -173,6 +184,7 @@ class AdvancedSearchFilter extends AbstractFilter /** * Returns the expression for a specific filter. + * * @param QueryBuilder $queryBuilder * @param $filter * @@ -227,6 +239,26 @@ class AdvancedSearchFilter extends AbstractFilter } /** + * Returns the expression for a specific sort order. + * + * @param QueryBuilder $queryBuilder + * @param $sorter + * + * @return \Doctrine\ORM\Query\Expr\Comparison|\Doctrine\ORM\Query\Expr\Func + * @throws \Exception + */ + private function applyOrderByExpression(QueryBuilder $queryBuilder, $sorter) + { + if ($sorter["association"] !== null) { + $alias = $this->getAlias("o.".$sorter["association"]).".".$sorter["property"]; + } else { + $alias = "o.".$sorter["property"]; + } + + return $queryBuilder->orderBy($alias, $sorter["direction"]); + } + + /** * {@inheritdoc} */ protected function extractProperties(Request $request) @@ -245,7 +277,21 @@ class AdvancedSearchFilter extends AbstractFilter } } - return $filters; + $sorters = array(); + + if ($request->query->has("order")) { + $data = json_decode($request->query->get("order")); + + if (is_array($data)) { + foreach ($data as $sorter) { + $sorters[] = $this->extractJSONSorters($sorter); + } + } elseif (is_object($data)) { + $sorters[] = $this->extractJSONSorters($data); + } + } + + return array("filters" => $filters, "sorters" => $sorters); } /** @@ -310,4 +356,50 @@ class AdvancedSearchFilter extends AbstractFilter return $filter; } + + /** + * Extracts the sorters from the JSON object. + * + * @param $data + * + * @return array An array containing the property, operator and value keys + * @throws \Exception + */ + private function extractJSONSorters($data) + { + $sorter = array(); + + if ($data->property) { + if (strpos($data->property, ".") !== false) { + $associations = explode(".", $data->property); + + $property = array_pop($associations); + + $sorter["association"] = implode(".", $associations); + $sorter["property"] = $property; + } else { + $sorter["association"] = null; + $sorter["property"] = $data->property; + } + + } else { + throw new \Exception("You need to set the filter property"); + } + + if ($data->direction) { + switch (strtoupper($data->direction)) { + case "DESC": + $sorter["direction"] = "DESC"; + break; + case "ASC": + default: + $sorter["direction"] = "ASC"; + break; + } + } else { + $sorter["direction"] = "ASC"; + } + + return $sorter; + } } diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Data/HydraProxy.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Data/HydraProxy.js @@ -11,7 +11,7 @@ Ext.define("PartKeepr.data.HydraProxy", { appendId: false, limitParam: "itemsPerPage", defaultListenerScope: true, - sortParam: "", + sortParam: "order", constructor: function (config) { @@ -51,25 +51,6 @@ Ext.define("PartKeepr.data.HydraProxy", { return this.callParent([request]); }, - getParams: function (operation) - { - if (!operation.isReadOperation) { - return {}; - } - - var params = this.callParent(arguments); - var out = [], - i, - sorters = operation.getSorters(); - - if (sorters) { - for (i = 0; i < operation.getSorters().length; i++) { - params["order[" + sorters[i].getProperty() + "]"] = sorters[i].getDirection(); - } - } - - return params; - }, /** * Calls a specific action on the record. * @todo Document on how we call actions on entities