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:
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