Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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

  • Loading branch information...
commit 3cbe9c764ca1b27ba980796c9c72be57c0327eaa 1 parent f37cd36
Hannes Magnusson authored July 11, 2012 derickr committed August 31, 2012
78  collection.c
@@ -46,6 +46,17 @@ static int is_safe_op(zval *options TSRMLS_DC);
46 46
 static void safe_op(mongo_con_manager *manager, mongo_connection *connection, zval *cursor_z, buffer *buf, zval *return_value TSRMLS_DC);
47 47
 static zval* append_getlasterror(zval *coll, buffer *buf, zval *options TSRMLS_DC);
48 48
 
  49
+ZEND_BEGIN_ARG_INFO_EX(arginfo_distinct, 0, 0, 1)
  50
+	ZEND_ARG_INFO(0, key)
  51
+	ZEND_ARG_INFO(0, query)
  52
+ZEND_END_ARG_INFO()
  53
+
  54
+ZEND_BEGIN_ARG_INFO_EX(arginfo_aggregate, 0, 0, 1)
  55
+	ZEND_ARG_INFO(0, pipelines)
  56
+	ZEND_ARG_INFO(0, pipeline)
  57
+	ZEND_ARG_INFO(0, ..)
  58
+ZEND_END_ARG_INFO()
  59
+
49 60
 PHP_METHOD(MongoCollection, __construct) {
50 61
   zval *parent, *name, *zns, *w, *wtimeout;
51 62
   mongo_collection *c;
@@ -1248,6 +1259,72 @@ PHP_METHOD(MongoCollection, toIndexString) {
1248 1259
   RETURN_STRING(name, 0)
1249 1260
 }
1250 1261
 
  1262
+/* {{{ proto array MongoCollection::aggregate(array piplines, [, array pipeline [, ...]])
  1263
+   Wrapper for the aggregate runCommand. Either one array of piplines, or variable pipeline arguments */
  1264
+PHP_METHOD(MongoCollection, aggregate)
  1265
+{
  1266
+    zval ***argv, *pipelines, *data, *retval, **values, *tmp;
  1267
+    int argc;
  1268
+
  1269
+    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &argv, &argc) == FAILURE) {
  1270
+        return;
  1271
+    }
  1272
+
  1273
+    mongo_collection *c = (mongo_collection*)zend_object_store_get_object(getThis() TSRMLS_CC);
  1274
+    MONGO_CHECK_INITIALIZED(c->ns, MongoCollection);
  1275
+
  1276
+    for(int i = 0; i < argc; i++) {
  1277
+        tmp = *argv[i];
  1278
+        if (Z_TYPE_P(tmp) != IS_ARRAY) {
  1279
+            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument %d is not an array", i+1);
  1280
+            return;
  1281
+        }
  1282
+    }
  1283
+
  1284
+    MAKE_STD_ZVAL(data);
  1285
+    array_init(data);
  1286
+
  1287
+    add_assoc_zval(data, "aggregate", c->name);
  1288
+    zval_add_ref(&c->name);
  1289
+
  1290
+    if (argc == 1) {
  1291
+        Z_ADDREF_PP(*argv);
  1292
+        add_assoc_zval(data, "pipeline", **argv);
  1293
+    }
  1294
+    else {
  1295
+        MAKE_STD_ZVAL(pipelines);
  1296
+        array_init(pipelines);
  1297
+
  1298
+        for(int i = 0; i < argc; i++) {
  1299
+            tmp = *argv[i];
  1300
+            Z_ADDREF_P(tmp);
  1301
+            if (zend_hash_next_index_insert(Z_ARRVAL_P(pipelines), &tmp, sizeof(zval *), NULL) == FAILURE) {
  1302
+                Z_DELREF_P(tmp);
  1303
+                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create pipelines array");
  1304
+                efree(argv);
  1305
+                RETURN_FALSE;
  1306
+            }
  1307
+        }
  1308
+        add_assoc_zval(data, "pipeline", pipelines);
  1309
+    }
  1310
+    efree(argv);
  1311
+
  1312
+    MAKE_STD_ZVAL(retval);
  1313
+    MONGO_CMD(retval, c->parent);
  1314
+
  1315
+    if (zend_hash_find(Z_ARRVAL_P(retval), "result", strlen("result")+1, (void **)&values) == SUCCESS) {
  1316
+        array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_PP(values)));
  1317
+        zend_hash_copy(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(values), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
  1318
+    } else {
  1319
+        RETVAL_FALSE;
  1320
+    }
  1321
+
  1322
+    zval_ptr_dtor(&data);
  1323
+    zval_ptr_dtor(&retval);
  1324
+}
  1325
+/* }}} */
  1326
+
  1327
+
1251 1328
 /* {{{ proto array MongoCollection::distinct(string key [, array query])
1252 1329
  * Returns a list of distinct values for the given key across a collection */
1253 1330
 PHP_METHOD(MongoCollection, distinct)
@@ -1546,6 +1623,7 @@ static zend_function_entry MongoCollection_methods[] = {
1546 1623
   PHP_ME(MongoCollection, toIndexString, arginfo_toIndexString, ZEND_ACC_PROTECTED|ZEND_ACC_STATIC)
1547 1624
   PHP_ME(MongoCollection, group, arginfo_group, ZEND_ACC_PUBLIC)
1548 1625
   PHP_ME(MongoCollection, distinct, arginfo_distinct, ZEND_ACC_PUBLIC)
  1626
+  PHP_ME(MongoCollection, aggregate, arginfo_aggregate, ZEND_ACC_PUBLIC)
1549 1627
   {NULL, NULL, NULL}
1550 1628
 };
1551 1629
 
139  tests/generic/mongocollection-aggregate.phpt
... ...
@@ -0,0 +1,139 @@
  1
+--TEST--
  2
+MongoCollection::aggregate() basic tests
  3
+--SKIPIF--
  4
+<?php $needs = "2.1.0"; require __DIR__ . "/skipif.inc" ?>
  5
+--FILE--
  6
+<?php
  7
+require __DIR__ . "/../utils.inc";
  8
+
  9
+$m = mongo();
  10
+$c = $m->selectDB("phpunit")->selectCollection("article");
  11
+$c->drop();
  12
+$data = array (
  13
+    'title' => 'this is my title',
  14
+    'author' => 'bob',
  15
+    'posted' => new MongoDate,
  16
+    'pageViews' => 5,
  17
+    'tags' => 
  18
+    array (
  19
+      0 => 'fun',
  20
+      1 => 'good',
  21
+      2 => 'fun',
  22
+    ),
  23
+    'comments' => 
  24
+    array (
  25
+      0 => 
  26
+      array (
  27
+        'author' => 'joe',
  28
+        'text' => 'this is cool',
  29
+      ),
  30
+      1 => 
  31
+      array (
  32
+        'author' => 'sam',
  33
+        'text' => 'this is bad',
  34
+      ),
  35
+    ),
  36
+    'other' => 
  37
+    array (
  38
+      'foo' => 5,
  39
+    ),
  40
+);
  41
+$d = $c->insert($data, array("safe" => true));
  42
+
  43
+$ops = array(
  44
+    array(
  45
+        '$project' => array(
  46
+            "author" => 1,
  47
+            "tags"   => 1,
  48
+        )
  49
+    ),
  50
+    array('$unwind' => '$tags'),
  51
+    array(
  52
+        '$group' => array(
  53
+            "_id" => array("tags" => 1),
  54
+            "authors" => array('$addToSet' => '$author'),
  55
+        )
  56
+    )
  57
+);
  58
+
  59
+
  60
+$alone = $c->aggregate($ops);
  61
+$multiple = $c->aggregate(current($ops), next($ops), next($ops));
  62
+var_dump($alone == $multiple, $alone, $multiple);
  63
+$c->drop();
  64
+
  65
+$c->aggregate();
  66
+$c->aggregate("string");
  67
+$c->aggregate($ops, "string");
  68
+$retval = $c->aggregate((object)$ops);
  69
+?>
  70
+===DONE===
  71
+<?php exit(0); ?>
  72
+--EXPECTF--
  73
+bool(true)
  74
+array(2) {
  75
+  [0]=>
  76
+  array(2) {
  77
+    ["_id"]=>
  78
+    array(1) {
  79
+      ["tags"]=>
  80
+      string(4) "good"
  81
+    }
  82
+    ["authors"]=>
  83
+    array(1) {
  84
+      [0]=>
  85
+      string(3) "bob"
  86
+    }
  87
+  }
  88
+  [1]=>
  89
+  array(2) {
  90
+    ["_id"]=>
  91
+    array(1) {
  92
+      ["tags"]=>
  93
+      string(3) "fun"
  94
+    }
  95
+    ["authors"]=>
  96
+    array(1) {
  97
+      [0]=>
  98
+      string(3) "bob"
  99
+    }
  100
+  }
  101
+}
  102
+array(2) {
  103
+  [0]=>
  104
+  array(2) {
  105
+    ["_id"]=>
  106
+    array(1) {
  107
+      ["tags"]=>
  108
+      string(4) "good"
  109
+    }
  110
+    ["authors"]=>
  111
+    array(1) {
  112
+      [0]=>
  113
+      string(3) "bob"
  114
+    }
  115
+  }
  116
+  [1]=>
  117
+  array(2) {
  118
+    ["_id"]=>
  119
+    array(1) {
  120
+      ["tags"]=>
  121
+      string(3) "fun"
  122
+    }
  123
+    ["authors"]=>
  124
+    array(1) {
  125
+      [0]=>
  126
+      string(3) "bob"
  127
+    }
  128
+  }
  129
+}
  130
+
  131
+Warning: MongoCollection::aggregate() expects at least 1 parameter, 0 given in %s on line %d
  132
+
  133
+Warning: MongoCollection::aggregate(): Argument 1 is not an array in %s on line %d
  134
+
  135
+Warning: MongoCollection::aggregate(): Argument 2 is not an array in %s on line %d
  136
+
  137
+Warning: MongoCollection::aggregate(): Argument 1 is not an array in %s on line %d
  138
+===DONE===
  139
+
7  tests/generic/skipif.inc
@@ -13,3 +13,10 @@ if (!$m) {
13 13
     die("skip Did you remember to configure " . realpath($cfg) . " based on your environment?");
14 14
 }
15 15
 
  16
+if (isset($needs)) {
  17
+    $serverversion = serverversion($m);
  18
+    if (version_compare($serverversion, $needs, "lt")) {
  19
+        die("skip This test requires MongoDB $needs, but you are running $serverversion");
  20
+    }
  21
+}
  22
+
4  tests/utils.inc
@@ -146,6 +146,10 @@ function password($db = null) {
146 146
     }
147 147
     return null;
148 148
 }
  149
+function serverversion($m) {
  150
+    $data = $m->selectDB(dbname())->command(array('buildinfo'=>true));
  151
+    return $data["version"];
  152
+}
149 153
 
150 154
 if (!function_exists("iterator_to_array")) {
151 155
     function iterator_to_array($it) {

0 notes on commit 3cbe9c7

Please sign in to comment.
Something went wrong with that request. Please try again.