Skip to content

->[to|from]Array() -> [to|from]PHP(). "root" typemapping. Default "root" to stdclass, not array #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 15, 2015
Merged
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
8 changes: 5 additions & 3 deletions php_bson.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ typedef struct {
zend_class_entry *document;
php_phongo_bson_typemap_types array_type;
zend_class_entry *array;
php_phongo_bson_typemap_types root_type;
zend_class_entry *root;
} php_phongo_bson_typemap;

typedef struct {
Expand All @@ -64,14 +66,14 @@ typedef struct {
zend_class_entry *odm;
} php_phongo_bson_state;

#define PHONGO_BSON_STATE_INITIALIZER {NULL, { PHONGO_TYPEMAP_NONE, NULL, PHONGO_TYPEMAP_NONE, NULL}, NULL}
#define PHONGO_BSON_STATE_INITIALIZER {NULL, { PHONGO_TYPEMAP_NONE, NULL, PHONGO_TYPEMAP_NONE, NULL, PHONGO_TYPEMAP_NONE, NULL}, NULL}

PHONGO_API void zval_to_bson(zval *data, php_phongo_bson_flags_t flags, bson_t *bson, bson_t **bson_out TSRMLS_DC);
PHONGO_API int bson_to_zval(const unsigned char *data, int data_len, php_phongo_bson_state *state);
PHONGO_API void php_phongo_bson_typemap_to_state(zval *typemap, php_phongo_bson_typemap *map TSRMLS_DC);

PHP_FUNCTION(toArray);
PHP_FUNCTION(fromArray);
PHP_FUNCTION(toPHP);
PHP_FUNCTION(fromPHP);
PHP_FUNCTION(toJSON);
PHP_FUNCTION(fromJSON);

Expand Down
22 changes: 17 additions & 5 deletions php_phongo.c
Original file line number Diff line number Diff line change
Expand Up @@ -1346,13 +1346,19 @@ void php_phongo_server_to_zval(zval *retval, const mongoc_server_description_t *
}
if (sd->tags.len) {
php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER;
/* Use native arrays for debugging output */
state.map.root_type = PHONGO_TYPEMAP_NATIVE_ARRAY;
state.map.document_type = PHONGO_TYPEMAP_NATIVE_ARRAY;

MAKE_STD_ZVAL(state.zchild);
bson_to_zval(bson_get_data(&sd->tags), sd->tags.len, &state);
add_assoc_zval_ex(retval, ZEND_STRS("tags"), state.zchild);
}
{
php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER;
/* Use native arrays for debugging output */
state.map.root_type = PHONGO_TYPEMAP_NATIVE_ARRAY;
state.map.document_type = PHONGO_TYPEMAP_NATIVE_ARRAY;

MAKE_STD_ZVAL(state.zchild);
bson_to_zval(bson_get_data(&sd->last_is_master), sd->last_is_master.len, &state);
Expand All @@ -1370,6 +1376,9 @@ void php_phongo_read_preference_to_zval(zval *retval, const mongoc_read_prefs_t
add_assoc_long_ex(retval, ZEND_STRS("mode"), read_prefs->mode);
if (read_prefs->tags.len) {
php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER;
/* Use native arrays for debugging output */
state.map.root_type = PHONGO_TYPEMAP_NATIVE_ARRAY;
state.map.document_type = PHONGO_TYPEMAP_NATIVE_ARRAY;

MAKE_STD_ZVAL(state.zchild);
bson_to_zval(bson_get_data(&read_prefs->tags), read_prefs->tags.len, &state);
Expand Down Expand Up @@ -1432,6 +1441,9 @@ void php_phongo_cursor_to_zval(zval *retval, php_phongo_cursor_t *cursor) /* {{{
_ADD_BOOL(zcursor, has_fields);
#undef _ADD_BOOL

/* Avoid using PHONGO_TYPEMAP_NATIVE_ARRAY for decoding query, selector,
* and current documents so that users can differentiate BSON arrays
* and documents. */
{
php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER;

Expand Down Expand Up @@ -2063,11 +2075,11 @@ PHP_MINFO_FUNCTION(mongodb)

/* {{{ mongodb_functions[]
*/
ZEND_BEGIN_ARG_INFO_EX(ai_bson_fromArray, 0, 0, 1)
ZEND_ARG_INFO(0, array)
ZEND_BEGIN_ARG_INFO_EX(ai_bson_fromPHP, 0, 0, 1)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO();

ZEND_BEGIN_ARG_INFO_EX(ai_bson_toArray, 0, 0, 1)
ZEND_BEGIN_ARG_INFO_EX(ai_bson_toPHP, 0, 0, 1)
ZEND_ARG_INFO(0, bson)
ZEND_END_ARG_INFO();

Expand All @@ -2080,8 +2092,8 @@ ZEND_BEGIN_ARG_INFO_EX(ai_bson_fromJSON, 0, 0, 1)
ZEND_END_ARG_INFO();

const zend_function_entry mongodb_functions[] = {
ZEND_NS_FE(BSON_NAMESPACE, fromArray, ai_bson_fromArray)
ZEND_NS_FE(BSON_NAMESPACE, toArray, ai_bson_toArray)
ZEND_NS_FE(BSON_NAMESPACE, fromPHP, ai_bson_fromPHP)
ZEND_NS_FE(BSON_NAMESPACE, toPHP, ai_bson_toPHP)
ZEND_NS_FE(BSON_NAMESPACE, toJSON, ai_bson_toJSON)
ZEND_NS_FE(BSON_NAMESPACE, fromJSON, ai_bson_fromJSON)
PHP_FE_END
Expand Down
2 changes: 2 additions & 0 deletions src/MongoDB/Query.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ HashTable *php_phongo_query_get_debug_info(zval *object, int *is_temp TSRMLS_DC)

array_init_size(&retval, 6);

/* Avoid using PHONGO_TYPEMAP_NATIVE_ARRAY for decoding query and selector
* documents so that users can differentiate BSON arrays and documents. */
if (intern->query) {
php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER;

Expand Down
4 changes: 4 additions & 0 deletions src/MongoDB/Server.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ PHP_METHOD(Server, getTags)

if ((sd = mongoc_topology_description_server_by_id(&intern->client->topology->description, intern->server_id))) {
php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER;
state.map.root_type = PHONGO_TYPEMAP_NATIVE_ARRAY;
state.map.document_type = PHONGO_TYPEMAP_NATIVE_ARRAY;

MAKE_STD_ZVAL(state.zchild);
bson_to_zval(bson_get_data(&sd->tags), sd->tags.len, &state);
Expand Down Expand Up @@ -191,6 +193,8 @@ PHP_METHOD(Server, getInfo)

if ((sd = mongoc_topology_description_server_by_id(&intern->client->topology->description, intern->server_id))) {
php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER;
state.map.root_type = PHONGO_TYPEMAP_NATIVE_ARRAY;
state.map.document_type = PHONGO_TYPEMAP_NATIVE_ARRAY;

MAKE_STD_ZVAL(state.zchild);
bson_to_zval(bson_get_data(&sd->last_is_master), sd->last_is_master.len, &state);
Expand Down
6 changes: 5 additions & 1 deletion src/MongoDB/WriteResult.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ PHP_METHOD(WriteResult, getUpsertedIds)
}
}
/* }}} */
/* {{{ proto WriteConcernError[] WriteResult::getWriteConcernError()
/* {{{ proto WriteConcernError WriteResult::getWriteConcernError()
Return any write concern error that occurred */
PHP_METHOD(WriteResult, getWriteConcernError)
{
Expand Down Expand Up @@ -444,6 +444,10 @@ HashTable *php_phongo_writeresult_get_debug_info(zval *object, int *is_temp TSRM
add_assoc_long_ex(&retval, ZEND_STRS("nRemoved"), intern->write_result.nRemoved);
add_assoc_long_ex(&retval, ZEND_STRS("nUpserted"), intern->write_result.nUpserted);

/* Use native arrays for debugging output */
state.map.root_type = PHONGO_TYPEMAP_NATIVE_ARRAY;
state.map.document_type = PHONGO_TYPEMAP_NATIVE_ARRAY;

MAKE_STD_ZVAL(state.zchild);
bson_to_zval(bson_get_data(&intern->write_result.upserted), intern->write_result.upserted.len, &state);
add_assoc_zval_ex(&retval, ZEND_STRS("upsertedIds"), state.zchild);
Expand Down
81 changes: 61 additions & 20 deletions src/bson.c
Original file line number Diff line number Diff line change
Expand Up @@ -896,17 +896,40 @@ int bson_to_zval(const unsigned char *data, int data_len, php_phongo_bson_state
return 0;
}

/* We initialize an array because it will either be returned as-is (native
* array in type map), passed to bsonUnserialize() (ODM class), or used to
* initialize a stdClass object (native object in type map). */
array_init(state->zchild);
bson_iter_visit_all(&iter, &php_bson_visitors, state);
if ((state->map.array || state->odm) && instanceof_function(state->odm ? state->odm : state->map.array, php_phongo_unserializable_ce TSRMLS_CC)) {
zval *obj = NULL;

MAKE_STD_ZVAL(obj);
object_init_ex(obj, state->odm ? state->odm : state->map.array);
zend_call_method_with_1_params(&obj, NULL, NULL, BSON_UNSERIALIZE_FUNC_NAME, NULL, state->zchild);
SEPARATE_ZVAL(&state->zchild);
zval_dtor(state->zchild);
ZVAL_ZVAL(state->zchild, obj, 1, 1);

/* If php_phongo_bson_visit_binary() finds an ODM class, it supersedes our
* document type. */
if (state->odm) {
state->map.root_type = PHONGO_TYPEMAP_CLASS;
}

switch (state->map.root_type) {
case PHONGO_TYPEMAP_NATIVE_ARRAY:
/* Nothing to do here */
break;

case PHONGO_TYPEMAP_CLASS:
/* If the class implements Unserializable, initialize the object
* from our array data; otherwise, fall through to native object. */
if (instanceof_function(state->odm ? state->odm : state->map.root, php_phongo_unserializable_ce TSRMLS_CC)) {
zval *obj = NULL;

MAKE_STD_ZVAL(obj);
object_init_ex(obj, state->odm ? state->odm : state->map.root);
zend_call_method_with_1_params(&obj, NULL, NULL, BSON_UNSERIALIZE_FUNC_NAME, NULL, state->zchild);
zval_ptr_dtor(&state->zchild);
state->zchild = obj;
break;
}

case PHONGO_TYPEMAP_NATIVE_OBJECT:
default:
object_and_properties_init(state->zchild, zend_standard_class_def, Z_ARRVAL_P(state->zchild));
}

if (bson_reader_read(reader, &eof) || !eof) {
Expand All @@ -920,9 +943,9 @@ int bson_to_zval(const unsigned char *data, int data_len, php_phongo_bson_state
return 1;
}

/* {{{ proto string BSON\fromArray(array|object data)
Returns the BSON representation of a value */
PHP_FUNCTION(fromArray)
/* {{{ proto string BSON\fromPHP(array|object $value)
Returns the BSON representation of a PHP value */
PHP_FUNCTION(fromPHP)
{
zval *data;
bson_t *bson;
Expand All @@ -947,7 +970,6 @@ void php_phongo_bson_typemap_to_state(zval *typemap, php_phongo_bson_typemap *ma
char *classname;
int classname_len;
zend_bool classname_free = 0;
zend_class_entry *array_ce = NULL, *document_ce = NULL;

classname = php_array_fetchl_string(typemap, "array", sizeof("array")-1, &classname_len, &classname_free);
if (classname_len) {
Expand All @@ -956,8 +978,8 @@ void php_phongo_bson_typemap_to_state(zval *typemap, php_phongo_bson_typemap *ma
} else if (!strcasecmp(classname, "stdclass") || !strcasecmp(classname, "object")) {
map->array_type = PHONGO_TYPEMAP_NATIVE_OBJECT;
} else {
zend_class_entry *array_ce = zend_fetch_class(classname, classname_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
map->array_type = PHONGO_TYPEMAP_CLASS;
array_ce = zend_fetch_class(classname, classname_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);

if (instanceof_function(array_ce, php_phongo_unserializable_ce TSRMLS_CC)) {
map->array = array_ce;
Expand All @@ -975,8 +997,8 @@ void php_phongo_bson_typemap_to_state(zval *typemap, php_phongo_bson_typemap *ma
} else if (!strcasecmp(classname, "stdclass") || !strcasecmp(classname, "object")) {
map->document_type = PHONGO_TYPEMAP_NATIVE_OBJECT;
} else {
zend_class_entry *document_ce = zend_fetch_class(classname, classname_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
map->document_type = PHONGO_TYPEMAP_CLASS;
document_ce = zend_fetch_class(classname, classname_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);

if (instanceof_function(document_ce, php_phongo_unserializable_ce TSRMLS_CC)) {
map->document = document_ce;
Expand All @@ -986,11 +1008,30 @@ void php_phongo_bson_typemap_to_state(zval *typemap, php_phongo_bson_typemap *ma
efree(classname);
}
}

classname = php_array_fetchl_string(typemap, "root", sizeof("root")-1, &classname_len, &classname_free);
if (classname_len) {
if (!strcasecmp(classname, "array")) {
map->root_type = PHONGO_TYPEMAP_NATIVE_ARRAY;
} else if (!strcasecmp(classname, "stdclass") || !strcasecmp(classname, "object")) {
map->root_type = PHONGO_TYPEMAP_NATIVE_OBJECT;
} else {
zend_class_entry *root_ce = zend_fetch_class(classname, classname_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
map->root_type = PHONGO_TYPEMAP_CLASS;

if (instanceof_function(root_ce, php_phongo_unserializable_ce TSRMLS_CC)) {
map->root = root_ce;
}
}
if (classname_free) {
efree(classname);
}
}
}
}
/* {{{ proto string BSON\toArray(string data [, array $typemap = array()])
Returns the PHP representation of a BSON value, optionally converting them into custom types/classes */
PHP_FUNCTION(toArray)
/* {{{ proto array|object BSON\toPHP(string $bson [, array $typemap = array()])
Returns the PHP representation of a BSON value, optionally converting it into a custom class */
PHP_FUNCTION(toPHP)
{
char *data;
int data_len;
Expand All @@ -1014,7 +1055,7 @@ PHP_FUNCTION(toArray)
}
/* }}} */

/* {{{ proto BSON\toJSON BSON\toJSON(string data)
/* {{{ proto string BSON\toJSON(string $bson)
Returns the JSON representation of a BSON value */
PHP_FUNCTION(toJSON)
{
Expand Down Expand Up @@ -1045,7 +1086,7 @@ PHP_FUNCTION(toJSON)
}
/* }}} */

/* {{{ proto string BSON\fromJSON(string data)
/* {{{ proto string BSON\fromJSON(string $json)
Returns the BSON representation of a JSON value */
PHP_FUNCTION(fromJSON)
{
Expand Down
6 changes: 3 additions & 3 deletions tests/bson/bson-binary-001.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ throws(function() use($classname) {


foreach($tests as $n => $test) {
$s = fromArray($test);
$s = fromPHP($test);
echo "Test#{$n} ", $json = toJSON($s), "\n";
$bson = fromJSON($json);
$testagain = toArray($bson);
var_dump(toJSON(fromArray($test)), toJSON(fromArray($testagain)));
$testagain = toPHP($bson);
var_dump(toJSON(fromPHP($test)), toJSON(fromPHP($testagain)));
var_dump((object)$test == (object)$testagain);
}

Expand Down
6 changes: 3 additions & 3 deletions tests/bson/bson-decode-001.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ $tests = array(
);

foreach($tests as $n => $test) {
$s = fromArray($test);
$s = fromPHP($test);
echo "Test#{$n} ", toJSON($s), "\n";
$val = toArray($s);
if ($val == $test) {
$val = toPHP($s);
if ($val == (object) $test) {
echo "OK\n";
} else {
var_dump($val, $test);
Expand Down
6 changes: 3 additions & 3 deletions tests/bson/bson-decode-002.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ $tests = array(
);

foreach($tests as $n => $test) {
$s = BSON\fromArray($test);
echo "Test#{$n} ", BSON\toJSON($s), "\n";
$val = BSON\toArray($s, array("document"=> "MyArrayObject", "array" => "MyArrayObject"));
$s = fromPHP($test);
echo "Test#{$n} ", toJSON($s), "\n";
$val = toPHP($s, array("root"=> "MyArrayObject", "document"=> "MyArrayObject", "array" => "MyArrayObject"));
var_dump($val);
}
?>
Expand Down
2 changes: 1 addition & 1 deletion tests/bson/bson-encode-001.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ $tests = array(
);

foreach($tests as $n => $test) {
$s = fromArray($test);
$s = fromPHP($test);
echo "Test#{$n} ", toJSON($s), "\n";
hex_dump($s);
}
Expand Down
Loading