[6.x] Relax group/grid fieldtype check in ReplicatorController - #14068
Conversation
|
I think we explicitly checked for the fieldtypes for a reason. I could be misremembering though. I'm probably wrong and this is a correct fix but I want to check the history and do some more testing before merging. |
|
Hello, is there any update on this issue? We are experiencing the same error as well. Thank you in advance! |
jasonvarga
left a comment
There was a problem hiding this comment.
Thanks Duncan — the underlying fix is right, but a few things need sorting before this can go in.
The branch merging 6.x pulled in the endpoint hardening from #14255, and this PR's new test wasn't converted along with the rest of the file, so CI is red across nearly every PHP shard.
Separately, on my earlier comment about why we checked the fieldtypes explicitly — I dug into it. The type whitelist wasn't protecting us from addon fieldtypes with an unrelated fields key (that shape was already broken before this PR, and nothing in core has one — only Group and Grid persist a top-level fields key). What it was protecting us from is that $config isn't always a field config. Details inline.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011yxrHxZC18iQiRgJgDjccK
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011yxrHxZC18iQiRgJgDjccK
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011yxrHxZC18iQiRgJgDjccK
|
Thanks for digging into the history, that explains it.
|
|
Hi everyone, I managed to fix it using this custom “PR” and the composer-patches package to inject it. Maybe it'll help you, if you still need it. Codediff --git a/resources/js/components/fieldtypes/replicator/Replicator.vue b/resources/js/components/fieldtypes/replicator/Replicator.vue
index d2843c3f0..6cef1a737 100644
--- a/resources/js/components/fieldtypes/replicator/Replicator.vue
+++ b/resources/js/components/fieldtypes/replicator/Replicator.vue
@@ -274,17 +274,20 @@ export default {
return this.fieldPathKeys
.map((key, index) => {
- if (['attrs', 'values'].includes(key)) return;
+ if (['attrs', 'values'].includes(key) || key === '') return;
- if (Number.isInteger(parseInt(key))) {
- let setValues = data_get(this.publishContainer.values, this.fieldPathKeys.slice(0, index + 1).join('.'));
+ if (/^\d+$/.test(key)) {
+ let setValues = data_get(
+ this.publishContainer.values,
+ this.fieldPathKeys.slice(0, index + 1).join('.'),
+ );
- return setValues.attrs?.values.type || setValues.type;
+ return setValues?.attrs?.values?.type || setValues?.type || undefined;
}
return key;
})
- .filter((key) => key !== undefined)
+ .filter((key) => !!key)
.concat(this.handle)
.join('.');
},
diff --git a/src/Http/Controllers/CP/Fieldtypes/ReplicatorSetController.php b/src/Http/Controllers/CP/Fieldtypes/ReplicatorSetController.php
index fa7c946ae..156efef1d 100644
--- a/src/Http/Controllers/CP/Fieldtypes/ReplicatorSetController.php
+++ b/src/Http/Controllers/CP/Fieldtypes/ReplicatorSetController.php
@@ -4,7 +4,6 @@ namespace Statamic\Http\Controllers\CP\Fieldtypes;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Http\Request;
-use Illuminate\Support\Str;
use Statamic\Exceptions\NotFoundHttpException;
use Statamic\Facades;
use Statamic\Facades\Data;
@@ -70,17 +69,28 @@ class ReplicatorSetController extends CpController
private function getReplicatorField(Blueprint $blueprint, string $field): Field
{
- $remainingFieldPathComponents = explode('.', $field);
+ $remainingFieldPathComponents = array_values(array_filter(
+ explode('.', $field),
+ fn ($component) => $component !== ''
+ ));
- $config = $blueprint->fields()->all()->get($remainingFieldPathComponents[0])->config();
+ if ($remainingFieldPathComponents === []) {
+ throw new \Exception("Cannot find Replicator field [$field]");
+ }
+
+ $blueprintField = $blueprint->fields()->all()->get($remainingFieldPathComponents[0]);
+
+ if (! $blueprintField) {
+ throw new \Exception("Cannot find Replicator field [$field]");
+ }
- $config = $this->getConfig($config, $remainingFieldPathComponents);
+ $config = $this->getConfig($blueprintField->config(), $remainingFieldPathComponents);
if (! isset($config['type'])) {
throw new \Exception("Cannot find Replicator field [$field]");
}
- return new Field(Str::afterLast($field, '.'), $config);
+ return new Field($remainingFieldPathComponents[array_key_last($remainingFieldPathComponents)], $config);
}
private function getConfig(array $config, array $remainingFieldPathComponents): array
@@ -103,16 +113,41 @@ class ReplicatorSetController extends CpController
if ($isGroupOrGrid) {
array_shift($remainingFieldPathComponents);
+ if ($remainingFieldPathComponents === []) {
+ return $config;
+ }
+
$fields = $this->resolveFields($config['fields'] ?? []);
+ $handle = $remainingFieldPathComponents[0];
- return $this->getConfig($fields[$remainingFieldPathComponents[0]]['field'], $remainingFieldPathComponents);
+ if (! isset($fields[$handle]['field'])) {
+ throw new \Exception("Cannot find field [{$handle}]");
+ }
+
+ return $this->getConfig($fields[$handle]['field'], $remainingFieldPathComponents);
}
- $fields = $this->resolveFields($config[$remainingFieldPathComponents[0]]['fields']);
+ $setHandle = $remainingFieldPathComponents[0] ?? null;
+
+ if ($setHandle === null || $setHandle === '' || ! isset($config[$setHandle]['fields'])) {
+ throw new \Exception("Cannot find Replicator set [{$setHandle}]");
+ }
+
+ $fields = $this->resolveFields($config[$setHandle]['fields']);
array_shift($remainingFieldPathComponents);
- return $this->getConfig($fields[$remainingFieldPathComponents[0]]['field'], $remainingFieldPathComponents);
+ if ($remainingFieldPathComponents === []) {
+ throw new \Exception("Cannot find nested field in Replicator set [{$setHandle}]");
+ }
+
+ $handle = $remainingFieldPathComponents[0];
+
+ if (! isset($fields[$handle]['field'])) {
+ throw new \Exception("Cannot find field [{$handle}]");
+ }
+
+ return $this->getConfig($fields[$handle]['field'], $remainingFieldPathComponents);
}
private function flattenSets(array $sets): array |
This pull request relaxes the group/grid fieldtype check in
ReplicatorController, fixing an issue where Bard/Replicator sets couldn't be added when nested inside a custom fieldtype.Fixes #14066