44
55namespace 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 */
1220final 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}
0 commit comments