Skip to content

Commit

Permalink
Merge pull request #89 from asev/sorting_fields
Browse files Browse the repository at this point in the history
Sort by multiple fields
  • Loading branch information
Mantas Urnieža committed Jun 15, 2015
2 parents 124ec0d + 143f726 commit 6278e68
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 16 deletions.
34 changes: 26 additions & 8 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,22 @@ private function buildFilterTree($filterName)
->arrayNode('choices')
->prototype('array')
->beforeNormalization()
->ifTrue(
->always(
function ($v) {
return empty($v['label']);
}
)
->then(
function ($v) {
$v['label'] = $v['field'];
if (empty($v['fields']) && !empty($v['field'])) {
$field = ['field' => $v['field']];
if (array_key_exists('order', $v)) {
$field['order'] = $v['order'];
}
if (array_key_exists('mode', $v)) {
$field['mode'] = $v['mode'];
}
$v['fields'][] = $field;
}

if (empty($v['label'])) {
$v['label'] = $v['fields'][0]['field'];
}

return $v;
}
Expand All @@ -197,11 +205,21 @@ function ($v) {
->addDefaultsIfNotSet()
->children()
->scalarNode('label')->end()
->scalarNode('field')->isRequired()->end()
->scalarNode('field')->end()
->scalarNode('order')->defaultValue('asc')->end()
->scalarNode('mode')->defaultNull()->end()
->scalarNode('key')->info('Custom parameter value')->end()
->booleanNode('default')->defaultFalse()->end()
->arrayNode('fields')
->isRequired()
->requiresAtLeastOneElement()
->prototype('array')
->children()
->scalarNode('field')->isRequired()->end()
->scalarNode('order')->defaultValue('asc')->end()
->scalarNode('mode')->defaultNull()->end()
->end()
->end()
->end()
->end()
->end()
Expand Down
18 changes: 10 additions & 8 deletions Filters/Widget/Sort/Sort.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@ class Sort extends AbstractSingleRequestValueFilter implements ViewDataFactoryIn
public function modifySearch(Search $search, FilterState $state = null, SearchRequest $request = null)
{
if ($state && $state->isActive()) {
$search->addSort(
new EsSort(
$this->choices[$state->getValue()]['field'],
$this->choices[$state->getValue()]['order'],
null,
$this->choices[$state->getValue()]['mode']
)
);
$stateValue = $state->getValue();

if (!empty($this->choices[$stateValue]['fields'])) {
foreach ($this->choices[$stateValue]['fields'] as $sortField) {
$search->addSort(new EsSort($sortField['field'], $sortField['order'], null, $sortField['mode']));
}
} else {
$sortField = $this->choices[$stateValue];
$search->addSort(new EsSort($sortField['field'], $sortField['order'], null, $sortField['mode']));
}
} else {
foreach ($this->choices as $choice) {
if ($choice['default']) {
Expand Down
17 changes: 17 additions & 0 deletions Resources/doc/filter/sort.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,22 @@ After which you can specify multiple sort options/choices:
+------------------------+--------------------------------------------------------------------+
| `mode` | For any arrays: `min`, `max`, for numeric arrays `avg`, `sum`. |
+------------------------+--------------------------------------------------------------------+
| `fields` | Array of fields to sort on. For more information see table below. |
+------------------------+--------------------------------------------------------------------+

.. note:: `field`, `order`, and `mode` are ignored if at least one of fields is defined.

Each object in `fields` array specifies sorting condition. Available parameters are defined below:

+------------------------+--------------------------------------------------------------------+
| Setting name | Meaning |
+========================+====================================================================+
| `field` | Specifies the field in repository to sort on. (e.g. `item_color`) |
+------------------------+--------------------------------------------------------------------+
| `order` | Order to sort by. Default `asc`. Valid values: `asc`, `desc`. |
+------------------------+--------------------------------------------------------------------+
| `mode` | For any arrays: `min`, `max`, for numeric arrays `avg`, `sum`. |
+------------------------+--------------------------------------------------------------------+

Example:

Expand All @@ -83,6 +99,7 @@ Example:
choices:
- { label: Color ascending, field: item_color, default: true }
- { label: Color descending, field: item_color, order: desc }
- { label: 'In stock & cheap', fields: [{field: stock, order: desc}, {field: price}] }
..
Expand Down
36 changes: 36 additions & 0 deletions Tests/Unit/DependencyInjection/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,34 @@ public function getTestConfigurationData()
$expectedConfig['filters']['sort']['sorting']['choices'][0]['default'] = false;
$expectedConfig['filters']['sort']['sorting']['choices'][0]['order'] = 'asc';
$expectedConfig['filters']['sort']['sorting']['choices'][0]['mode'] = null;
$expectedConfig['filters']['sort']['sorting']['choices'][0]['fields'][0]['field'] = 'test';
$expectedConfig['filters']['sort']['sorting']['choices'][0]['fields'][0]['order'] = 'asc';
$expectedConfig['filters']['sort']['sorting']['choices'][0]['fields'][0]['mode'] = null;
unset($customConfig['filters']['document_field']);
unset($customConfig['filters']['multi_choice']);
unset($customConfig['filters']['fuzzy']);
$cases[] = [
$customConfig,
$expectedConfig,
];

// Case #3 sorting by multiple fields.
$customConfig = $expectedBaseConfig;
$customConfig['filters']['sort']['sorting']['choices'][0]['fields'][0]['field'] = 'price';
$customConfig['filters']['sort']['sorting']['choices'][0]['fields'][1]['field'] = 'date';
$customConfig['filters']['sort']['sorting']['choices'][0]['fields'][1]['order'] = 'desc';
$expectedConfig = $customConfig;
$expectedConfig['filters']['choice'] = ['single_choice' => ['request_field' => 'choice', 'tags' => ['badged']]];
$expectedConfig['filters']['sort']['sorting']['choices'][0]['label'] = 'price';
$expectedConfig['filters']['sort']['sorting']['choices'][0]['default'] = false;
$expectedConfig['filters']['sort']['sorting']['choices'][0]['order'] = 'asc';
$expectedConfig['filters']['sort']['sorting']['choices'][0]['mode'] = null;
$expectedConfig['filters']['sort']['sorting']['choices'][0]['fields'][0]['field'] = 'price';
$expectedConfig['filters']['sort']['sorting']['choices'][0]['fields'][0]['order'] = 'asc';
$expectedConfig['filters']['sort']['sorting']['choices'][0]['fields'][0]['mode'] = null;
$expectedConfig['filters']['sort']['sorting']['choices'][0]['fields'][1]['field'] = 'date';
$expectedConfig['filters']['sort']['sorting']['choices'][0]['fields'][1]['order'] = 'desc';
$expectedConfig['filters']['sort']['sorting']['choices'][0]['fields'][1]['mode'] = null;
unset($customConfig['filters']['document_field']);
unset($customConfig['filters']['multi_choice']);
unset($customConfig['filters']['fuzzy']);
Expand Down Expand Up @@ -219,6 +247,14 @@ public function getTestConfigurationExceptionData()
'. Permissible values: "_term", "_count"',
];

// Case #8 Sorting fields are not set.
$config = $this->getBaseConfiguration();
$config['filters']['sort']['sorting']['choices'][0]['label'] = 'test';
$cases[] = [
$config,
'The child node "fields" at path "ongr_filter_manager.filters.sort.sorting.choices.0" must be configured.',
];

return $cases;
}

Expand Down
1 change: 1 addition & 0 deletions Tests/app/config/config_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,4 @@ ongr_filter_manager:
request_field: 'sort'
choices:
- { label: foo, field: price, default: true, order: asc }
- { label: bar, fields: [{field: price, order: asc}, {field: date, order: desc}]}

0 comments on commit 6278e68

Please sign in to comment.