Skip to content

Commit 68d2eab

Browse files
[5.x] Harden DataCollection sort value resolution (#14693)
Co-authored-by: Jason Varga <jason@pixelfear.com>
1 parent e172aa6 commit 68d2eab

2 files changed

Lines changed: 69 additions & 10 deletions

File tree

src/Data/DataCollection.php

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
use Illuminate\Support\Collection as IlluminateCollection;
88
use Statamic\Exceptions\MethodNotFoundException;
99
use Statamic\Facades\Compare;
10+
use Statamic\Query\ResolveValue;
1011
use Statamic\Search\PlainResult;
1112
use Statamic\Search\Result;
12-
use Statamic\Support\Str;
1313

1414
/**
1515
* An abstract collection of data types.
@@ -100,15 +100,7 @@ protected function getSortableValue($sort, $item)
100100
$item = $item->getSearchable() ?? $item;
101101
}
102102

103-
if (method_exists($item, $method = Str::camel($sort))) {
104-
return $this->normalizeSortableValue(call_user_func([$item, $method]));
105-
}
106-
107-
if (method_exists($item, 'value')) {
108-
return $this->normalizeSortableValue($item->value($sort));
109-
}
110-
111-
return $this->normalizeSortableValue($item->get($sort));
103+
return $this->normalizeSortableValue((new ResolveValue)($item, $sort));
112104
}
113105

114106
/**

tests/Data/DataCollectionTest.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
namespace Tests\Data;
44

55
use PHPUnit\Framework\Attributes\Test;
6+
use Statamic\Contracts\Search\Searchable;
67
use Statamic\Data\DataCollection;
8+
use Statamic\Search\Result;
79
use Tests\TestCase;
810

911
class DataCollectionTest extends TestCase
@@ -31,4 +33,69 @@ public function it_sorts_by_first_item_in_arrays()
3133

3234
$this->assertEquals([1, 3, 2], $collection->multisort('foos')->pluck('id')->all());
3335
}
36+
37+
#[Test]
38+
public function sorting_by_unsafe_method_does_not_invoke_it()
39+
{
40+
$a = new DataCollectionTestObject('alfa');
41+
$b = new DataCollectionTestObject('bravo');
42+
43+
$collection = new DataCollection([$a, $b]);
44+
45+
$collection->multisort('delete');
46+
47+
$this->assertFalse($a->deleted);
48+
$this->assertFalse($b->deleted);
49+
}
50+
51+
#[Test]
52+
public function sorting_search_results_by_unsafe_method_does_not_invoke_it()
53+
{
54+
$a = new DataCollectionTestObject('alfa');
55+
$b = new DataCollectionTestObject('bravo');
56+
57+
$collection = new DataCollection([
58+
new Result($a, 'test'),
59+
new Result($b, 'test'),
60+
]);
61+
62+
$collection->multisort('delete');
63+
64+
$this->assertFalse($a->deleted);
65+
$this->assertFalse($b->deleted);
66+
}
67+
}
68+
69+
class DataCollectionTestObject implements Searchable
70+
{
71+
public bool $deleted = false;
72+
73+
public function __construct(public string $title)
74+
{
75+
}
76+
77+
public function delete()
78+
{
79+
$this->deleted = true;
80+
}
81+
82+
public function get($key)
83+
{
84+
return $this->{$key} ?? null;
85+
}
86+
87+
public function getSearchValue(string $field)
88+
{
89+
return $this->{$field} ?? null;
90+
}
91+
92+
public function getSearchReference(): string
93+
{
94+
return 'test::'.$this->title;
95+
}
96+
97+
public function toSearchResult(): Result
98+
{
99+
return new Result($this, 'test');
100+
}
34101
}

0 commit comments

Comments
 (0)