Skip to content

Commit 39cf918

Browse files
committed
PHPLIB-63: Use model class to validate index creation args
1 parent 3108162 commit 39cf918

File tree

2 files changed

+106
-37
lines changed

2 files changed

+106
-37
lines changed

src/Collection.php

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use MongoDB\Exception\UnexpectedTypeException;
1515
use MongoDB\Model\IndexInfoIterator;
1616
use MongoDB\Model\IndexInfoIteratorIterator;
17-
use stdClass;
17+
use MongoDB\Model\IndexInput;
1818

1919
class Collection
2020
{
@@ -286,33 +286,20 @@ public function createIndex($key, array $options = array())
286286
* @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/
287287
* @param array $indexes List of index specifications
288288
* @return string[] The names of the created indexes
289-
* @throws InvalidArgumentException if an index specification does not
290-
* contain a "key" document
291-
* @throws UnexpectedTypeException if an index specification is not an array
292-
* or a "key" document is not an array or
293-
* object
289+
* @throws InvalidArgumentException if an index specification is invalid
294290
*/
295291
public function createIndexes(array $indexes)
296292
{
297-
foreach ($indexes as &$index) {
293+
foreach ($indexes as $i => $index) {
298294
if ( ! is_array($index)) {
299295
throw new UnexpectedTypeException($index, 'array');
300296
}
301297

302-
if ( ! isset($index['key'])) {
303-
throw new InvalidArgumentException('Required "key" document is missing from index specification');
298+
if ( ! isset($index['ns'])) {
299+
$index['ns'] = $this->ns;
304300
}
305301

306-
if ( ! is_array($index['key']) && ! is_object($index['key'])) {
307-
throw new UnexpectedTypeException($index['key'], 'array or object');
308-
}
309-
310-
$index['key'] = (object) $index['key'];
311-
$index['ns'] = $this->ns;
312-
313-
if ( ! isset($index['name'])) {
314-
$index['name'] = $this->generateIndexName($index['key']);
315-
}
302+
$indexes[$i] = new IndexInput($index);
316303
}
317304

318305
$readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
@@ -327,7 +314,7 @@ public function createIndexes(array $indexes)
327314
$this->createIndexesLegacy($server, $indexes);
328315
}
329316

330-
return array_map(function(array $index) { return $index['name']; }, $indexes);
317+
return array_map(function(IndexInput $index) { return (string) $index; }, $indexes);
331318
}
332319

333320
/**
@@ -1248,23 +1235,6 @@ private function createIndexesLegacy(Server $server, array $indexes)
12481235
$server->executeBulkWrite($this->dbname . '.system.indexes', $bulk);
12491236
}
12501237

1251-
/**
1252-
* Generates an index name from its key specification.
1253-
*
1254-
* @param object $key
1255-
* @return string
1256-
*/
1257-
private function generateIndexName(stdClass $key)
1258-
{
1259-
$name = '';
1260-
1261-
foreach ($key as $field => $type) {
1262-
$name .= ($name != '' ? '_' : '') . $field . '_' . $type;
1263-
}
1264-
1265-
return $name;
1266-
}
1267-
12681238
/**
12691239
* Returns information for all indexes for this collection using the
12701240
* listIndexes command.

src/Model/IndexInput.php

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
namespace MongoDB\Model;
4+
5+
use BSON\Serializable;
6+
7+
/**
8+
* Index input model class.
9+
*
10+
* This class is used to validate user input for index creation.
11+
*
12+
* @internal
13+
* @see MongoDB\Collection::createIndexes()
14+
* @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst
15+
* @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/
16+
*/
17+
class IndexInput implements Serializable
18+
{
19+
private $index;
20+
21+
/**
22+
* Constructor.
23+
*
24+
* @param array $index Index specification
25+
*/
26+
public function __construct(array $index)
27+
{
28+
if ( ! isset($index['key'])) {
29+
throw new InvalidArgumentException('Required "key" document is missing from index specification');
30+
}
31+
32+
if ( ! is_array($index['key']) && ! is_object($index['key'])) {
33+
throw new UnexpectedTypeException($index['key'], 'array or object');
34+
}
35+
36+
foreach ($index['key'] as $order) {
37+
if ( ! is_int($order) && ! is_float($order) && ! is_string($order)) {
38+
throw new UnexpectedTypeException($order, 'numeric or string');
39+
}
40+
}
41+
42+
if ( ! isset($index['ns'])) {
43+
throw new InvalidArgumentException('Required "ns" option is missing from index specification');
44+
}
45+
46+
if ( ! is_string($index['ns'])) {
47+
throw new UnexpectedTypeException($index['ns'], 'string');
48+
}
49+
50+
if ( ! isset($index['name'])) {
51+
$index['name'] = $this->generateName($index['key']);
52+
}
53+
54+
if ( ! is_string($index['name'])) {
55+
throw new UnexpectedTypeException($index['name'], 'string');
56+
}
57+
58+
$this->index = $index;
59+
}
60+
61+
/**
62+
* Serialize the index information to BSON for index creation.
63+
*
64+
* @see MongoDB\Collection::createIndexes()
65+
* @see http://php.net/bson-serializable.bsonserialize
66+
*/
67+
public function bsonSerialize()
68+
{
69+
return $this->index;
70+
}
71+
72+
/**
73+
* Return the index name.
74+
*
75+
* @param string
76+
*/
77+
public function __toString()
78+
{
79+
return $this->index['name'];
80+
}
81+
82+
/**
83+
* Generates an index name from its key specification.
84+
*
85+
* @param array|object $key Document containing fields mapped to values,
86+
* which denote order or an index type
87+
* @return string
88+
*/
89+
private function generateName($key)
90+
{
91+
$name = '';
92+
93+
foreach ($key as $field => $type) {
94+
$name .= ($name != '' ? '_' : '') . $field . '_' . $type;
95+
}
96+
97+
return $name;
98+
}
99+
}

0 commit comments

Comments
 (0)