Skip to content

Commit

Permalink
PHPC-2350: Implement JSON methods for PackedArray
Browse files Browse the repository at this point in the history
  • Loading branch information
alcaeus committed Sep 12, 2024
1 parent 7ba3371 commit a14469f
Show file tree
Hide file tree
Showing 11 changed files with 385 additions and 4 deletions.
72 changes: 72 additions & 0 deletions src/BSON/PackedArray.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions src/BSON/PackedArray.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
22 changes: 18 additions & 4 deletions src/BSON/PackedArray_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions tests/bson/bson-packedarray-fromJSON-001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
--TEST--
MongoDB\BSON\PackedArray::fromJSON(): Decoding JSON
--FILE--
<?php

require_once __DIR__ . '/../utils/basic.inc';

$tests = [
'[]',
'[ 1, 2, 3 ]',
'[[ 1, 2, 3 ]]',
'[{ "bar": 1 }]',
];

foreach ($tests as $json) {
printf("Test %s\n", $json);
$bson = MongoDB\BSON\PackedArray::fromJSON($json);
hex_dump((string) $bson);
}

?>
===DONE===
<?php exit(0); ?>
--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===
50 changes: 50 additions & 0 deletions tests/bson/bson-packedarray-fromJSON-002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
--TEST--
MongoDB\BSON\PackedArray::fromJSON(): Decoding extended JSON types
--FILE--
<?php

require_once __DIR__ . '/../utils/basic.inc';

$tests = [
'[{ "$oid": "56315a7c6118fd1b920270b1" }]',
'[{ "$binary": "Zm9v", "$type": "00" }]',
'[{ "$date": "2015-10-28T00:00:00Z" }]',
'[{ "$timestamp": { "t": 1446084619, "i": 0 }}]',
'[{ "$regex": "pattern", "$options": "i" }]',
'[{ "$undefined": true }]',
'[{ "$minKey": 1 }]',
'[{ "$maxKey": 1 }]',
'[{ "$numberLong": "1234" }]',
];

foreach ($tests as $json) {
printf("Test %s\n", $json);
$bson = MongoDB\BSON\PackedArray::fromJSON($json);
hex_dump((string) $bson);
}

?>
===DONE===
<?php exit(0); ?>
--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===
29 changes: 29 additions & 0 deletions tests/bson/bson-packedarray-fromJSON-003.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--TEST--
MongoDB\BSON\PackedArray::fromJSON(): Decoding JSON object
--FILE--
<?php

require_once __DIR__ . '/../utils/basic.inc';

$bson = MongoDB\BSON\PackedArray::fromJSON('{ "foo": "bar" }');
var_dump($bson);
hex_dump((string) $bson);
echo $bson->toCanonicalExtendedJSON(), PHP_EOL;

?>
===DONE===
<?php exit(0); ?>
--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===
17 changes: 17 additions & 0 deletions tests/bson/bson-packedarray-fromJSON_error-001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
MongoDB\BSON\PackedArray::fromJSON(): invalid JSON
--FILE--
<?php

require_once __DIR__ . '/../utils/basic.inc';

throws(function() {
MongoDB\BSON\PackedArray::fromJSON('foo');
}, 'MongoDB\Driver\Exception\UnexpectedValueException');

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
OK: Got MongoDB\Driver\Exception\UnexpectedValueException
===DONE===
41 changes: 41 additions & 0 deletions tests/bson/bson-packedarray-toCanonicalExtendedJSON-001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
--TEST--
MongoDB\BSON\PackedArray::toCanonicalExtendedJSON(): Encoding JSON
--FILE--
<?php

require_once __DIR__ . '/../utils/basic.inc';

$tests = [
[],
[ null ],
[ true ],
[ 'foo' ],
[ 123 ],
[ 1.0, ],
[ NAN ],
[ INF ],
[ -INF ],
[ [ 'foo', 'bar' ]],
[ [ 'foo' => 'bar' ]],
];

foreach ($tests as $value) {
echo MongoDB\BSON\PackedArray::fromPHP($value)->toCanonicalExtendedJSON(), "\n";
}

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
[ ]
[ null ]
[ true ]
[ "foo" ]
[ { "$numberInt" : "123" } ]
[ { "$numberDouble" : "1.0" } ]
[ { "$numberDouble" : "NaN" } ]
[ { "$numberDouble" : "Infinity" } ]
[ { "$numberDouble" : "-Infinity" } ]
[ [ "foo", "bar" ] ]
[ { "foo" : "bar" } ]
===DONE===
Loading

0 comments on commit a14469f

Please sign in to comment.