/* {{{ MongoCursor->sort */ PHP_METHOD(MongoCursor, sort) { zval *orderby, *fields; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &fields) == FAILURE) { return; } if (IS_SCALAR_P(fields)) { zend_error(E_WARNING, "MongoCursor::sort() expects parameter 1 to be an array or object"); return; } MAKE_STD_ZVAL(orderby); ZVAL_STRING(orderby, "$orderby", 1); MONGO_METHOD2(MongoCursor, addOption, return_value, getThis(), orderby, fields); zval_ptr_dtor(&orderby); }
/* {{{ MongoCursor::fields */ PHP_METHOD(MongoCursor, fields) { zval *z; preiteration_setup; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &z) == FAILURE) { return; } if (IS_SCALAR_P(z)) { zend_error(E_WARNING, "MongoCursor::fields() expects parameter 1 to be an array or object"); return; } zval_ptr_dtor(&cursor->fields); cursor->fields = z; zval_add_ref(&z); RETURN_ZVAL(getThis(), 1, 0); }
/* {{{ proto bool MongoDBRef::isRef(mixed ref) Checks if $ref has a $ref and $id property/key */ PHP_METHOD(MongoDBRef, isRef) { zval *ref; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &ref) == FAILURE) { return; } if (IS_SCALAR_P(ref)) { RETURN_FALSE; } /* check that $ref and $id fields exists */ if (zend_hash_exists(HASH_P(ref), "$ref", strlen("$ref") + 1) && zend_hash_exists(HASH_P(ref), "$id", strlen("$id") + 1)) { /* good enough */ RETURN_TRUE; } RETURN_FALSE; }
/* {{{ MongoCursor->hint */ PHP_METHOD(MongoCursor, hint) { zval *zfields, *query; mongo_cursor *cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); MONGO_CHECK_INITIALIZED(cursor->link, MongoCursor); if (cursor->started_iterating) { zend_throw_exception(mongo_ce_CursorException, "cannot modify cursor after beginning iteration.", 0 TSRMLS_CC); return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zfields) == FAILURE || IS_SCALAR_P(zfields)) { return; } query = cursor->query; zval_add_ref(&zfields); add_assoc_zval(query, "$hint", zfields); RETURN_ZVAL(getThis(), 1, 0); }
PHP_METHOD(MongoDB, command) { zval limit, *temp, *cmd, *cursor, *ns, *options = 0; mongo_db *db; mongo_link *link; char *cmd_ns; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|a", &cmd, &options) == FAILURE) { return; } if (IS_SCALAR_P(cmd)) { zend_error(E_WARNING, "MongoDB::command() expects parameter 1 to be an array or object"); return; } PHP_MONGO_GET_DB(getThis()); // create db.$cmd MAKE_STD_ZVAL(ns); cmd_ns = get_cmd_ns(Z_STRVAL_P(db->name), Z_STRLEN_P(db->name)); ZVAL_STRING(ns, cmd_ns, 0); // create cursor MAKE_STD_ZVAL(cursor); object_init_ex(cursor, mongo_ce_Cursor); MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); MONGO_METHOD3(MongoCursor, __construct, temp, cursor, db->link, ns, cmd); zval_ptr_dtor(&ns); zval_ptr_dtor(&temp); MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); // limit Z_TYPE(limit) = IS_LONG; Z_LVAL(limit) = -1; MONGO_METHOD1(MongoCursor, limit, temp, cursor, &limit); zval_ptr_dtor(&temp); if (options) { zval **timeout; if (zend_hash_find(HASH_P(options), "timeout", strlen("timeout")+1, (void**)&timeout) == SUCCESS) { MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); MONGO_METHOD1(MongoCursor, timeout, temp, cursor, *timeout); zval_ptr_dtor(&temp); } } // make sure commands aren't be sent to slaves PHP_MONGO_GET_LINK(db->link); if (link->rs) { zval slave_okay; Z_TYPE(slave_okay) = IS_BOOL; Z_LVAL(slave_okay) = 0; MAKE_STD_ZVAL(temp); ZVAL_NULL(temp); MONGO_METHOD1(MongoCursor, slaveOkay, temp, cursor, &slave_okay); zval_ptr_dtor(&temp); } // query MONGO_METHOD(MongoCursor, getNext, return_value, cursor); clear_exception(return_value TSRMLS_CC); zend_objects_store_del_ref(cursor TSRMLS_CC); zval_ptr_dtor(&cursor); }
static void php_mongo_enumerate_collections(INTERNAL_FUNCTION_PARAMETERS, int full_collection) { zend_bool system_col = 0; zval *nss, *collection, *cursor, *list, *next; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &system_col) == FAILURE) { return; } // select db.system.namespaces collection MAKE_STD_ZVAL(nss); ZVAL_STRING(nss, "system.namespaces", 1); MAKE_STD_ZVAL(collection); MONGO_METHOD1(MongoDB, selectCollection, collection, getThis(), nss); // list to return MAKE_STD_ZVAL(list); array_init(list); // do find MAKE_STD_ZVAL(cursor); MONGO_METHOD(MongoCollection, find, cursor, collection); // populate list MAKE_STD_ZVAL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); while (!IS_SCALAR_P(next)) { zval *c, *zname; zval **collection; char *name, *first_dot, *system; // check that the ns is valid and not an index (contains $) if (zend_hash_find(HASH_P(next), "name", 5, (void**)&collection) == FAILURE || strchr(Z_STRVAL_PP(collection), '$')) { zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); ZVAL_NULL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); continue; } first_dot = strchr(Z_STRVAL_PP(collection), '.'); system = strstr(Z_STRVAL_PP(collection), ".system."); // check that this isn't a system ns if (!system_col && (system && first_dot == system) || (name = strchr(Z_STRVAL_PP(collection), '.')) == 0) { zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); ZVAL_NULL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); continue; } // take a substring after the first "." name++; // "foo." was allowed in earlier versions if (name == '\0') { zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); ZVAL_NULL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); continue; } if (full_collection) { MAKE_STD_ZVAL(c); ZVAL_NULL(c); MAKE_STD_ZVAL(zname); ZVAL_NULL(zname); // name must be copied because it is a substring of // a string that will be garbage collected in a sec ZVAL_STRING(zname, name, 1); MONGO_METHOD1(MongoDB, selectCollection, c, getThis(), zname); add_next_index_zval(list, c); zval_ptr_dtor(&zname); } else { add_next_index_string(list, name, 1); } zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); } zval_ptr_dtor(&next); zval_ptr_dtor(&nss); zval_ptr_dtor(&cursor); zval_ptr_dtor(&collection); RETURN_ZVAL(list, 0, 1); }
/* {{{ MongoDBRef::get() */ PHP_METHOD(MongoDBRef, get) { zval *db, *ref, *collection, *query; zval **ns, **id, **dbname; zend_bool alloced_db = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz", &db, mongo_ce_DB, &ref) == FAILURE) { return; } if ( IS_SCALAR_P(ref) || zend_hash_find(HASH_P(ref), "$ref", strlen("$ref") + 1, (void**)&ns) == FAILURE || zend_hash_find(HASH_P(ref), "$id", strlen("$id") + 1, (void**)&id) == FAILURE ) { RETURN_NULL(); } if (Z_TYPE_PP(ns) != IS_STRING) { zend_throw_exception(mongo_ce_Exception, "MongoDBRef::get: $ref field must be a string", 10 TSRMLS_CC); return; } /* if this reference contains a db name, we have to switch dbs */ if (zend_hash_find(HASH_P(ref), "$db", strlen("$db") + 1, (void**)&dbname) == SUCCESS) { mongo_db *temp_db = (mongo_db*)zend_object_store_get_object(db TSRMLS_CC); /* just to be paranoid, make sure dbname is a string */ if (Z_TYPE_PP(dbname) != IS_STRING) { zend_throw_exception(mongo_ce_Exception, "MongoDBRef::get: $db field must be a string", 11 TSRMLS_CC); return; } /* if the name in the $db field doesn't match the current db, make up * a new db */ if (strcmp(Z_STRVAL_PP(dbname), Z_STRVAL_P(temp_db->name)) != 0) { zval *new_db_z; MAKE_STD_ZVAL(new_db_z); ZVAL_NULL(new_db_z); MONGO_METHOD1(MongoClient, selectDB, new_db_z, temp_db->link, *dbname); /* make the new db the current one */ db = new_db_z; /* so we can dtor this later */ alloced_db = 1; } } /* get the collection */ MAKE_STD_ZVAL(collection); MONGO_METHOD1(MongoDB, selectCollection, collection, db, *ns); /* query for the $id */ MAKE_STD_ZVAL(query); array_init(query); add_assoc_zval(query, "_id", *id); zval_add_ref(id); /* return whatever's there */ MONGO_METHOD1(MongoCollection, findOne, return_value, collection, query); /* cleanup */ zval_ptr_dtor(&collection); zval_ptr_dtor(&query); if (alloced_db) { zval_ptr_dtor(&db); } }
/* {{{ MongoCursor->__construct */ PHP_METHOD(MongoCursor, __construct) { zval *zlink = 0, *zns = 0, *zquery = 0, *zfields = 0, *empty, *timeout; zval **data; mongo_cursor *cursor; mongo_link *link; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oz|zz", &zlink, mongo_ce_Mongo, &zns, &zquery, &zfields) == FAILURE) { return; } if ((zquery && IS_SCALAR_P(zquery)) || (zfields && IS_SCALAR_P(zfields))) { zend_error(E_WARNING, "MongoCursor::__construct() expects parameters 3 and 4 to be arrays or objects"); return; } // if query or fields weren't passed, make them default to an empty array MAKE_STD_ZVAL(empty); object_init(empty); // these are both initialized to the same zval, but that's okay because // there's no way to change them without creating a new cursor if (!zquery || (Z_TYPE_P(zquery) == IS_ARRAY && zend_hash_num_elements(HASH_P(zquery)) == 0)) { zquery = empty; } if (!zfields) { zfields = empty; } cursor = (mongo_cursor*)zend_object_store_get_object(getThis() TSRMLS_CC); // db connection cursor->resource = zlink; zval_add_ref(&zlink); // db connection resource PHP_MONGO_GET_LINK(zlink); cursor->link = link; // change ['x', 'y', 'z'] into {'x' : 1, 'y' : 1, 'z' : 1} if (Z_TYPE_P(zfields) == IS_ARRAY) { HashPosition pointer; zval *fields; MAKE_STD_ZVAL(fields); array_init(fields); // fields to return for(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(zfields), &pointer); zend_hash_get_current_data_ex(Z_ARRVAL_P(zfields), (void**) &data, &pointer) == SUCCESS; zend_hash_move_forward_ex(Z_ARRVAL_P(zfields), &pointer)) { int key_type, key_len; ulong index; char *key; key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(zfields), &key, (uint*)&key_len, &index, NO_DUP, &pointer); if (key_type == HASH_KEY_IS_LONG) { if (Z_TYPE_PP(data) == IS_STRING) { add_assoc_long(fields, Z_STRVAL_PP(data), 1); } else { zval_ptr_dtor(&empty); zval_ptr_dtor(&fields); zend_throw_exception(mongo_ce_Exception, "field names must be strings", 0 TSRMLS_CC); return; } } else { add_assoc_zval(fields, key, *data); zval_add_ref(data); } } cursor->fields = fields; } // if it's already an object, we don't have to worry else { cursor->fields = zfields; zval_add_ref(&zfields); } // ns convert_to_string(zns); cursor->ns = estrdup(Z_STRVAL_P(zns)); // query cursor->query = zquery; zval_add_ref(&zquery); // reset iteration pointer, just in case MONGO_METHOD(MongoCursor, reset, return_value, getThis()); cursor->at = 0; cursor->num = 0; cursor->special = 0; cursor->persist = 0; timeout = zend_read_static_property(mongo_ce_Cursor, "timeout", strlen("timeout"), NOISY TSRMLS_CC); cursor->timeout = Z_LVAL_P(timeout); cursor->opts = link->slave_okay ? (1 << 2) : 0; // get rid of extra ref zval_ptr_dtor(&empty); }
PHP_METHOD(MongoDB, listCollections) { // select db.system.namespaces collection zval *nss, *collection, *cursor, *list, *next; MAKE_STD_ZVAL(nss); ZVAL_STRING(nss, "system.namespaces", 1); MAKE_STD_ZVAL(collection); MONGO_METHOD1(MongoDB, selectCollection, collection, getThis(), nss); // list to return MAKE_STD_ZVAL(list); array_init(list); // do find MAKE_STD_ZVAL(cursor); MONGO_METHOD(MongoCollection, find, cursor, collection); // populate list MAKE_STD_ZVAL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); while (!IS_SCALAR_P(next)) { zval *c, *zname; zval **collection; char *name, *first_dot, *system; // check that the ns is valid and not an index (contains $) if (zend_hash_find(HASH_P(next), "name", 5, (void**)&collection) == FAILURE || strchr(Z_STRVAL_PP(collection), '$')) { zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); ZVAL_NULL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); continue; } first_dot = strchr(Z_STRVAL_PP(collection), '.'); system = strstr(Z_STRVAL_PP(collection), ".system."); // check that this isn't a system ns if ((system && first_dot == system) || (name = strchr(Z_STRVAL_PP(collection), '.')) == 0) { zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); ZVAL_NULL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); continue; } // take a substring after the first "." name++; // "foo." was allowed in earlier versions if (name == '\0') { zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); ZVAL_NULL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); continue; } MAKE_STD_ZVAL(c); ZVAL_NULL(c); MAKE_STD_ZVAL(zname); ZVAL_NULL(zname); // name must be copied because it is a substring of // a string that will be garbage collected in a sec ZVAL_STRING(zname, name, 1); MONGO_METHOD1(MongoDB, selectCollection, c, getThis(), zname); add_next_index_zval(list, c); zval_ptr_dtor(&zname); zval_ptr_dtor(&next); MAKE_STD_ZVAL(next); MONGO_METHOD(MongoCursor, getNext, next, cursor); } zval_ptr_dtor(&next); zval_ptr_dtor(&nss); zval_ptr_dtor(&cursor); zval_ptr_dtor(&collection); RETURN_ZVAL(list, 0, 1); }