Skip to content

Commit 4b29913

Browse files
committed
fix: guard against non-scalar values in UniqueCustomFieldValue rule
When multi-value fields (link, email, phone) receive malformed input such as array-of-objects instead of array-of-strings, the (string) cast on line 39 throws an ErrorException. Skip non-scalar values since they cannot be meaningfully compared for uniqueness and will be caught by other validation rules (string, regex, max).
1 parent 653534c commit 4b29913

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

src/Rules/UniqueCustomFieldValue.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ public function validate(string $attribute, mixed $value, Closure $fail): void
3434
if (blank($singleValue)) {
3535
continue;
3636
}
37-
37+
if (! is_scalar($singleValue)) {
38+
continue;
39+
}
3840
$normalizedValue = $fieldType
3941
? $fieldType->setValue((string) $singleValue)
4042
: (string) $singleValue;

tests/Feature/Rules/UniqueCustomFieldValueTest.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,56 @@ function storeTextValueForPost(Post $post, CustomField $field, string $value): v
330330
});
331331
});
332332

333+
describe('Non-scalar value handling', function (): void {
334+
it('does not crash when link field receives array-of-objects instead of array-of-strings', function (): void {
335+
$rule = new UniqueCustomFieldValue($this->linkField);
336+
$errors = [];
337+
338+
$rule->validate(
339+
'custom_fields.domains',
340+
[['url' => 'https://example.com']],
341+
function (string $message) use (&$errors): void {
342+
$errors[] = $message;
343+
}
344+
);
345+
346+
expect($errors)->toBeEmpty();
347+
});
348+
349+
it('does not crash when text field receives an array instead of a string', function (): void {
350+
$rule = new UniqueCustomFieldValue($this->textField);
351+
$errors = [];
352+
353+
$rule->validate(
354+
'custom_fields.slug',
355+
['nested', 'array'],
356+
function (string $message) use (&$errors): void {
357+
$errors[] = $message;
358+
}
359+
);
360+
361+
expect($errors)->toBeEmpty();
362+
});
363+
364+
it('still validates scalar values after skipping non-scalar ones', function (): void {
365+
$existing = Post::factory()->create();
366+
storeLinkValueForPost($existing, $this->linkField, ['taken.com']);
367+
368+
$rule = new UniqueCustomFieldValue($this->linkField);
369+
$errors = [];
370+
371+
$rule->validate(
372+
'custom_fields.domains',
373+
[['url' => 'https://skip.me'], 'taken.com'],
374+
function (string $message) use (&$errors): void {
375+
$errors[] = $message;
376+
}
377+
);
378+
379+
expect($errors)->not->toBeEmpty();
380+
});
381+
});
382+
333383
describe('Morph alias resolution', function (): void {
334384
beforeEach(function (): void {
335385
Relation::morphMap([

0 commit comments

Comments
 (0)