55use Exception ;
66use Illuminate \Contracts \Validation \Rule ;
77use Illuminate \JsonSchema \JsonSchema as Schema ;
8+ use JsonException ;
89use Opis \JsonSchema \Errors \ValidationError ;
910use Opis \JsonSchema \Validator ;
1011
1112class JsonSchema implements Rule
1213{
13- /**
14- * The JSON schema instance.
15- */
16- protected Schema $ schema ;
17-
1814 /**
1915 * The validation error message.
2016 */
@@ -23,9 +19,8 @@ class JsonSchema implements Rule
2319 /**
2420 * Create a new JSON schema validation rule.
2521 */
26- public function __construct (Schema $ schema )
22+ public function __construct (protected Schema $ schema )
2723 {
28- $ this ->schema = $ schema ;
2924 }
3025
3126 /**
@@ -41,27 +36,31 @@ public function passes($attribute, $value): bool
4136 // Normalize the data to what Opis expects
4237 $ data = $ this ->normalizeData ($ value );
4338
44- if ($ data === null && $ this ->errorMessage ) {
39+ if ($ data === null && $ this ->errorMessage !== null ) {
4540 return false ;
4641 }
4742
4843 try {
49- $ validator = new Validator ;
50- $ schemaString = $ this ->schema ->toString ();
51- $ result = $ validator ->validate ($ data , $ schemaString );
44+ $ result = (new Validator )->validate ($ data , $ this ->schema ->toString ());
5245
53- if (! $ result ->isValid ()) {
54- $ this ->errorMessage = $ this ->formatValidationError ($ result ->error ());
55-
56- return false ;
46+ if ($ result ->isValid ()) {
47+ return true ;
5748 }
5849
59- return true ;
50+ $ this -> errorMessage = $ this -> formatValidationError ( $ result -> error ()) ;
6051 } catch (Exception $ e ) {
6152 $ this ->errorMessage = "Schema validation error: {$ e ->getMessage ()}" ;
62-
63- return false ;
6453 }
54+
55+ return false ;
56+ }
57+
58+ /**
59+ * Get the validation error message.
60+ */
61+ public function message (): string
62+ {
63+ return $ this ->errorMessage ?? 'The :attribute does not match the required schema. ' ;
6564 }
6665
6766 /**
@@ -72,46 +71,34 @@ public function passes($attribute, $value): bool
7271 */
7372 protected function normalizeData ($ value )
7473 {
75- if (is_string ($ value )) {
76- $ decoded = json_decode ($ value );
77-
78- if (json_last_error () !== JSON_ERROR_NONE ) {
79- $ this ->errorMessage = 'Invalid JSON format: ' .json_last_error_msg ();
80-
81- return null ;
82- }
83-
84- return $ decoded ;
85- }
86-
8774 if (is_array ($ value ) || is_object ($ value )) {
8875 // Convert to JSON and back to ensure proper object/array structure for Opis
8976 return json_decode (json_encode ($ value , JSON_FORCE_OBJECT ), false );
9077 }
9178
92- return $ value ;
79+ if (! is_string ($ value )) {
80+ return $ value ;
81+ }
82+
83+ try {
84+ return json_decode ($ value , false , 512 , JSON_THROW_ON_ERROR );
85+ } catch (JsonException $ e ) {
86+ $ this ->errorMessage = "Invalid JSON format: {$ e ->getMessage ()}" ;
87+
88+ return null ;
89+ }
9390 }
9491
9592 /**
9693 * Format the validation error message.
9794 */
98- protected function formatValidationError (? ValidationError $ error ): string
95+ protected function formatValidationError (ValidationError $ error ): string
9996 {
10097 $ keyword = $ error ->keyword ();
10198 $ dataPath = implode ('. ' , $ error ->data ()->path () ?? []);
10299
103- if ($ dataPath ) {
104- return "Validation failed at ' {$ dataPath }': {$ keyword }" ;
105- }
106-
107- return "Validation failed: {$ keyword }" ;
108- }
109-
110- /**
111- * Get the validation error message.
112- */
113- public function message (): string
114- {
115- return $ this ->errorMessage ?? 'The :attribute does not match the required schema. ' ;
100+ return $ dataPath !== '' ?
101+ "Validation failed at ' $ dataPath': $ keyword " :
102+ "Validation failed: $ keyword " ;
116103 }
117104}
0 commit comments