Skip to content

Commit 3442446

Browse files
feat: Update cast exception to include original value
Prior, the cast exception would contain the cast-value and not the original value, which can be confusing when reporting the validation error to users.
1 parent 6071ee1 commit 3442446

File tree

2 files changed

+58
-15
lines changed

2 files changed

+58
-15
lines changed

src/Fields/BaseField.php

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -151,17 +151,25 @@ final public function castValue($val)
151151
}
152152

153153
return null;
154-
} else {
155-
$val = $this->validateCastValue($val);
156-
if (!$this->constraintsDisabled) {
157-
$validationErrors = $this->checkConstraints($val);
158-
if (count($validationErrors) > 0) {
159-
throw new FieldValidationException($validationErrors);
154+
}
155+
156+
$castVal = $this->validateCastValue($val);
157+
158+
if (!$this->constraintsDisabled) {
159+
$validationErrors = $this->checkConstraints($castVal);
160+
161+
if (count($validationErrors) > 0) {
162+
foreach ($validationErrors as $i => $schemaError) {
163+
\assert($schemaError instanceof SchemaValidationError);
164+
$schemaError->extraDetails['value'] = $val;
165+
$validationErrors[$i] = $schemaError;
160166
}
161-
}
162167

163-
return $val;
168+
throw new FieldValidationException($validationErrors);
169+
}
164170
}
171+
172+
return $castVal;
165173
}
166174

167175
public function validateValue($val)
@@ -171,12 +179,6 @@ public function validateValue($val)
171179

172180
return [];
173181
} catch (FieldValidationException $e) {
174-
foreach ($e->validationErrors as $ve) {
175-
// Replace the cast-value for the violation, with the original value.
176-
// This so the error message contains the original representation of the invalid value.
177-
$ve->extraDetails['value'] = $val;
178-
}
179-
180182
return $e->validationErrors;
181183
}
182184
}

tests/Fields/BaseFieldTest.php

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Fields;
66

7+
use frictionlessdata\tableschema\Exceptions\FieldValidationException;
78
use frictionlessdata\tableschema\Fields\BaseField;
89
use PHPUnit\Framework\TestCase;
910

@@ -12,7 +13,7 @@
1213
*/
1314
class BaseFieldTest extends TestCase
1415
{
15-
public function testPreserveOriginalValueInValidationError(): void
16+
public function testPreserveOriginalValueInValidateError(): void
1617
{
1718
$descriptor = (object) [
1819
'name' => 'date_col',
@@ -38,4 +39,44 @@ protected function validateCastValue($val)
3839
$error->extraDetails['value']
3940
);
4041
}
42+
43+
public function testPreserveOriginalValueInCastError(): void
44+
{
45+
$descriptor = (object) [
46+
'name' => 'date_col',
47+
'constraints' => (object) ['minimum' => '2025-07-01'],
48+
];
49+
50+
$sut = new class($descriptor) extends BaseField {
51+
protected function validateCastValue($val)
52+
{
53+
// If the logic is wrong, this object will be in the error
54+
// instead of the original date string.
55+
return new \DateTimeImmutable($val);
56+
}
57+
};
58+
59+
$validatedValue = '2025-06-30';
60+
$exception = null;
61+
62+
try {
63+
$sut->castValue($validatedValue);
64+
} catch (FieldValidationException $exception) {
65+
}
66+
67+
self::assertNotNull($exception, 'An exception is expected for this test.');
68+
self::assertSame(
69+
'date_col: value is below minimum ("2025-06-30")',
70+
$exception->getMessage()
71+
);
72+
73+
$errors = $exception->validationErrors;
74+
75+
self::assertCount(1, $errors);
76+
$error = reset($errors);
77+
self::assertSame(
78+
$validatedValue,
79+
$error->extraDetails['value']
80+
);
81+
}
4182
}

0 commit comments

Comments
 (0)