Skip to content

Commit e82b1d0

Browse files
committed
PHPC-96: Add QueryResult->setTypemap() to overwrite array/object mapping
1 parent ac9da79 commit e82b1d0

File tree

6 files changed

+141
-29
lines changed

6 files changed

+141
-29
lines changed

php_bson.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ typedef enum {
3737

3838
PHONGO_API void zval_to_bson(zval *data, phongo_bson_flags_t flags, bson_t *bson, bson_t **bson_out TSRMLS_DC);
3939
PHONGO_API int bson_to_zval(const unsigned char *data, int data_len, php_phongo_bson_state *state);
40+
PHONGO_API void php_phongo_bson_typemap_to_state(zval *typemap, php_phongo_bson_typemap *map TSRMLS_DC);
4041

4142
PHP_FUNCTION(toArray);
4243
PHP_FUNCTION(fromArray);

php_phongo.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,7 +1202,6 @@ static void phongo_cursor_it_get_current_data(zend_object_iterator *iter, zval *
12021202

12031203
static void phongo_cursor_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
12041204
{
1205-
php_phongo_bson_state state = {NULL, {NULL, NULL} };
12061205
phongo_cursor_it *cursor_it = (phongo_cursor_it *)iter;
12071206
const bson_t *doc;
12081207

@@ -1219,15 +1218,15 @@ static void phongo_cursor_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
12191218
bson_iter_document(&cursor_it->first_batch_iter, &data_len, &data);
12201219

12211220
MAKE_STD_ZVAL(cursor_it->current);
1222-
state.zchild = cursor_it->current;
1223-
bson_to_zval(data, data_len, &state);
1221+
cursor_it->visitor_data.zchild = cursor_it->current;
1222+
bson_to_zval(data, data_len, &cursor_it->visitor_data);
12241223
return;
12251224
}
12261225
}
12271226
if (mongoc_cursor_next(cursor_it->cursor, &doc)) {
12281227
MAKE_STD_ZVAL(cursor_it->current);
1229-
state.zchild = cursor_it->current;
1230-
bson_to_zval(bson_get_data(doc), doc->len, &state);
1228+
cursor_it->visitor_data.zchild = cursor_it->current;
1229+
bson_to_zval(bson_get_data(doc), doc->len, &cursor_it->visitor_data);
12311230
} else {
12321231
cursor_it->current = NULL;
12331232
}
@@ -1236,7 +1235,6 @@ static void phongo_cursor_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
12361235

12371236
static void phongo_cursor_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
12381237
{
1239-
php_phongo_bson_state state = {NULL, {NULL, NULL} };
12401238
phongo_cursor_it *cursor_it = (phongo_cursor_it *)iter;
12411239

12421240
/* firstBatch is empty when the query simply didn't return any results */
@@ -1250,14 +1248,14 @@ static void phongo_cursor_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{
12501248

12511249
bson_iter_document(&cursor_it->first_batch_iter, &data_len, &data);
12521250
MAKE_STD_ZVAL(cursor_it->current);
1253-
state.zchild = cursor_it->current;
1254-
bson_to_zval(data, data_len, &state);
1251+
cursor_it->visitor_data.zchild = cursor_it->current;
1252+
bson_to_zval(data, data_len, &cursor_it->visitor_data);
12551253
}
12561254
}
12571255
} else {
12581256
MAKE_STD_ZVAL(cursor_it->current);
1259-
state.zchild = cursor_it->current;
1260-
bson_to_zval(bson_get_data(cursor_it->firstBatch), cursor_it->firstBatch->len, &state);
1257+
cursor_it->visitor_data.zchild = cursor_it->current;
1258+
bson_to_zval(bson_get_data(cursor_it->firstBatch), cursor_it->firstBatch->len, &cursor_it->visitor_data);
12611259
}
12621260
}
12631261
} /* }}} */

src/MongoDB/CommandResult.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ PHP_METHOD(CommandResult, getResponseDocument)
150150

151151

152152
if (intern->result.firstBatch) {
153-
php_phongo_bson_state state = {NULL, {{NULL, 0}, {NULL, 0}}};
153+
php_phongo_bson_state state = {NULL, {NULL, NULL}};
154154

155155
state.zchild = return_value;
156156
bson_to_zval(bson_get_data(intern->result.firstBatch), intern->result.firstBatch->len, &state);

src/MongoDB/QueryResult.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,31 @@ PHP_METHOD(QueryResult, __construct)
6767

6868
}
6969
/* }}} */
70+
/* {{{ proto void QueryResult::setTypemap(array $typemap)
71+
Sets a typemap to use for BSON unserialization */
72+
PHP_METHOD(QueryResult, setTypemap)
73+
{
74+
php_phongo_writeresult_t *intern;
75+
zend_error_handling error_handling;
76+
(void)return_value_ptr; (void)return_value_used;
77+
zval *typemap = NULL;
78+
php_phongo_bson_state state = {NULL, {NULL, NULL} };
79+
80+
81+
zend_replace_error_handling(EH_THROW, phongo_exception_from_phongo_domain(PHONGO_ERROR_INVALID_ARGUMENT), &error_handling TSRMLS_CC);
82+
intern = (php_phongo_writeresult_t *)zend_object_store_get_object(getThis() TSRMLS_CC);
83+
84+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a!", &typemap) == FAILURE) {
85+
zend_restore_error_handling(&error_handling TSRMLS_CC);
86+
return;
87+
}
88+
zend_restore_error_handling(&error_handling TSRMLS_CC);
89+
90+
php_phongo_bson_typemap_to_state(typemap, &state.map TSRMLS_CC);
91+
92+
intern->result.visitor_data = state;
93+
}
94+
/* }}} */
7095
/* {{{ proto MongoDB\Driver\Cursor QueryResult::getIterator()
7196
Returns the Cursor iterator */
7297
PHP_METHOD(QueryResult, getIterator)
@@ -170,6 +195,10 @@ PHP_METHOD(QueryResult, getServer)
170195
*/
171196
/* {{{ MongoDB\Driver\QueryResult */
172197

198+
ZEND_BEGIN_ARG_INFO_EX(ai_QueryResult_setTypemap, 0, 0, 1)
199+
ZEND_ARG_ARRAY_INFO(0, typemap, 0)
200+
ZEND_END_ARG_INFO();
201+
173202
ZEND_BEGIN_ARG_INFO_EX(ai_QueryResult___construct, 0, 0, 3)
174203
ZEND_ARG_OBJ_INFO(0, server, MongoDB\\Driver\\Server, 0)
175204
ZEND_ARG_OBJ_INFO(0, cursorId, MongoDB\\Driver\\CursorId, 0)
@@ -192,6 +221,7 @@ ZEND_END_ARG_INFO();
192221

193222

194223
static zend_function_entry php_phongo_queryresult_me[] = {
224+
PHP_ME(QueryResult, setTypemap, ai_QueryResult_setTypemap, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
195225
PHP_ME(QueryResult, __construct, ai_QueryResult___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
196226
PHP_ME(QueryResult, getIterator, ai_QueryResult_getIterator, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
197227
PHP_ME(QueryResult, setIteratorClass, ai_QueryResult_setIteratorClass, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)

src/bson.c

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -822,29 +822,19 @@ PHP_FUNCTION(fromArray)
822822
}
823823
/* }}} */
824824

825-
/* {{{ proto string BSON\toArray(string data [, array $typemap = array()])
826-
Returns the PHP representation of a BSON value, optionally converting them into custom types/classes */
827-
PHP_FUNCTION(toArray)
825+
void php_phongo_bson_typemap_to_state(zval *typemap, php_phongo_bson_typemap *map TSRMLS_DC)
828826
{
829-
char *data, *classname;
830-
int data_len, classname_len;
831-
zval *typemap = NULL;
832-
zend_bool classname_free = 0;
833-
zend_class_entry *array_ce = NULL, *document_ce = NULL;
834-
php_phongo_bson_state state = {NULL, {NULL, NULL} };
835-
836-
(void)return_value_ptr; (void)this_ptr; (void)return_value_used; /* We don't use these */
837-
838-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a!", &data, &data_len, &typemap) == FAILURE) {
839-
return;
840-
}
841-
842827
if (typemap) {
828+
char *classname;
829+
int classname_len;
830+
zend_bool classname_free = 0;
831+
zend_class_entry *array_ce = NULL, *document_ce = NULL;
832+
843833
classname = php_array_fetchl_string(typemap, "array", sizeof("array")-1, &classname_len, &classname_free);
844834
array_ce = zend_fetch_class(classname, classname_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
845835

846836
if (instanceof_function(array_ce, php_phongo_unserializable_ce TSRMLS_CC)) {
847-
state.map.array = array_ce;
837+
map->array = array_ce;
848838
}
849839
if (classname_free) {
850840
efree(classname);
@@ -853,12 +843,29 @@ PHP_FUNCTION(toArray)
853843
classname = php_array_fetchl_string(typemap, "document", sizeof("document")-1, &classname_len, &classname_free);
854844
document_ce = zend_fetch_class(classname, classname_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
855845
if (instanceof_function(document_ce, php_phongo_unserializable_ce TSRMLS_CC)) {
856-
state.map.document = document_ce;
846+
map->document = document_ce;
857847
}
858848
if (classname_free) {
859849
efree(classname);
860850
}
861851
}
852+
}
853+
/* {{{ proto string BSON\toArray(string data [, array $typemap = array()])
854+
Returns the PHP representation of a BSON value, optionally converting them into custom types/classes */
855+
PHP_FUNCTION(toArray)
856+
{
857+
char *data;
858+
int data_len;
859+
zval *typemap = NULL;
860+
php_phongo_bson_state state = {NULL, {NULL, NULL} };
861+
862+
(void)return_value_ptr; (void)this_ptr; (void)return_value_used; /* We don't use these */
863+
864+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a!", &data, &data_len, &typemap) == FAILURE) {
865+
return;
866+
}
867+
868+
php_phongo_bson_typemap_to_state(typemap, &state.map TSRMLS_CC);
862869

863870
state.zchild = return_value;
864871
if (!bson_to_zval((const unsigned char *)data, data_len, &state)) {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
--TEST--
2+
MongoDB\Driver\Server::executeQuery() with filter and projection
3+
--SKIPIF--
4+
<?php require "tests/utils/basic-skipif.inc" ?>
5+
--FILE--
6+
<?php
7+
require_once "tests/utils/basic.inc";
8+
9+
class MyArrayObject extends ArrayObject implements BSON\Unserializable {
10+
function bsonUnserialize(array $data) {
11+
parent::__construct($data);
12+
}
13+
}
14+
$manager = new MongoDB\Driver\Manager(MONGODB_URI);
15+
16+
$batch = new \MongoDB\Driver\WriteBatch();
17+
$batch->insert(array('_id' => 1, array('x' => 2, 'y' => 3)));
18+
$batch->insert(array('_id' => 2, array('x' => 3, 'y' => 4)));
19+
$batch->insert(array('_id' => 3, array('x' => 4, 'y' => 5)));
20+
$manager->executeWriteBatch(NS, $batch);
21+
22+
$query = new MongoDB\Driver\Query(array());
23+
$qr = $manager->executeQuery(NS, $query);
24+
$qr->setTypemap(array("document"=> "MyArrayObject", "array" => "MyArrayObject"));
25+
26+
foreach($qr as $obj) {
27+
var_dump($obj);
28+
}
29+
30+
?>
31+
===DONE===
32+
<?php exit(0); ?>
33+
--EXPECTF--
34+
array(2) {
35+
["_id"]=>
36+
int(1)
37+
[0]=>
38+
object(MyArrayObject)#%d (1) {
39+
[%s]=>
40+
array(2) {
41+
["x"]=>
42+
int(2)
43+
["y"]=>
44+
int(3)
45+
}
46+
}
47+
}
48+
array(2) {
49+
["_id"]=>
50+
int(2)
51+
[0]=>
52+
object(MyArrayObject)#%d (1) {
53+
[%s]=>
54+
array(2) {
55+
["x"]=>
56+
int(3)
57+
["y"]=>
58+
int(4)
59+
}
60+
}
61+
}
62+
array(2) {
63+
["_id"]=>
64+
int(3)
65+
[0]=>
66+
object(MyArrayObject)#%d (1) {
67+
[%s]=>
68+
array(2) {
69+
["x"]=>
70+
int(4)
71+
["y"]=>
72+
int(5)
73+
}
74+
}
75+
}
76+
===DONE===

0 commit comments

Comments
 (0)