Skip to content

Commit 8dc315b

Browse files
samdarkroxblnfk
andauthored
Fix #62: Fix Sort not taking defaults into account
Co-authored-by: Alexander Makarov <samdark@users.noreply.github.com> Co-authored-by: roxblnfk <roxblnfk@ya.ru>
1 parent 899988d commit 8dc315b

File tree

2 files changed

+119
-26
lines changed

2 files changed

+119
-26
lines changed

src/Reader/Sort.php

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,33 @@
44

55
namespace Yiisoft\Data\Reader;
66

7+
use function array_key_exists;
8+
use function is_array;
9+
use function is_int;
10+
use function is_string;
11+
712
/**
813
* Sort represents information relevant to sorting according to one or multiple item fields.
914
*
15+
* @template TSortFieldItem as array<string, int>
16+
* @template TConfigItem as array{asc: TSortFieldItem, desc: TSortFieldItem, default: string, label: string}
17+
* @template TConfig as array<string, TConfigItem>
1018
* @psalm-immutable
1119
*/
1220
final class Sort
1321
{
22+
/** @psalm-var TConfig */
23+
private array $config;
24+
25+
/**
26+
* @var array Field names to order by as keys, direction as values.
27+
*/
28+
private array $currentOrder = [];
29+
1430
/**
31+
* @var array $config A list of sortable fields along with their
32+
* configuration.
33+
*
1534
* ```php
1635
* [
1736
* 'age', // means will be sorted as is
@@ -35,42 +54,41 @@ final class Sort
3554
* 'label' => Inflector::camel2words('age'),
3655
* ]
3756
* ```
57+
*
58+
* The name field is a virtual field name that consists of two real fields, `first_name` amd `last_name`. Virtual
59+
* field name is used in order string or order array while real fields are used in final sorting criteria.
60+
*
61+
* Each configuration has the following options:
62+
*
63+
* - `asc` - criteria for ascending sorting.
64+
* - `desc` - criteria for descending sorting.
65+
* - `default` - default sorting. Could be either `asc` or `desc`. If not specified, `asc` is used.
66+
* - `label` -
67+
* @psalm-var array<int, string>|array<string, array<string, int|string>> $config
3868
*/
39-
private array $config;
40-
41-
/**
42-
* @var array field names to order by as keys, direction as values
43-
*/
44-
private array $currentOrder = [];
45-
4669
public function __construct(array $config)
4770
{
4871
$normalizedConfig = [];
4972
foreach ($config as $fieldName => $fieldConfig) {
50-
if (
51-
!(is_int($fieldName) && is_string($fieldConfig))
52-
&& !(is_string($fieldName) && is_array($fieldConfig))
53-
) {
54-
throw new \InvalidArgumentException('Invalid config format');
73+
if (!(is_int($fieldName) && is_string($fieldConfig) || is_string($fieldName) && is_array($fieldConfig))) {
74+
throw new \InvalidArgumentException('Invalid config format.');
5575
}
5676

5777
if (is_string($fieldConfig)) {
5878
$fieldName = $fieldConfig;
5979
$fieldConfig = [];
6080
}
6181

62-
if (!isset($fieldConfig['asc'], $fieldConfig['desc'])) {
63-
$normalizedConfig[$fieldName] = array_merge([
64-
'asc' => [$fieldName => SORT_ASC],
65-
'desc' => [$fieldName => SORT_DESC],
66-
'default' => 'asc',
67-
'label' => $fieldName,
68-
], $fieldConfig);
69-
} else {
70-
$normalizedConfig[$fieldName] = $fieldConfig;
71-
}
82+
/** @psalm-var TConfig $fieldConfig */
83+
$normalizedConfig[$fieldName] = array_merge([
84+
'asc' => [$fieldName => SORT_ASC],
85+
'desc' => [$fieldName => SORT_DESC],
86+
'default' => 'asc',
87+
'label' => $fieldName,
88+
], $fieldConfig);
7289
}
7390

91+
/** @psalm-var TConfig $normalizedConfig */
7492
$this->config = $normalizedConfig;
7593
}
7694

@@ -99,7 +117,7 @@ public function withOrderString(string $orderString): self
99117
}
100118

101119
/**
102-
* @param array $order field names to order by as keys, direction as values
120+
* @param array $order Field names to order by as keys, direction as values.
103121
*
104122
* @return $this
105123
*/
@@ -124,14 +142,30 @@ public function getOrderAsString(): string
124142
return implode(',', $parts);
125143
}
126144

145+
/**
146+
* Final sorting criteria to apply.
147+
*/
127148
public function getCriteria(): array
128149
{
129150
$criteria = [];
130-
foreach ($this->getOrder() as $field => $direction) {
131-
if (isset($this->config[$field][$direction])) {
132-
$criteria = array_merge($criteria, $this->config[$field][$direction]);
151+
$order = $this->getOrder();
152+
153+
$config = $this->config;
154+
155+
foreach ($order as $field => $direction) {
156+
if (!array_key_exists($field, $config)) {
157+
continue;
133158
}
159+
160+
$criteria += $config[$field][$direction];
161+
162+
unset($config[$field]);
134163
}
164+
165+
foreach ($config as $field => $fieldConfig) {
166+
$criteria += $fieldConfig[$fieldConfig['default']];
167+
}
168+
135169
return $criteria;
136170
}
137171
}

tests/Reader/SortTest.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,63 @@ public function testGetCriteria(): void
135135
'bee' => SORT_ASC,
136136
], $sort->getCriteria());
137137
}
138+
139+
public function testGetCriteriaDefaults(): void
140+
{
141+
$sort = (new Sort([
142+
'b' => [
143+
'asc' => ['bee' => SORT_ASC],
144+
'desc' => ['bee' => SORT_DESC],
145+
'default' => 'desc',
146+
'label' => 'B',
147+
],
148+
]))
149+
->withOrder([]);
150+
151+
$this->assertSame([
152+
'bee' => SORT_DESC,
153+
], $sort->getCriteria());
154+
}
155+
156+
public function testGetCriteriaOrder(): void
157+
{
158+
$sort = (new Sort([
159+
'b',
160+
'c',
161+
]))
162+
->withOrder(['c' => 'desc']);
163+
164+
$this->assertSame([
165+
'c' => SORT_DESC,
166+
'b' => SORT_ASC,
167+
], $sort->getCriteria());
168+
}
169+
170+
public function testGetCriteriaDefaultsWhenConfigIsNotComplete(): void
171+
{
172+
$sort = (new Sort([
173+
'b' => [
174+
'asc' => ['bee' => SORT_ASC],
175+
'desc' => ['bee' => SORT_DESC],
176+
],
177+
]))
178+
->withOrder([]);
179+
180+
$this->assertSame([
181+
'bee' => SORT_ASC,
182+
], $sort->getCriteria());
183+
}
184+
185+
public function testGetCriteriaWithShortFieldSyntax(): void
186+
{
187+
$sort = (new Sort([
188+
'id',
189+
'name',
190+
]))->withOrder(['name' => 'desc']);
191+
192+
$this->assertSame([
193+
'name' => SORT_DESC,
194+
'id' => SORT_ASC,
195+
], $sort->getCriteria());
196+
}
138197
}

0 commit comments

Comments
 (0)