TASK: Allow fields and sorting to contain a condition

This way integrators can configure when the sorting and fields should be
added.
This commit is contained in:
Daniel Siepmann 2017-10-29 12:25:25 +01:00
parent d937266bf5
commit bf91c4a5ba
Signed by: Daniel Siepmann
GPG key ID: 33D6629915560EF4
4 changed files with 266 additions and 163 deletions

View file

@ -165,7 +165,10 @@ class QueryFactory
try { try {
$scriptFields = $this->configuration->get('searching.fields.script_fields'); $scriptFields = $this->configuration->get('searching.fields.script_fields');
$scriptFields = $this->replaceArrayValuesWithRequestContent($searchRequest, $scriptFields); $scriptFields = $this->replaceArrayValuesWithRequestContent($searchRequest, $scriptFields);
$scriptFields = $this->filterByCondition($scriptFields);
if ($scriptFields !== []) {
$query = ArrayUtility::arrayMergeRecursiveOverrule($query, ['script_fields' => $scriptFields]); $query = ArrayUtility::arrayMergeRecursiveOverrule($query, ['script_fields' => $scriptFields]);
}
} catch (InvalidArgumentException $e) { } catch (InvalidArgumentException $e) {
// Nothing configured // Nothing configured
} }
@ -175,8 +178,11 @@ class QueryFactory
{ {
$sorting = $this->configuration->getIfExists('searching.sort') ?: []; $sorting = $this->configuration->getIfExists('searching.sort') ?: [];
$sorting = $this->replaceArrayValuesWithRequestContent($searchRequest, $sorting); $sorting = $this->replaceArrayValuesWithRequestContent($searchRequest, $sorting);
$sorting = $this->filterByCondition($sorting);
if ($sorting !== []) {
$query = ArrayUtility::arrayMergeRecursiveOverrule($query, ['sort' => $sorting]); $query = ArrayUtility::arrayMergeRecursiveOverrule($query, ['sort' => $sorting]);
} }
}
protected function addFilter(SearchRequestInterface $searchRequest, array &$query) protected function addFilter(SearchRequestInterface $searchRequest, array &$query)
{ {
@ -254,4 +260,19 @@ class QueryFactory
return $array; return $array;
} }
protected function filterByCondition(array $entries) : array
{
$entries = array_filter($entries, function ($entry) {
return !array_key_exists('condition', $entry) || (bool) $entry['condition'] === true;
});
foreach ($entries as $key => $entry) {
if (array_key_exists('condition', $entry)) {
unset($entries[$key]['condition']);
}
}
return $entries;
}
} }

View file

@ -41,8 +41,8 @@ facets
.. _filter: .. _filter:
``filter`` filter
""""""""""" ------
Used by: While building search request. Used by: While building search request.
@ -107,10 +107,92 @@ fieldValueFactor
missing = 1 missing = 1
} }
.. _mapping.filter:
mapping.filter
--------------
Allows to configure filter more in depth. If a filter with the given key exists, the TypoScript will
be added.
E.g. you submit a filter in form of:
.. code-block:: html
<f:form.textfield property="filter.distance.location.lat" value="51.168098" />
<f:form.textfield property="filter.distance.location.lon" value="6.381384" />
<f:form.textfield property="filter.distance.distance" value="100km" />
This will create a ``distance`` filter with subproperties. To make this filter actually work, you
can add the following TypoScript, which will be added to the filter::
mapping {
filter {
distance {
field = geo_distance
fields {
distance = distance
location = location
}
}
}
}
``fields`` has a special meaning here. This will actually map the properties of the filter to fields
in elasticsearch. In above example they do match, but you can also use different names in your form.
On the left hand side is the elasticsearch field name, on the right side the one submitted as a
filter.
The ``field``, in above example ``geo_distance``, will be used as the elasticsearch field for
filtering. This way you can use arbitrary filter names and map them to existing elasticsearch fields.
.. _fields:
fields
------
Defines the fields to fetch from elasticsearch. Two sub entries exist:
First ``stored_fields`` which is a list of comma separated fields which actually exist and will be
added. Typically you will use ``_source`` to fetch the whole indexed fields.
Second is ``script_fields``, which allow you to configure scripted fields for elasticsearch.
An example might look like the following::
fields {
script_fields {
distance {
condition = {request.filter.distance.location}
script {
params {
lat = {request.filter.distance.location.lat -> f:format.number()}
lon = {request.filter.distance.location.lon -> f:format.number()}
}
lang = painless
inline = doc["location"].arcDistance(params.lat,params.lon) * 0.001
}
}
}
}
In above example we add a single ``script_field`` called ``distance``. We add a condition when this
field should be added. The condition will be parsed as Fluidtemplate and is casted to bool via PHP.
If the condition is true, or no ``condition`` exists, the ``script_field`` will be added to the
query. The ``condition`` will be removed and everything else is submitted one to one to
elasticsearch, except each property is run through Fluidtemplate, to allow you to use information
from search request, e.g. to insert latitude and longitude from a filter, like in the above example.
.. _sort:
sort
----
Sort is handled like :ref:`fields`.
.. _mode: .. _mode:
``mode`` mode
"""""""" ----
Used by: Controller while preparing action. Used by: Controller while preparing action.