Skip to content

Commit da32884

Browse files
committed
Harden up the sort modifier. Closes #2450
The issue with 2450 was because when it was being sorted, the indexes were jumbled, and Antlers needs a zero indexed array to loop over. This also removes using a key argument named "value" triggering the primitive sort. You might have a multidimensional array with keys named value that you want to sort by. You can still just sort primitive arrays by doing {{ var | sort }} or {{ var sort="true" }}
1 parent 916ad7a commit da32884

File tree

2 files changed

+122
-9
lines changed

2 files changed

+122
-9
lines changed

src/Modifiers/CoreModifiers.php

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,23 +1757,22 @@ public function slugify($value)
17571757
*/
17581758
public function sort($value, $params)
17591759
{
1760-
$key = Arr::get($params, 0);
1761-
$is_descending = strtolower(Arr::get($params, 1)) == 'desc';
1760+
$key = Arr::get($params, 0, 'true');
1761+
$desc = strtolower(Arr::get($params, 1)) == 'desc';
17621762

1763-
// Enforce collection
1764-
$value = ($value instanceof Collection) ? $value : collect($value);
1763+
$value = $value instanceof Collection ? $value : collect($value);
17651764

1766-
// Random sort
17671765
if ($key === 'random') {
17681766
return $value->shuffle();
17691767
}
17701768

1771-
// Primitive array sort
1772-
if ($key === 'true' || $key == 'value') {
1773-
return $is_descending ? $value->sort()->reverse() : $value->sort();
1769+
if ($key === 'true') {
1770+
$value = $desc ? $value->sort()->reverse() : $value->sort();
1771+
} else {
1772+
$value = $desc ? $value->sortByDesc($key) : $value->sortBy($key);
17741773
}
17751774

1776-
return $is_descending ? $value->sortByDesc($key) : $value->sortBy($key);
1775+
return $value->values();
17771776
}
17781777

17791778
/**

tests/Modifiers/SortTest.php

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?php
2+
3+
namespace Tests\Modifiers;
4+
5+
use Statamic\Modifiers\Modify;
6+
use Tests\TestCase;
7+
8+
class SortTest extends TestCase
9+
{
10+
/** @test */
11+
public function it_sorts_primitive_arrays()
12+
{
13+
$arr = ['beta', 'zeta', 'alpha'];
14+
$expected = ['alpha', 'beta', 'zeta'];
15+
16+
$this->assertEquals($expected, $this->modify($arr));
17+
$this->assertEquals($expected, $this->modify($arr, 'true'));
18+
$this->assertEquals($expected, $this->modify($arr, 'true'));
19+
$this->assertEquals($expected, $this->modify($arr, ['true', 'asc']));
20+
21+
$this->assertEquals($expected, $this->modify(collect($arr)));
22+
$this->assertEquals($expected, $this->modify(collect($arr), 'true'));
23+
$this->assertEquals($expected, $this->modify(collect($arr), ['true', 'asc']));
24+
}
25+
26+
/** @test */
27+
public function it_sorts_primitive_arrays_descending()
28+
{
29+
$arr = ['beta', 'zeta', 'alpha'];
30+
$expected = ['zeta', 'beta', 'alpha'];
31+
32+
$this->assertEquals($expected, $this->modify($arr, ['true', 'desc']));
33+
$this->assertEquals($expected, $this->modify(collect($arr), ['true', 'desc']));
34+
}
35+
36+
/** @test */
37+
public function it_sorts_multidimensional_arrays_by_a_key()
38+
{
39+
$arr = [
40+
['value' => 'beta'],
41+
['value' => 'zeta'],
42+
['value' => 'alpha'],
43+
];
44+
45+
$expected = [
46+
['value' => 'alpha'],
47+
['value' => 'beta'],
48+
['value' => 'zeta'],
49+
];
50+
51+
$this->assertEquals($expected, $this->modify($arr, 'value'));
52+
$this->assertEquals($expected, $this->modify(collect($arr), 'value'));
53+
}
54+
55+
/** @test */
56+
public function it_sorts_multidimensional_arrays_by_a_key_descending()
57+
{
58+
$arr = [
59+
['value' => 'beta'],
60+
['value' => 'zeta'],
61+
['value' => 'alpha'],
62+
];
63+
64+
$expected = [
65+
['value' => 'zeta'],
66+
['value' => 'beta'],
67+
['value' => 'alpha'],
68+
];
69+
70+
$this->assertEquals($expected, $this->modify($arr, ['value', 'desc']));
71+
$this->assertEquals($expected, $this->modify(collect($arr), ['value', 'desc']));
72+
}
73+
74+
/** @test */
75+
public function it_sorts_primitive_arrays_randomly()
76+
{
77+
$this->assertSortsRandomly(['alpha', 'beta', 'zeta']);
78+
}
79+
80+
/** @test */
81+
public function it_sorts_multidimensional_arrays_randomly()
82+
{
83+
$this->assertSortsRandomly([
84+
['word' => 'alpha'],
85+
['word' => 'beta'],
86+
['word' => 'zeta'],
87+
]);
88+
}
89+
90+
private function assertSortsRandomly($arr)
91+
{
92+
$combinations = [];
93+
94+
foreach (collect()->times(100) as $time) {
95+
$modified = $this->modify($arr, 'random');
96+
97+
if (collect($modified)->keys()->first() != 0) {
98+
$this->fail('Collection is not zero indexed');
99+
}
100+
101+
$combinations[json_encode($modified)] = true;
102+
}
103+
104+
$this->assertNotCount(1, $combinations);
105+
}
106+
107+
public function modify($arr, $args = [])
108+
{
109+
$modified = Modify::value($arr)->sort($args)->fetch();
110+
111+
// It gets modified to a Collection, but it's easier to write tests as arrays.
112+
return $modified->all();
113+
}
114+
}

0 commit comments

Comments
 (0)