Skip to content

Commit 75f8348

Browse files
committed
PHPLIB-63: Use model class to validate index creation args
1 parent ed9c047 commit 75f8348

File tree

2 files changed

+107
-37
lines changed

2 files changed

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

0 commit comments

Comments
 (0)