Skip to content

Commit 88dd005

Browse files
duncanmccleanclaudejasonvarga
authored
[5.x] Harden query value resolution (#14476)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Jason Varga <jason@pixelfear.com>
1 parent ee88420 commit 88dd005

File tree

24 files changed

+394
-20
lines changed

24 files changed

+394
-20
lines changed

src/Assets/Asset.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,7 @@ public function hasDuration()
11161116

11171117
public function getQueryableValue(string $field)
11181118
{
1119-
if (method_exists($this, $method = Str::camel($field))) {
1119+
if (in_array($method = Str::camel($field), $this->queryableMethods())) {
11201120
return $this->{$method}();
11211121
}
11221122

@@ -1129,6 +1129,17 @@ public function getQueryableValue(string $field)
11291129
return $field->fieldtype()->toQueryableValue($value);
11301130
}
11311131

1132+
private function queryableMethods(): array
1133+
{
1134+
return [
1135+
'absoluteUrl', 'apiUrl', 'basename', 'blueprint', 'containerId', 'containerHandle', 'dimensions',
1136+
'duration', 'editUrl', 'exists', 'extension', 'filename', 'folder', 'guessedExtension',
1137+
'hasDimensions', 'hasDuration', 'height', 'id', 'isAudio', 'isImage', 'isMedia', 'isPdf',
1138+
'isPreviewable', 'isSvg', 'isVideo', 'lastModified', 'mimeType', 'orientation', 'path', 'pdfUrl',
1139+
'ratio', 'reference', 'size', 'thumbnailUrl', 'title', 'url', 'width',
1140+
];
1141+
}
1142+
11321143
public function getCurrentDirtyStateAttributes(): array
11331144
{
11341145
return array_merge([

src/Assets/AssetContainer.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Statamic\Contracts\Assets\AssetContainer as AssetContainerContract;
88
use Statamic\Contracts\Data\Augmentable;
99
use Statamic\Contracts\Data\Augmented;
10+
use Statamic\Contracts\Query\ContainsQueryableValues;
1011
use Statamic\Data\ExistsAsFile;
1112
use Statamic\Data\HasAugmentedInstance;
1213
use Statamic\Events\AssetContainerBlueprintFound;
@@ -27,9 +28,10 @@
2728
use Statamic\Facades\Stache;
2829
use Statamic\Facades\URL;
2930
use Statamic\Support\Arr;
31+
use Statamic\Support\Str;
3032
use Statamic\Support\Traits\FluentlyGetsAndSets;
3133

32-
class AssetContainer implements Arrayable, ArrayAccess, AssetContainerContract, Augmentable
34+
class AssetContainer implements Arrayable, ArrayAccess, AssetContainerContract, Augmentable, ContainsQueryableValues
3335
{
3436
use ExistsAsFile, FluentlyGetsAndSets, HasAugmentedInstance;
3537

@@ -693,6 +695,24 @@ public static function __callStatic($method, $parameters)
693695
return Facades\AssetContainer::{$method}(...$parameters);
694696
}
695697

698+
public function getQueryableValue(string $field)
699+
{
700+
if (in_array($method = Str::camel($field), $this->queryableMethods())) {
701+
return $this->{$method}();
702+
}
703+
704+
return null;
705+
}
706+
707+
private function queryableMethods(): array
708+
{
709+
return [
710+
'absoluteUrl', 'accessible', 'allowDownloading', 'allowMoving', 'allowRenaming', 'allowUploads',
711+
'blueprint', 'createFolders', 'diskHandle', 'diskPath', 'editUrl', 'handle', 'hasSearchIndex',
712+
'id', 'path', 'private', 'searchIndex', 'showUrl', 'sortDirection', 'sortField', 'title', 'url',
713+
];
714+
}
715+
696716
public function __toString()
697717
{
698718
return $this->handle();

src/Assets/AssetFolder.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
use League\Flysystem\PathTraversalDetected;
77
use Statamic\Assets\AssetUploader as Uploader;
88
use Statamic\Contracts\Assets\AssetFolder as Contract;
9+
use Statamic\Contracts\Query\ContainsQueryableValues;
910
use Statamic\Events\AssetFolderDeleted;
1011
use Statamic\Events\AssetFolderSaved;
1112
use Statamic\Facades\AssetContainer;
1213
use Statamic\Facades\Path;
1314
use Statamic\Support\Str;
1415
use Statamic\Support\Traits\FluentlyGetsAndSets;
1516

16-
class AssetFolder implements Arrayable, Contract
17+
class AssetFolder implements Arrayable, ContainsQueryableValues, Contract
1718
{
1819
use FluentlyGetsAndSets;
1920

@@ -237,4 +238,20 @@ public function toArray()
237238
'basename' => (string) $this->basename(),
238239
];
239240
}
241+
242+
public function getQueryableValue(string $field)
243+
{
244+
if (in_array($method = Str::camel($field), $this->queryableMethods())) {
245+
return $this->{$method}();
246+
}
247+
248+
return null;
249+
}
250+
251+
private function queryableMethods(): array
252+
{
253+
return [
254+
'basename', 'count', 'lastModified', 'path', 'resolvedPath', 'size', 'title',
255+
];
256+
}
240257
}

src/Auth/User.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ protected function getComputedCallbacks()
365365

366366
public function getQueryableValue(string $field)
367367
{
368-
if (method_exists($this, $method = Str::camel($field))) {
368+
if (in_array($method = Str::camel($field), $this->queryableMethods())) {
369369
return $this->{$method}();
370370
}
371371

@@ -377,4 +377,13 @@ public function getQueryableValue(string $field)
377377

378378
return $field->fieldtype()->toQueryableValue($value);
379379
}
380+
381+
private function queryableMethods(): array
382+
{
383+
return [
384+
'apiUrl', 'avatar', 'blueprint', 'editUrl', 'email', 'gravatarUrl', 'groups', 'hasAvatarField',
385+
'id', 'initials', 'isSuper', 'isTaxonomizable', 'lastLogin', 'name', 'path', 'preferredLocale',
386+
'preferredTheme', 'reference', 'roles', 'title',
387+
];
388+
}
380389
}

src/Entries/Collection.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use InvalidArgumentException;
88
use Statamic\Contracts\Data\Augmentable as AugmentableContract;
99
use Statamic\Contracts\Entries\Collection as Contract;
10+
use Statamic\Contracts\Query\ContainsQueryableValues;
1011
use Statamic\Data\ContainsCascadingData;
1112
use Statamic\Data\ExistsAsFile;
1213
use Statamic\Data\HasAugmentedData;
@@ -35,7 +36,7 @@
3536

3637
use function Statamic\trans as __;
3738

38-
class Collection implements Arrayable, ArrayAccess, AugmentableContract, Contract
39+
class Collection implements Arrayable, ArrayAccess, AugmentableContract, ContainsQueryableValues, Contract
3940
{
4041
use ContainsCascadingData, ExistsAsFile, FluentlyGetsAndSets, HasAugmentedData, HasDirtyState;
4142

@@ -948,6 +949,24 @@ public function augmentedArrayData()
948949
];
949950
}
950951

952+
public function getQueryableValue(string $field)
953+
{
954+
if (in_array($method = Str::camel($field), $this->queryableMethods())) {
955+
return $this->{$method}();
956+
}
957+
958+
return null;
959+
}
960+
961+
private function queryableMethods(): array
962+
{
963+
return [
964+
'dated', 'defaultPublishState', 'editUrl', 'handle', 'hasStructure', 'id', 'layout', 'mount',
965+
'orderable', 'path', 'requiresSlugs', 'revisionsEnabled', 'sites', 'sortDirection', 'sortField',
966+
'structureHandle', 'taxonomies', 'template', 'title', 'url', 'uri',
967+
];
968+
}
969+
951970
public function getCurrentDirtyStateAttributes(): array
952971
{
953972
return $this->fileData();

src/Entries/Entry.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1098,7 +1098,7 @@ public function getQueryableValue(string $field)
10981098
Blink::store('entry-uris')->forget($this->id());
10991099
}
11001100

1101-
if (method_exists($this, $method = Str::camel($field))) {
1101+
if (in_array($method = Str::camel($field), $this->queryableMethods())) {
11021102
return $this->{$method}();
11031103
}
11041104

@@ -1111,6 +1111,16 @@ public function getQueryableValue(string $field)
11111111
return $field->fieldtype()->toQueryableValue($value);
11121112
}
11131113

1114+
private function queryableMethods(): array
1115+
{
1116+
return [
1117+
'apiUrl', 'blueprint', 'collection', 'collectionHandle', 'date', 'editUrl', 'hasDate', 'hasExplicitDate', 'hasOrigin',
1118+
'hasSeconds', 'hasStructure', 'hasTime', 'id', 'isRedirect', 'isRoot', 'lastModified', 'lastModifiedBy',
1119+
'layout', 'locale', 'order', 'path', 'private', 'published', 'redirectUrl', 'reference', 'site', 'sites', 'slug',
1120+
'status', 'template', 'uri', 'url', 'urlWithoutRedirect',
1121+
];
1122+
}
1123+
11141124
public function getSearchValue(string $field)
11151125
{
11161126
return method_exists($this, $field) ? $this->$field() : $this->value($field);

src/Fields/Blueprint.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Illuminate\Contracts\Support\Arrayable;
99
use Illuminate\Support\Collection;
1010
use Statamic\Contracts\Data\Augmentable;
11+
use Statamic\Contracts\Query\ContainsQueryableValues;
1112
use Statamic\Contracts\Query\QueryableValue;
1213
use Statamic\CP\Column;
1314
use Statamic\CP\Columns;
@@ -30,7 +31,7 @@
3031

3132
use function Statamic\trans as __;
3233

33-
class Blueprint implements Arrayable, ArrayAccess, Augmentable, QueryableValue
34+
class Blueprint implements Arrayable, ArrayAccess, Augmentable, ContainsQueryableValues, QueryableValue
3435
{
3536
use ExistsAsFile, HasAugmentedData;
3637

@@ -792,4 +793,21 @@ public function writeFile($path = null)
792793
{
793794
File::put($path ?? $this->buildPath(), $this->fileContents());
794795
}
796+
797+
public function getQueryableValue(string $field)
798+
{
799+
if (in_array($method = Str::camel($field), $this->queryableMethods())) {
800+
return $this->{$method}();
801+
}
802+
803+
return null;
804+
}
805+
806+
private function queryableMethods(): array
807+
{
808+
return [
809+
'columns', 'fields', 'handle', 'hidden', 'isEmpty', 'isDeletable', 'isResettable',
810+
'namespace', 'order', 'path', 'tabs', 'title',
811+
];
812+
}
795813
}

src/Fields/Fieldset.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Statamic\Fields;
44

5+
use Statamic\Contracts\Query\ContainsQueryableValues;
56
use Statamic\Events\FieldsetCreated;
67
use Statamic\Events\FieldsetCreating;
78
use Statamic\Events\FieldsetDeleted;
@@ -21,7 +22,7 @@
2122
use Statamic\Support\Arr;
2223
use Statamic\Support\Str;
2324

24-
class Fieldset
25+
class Fieldset implements ContainsQueryableValues
2526
{
2627
protected $handle;
2728
protected $contents = [];
@@ -296,6 +297,23 @@ public function reset()
296297
return true;
297298
}
298299

300+
public function getQueryableValue(string $field)
301+
{
302+
if (in_array($method = Str::camel($field), $this->queryableMethods())) {
303+
return $this->{$method}();
304+
}
305+
306+
return null;
307+
}
308+
309+
private function queryableMethods(): array
310+
{
311+
return [
312+
'editUrl', 'fields', 'handle', 'isDeletable', 'isResettable',
313+
'namespace', 'path', 'title',
314+
];
315+
}
316+
299317
public static function __callStatic($method, $parameters)
300318
{
301319
return Facades\Fieldset::{$method}(...$parameters);

src/Forms/Form.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Statamic\Contracts\Forms\Form as FormContract;
99
use Statamic\Contracts\Forms\Submission;
1010
use Statamic\Contracts\Forms\SubmissionQueryBuilder;
11+
use Statamic\Contracts\Query\ContainsQueryableValues;
1112
use Statamic\Data\ContainsData;
1213
use Statamic\Data\HasAugmentedInstance;
1314
use Statamic\Events\FormBlueprintFound;
@@ -26,9 +27,10 @@
2627
use Statamic\Forms\Exporters\Exporter;
2728
use Statamic\Statamic;
2829
use Statamic\Support\Arr;
30+
use Statamic\Support\Str;
2931
use Statamic\Support\Traits\FluentlyGetsAndSets;
3032

31-
class Form implements Arrayable, Augmentable, FormContract
33+
class Form implements Arrayable, Augmentable, ContainsQueryableValues, FormContract
3234
{
3335
use ContainsData, FluentlyGetsAndSets, HasAugmentedInstance;
3436

@@ -444,4 +446,27 @@ public function exporter(string $handle): ?Exporter
444446
{
445447
return $this->exporters()->get($handle);
446448
}
449+
450+
public function getQueryableValue(string $field)
451+
{
452+
if (in_array($method = Str::camel($field), $this->queryableMethods())) {
453+
return $this->{$method}();
454+
}
455+
456+
$value = $this->get($field);
457+
458+
if (! $field = $this->blueprint()->field($field)) {
459+
return $value;
460+
}
461+
462+
return $field->fieldtype()->toQueryableValue($value);
463+
}
464+
465+
private function queryableMethods(): array
466+
{
467+
return [
468+
'actionUrl', 'apiUrl', 'blueprint', 'dateFormat', 'editUrl', 'fields',
469+
'handle', 'honeypot', 'path', 'submissions', 'title',
470+
];
471+
}
447472
}

src/Forms/Submission.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Carbon\Carbon;
66
use Statamic\Contracts\Data\Augmentable;
77
use Statamic\Contracts\Forms\Submission as SubmissionContract;
8+
use Statamic\Contracts\Query\ContainsQueryableValues;
89
use Statamic\Data\ContainsData;
910
use Statamic\Data\ExistsAsFile;
1011
use Statamic\Data\HasAugmentedData;
@@ -21,9 +22,10 @@
2122
use Statamic\Facades\Stache;
2223
use Statamic\Forms\Uploaders\AssetsUploader;
2324
use Statamic\Forms\Uploaders\FilesUploader;
25+
use Statamic\Support\Str;
2426
use Statamic\Support\Traits\FluentlyGetsAndSets;
2527

26-
class Submission implements Augmentable, SubmissionContract
28+
class Submission implements Augmentable, ContainsQueryableValues, SubmissionContract
2729
{
2830
use ContainsData, ExistsAsFile, FluentlyGetsAndSets, HasAugmentedData, TracksQueriedColumns, TracksQueriedRelations;
2931

@@ -274,6 +276,28 @@ public function fileData()
274276
return $this->data()->all();
275277
}
276278

279+
public function getQueryableValue(string $field)
280+
{
281+
if (in_array($method = Str::camel($field), $this->queryableMethods())) {
282+
return $this->{$method}();
283+
}
284+
285+
$value = $this->get($field);
286+
287+
if (! $field = $this->blueprint()->field($field)) {
288+
return $value;
289+
}
290+
291+
return $field->fieldtype()->toQueryableValue($value);
292+
}
293+
294+
private function queryableMethods(): array
295+
{
296+
return [
297+
'blueprint', 'date', 'form', 'formattedDate', 'id', 'path',
298+
];
299+
}
300+
277301
public function __get($key)
278302
{
279303
return $this->get($key);

0 commit comments

Comments
 (0)