@@ -21,21 +21,23 @@ class Sort extends LookupRefValidations
21
21
* Both $sortIndex and $sortOrder can be arrays, to provide multi-level sorting.
22
22
*
23
23
* @param mixed $sortArray The range of cells being sorted
24
- * @param mixed $sortIndex Whether the uniqueness should be determined by row ( the default) or by column
24
+ * @param mixed $sortIndex The column or row number within the sortArray to sort on
25
25
* @param mixed $sortOrder Flag indicating whether to sort ascending or descending
26
26
* Ascending = 1 (self::ORDER_ASCENDING)
27
27
* Descending = -1 (self::ORDER_DESCENDING)
28
28
* @param mixed $byColumn Whether the sort should be determined by row (the default) or by column
29
29
*
30
30
* @return mixed The sorted values from the sort range
31
31
*/
32
- public static function sort ($ sortArray , $ sortIndex = [ 1 ] , $ sortOrder = self ::ORDER_ASCENDING , $ byColumn = false )
32
+ public static function sort ($ sortArray , $ sortIndex = 1 , $ sortOrder = self ::ORDER_ASCENDING , $ byColumn = false )
33
33
{
34
34
if (!is_array ($ sortArray )) {
35
35
// Scalars are always returned "as is"
36
36
return $ sortArray ;
37
37
}
38
38
39
+ $ sortArray = self ::enumerateArrayKeys ($ sortArray );
40
+
39
41
$ byColumn = (bool ) $ byColumn ;
40
42
$ lookupIndexSize = $ byColumn ? count ($ sortArray ) : count ($ sortArray [0 ]);
41
43
@@ -68,6 +70,12 @@ public static function sort($sortArray, $sortIndex = [1], $sortOrder = self::ORD
68
70
*
69
71
* @param mixed $sortArray The range of cells being sorted
70
72
* @param mixed $args
73
+ * At least one additional argument must be provided, The vector or range to sort on
74
+ * After that, arguments are passed as pairs:
75
+ * sort order: ascending or descending
76
+ * Ascending = 1 (self::ORDER_ASCENDING)
77
+ * Descending = -1 (self::ORDER_DESCENDING)
78
+ * additional arrays or ranges for multi-level sorting
71
79
*
72
80
* @return mixed The sorted values from the sort range
73
81
*/
@@ -78,6 +86,8 @@ public static function sortBy($sortArray, ...$args)
78
86
return $ sortArray ;
79
87
}
80
88
89
+ $ sortArray = self ::enumerateArrayKeys ($ sortArray );
90
+
81
91
$ lookupArraySize = count ($ sortArray );
82
92
$ argumentCount = count ($ args );
83
93
@@ -94,19 +104,33 @@ public static function sortBy($sortArray, ...$args)
94
104
return self ::processSortBy ($ sortArray , $ sortBy , $ sortOrder );
95
105
}
96
106
107
+ private static function enumerateArrayKeys (array $ sortArray ): array
108
+ {
109
+ array_walk (
110
+ $ sortArray ,
111
+ function (&$ columns ): void {
112
+ if (is_array ($ columns )) {
113
+ $ columns = array_values ($ columns );
114
+ }
115
+ }
116
+ );
117
+
118
+ return array_values ($ sortArray );
119
+ }
120
+
97
121
/**
98
122
* @param mixed $sortIndex
99
123
* @param mixed $sortOrder
100
124
*/
101
- private static function validateScalarArgumentsForSort (&$ sortIndex , &$ sortOrder , int $ lookupIndexSize ): void
125
+ private static function validateScalarArgumentsForSort (&$ sortIndex , &$ sortOrder , int $ sortArraySize ): void
102
126
{
103
127
if (is_array ($ sortIndex ) || is_array ($ sortOrder )) {
104
128
throw new Exception (ExcelError::VALUE ());
105
129
}
106
130
107
131
$ sortIndex = self ::validatePositiveInt ($ sortIndex , false );
108
132
109
- if ($ sortIndex > $ lookupIndexSize ) {
133
+ if ($ sortIndex > $ sortArraySize ) {
110
134
throw new Exception (ExcelError::VALUE ());
111
135
}
112
136
@@ -116,15 +140,15 @@ private static function validateScalarArgumentsForSort(&$sortIndex, &$sortOrder,
116
140
/**
117
141
* @param mixed $sortVector
118
142
*/
119
- private static function validateSortVector ($ sortVector , int $ lookupArraySize ): array
143
+ private static function validateSortVector ($ sortVector , int $ sortArraySize ): array
120
144
{
121
145
if (!is_array ($ sortVector )) {
122
146
throw new Exception (ExcelError::VALUE ());
123
147
}
124
148
125
149
// It doesn't matter if it's a row or a column vectors, it works either way
126
150
$ sortVector = Functions::flattenArray ($ sortVector );
127
- if (count ($ sortVector ) !== $ lookupArraySize ) {
151
+ if (count ($ sortVector ) !== $ sortArraySize ) {
128
152
throw new Exception (ExcelError::VALUE ());
129
153
}
130
154
@@ -148,14 +172,14 @@ private static function validateSortOrder($sortOrder): int
148
172
* @param array $sortIndex
149
173
* @param mixed $sortOrder
150
174
*/
151
- private static function validateArrayArgumentsForSort (&$ sortIndex , &$ sortOrder , int $ lookupIndexSize ): void
175
+ private static function validateArrayArgumentsForSort (&$ sortIndex , &$ sortOrder , int $ sortArraySize ): void
152
176
{
153
177
// It doesn't matter if they're row or column vectors, it works either way
154
178
$ sortIndex = Functions::flattenArray ($ sortIndex );
155
179
$ sortOrder = Functions::flattenArray ($ sortOrder );
156
180
157
181
if (
158
- count ($ sortOrder ) === 0 || count ($ sortOrder ) > $ lookupIndexSize ||
182
+ count ($ sortOrder ) === 0 || count ($ sortOrder ) > $ sortArraySize ||
159
183
(count ($ sortOrder ) > count ($ sortIndex ))
160
184
) {
161
185
throw new Exception (ExcelError::VALUE ());
@@ -170,7 +194,7 @@ private static function validateArrayArgumentsForSort(&$sortIndex, &$sortOrder,
170
194
}
171
195
172
196
foreach ($ sortIndex as $ key => &$ value ) {
173
- self ::validateScalarArgumentsForSort ($ value , $ sortOrder [$ key ], $ lookupIndexSize );
197
+ self ::validateScalarArgumentsForSort ($ value , $ sortOrder [$ key ], $ sortArraySize );
174
198
}
175
199
}
176
200
@@ -195,7 +219,7 @@ function ($value) {
195
219
* @param array[] $sortIndex
196
220
* @param int[] $sortOrder
197
221
*/
198
- private static function processSortBy (array $ lookupArray , array $ sortIndex , $ sortOrder ): array
222
+ private static function processSortBy (array $ sortArray , array $ sortIndex , $ sortOrder ): array
199
223
{
200
224
$ sortArguments = [];
201
225
$ sortData = [];
@@ -204,32 +228,32 @@ private static function processSortBy(array $lookupArray, array $sortIndex, $sor
204
228
$ sortArguments [] = self ::prepareSortVectorValues ($ sortValues );
205
229
$ sortArguments [] = $ sortOrder [$ index ] === self ::ORDER_ASCENDING ? SORT_ASC : SORT_DESC ;
206
230
}
207
- $ sortArguments = self ::applyPHP7Patch ($ lookupArray , $ sortArguments );
231
+ $ sortArguments = self ::applyPHP7Patch ($ sortArray , $ sortArguments );
208
232
209
233
$ sortVector = self ::executeVectorSortQuery ($ sortData , $ sortArguments );
210
234
211
- return self ::sortLookupArrayFromVector ($ lookupArray , $ sortVector );
235
+ return self ::sortLookupArrayFromVector ($ sortArray , $ sortVector );
212
236
}
213
237
214
238
/**
215
239
* @param int[] $sortIndex
216
240
* @param int[] $sortOrder
217
241
*/
218
- private static function sortByRow (array $ lookupArray , array $ sortIndex , array $ sortOrder ): array
242
+ private static function sortByRow (array $ sortArray , array $ sortIndex , array $ sortOrder ): array
219
243
{
220
- $ sortVector = self ::buildVectorForSort ($ lookupArray , $ sortIndex , $ sortOrder );
244
+ $ sortVector = self ::buildVectorForSort ($ sortArray , $ sortIndex , $ sortOrder );
221
245
222
- return self ::sortLookupArrayFromVector ($ lookupArray , $ sortVector );
246
+ return self ::sortLookupArrayFromVector ($ sortArray , $ sortVector );
223
247
}
224
248
225
249
/**
226
250
* @param int[] $sortIndex
227
251
* @param int[] $sortOrder
228
252
*/
229
- private static function sortByColumn (array $ lookupArray , array $ sortIndex , array $ sortOrder ): array
253
+ private static function sortByColumn (array $ sortArray , array $ sortIndex , array $ sortOrder ): array
230
254
{
231
- $ lookupArray = Matrix::transpose ($ lookupArray );
232
- $ result = self ::sortByRow ($ lookupArray , $ sortIndex , $ sortOrder );
255
+ $ sortArray = Matrix::transpose ($ sortArray );
256
+ $ result = self ::sortByRow ($ sortArray , $ sortIndex , $ sortOrder );
233
257
234
258
return Matrix::transpose ($ result );
235
259
}
@@ -238,17 +262,17 @@ private static function sortByColumn(array $lookupArray, array $sortIndex, array
238
262
* @param int[] $sortIndex
239
263
* @param int[] $sortOrder
240
264
*/
241
- private static function buildVectorForSort (array $ lookupArray , array $ sortIndex , array $ sortOrder ): array
265
+ private static function buildVectorForSort (array $ sortArray , array $ sortIndex , array $ sortOrder ): array
242
266
{
243
267
$ sortArguments = [];
244
268
$ sortData = [];
245
269
foreach ($ sortIndex as $ index => $ sortIndexValue ) {
246
- $ sortValues = array_column ($ lookupArray , $ sortIndexValue - 1 );
270
+ $ sortValues = array_column ($ sortArray , $ sortIndexValue - 1 );
247
271
$ sortData [] = $ sortValues ;
248
272
$ sortArguments [] = self ::prepareSortVectorValues ($ sortValues );
249
273
$ sortArguments [] = $ sortOrder [$ index ] === self ::ORDER_ASCENDING ? SORT_ASC : SORT_DESC ;
250
274
}
251
- $ sortArguments = self ::applyPHP7Patch ($ lookupArray , $ sortArguments );
275
+ $ sortArguments = self ::applyPHP7Patch ($ sortArray , $ sortArguments );
252
276
253
277
$ sortData = self ::executeVectorSortQuery ($ sortData , $ sortArguments );
254
278
@@ -279,12 +303,12 @@ private static function executeVectorSortQuery(array $sortData, array $sortArgum
279
303
return $ sortedData ;
280
304
}
281
305
282
- private static function sortLookupArrayFromVector (array $ lookupArray , array $ sortVector ): array
306
+ private static function sortLookupArrayFromVector (array $ sortArray , array $ sortVector ): array
283
307
{
284
308
// Building a new array in the correct (sorted) order works; but may be memory heavy for larger arrays
285
309
$ sortedArray = [];
286
310
foreach ($ sortVector as $ index ) {
287
- $ sortedArray [] = $ lookupArray [$ index ];
311
+ $ sortedArray [] = $ sortArray [$ index ];
288
312
}
289
313
290
314
return $ sortedArray ;
@@ -306,10 +330,10 @@ private static function sortLookupArrayFromVector(array $lookupArray, array $sor
306
330
* MS Excel replicates the PHP 8.0.0 behaviour, retaining the original order of matching elements.
307
331
* To replicate that behaviour with PHP 7, we add an extra sort based on the row index.
308
332
*/
309
- private static function applyPHP7Patch (array $ lookupArray , array $ sortArguments ): array
333
+ private static function applyPHP7Patch (array $ sortArray , array $ sortArguments ): array
310
334
{
311
335
if (PHP_VERSION_ID < 80000 ) {
312
- $ sortArguments [] = range (1 , count ($ lookupArray ));
336
+ $ sortArguments [] = range (1 , count ($ sortArray ));
313
337
$ sortArguments [] = SORT_ASC ;
314
338
}
315
339
0 commit comments