json-schema icon indicating copy to clipboard operation
json-schema copied to clipboard

\JsonSchema\Constraints\BaseConstraint::arrayToObjectRecursive() doesn't convert empty arrays to objects

Open shtrom opened this issue 8 years ago • 5 comments

When an empty array is given to \JsonSchema\Constraints\BaseConstraint::arrayToObjectRecursive(), it is returned identical. This leads to issues later on when using a SchemaStorage to contain this schema. Such an empty schema is only really used for tests, but this currently requires workarounds.

The following example code

use \JsonSchema\Validator;
print_r(Validator::arrayToObjectRecursive([ "baz" => [ "bar" => "baz" ]  ])); 
print_r(Validator::arrayToObjectRecursive([]));

results in

stdClass Object
(
    [baz] => stdClass Object
        (
            [bar] => baz
        )

)
Array
(
)

shtrom avatar Apr 05 '17 07:04 shtrom

Hum, this seems to only be on the 5.x.x branch.

Adding cast to (object) before (well, after the keyword) the return in https://github.com/justinrainbow/json-schema/blob/5.x.x/src/JsonSchema/Constraints/BaseConstraint.php#L146 seems to fix the issue.

shtrom avatar Apr 05 '17 07:04 shtrom

Strike that, it's on 6.0.0-dev, too.

shtrom avatar Apr 05 '17 07:04 shtrom

Thanks - fixed in #409. This will be backported to 5.x.x after merge.

erayd avatar Apr 05 '17 08:04 erayd

The issue was fixed for passing an empty array directly, but still persists for nested empty arrays.

// Directly passing an empty array.
$array = [];
$object = \JsonSchema\Validator::arrayToObjectRecursive($array);
print_r($object);
// stdClass Object
// (
// )
// Passing a nested empty array.
$array = ['shouldBeAnObject' => []];
$object = \JsonSchema\Validator::arrayToObjectRecursive($array);
print_r($object);
// stdClass Object
// (
//     [shouldBeAnObject] => Array
//         (
//         )
// )

It could be fixed by passing JSON_FORCE_OBJECT flag to json_encode used in arrayToObjectRecursive method. https://github.com/justinrainbow/json-schema/blob/master/src/JsonSchema/Constraints/BaseConstraint.php#L145 https://www.php.net/manual/en/function.json-encode.php https://www.php.net/manual/en/json.constants.php#constant.json-force-object

--- a/src/JsonSchema/Constraints/BaseConstraint.php
+++ b/src/JsonSchema/Constraints/BaseConstraint.php
@@ -142,7 +142,7 @@ class BaseConstraint
      */
     public static function arrayToObjectRecursive($array)
     {
-        $json = json_encode($array);
+        $json = json_encode($array, \JSON_FORCE_OBJECT);
         if (json_last_error() !== \JSON_ERROR_NONE) {
             $message = 'Unable to encode schema array as JSON';
             if (function_exists('json_last_error_msg')) {
// Passing a nested empty array after adding JSON_FORCE_OBJECT flag.
$array = ['shouldBeAnObject' => []];
$object = \JsonSchema\Validator::arrayToObjectRecursive($array);
print_r($object);
// stdClass Object
// (
//     [shouldBeAnObject] => stdClass Object
//         (
//         )
// )

wotnak avatar Sep 09 '23 11:09 wotnak

Although, adding JSON_FORCE_OBJECT flag would also change how nested not empty not associative arrays are treated, so probably not the best solution.

// Currently.
$array = ['key' => ['value1', 'value2']];
$object = \JsonSchema\Validator::arrayToObjectRecursive($array);
// stdClass Object
// (
//     [key] => Array
//         (
//             [0] => value1
//             [1] => value2
//         )
// )
// After adding JSON_FORCE_OBJECT flag.
$array = ['key' => ['value1', 'value2']];
$object = \JsonSchema\Validator::arrayToObjectRecursive($array);
// stdClass Object
// (
//     [key] => stdClass Object
//         (
//             [0] => value1
//             [1] => value2
//         )
// )

wotnak avatar Sep 09 '23 12:09 wotnak