Skip to content

Commit 2e59afc

Browse files
committed
fix: remove string-only validation rules from multi-value field types
LinkFieldType (multiChoice) allowed starts_with and url as configurable validation rules, but these expect string values and crash with TypeError when applied to array values stored in json_value. - Remove STARTS_WITH and URL from LinkFieldType availableValidationRules - Add CleanMultiValueValidationRulesStep upgrade step to clean existing database records with incompatible rules - Update test datasets to reflect the corrected allowed rules
1 parent 2a71597 commit 2e59afc

5 files changed

Lines changed: 116 additions & 8 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Relaticle\CustomFields\Console\Commands\Upgrade\Steps;
6+
7+
use Illuminate\Console\Command;
8+
use Relaticle\CustomFields\Console\Commands\Upgrade\UpgradeStep;
9+
use Relaticle\CustomFields\Console\Commands\Upgrade\UpgradeStepResult;
10+
use Relaticle\CustomFields\CustomFields;
11+
12+
/**
13+
* Removes string-only validation rules from multi-value field types.
14+
*
15+
* Multi-value fields (link, email, phone) store arrays in json_value.
16+
* Rules like starts_with and url expect strings and cause TypeErrors.
17+
*/
18+
final class CleanMultiValueValidationRulesStep implements UpgradeStep
19+
{
20+
/** @var list<string> */
21+
private const MULTI_VALUE_FIELD_TYPES = ['link', 'email', 'phone'];
22+
23+
/** @var list<string> */
24+
private const STRING_ONLY_RULES = [
25+
'starts_with',
26+
'ends_with',
27+
'doesnt_start_with',
28+
'doesnt_end_with',
29+
'url',
30+
'email',
31+
'string',
32+
'alpha',
33+
'alpha_num',
34+
'alpha_dash',
35+
'regex',
36+
'not_regex',
37+
'active_url',
38+
'ascii',
39+
'ip',
40+
'ipv4',
41+
'ipv6',
42+
'json',
43+
'mac_address',
44+
'uuid',
45+
'uppercase',
46+
];
47+
48+
public function name(): string
49+
{
50+
return 'Clean Multi-Value Validation Rules';
51+
}
52+
53+
public function description(): string
54+
{
55+
return 'Remove string-only validation rules (starts_with, url, etc.) from multi-value fields';
56+
}
57+
58+
public function execute(bool $dryRun, Command $command): UpgradeStepResult
59+
{
60+
$fieldModel = CustomFields::newCustomFieldModel();
61+
62+
$affectedFields = $fieldModel->newQuery()
63+
->whereIn('type', self::MULTI_VALUE_FIELD_TYPES)
64+
->whereNotNull('validation_rules')
65+
->get();
66+
67+
$processed = 0;
68+
$failed = 0;
69+
70+
foreach ($affectedFields as $field) {
71+
$rules = $field->validation_rules?->toCollection() ?? collect();
72+
73+
$invalidRules = $rules->filter(
74+
fn ($rule) => in_array($rule->name, self::STRING_ONLY_RULES, true)
75+
);
76+
77+
if ($invalidRules->isEmpty()) {
78+
continue;
79+
}
80+
81+
$ruleNames = $invalidRules->pluck('name')->implode(', ');
82+
$command->line(" Processing field '{$field->name}' (type: {$field->type}, id: {$field->id}): removing [{$ruleNames}]");
83+
84+
if (! $dryRun) {
85+
$cleanedRules = $rules->reject(
86+
fn ($rule) => in_array($rule->name, self::STRING_ONLY_RULES, true)
87+
)->values()->toArray();
88+
89+
try {
90+
$field->update([
91+
'validation_rules' => $cleanedRules === [] ? null : $cleanedRules,
92+
]);
93+
$processed++;
94+
} catch (\Throwable $e) {
95+
$command->line(" <error>Failed to update field {$field->id}: {$e->getMessage()}</error>");
96+
$failed++;
97+
}
98+
} else {
99+
$processed++;
100+
}
101+
}
102+
103+
if ($processed === 0 && $failed === 0) {
104+
$command->line(' <info>No fields need cleanup</info>');
105+
106+
return UpgradeStepResult::skipped('No multi-value fields with string-only validation rules found');
107+
}
108+
109+
return UpgradeStepResult::success($processed, $failed);
110+
}
111+
}

src/Console/Commands/UpgradeCommand.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Relaticle\CustomFields\Console\Commands;
66

77
use Illuminate\Console\Command;
8+
use Relaticle\CustomFields\Console\Commands\Upgrade\Steps\CleanMultiValueValidationRulesStep;
89
use Relaticle\CustomFields\Console\Commands\Upgrade\Steps\ClearCachesStep;
910
use Relaticle\CustomFields\Console\Commands\Upgrade\Steps\MigrateEmailFormatStep;
1011
use Relaticle\CustomFields\Console\Commands\Upgrade\Steps\MigrateLookupFieldsStep;
@@ -32,6 +33,7 @@ final class UpgradeCommand extends Command
3233
'lookup-fields' => MigrateLookupFieldsStep::class,
3334
'email-format' => MigrateEmailFormatStep::class,
3435
'phone-format' => MigratePhoneFormatStep::class,
36+
'clean-multivalue-rules' => CleanMultiValueValidationRulesStep::class,
3537
'validate-schema' => ValidateSchemaStep::class,
3638
'clear-caches' => ClearCachesStep::class,
3739
];

src/FieldTypeSystem/Definitions/LinkFieldType.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ public function configure(): FieldSchema
3434
->defaultItemValidationRules(['max:2048', 'regex:/^(https?:\/\/)?([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}(\/.*)?$/'])
3535
->availableValidationRules([
3636
ValidationRule::REQUIRED,
37-
ValidationRule::URL,
38-
ValidationRule::STARTS_WITH,
3937
ValidationRule::MIN,
4038
ValidationRule::MAX,
4139
]);

tests/Datasets/FieldTypesDataset.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,7 @@
275275
'link_field' => [
276276
'fieldType' => 'link',
277277
'config' => [
278-
'validation_rules' => [
279-
['name' => 'url', 'parameters' => []],
280-
['name' => 'starts_with', 'parameters' => ['http://', 'https://']],
281-
],
278+
'validation_rules' => [],
282279
],
283280
'testValues' => [
284281
'valid' => ['https://example.com', 'http://test.org', 'https://www.google.com'],

tests/Datasets/ValidationRulesDataset.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -590,8 +590,8 @@
590590
],
591591
'url_field_rules' => [
592592
'fieldType' => 'link',
593-
'allowedRules' => ['required', 'url', 'starts_with'],
594-
'disallowedRules' => ['numeric', 'alpha', 'boolean', 'array', 'date', 'integer'],
593+
'allowedRules' => ['required', 'min', 'max'],
594+
'disallowedRules' => ['numeric', 'alpha', 'boolean', 'array', 'date', 'integer', 'starts_with', 'url'],
595595
],
596596
'phone_field_rules' => [
597597
'fieldType' => 'phone',

0 commit comments

Comments
 (0)