diff --git a/src/BSON/PackedArray.c b/src/BSON/PackedArray.c index ac9fb5b4f..b6a34d010 100644 --- a/src/BSON/PackedArray.c +++ b/src/BSON/PackedArray.c @@ -81,8 +81,58 @@ static HashTable* php_phongo_packedarray_get_properties_hash(phongo_compat_objec return props; } +static bool php_phongo_packedarray_to_json(zval* return_value, bson_json_mode_t mode, const bson_t* bson) +{ + char* json = NULL; + size_t json_len; + bson_json_opts_t* opts = bson_json_opts_new(mode, BSON_MAX_LEN_UNLIMITED); + bool ret = false; + + bson_json_opts_set_outermost_array(opts, true); + + json = bson_as_json_with_opts(bson, &json_len, opts); + + if (json) { + ZVAL_STRINGL(return_value, json, json_len); + bson_free(json); + ret = true; + } else { + ZVAL_UNDEF(return_value); + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Could not convert BSON array to a JSON string"); + } + + bson_json_opts_destroy(opts); + + return ret; +} + PHONGO_DISABLED_CONSTRUCTOR(MongoDB_BSON_PackedArray) +static PHP_METHOD(MongoDB_BSON_PackedArray, fromJSON) +{ + zval zv; + php_phongo_packedarray_t* intern; + zend_string* json; + bson_t* bson; + bson_error_t error; + + PHONGO_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(json) + PHONGO_PARSE_PARAMETERS_END(); + + bson = bson_new_from_json((const uint8_t*) ZSTR_VAL(json), ZSTR_LEN(json), &error); + if (!bson) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s", error.domain == BSON_ERROR_JSON ? error.message : "Error parsing JSON"); + return; + } + + object_init_ex(&zv, php_phongo_packedarray_ce); + intern = Z_PACKEDARRAY_OBJ_P(&zv); + intern->bson = bson; + + RETURN_ZVAL(&zv, 1, 1); +} + static PHP_METHOD(MongoDB_BSON_PackedArray, fromPHP) { zval zv; @@ -192,6 +242,28 @@ static PHP_METHOD(MongoDB_BSON_PackedArray, has) RETURN_BOOL(php_phongo_packedarray_has(intern, index)); } +static PHP_METHOD(MongoDB_BSON_PackedArray, toCanonicalExtendedJSON) +{ + php_phongo_packedarray_t* intern; + + PHONGO_PARSE_PARAMETERS_NONE(); + + intern = Z_PACKEDARRAY_OBJ_P(getThis()); + + php_phongo_packedarray_to_json(return_value, BSON_JSON_MODE_CANONICAL, intern->bson); +} + +static PHP_METHOD(MongoDB_BSON_PackedArray, toRelaxedExtendedJSON) +{ + php_phongo_packedarray_t* intern; + + PHONGO_PARSE_PARAMETERS_NONE(); + + intern = Z_PACKEDARRAY_OBJ_P(getThis()); + + php_phongo_packedarray_to_json(return_value, BSON_JSON_MODE_RELAXED, intern->bson); +} + static PHP_METHOD(MongoDB_BSON_PackedArray, toPHP) { php_phongo_packedarray_t* intern; diff --git a/src/BSON/PackedArray.stub.php b/src/BSON/PackedArray.stub.php index bb9f36097..819477f32 100644 --- a/src/BSON/PackedArray.stub.php +++ b/src/BSON/PackedArray.stub.php @@ -11,6 +11,8 @@ final class PackedArray implements \IteratorAggregate, \Serializable, \ArrayAcce { private function __construct() {} + final static public function fromJSON(string $json): PackedArray {} + final static public function fromPHP(array $value): PackedArray {} #if PHP_VERSION_ID >= 80000 @@ -31,6 +33,10 @@ final public function toPHP(?array $typeMap = null): array|object {} final public function toPHP(?array $typeMap = null) {} #endif + final public function toCanonicalExtendedJSON(): string {} + + final public function toRelaxedExtendedJSON(): string {} + #if PHP_VERSION_ID >= 80000 public function offsetExists(mixed $offset): bool {} # else diff --git a/src/BSON/PackedArray_arginfo.h b/src/BSON/PackedArray_arginfo.h index 7d9e2c374..24cdb3970 100644 --- a/src/BSON/PackedArray_arginfo.h +++ b/src/BSON/PackedArray_arginfo.h @@ -1,9 +1,13 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: db49af73e3b8ef35fa6ed70fd8c097e0de69f17e */ + * Stub hash: 792eeecef52e338fc07db86926729eecc024885a */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray___construct, 0, 0, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_fromJSON, 0, 1, MongoDB\\BSON\\PackedArray, 0) + ZEND_ARG_TYPE_INFO(0, json, IS_STRING, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_fromPHP, 0, 1, MongoDB\\BSON\\PackedArray, 0) ZEND_ARG_TYPE_INFO(0, value, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -39,6 +43,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_toPHP, 0, 0, 0) ZEND_END_ARG_INFO() #endif +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_toCanonicalExtendedJSON, 0, 0, IS_STRING, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_MongoDB_BSON_PackedArray_toRelaxedExtendedJSON arginfo_class_MongoDB_BSON_PackedArray_toCanonicalExtendedJSON + #if PHP_VERSION_ID >= 80000 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_offsetExists, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) @@ -89,14 +98,13 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_o ZEND_END_ARG_INFO() #endif -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray___toString, 0, 0, IS_STRING, 0) -ZEND_END_ARG_INFO() +#define arginfo_class_MongoDB_BSON_PackedArray___toString arginfo_class_MongoDB_BSON_PackedArray_toCanonicalExtendedJSON ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray___set_state, 0, 1, MongoDB\\BSON\\PackedArray, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() -#define arginfo_class_MongoDB_BSON_PackedArray_serialize arginfo_class_MongoDB_BSON_PackedArray___toString +#define arginfo_class_MongoDB_BSON_PackedArray_serialize arginfo_class_MongoDB_BSON_PackedArray_toCanonicalExtendedJSON #if PHP_VERSION_ID >= 80000 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_unserialize, 0, 1, IS_VOID, 0) @@ -119,6 +127,7 @@ ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_PackedArray, __construct); +static ZEND_METHOD(MongoDB_BSON_PackedArray, fromJSON); static ZEND_METHOD(MongoDB_BSON_PackedArray, fromPHP); #if PHP_VERSION_ID >= 80000 static ZEND_METHOD(MongoDB_BSON_PackedArray, get); @@ -134,6 +143,8 @@ static ZEND_METHOD(MongoDB_BSON_PackedArray, toPHP); #if !(PHP_VERSION_ID >= 80000) static ZEND_METHOD(MongoDB_BSON_PackedArray, toPHP); #endif +static ZEND_METHOD(MongoDB_BSON_PackedArray, toCanonicalExtendedJSON); +static ZEND_METHOD(MongoDB_BSON_PackedArray, toRelaxedExtendedJSON); #if PHP_VERSION_ID >= 80000 static ZEND_METHOD(MongoDB_BSON_PackedArray, offsetExists); #endif @@ -173,6 +184,7 @@ static ZEND_METHOD(MongoDB_BSON_PackedArray, __serialize); static const zend_function_entry class_MongoDB_BSON_PackedArray_methods[] = { ZEND_ME(MongoDB_BSON_PackedArray, __construct, arginfo_class_MongoDB_BSON_PackedArray___construct, ZEND_ACC_PRIVATE) + ZEND_ME(MongoDB_BSON_PackedArray, fromJSON, arginfo_class_MongoDB_BSON_PackedArray_fromJSON, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, fromPHP, arginfo_class_MongoDB_BSON_PackedArray_fromPHP, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) #if PHP_VERSION_ID >= 80000 ZEND_ME(MongoDB_BSON_PackedArray, get, arginfo_class_MongoDB_BSON_PackedArray_get, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) @@ -188,6 +200,8 @@ static const zend_function_entry class_MongoDB_BSON_PackedArray_methods[] = { #if !(PHP_VERSION_ID >= 80000) ZEND_ME(MongoDB_BSON_PackedArray, toPHP, arginfo_class_MongoDB_BSON_PackedArray_toPHP, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) #endif + ZEND_ME(MongoDB_BSON_PackedArray, toCanonicalExtendedJSON, arginfo_class_MongoDB_BSON_PackedArray_toCanonicalExtendedJSON, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) + ZEND_ME(MongoDB_BSON_PackedArray, toRelaxedExtendedJSON, arginfo_class_MongoDB_BSON_PackedArray_toRelaxedExtendedJSON, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) #if PHP_VERSION_ID >= 80000 ZEND_ME(MongoDB_BSON_PackedArray, offsetExists, arginfo_class_MongoDB_BSON_PackedArray_offsetExists, ZEND_ACC_PUBLIC) #endif diff --git a/tests/bson/bson-packedarray-fromJSON-001.phpt b/tests/bson/bson-packedarray-fromJSON-001.phpt new file mode 100644 index 000000000..647a919aa --- /dev/null +++ b/tests/bson/bson-packedarray-fromJSON-001.phpt @@ -0,0 +1,37 @@ +--TEST-- +MongoDB\BSON\PackedArray::fromJSON(): Decoding JSON +--FILE-- + +===DONE=== + +--EXPECT-- +Test [] + 0 : 05 00 00 00 00 [.....] +Test [ 1, 2, 3 ] + 0 : 1a 00 00 00 10 30 00 01 00 00 00 10 31 00 02 00 [.....0......1...] + 10 : 00 00 10 32 00 03 00 00 00 00 [...2......] +Test [[ 1, 2, 3 ]] + 0 : 22 00 00 00 04 30 00 1a 00 00 00 10 30 00 01 00 ["....0......0...] + 10 : 00 00 10 31 00 02 00 00 00 10 32 00 03 00 00 00 [...1......2.....] + 20 : 00 00 [..] +Test [{ "bar": 1 }] + 0 : 16 00 00 00 03 30 00 0e 00 00 00 10 62 61 72 00 [.....0......bar.] + 10 : 01 00 00 00 00 00 [......] +===DONE=== diff --git a/tests/bson/bson-packedarray-fromJSON-002.phpt b/tests/bson/bson-packedarray-fromJSON-002.phpt new file mode 100644 index 000000000..84f46421a --- /dev/null +++ b/tests/bson/bson-packedarray-fromJSON-002.phpt @@ -0,0 +1,50 @@ +--TEST-- +MongoDB\BSON\PackedArray::fromJSON(): Decoding extended JSON types +--FILE-- + +===DONE=== + +--EXPECT-- +Test [{ "$oid": "56315a7c6118fd1b920270b1" }] + 0 : 14 00 00 00 07 30 00 56 31 5a 7c 61 18 fd 1b 92 [.....0.V1Z|a....] + 10 : 02 70 b1 00 [.p..] +Test [{ "$binary": "Zm9v", "$type": "00" }] + 0 : 10 00 00 00 05 30 00 03 00 00 00 00 66 6f 6f 00 [.....0......foo.] +Test [{ "$date": "2015-10-28T00:00:00Z" }] + 0 : 10 00 00 00 09 30 00 00 80 be ab 50 01 00 00 00 [.....0.....P....] +Test [{ "$timestamp": { "t": 1446084619, "i": 0 }}] + 0 : 10 00 00 00 11 30 00 00 00 00 00 0b 80 31 56 00 [.....0.......1V.] +Test [{ "$regex": "pattern", "$options": "i" }] + 0 : 12 00 00 00 0b 30 00 70 61 74 74 65 72 6e 00 69 [.....0.pattern.i] + 10 : 00 00 [..] +Test [{ "$undefined": true }] + 0 : 08 00 00 00 06 30 00 00 [.....0..] +Test [{ "$minKey": 1 }] + 0 : 08 00 00 00 ff 30 00 00 [.....0..] +Test [{ "$maxKey": 1 }] + 0 : 08 00 00 00 7f 30 00 00 [.....0..] +Test [{ "$numberLong": "1234" }] + 0 : 10 00 00 00 12 30 00 d2 04 00 00 00 00 00 00 00 [.....0..........] +===DONE=== diff --git a/tests/bson/bson-packedarray-fromJSON-003.phpt b/tests/bson/bson-packedarray-fromJSON-003.phpt new file mode 100644 index 000000000..ebebbf3c9 --- /dev/null +++ b/tests/bson/bson-packedarray-fromJSON-003.phpt @@ -0,0 +1,29 @@ +--TEST-- +MongoDB\BSON\PackedArray::fromJSON(): Decoding JSON object +--FILE-- +toCanonicalExtendedJSON(), PHP_EOL; + +?> +===DONE=== + +--EXPECTF-- +object(MongoDB\BSON\PackedArray)#%d (%d) { + ["data"]=> + string(24) "EgAAAAJmb28ABAAAAGJhcgAA" + ["value"]=> + array(1) { + [0]=> + string(3) "bar" + } +} + 0 : 12 00 00 00 02 66 6f 6f 00 04 00 00 00 62 61 72 [.....foo.....bar] + 10 : 00 00 [..] +[ "bar" ] +===DONE=== diff --git a/tests/bson/bson-packedarray-fromJSON_error-001.phpt b/tests/bson/bson-packedarray-fromJSON_error-001.phpt new file mode 100644 index 000000000..6a9535325 --- /dev/null +++ b/tests/bson/bson-packedarray-fromJSON_error-001.phpt @@ -0,0 +1,17 @@ +--TEST-- +MongoDB\BSON\PackedArray::fromJSON(): invalid JSON +--FILE-- + +===DONE=== + +--EXPECT-- +OK: Got MongoDB\Driver\Exception\UnexpectedValueException +===DONE=== diff --git a/tests/bson/bson-packedarray-toCanonicalExtendedJSON-001.phpt b/tests/bson/bson-packedarray-toCanonicalExtendedJSON-001.phpt new file mode 100644 index 000000000..b92465122 --- /dev/null +++ b/tests/bson/bson-packedarray-toCanonicalExtendedJSON-001.phpt @@ -0,0 +1,41 @@ +--TEST-- +MongoDB\BSON\PackedArray::toCanonicalExtendedJSON(): Encoding JSON +--FILE-- + 'bar' ]], +]; + +foreach ($tests as $value) { + echo MongoDB\BSON\PackedArray::fromPHP($value)->toCanonicalExtendedJSON(), "\n"; +} + +?> +===DONE=== + +--EXPECT-- +[ ] +[ null ] +[ true ] +[ "foo" ] +[ { "$numberInt" : "123" } ] +[ { "$numberDouble" : "1.0" } ] +[ { "$numberDouble" : "NaN" } ] +[ { "$numberDouble" : "Infinity" } ] +[ { "$numberDouble" : "-Infinity" } ] +[ [ "foo", "bar" ] ] +[ { "foo" : "bar" } ] +===DONE=== diff --git a/tests/bson/bson-packedarray-toCanonicalJSON-002.phpt b/tests/bson/bson-packedarray-toCanonicalJSON-002.phpt new file mode 100644 index 000000000..004d8c41f --- /dev/null +++ b/tests/bson/bson-packedarray-toCanonicalJSON-002.phpt @@ -0,0 +1,37 @@ +--TEST-- +MongoDB\BSON\PackedArray::toCanonicalExtendedJSON(): Encoding extended JSON types +--FILE-- + 1]) ], + [new MongoDB\BSON\MinKey ], + [new MongoDB\BSON\MaxKey ], +]; + +foreach ($tests as $value) { + echo MongoDB\BSON\PackedArray::fromPHP($value)->toCanonicalExtendedJSON(), "\n"; +} + +?> +===DONE=== + +--EXPECT-- +[ { "$oid" : "56315a7c6118fd1b920270b1" } ] +[ { "$binary" : { "base64" : "Zm9v", "subType" : "00" } } ] +[ { "$date" : { "$numberLong" : "1445990400000" } } ] +[ { "$timestamp" : { "t" : 5678, "i" : 1234 } } ] +[ { "$regularExpression" : { "pattern" : "pattern", "options" : "i" } } ] +[ { "$code" : "function() { return 1; }" } ] +[ { "$code" : "function() { return a; }", "$scope" : { "a" : { "$numberInt" : "1" } } } ] +[ { "$minKey" : 1 } ] +[ { "$maxKey" : 1 } ] +===DONE=== diff --git a/tests/bson/bson-packedarray-toRelaxedExtendedJSON-001.phpt b/tests/bson/bson-packedarray-toRelaxedExtendedJSON-001.phpt new file mode 100644 index 000000000..4f8510407 --- /dev/null +++ b/tests/bson/bson-packedarray-toRelaxedExtendedJSON-001.phpt @@ -0,0 +1,41 @@ +--TEST-- +MongoDB\BSON\PackedArray::toRelaxedExtendedJSON(): Encoding JSON +--FILE-- + 'bar' ]], +]; + +foreach ($tests as $value) { + echo MongoDB\BSON\PackedArray::fromPHP($value)->toRelaxedExtendedJSON(), "\n"; +} + +?> +===DONE=== + +--EXPECT-- +[ ] +[ null ] +[ true ] +[ "foo" ] +[ 123 ] +[ 1.0 ] +[ { "$numberDouble" : "NaN" } ] +[ { "$numberDouble" : "Infinity" } ] +[ { "$numberDouble" : "-Infinity" } ] +[ [ "foo", "bar" ] ] +[ { "foo" : "bar" } ] +===DONE=== diff --git a/tests/bson/bson-packedarray-toRelaxedExtendedJSON-002.phpt b/tests/bson/bson-packedarray-toRelaxedExtendedJSON-002.phpt new file mode 100644 index 000000000..3fb07f974 --- /dev/null +++ b/tests/bson/bson-packedarray-toRelaxedExtendedJSON-002.phpt @@ -0,0 +1,37 @@ +--TEST-- +MongoDB\BSON\PackedArray::toRelaxedExtendedJSON(): Encoding extended JSON types +--FILE-- + 1]) ], + [ new MongoDB\BSON\MinKey ], + [ new MongoDB\BSON\MaxKey ], +]; + +foreach ($tests as $value) { + echo MongoDB\BSON\PackedArray::fromPHP($value)->toRelaxedExtendedJSON(), "\n"; +} + +?> +===DONE=== + +--EXPECT-- +[ { "$oid" : "56315a7c6118fd1b920270b1" } ] +[ { "$binary" : { "base64" : "Zm9v", "subType" : "00" } } ] +[ { "$date" : "2015-10-28T00:00:00Z" } ] +[ { "$timestamp" : { "t" : 5678, "i" : 1234 } } ] +[ { "$regularExpression" : { "pattern" : "pattern", "options" : "i" } } ] +[ { "$code" : "function() { return 1; }" } ] +[ { "$code" : "function() { return a; }", "$scope" : { "a" : 1 } } ] +[ { "$minKey" : 1 } ] +[ { "$maxKey" : 1 } ] +===DONE===