Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/json-schema/code-generation/from-classes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ class ModernUser
// Generate with Draft 2019-09 for deprecated support
$schema = Schema::fromClass(
ModernUser::class,
version: SchemaVersion::Draft_2019_09
schemaVersion: SchemaVersion::Draft_2019_09
);

// The generated schema will include "deprecated": true for old_email
Expand Down
2 changes: 1 addition & 1 deletion docs/json-schema/code-generation/from-closures.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ $modernApiClosure = function (
// Generate with Draft 2019-09 for deprecated support
$modernSchema = Schema::fromClosure(
$modernApiClosure,
version: SchemaVersion::Draft_2019_09
schemaVersion: SchemaVersion::Draft_2019_09
);

// Apply validation rules programmatically after generation
Expand Down
2 changes: 1 addition & 1 deletion docs/json-schema/code-generation/from-enums.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ enum OrderStatus: string
// Generate with Draft 2019-09 for advanced features
$schema = Schema::fromEnum(
OrderStatus::class,
version: SchemaVersion::Draft_2019_09
schemaVersion: SchemaVersion::Draft_2019_09
);

// The generated schema includes all enum values in the enum array
Expand Down
4 changes: 2 additions & 2 deletions docs/json-schema/schema-types/union.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ $dbFieldSchema = Schema::union([

$recordSchema = Schema::object('database_record')
->properties(
Schema::integer('id')->required(),
Schema::additionalProperties($dbFieldSchema)
Schema::integer('id')->required()
)
->additionalProperties($dbFieldSchema)
->description('Flexible database record with typed fields');
```

Expand Down
46 changes: 31 additions & 15 deletions docs/json-schema/validation/error-handling.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ try {
} catch (SchemaException $e) {
echo "Error: " . $e->getMessage(); // User-friendly message
echo "Code: " . $e->getCode(); // Error code
echo "Property: " . $e->getProperty(); // Failed property (if available)
echo "Value: " . $e->getFailedValue(); // Value that failed (if available)

// Get detailed error information
$errors = $e->getErrors();
print_r($errors); // Array with paths as keys and messages as values
}
```

Expand Down Expand Up @@ -75,7 +77,13 @@ foreach ($testCases as $index => $testData) {
} catch (SchemaException $e) {
echo "Test case {$index}: {$e->getMessage()}\n";
echo " Error code: {$e->getCode()}\n";
echo " Failed property: " . ($e->getProperty() ?? 'unknown') . "\n\n";

// Get detailed errors with property paths
$errors = $e->getErrors();
foreach ($errors as $path => $message) {
echo " Failed property: {$path} - {$message}\n";
}
echo "\n";
}
}
```
Expand Down Expand Up @@ -141,8 +149,12 @@ $requiredSchema = Schema::object('user')
try {
$requiredSchema->validate(['name' => 'John']); // Missing email
} catch (SchemaException $e) {
echo $e->getMessage(); // "Property 'email' is required"
echo $e->getProperty(); // "email"
echo $e->getMessage(); // Error message

// Get detailed errors
$errors = $e->getErrors();
// Errors array contains property paths as keys
print_r($errors);
}
```

Expand Down Expand Up @@ -190,10 +202,14 @@ class UserFriendlyErrorHandler

public function getFieldSpecificMessage(SchemaException $e): string
{
$property = $e->getProperty();
$errors = $e->getErrors();
$friendlyMessage = $this->getFriendlyMessage($e);

if ($property) {

// Get the first error property path
if (!empty($errors)) {
$firstPath = array_key_first($errors);
// Remove leading slash and convert to readable format
$property = ltrim($firstPath, '/');
$fieldName = ucfirst(str_replace('_', ' ', $property));
return "{$fieldName}: {$friendlyMessage}";
}
Expand Down Expand Up @@ -261,7 +277,6 @@ class ValidatorWithResults
'message' => $e->getMessage(),
'code' => $e->getCode(),
'field' => $e->getProperty(),
'value' => $e->getFailedValue()
];
}

Expand Down Expand Up @@ -320,7 +335,6 @@ class NestedErrorHandler
$errors[] = [
'path' => $fieldPath,
'message' => $e->getMessage(),
'value' => $e->getFailedValue()
];
}

Expand Down Expand Up @@ -427,11 +441,14 @@ Provide helpful suggestions for common validation errors:
```php
class ErrorRecoveryHelper
{
public function suggestCorrections(SchemaException $e): array
/**
* Suggest corrections based on validation errors.
* Note: Pass the original value if you need value-specific suggestions.
*/
public function suggestCorrections(SchemaException $e, mixed $value = null): array
{
$suggestions = [];
$message = $e->getMessage();
$value = $e->getFailedValue();

// Email format suggestions
if (strpos($message, 'email') !== false && is_string($value)) {
Expand Down Expand Up @@ -480,14 +497,13 @@ class ErrorRecoveryHelper
return $suggestions;
}

public function getDetailedError(SchemaException $e): array
public function getDetailedError(SchemaException $e, mixed $value = null): array
{
return [
'message' => $e->getMessage(),
'code' => $e->getCode(),
'field' => $e->getProperty(),
'value' => $e->getFailedValue(),
'suggestions' => $this->suggestCorrections($e)
'suggestions' => $this->suggestCorrections($e, $value)
];
}
}
Expand Down
37 changes: 37 additions & 0 deletions src/Exceptions/SchemaException.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,41 @@

return $errors;
}

/**
* Get the first property path that failed validation.
* Returns the property path without the leading slash (e.g., 'email' instead of '/email').
*
* @return string|null The property path or null if no errors
*/
public function getProperty(): ?string
{
$errors = $this->getErrors();

if (empty($errors)) {

Check failure on line 59 in src/Exceptions/SchemaException.php

View workflow job for this annotation

GitHub Actions / phpstan

Construct empty() is not allowed. Use more strict comparison.
return null;
}

$firstPath = array_key_first($errors);

// Remove leading slash for cleaner output
return ltrim((string) $firstPath, '/');

Check failure on line 66 in src/Exceptions/SchemaException.php

View workflow job for this annotation

GitHub Actions / phpstan

Casting to string something that's already string.
}

/**
* Get the first property path that failed validation with the leading slash.
* Returns the full path as used in the errors array (e.g., '/email').
*
* @return string|null The full property path or null if no errors
*/
public function getPropertyPath(): ?string
{
$errors = $this->getErrors();

if (empty($errors)) {

Check failure on line 79 in src/Exceptions/SchemaException.php

View workflow job for this annotation

GitHub Actions / phpstan

Construct empty() is not allowed. Use more strict comparison.
return null;
}

return (string) array_key_first($errors);

Check failure on line 83 in src/Exceptions/SchemaException.php

View workflow job for this annotation

GitHub Actions / phpstan

Casting to string something that's already string.
}
}
Loading