Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed PHP-421 (Implement MongoCollection->aggregate())

  • Loading branch information...
commit 3cbe9c764ca1b27ba980796c9c72be57c0327eaa 1 parent f37cd36
@bjori bjori authored committed
View
78 collection.c
@@ -46,6 +46,17 @@ static int is_safe_op(zval *options TSRMLS_DC);
static void safe_op(mongo_con_manager *manager, mongo_connection *connection, zval *cursor_z, buffer *buf, zval *return_value TSRMLS_DC);
static zval* append_getlasterror(zval *coll, buffer *buf, zval *options TSRMLS_DC);
+ZEND_BEGIN_ARG_INFO_EX(arginfo_distinct, 0, 0, 1)
+ ZEND_ARG_INFO(0, key)
+ ZEND_ARG_INFO(0, query)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_aggregate, 0, 0, 1)
+ ZEND_ARG_INFO(0, pipelines)
+ ZEND_ARG_INFO(0, pipeline)
+ ZEND_ARG_INFO(0, ..)
+ZEND_END_ARG_INFO()
+
PHP_METHOD(MongoCollection, __construct) {
zval *parent, *name, *zns, *w, *wtimeout;
mongo_collection *c;
@@ -1248,6 +1259,72 @@ PHP_METHOD(MongoCollection, toIndexString) {
RETURN_STRING(name, 0)
}
+/* {{{ proto array MongoCollection::aggregate(array piplines, [, array pipeline [, ...]])
+ Wrapper for the aggregate runCommand. Either one array of piplines, or variable pipeline arguments */
+PHP_METHOD(MongoCollection, aggregate)
+{
+ zval ***argv, *pipelines, *data, *retval, **values, *tmp;
+ int argc;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &argv, &argc) == FAILURE) {
+ return;
+ }
+
+ mongo_collection *c = (mongo_collection*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ MONGO_CHECK_INITIALIZED(c->ns, MongoCollection);
+
+ for(int i = 0; i < argc; i++) {
+ tmp = *argv[i];
+ if (Z_TYPE_P(tmp) != IS_ARRAY) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument %d is not an array", i+1);
+ return;
+ }
+ }
+
+ MAKE_STD_ZVAL(data);
+ array_init(data);
+
+ add_assoc_zval(data, "aggregate", c->name);
+ zval_add_ref(&c->name);
+
+ if (argc == 1) {
+ Z_ADDREF_PP(*argv);
+ add_assoc_zval(data, "pipeline", **argv);
+ }
+ else {
+ MAKE_STD_ZVAL(pipelines);
+ array_init(pipelines);
+
+ for(int i = 0; i < argc; i++) {
+ tmp = *argv[i];
+ Z_ADDREF_P(tmp);
+ if (zend_hash_next_index_insert(Z_ARRVAL_P(pipelines), &tmp, sizeof(zval *), NULL) == FAILURE) {
+ Z_DELREF_P(tmp);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create pipelines array");
+ efree(argv);
+ RETURN_FALSE;
+ }
+ }
+ add_assoc_zval(data, "pipeline", pipelines);
+ }
+ efree(argv);
+
+ MAKE_STD_ZVAL(retval);
+ MONGO_CMD(retval, c->parent);
+
+ if (zend_hash_find(Z_ARRVAL_P(retval), "result", strlen("result")+1, (void **)&values) == SUCCESS) {
+ array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_PP(values)));
+ zend_hash_copy(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(values), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ } else {
+ RETVAL_FALSE;
+ }
+
+ zval_ptr_dtor(&data);
+ zval_ptr_dtor(&retval);
+}
+/* }}} */
+
+
/* {{{ proto array MongoCollection::distinct(string key [, array query])
* Returns a list of distinct values for the given key across a collection */
PHP_METHOD(MongoCollection, distinct)
@@ -1546,6 +1623,7 @@ static zend_function_entry MongoCollection_methods[] = {
PHP_ME(MongoCollection, toIndexString, arginfo_toIndexString, ZEND_ACC_PROTECTED|ZEND_ACC_STATIC)
PHP_ME(MongoCollection, group, arginfo_group, ZEND_ACC_PUBLIC)
PHP_ME(MongoCollection, distinct, arginfo_distinct, ZEND_ACC_PUBLIC)
+ PHP_ME(MongoCollection, aggregate, arginfo_aggregate, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
View
139 tests/generic/mongocollection-aggregate.phpt
@@ -0,0 +1,139 @@
+--TEST--
+MongoCollection::aggregate() basic tests
+--SKIPIF--
+<?php $needs = "2.1.0"; require __DIR__ . "/skipif.inc" ?>
+--FILE--
+<?php
+require __DIR__ . "/../utils.inc";
+
+$m = mongo();
+$c = $m->selectDB("phpunit")->selectCollection("article");
+$c->drop();
+$data = array (
+ 'title' => 'this is my title',
+ 'author' => 'bob',
+ 'posted' => new MongoDate,
+ 'pageViews' => 5,
+ 'tags' =>
+ array (
+ 0 => 'fun',
+ 1 => 'good',
+ 2 => 'fun',
+ ),
+ 'comments' =>
+ array (
+ 0 =>
+ array (
+ 'author' => 'joe',
+ 'text' => 'this is cool',
+ ),
+ 1 =>
+ array (
+ 'author' => 'sam',
+ 'text' => 'this is bad',
+ ),
+ ),
+ 'other' =>
+ array (
+ 'foo' => 5,
+ ),
+);
+$d = $c->insert($data, array("safe" => true));
+
+$ops = array(
+ array(
+ '$project' => array(
+ "author" => 1,
+ "tags" => 1,
+ )
+ ),
+ array('$unwind' => '$tags'),
+ array(
+ '$group' => array(
+ "_id" => array("tags" => 1),
+ "authors" => array('$addToSet' => '$author'),
+ )
+ )
+);
+
+
+$alone = $c->aggregate($ops);
+$multiple = $c->aggregate(current($ops), next($ops), next($ops));
+var_dump($alone == $multiple, $alone, $multiple);
+$c->drop();
+
+$c->aggregate();
+$c->aggregate("string");
+$c->aggregate($ops, "string");
+$retval = $c->aggregate((object)$ops);
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+bool(true)
+array(2) {
+ [0]=>
+ array(2) {
+ ["_id"]=>
+ array(1) {
+ ["tags"]=>
+ string(4) "good"
+ }
+ ["authors"]=>
+ array(1) {
+ [0]=>
+ string(3) "bob"
+ }
+ }
+ [1]=>
+ array(2) {
+ ["_id"]=>
+ array(1) {
+ ["tags"]=>
+ string(3) "fun"
+ }
+ ["authors"]=>
+ array(1) {
+ [0]=>
+ string(3) "bob"
+ }
+ }
+}
+array(2) {
+ [0]=>
+ array(2) {
+ ["_id"]=>
+ array(1) {
+ ["tags"]=>
+ string(4) "good"
+ }
+ ["authors"]=>
+ array(1) {
+ [0]=>
+ string(3) "bob"
+ }
+ }
+ [1]=>
+ array(2) {
+ ["_id"]=>
+ array(1) {
+ ["tags"]=>
+ string(3) "fun"
+ }
+ ["authors"]=>
+ array(1) {
+ [0]=>
+ string(3) "bob"
+ }
+ }
+}
+
+Warning: MongoCollection::aggregate() expects at least 1 parameter, 0 given in %s on line %d
+
+Warning: MongoCollection::aggregate(): Argument 1 is not an array in %s on line %d
+
+Warning: MongoCollection::aggregate(): Argument 2 is not an array in %s on line %d
+
+Warning: MongoCollection::aggregate(): Argument 1 is not an array in %s on line %d
+===DONE===
+
View
7 tests/generic/skipif.inc
@@ -13,3 +13,10 @@ if (!$m) {
die("skip Did you remember to configure " . realpath($cfg) . " based on your environment?");
}
+if (isset($needs)) {
+ $serverversion = serverversion($m);
+ if (version_compare($serverversion, $needs, "lt")) {
+ die("skip This test requires MongoDB $needs, but you are running $serverversion");
+ }
+}
+
View
4 tests/utils.inc
@@ -146,6 +146,10 @@ function password($db = null) {
}
return null;
}
+function serverversion($m) {
+ $data = $m->selectDB(dbname())->command(array('buildinfo'=>true));
+ return $data["version"];
+}
if (!function_exists("iterator_to_array")) {
function iterator_to_array($it) {
Please sign in to comment.
Something went wrong with that request. Please try again.