Skip to content

Commit edf7c95

Browse files
committed
PHPLIB-518: Provide MongoDB\Collection::rename() method to rename a collection
1 parent 903e101 commit edf7c95

File tree

5 files changed

+441
-0
lines changed

5 files changed

+441
-0
lines changed

src/Collection.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
use MongoDB\Operation\InsertOne;
5454
use MongoDB\Operation\ListIndexes;
5555
use MongoDB\Operation\MapReduce;
56+
use MongoDB\Operation\RenameCollection;
5657
use MongoDB\Operation\ReplaceOne;
5758
use MongoDB\Operation\UpdateMany;
5859
use MongoDB\Operation\UpdateOne;
@@ -1004,6 +1005,34 @@ public function mapReduce(JavascriptInterface $map, JavascriptInterface $reduce,
10041005
return $operation->execute($server);
10051006
}
10061007

1008+
/**
1009+
* Renames the collection.
1010+
*
1011+
* @see RenameCollection::__construct() for supported options
1012+
* @param string $newCollectionName New name for this collection
1013+
* @param array $options Additional options
1014+
* @return array|object Command result document
1015+
* @throws UnsupportedException if options are not supported by the selected server
1016+
* @throws InvalidArgumentException for parameter/option parsing errors
1017+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
1018+
*/
1019+
public function renameCollection($newCollectionName, array $options = [])
1020+
{
1021+
if (! isset($options['typeMap'])) {
1022+
$options['typeMap'] = $this->typeMap;
1023+
}
1024+
1025+
$server = select_server($this->manager, $options);
1026+
1027+
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) {
1028+
$options['writeConcern'] = $this->writeConcern;
1029+
}
1030+
1031+
$operation = new RenameCollection($this->databaseName, $this->collectionName, $newCollectionName, $options);
1032+
1033+
return $operation->execute($server);
1034+
}
1035+
10071036
/**
10081037
* Replaces at most one document matching the filter.
10091038
*

src/Database.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
use MongoDB\Operation\ListCollectionNames;
4040
use MongoDB\Operation\ListCollections;
4141
use MongoDB\Operation\ModifyCollection;
42+
use MongoDB\Operation\RenameCollection;
4243
use MongoDB\Operation\Watch;
4344
use Traversable;
4445

@@ -470,6 +471,34 @@ public function modifyCollection($collectionName, array $collectionOptions, arra
470471
return $operation->execute($server);
471472
}
472473

474+
/**
475+
* Rename a collection within this database.
476+
*
477+
* @see RenameCollection::__construct() for supported options
478+
* @param string $newCollectionName New name for this collection
479+
* @param array $options Additional options
480+
* @return array|object Command result document
481+
* @throws UnsupportedException if options are unsupported on the selected server
482+
* @throws InvalidArgumentException for parameter/option parsing errors
483+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
484+
*/
485+
public function renameCollection($collectionName, $newCollectionName, array $options = [])
486+
{
487+
if (! isset($options['typeMap'])) {
488+
$options['typeMap'] = $this->typeMap;
489+
}
490+
491+
$server = select_server($this->manager, $options);
492+
493+
if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) {
494+
$options['writeConcern'] = $this->writeConcern;
495+
}
496+
497+
$operation = new RenameCollection($this->databaseName, $collectionName, $newCollectionName, $options);
498+
499+
return $operation->execute($server);
500+
}
501+
473502
/**
474503
* Select a collection within this database.
475504
*

src/Operation/RenameCollection.php

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
<?php
2+
/*
3+
* Copyright 2015-2017 MongoDB, Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
namespace MongoDB\Operation;
19+
20+
use MongoDB\Driver\Command;
21+
use MongoDB\Driver\Exception\CommandException;
22+
use MongoDB\Driver\Server;
23+
use MongoDB\Driver\Session;
24+
use MongoDB\Driver\WriteConcern;
25+
use MongoDB\Exception\InvalidArgumentException;
26+
use MongoDB\Exception\UnsupportedException;
27+
use function current;
28+
use function is_array;
29+
use function MongoDB\server_supports_feature;
30+
31+
/**
32+
* Operation for the rename command.
33+
*
34+
* @api
35+
* @see \MongoDB\Collection::rename()
36+
* @see \MongoDB\Database::renameCollection()
37+
* @see https://docs.mongodb.org/manual/reference/command/renameCollection/
38+
*/
39+
class RenameCollection implements Executable
40+
{
41+
/** @var integer */
42+
private static $errorCodeNamespaceNotFound = 26;
43+
44+
/** @var string */
45+
private static $errorMessageNamespaceNotFound = 'ns not found';
46+
47+
/** @var integer */
48+
private static $wireVersionForWriteConcern = 5;
49+
50+
/** @var string */
51+
private $databaseName;
52+
53+
/** @var string */
54+
private $collectionName;
55+
56+
/** @var string */
57+
private $newCollectionName;
58+
59+
/** @var array */
60+
private $options;
61+
62+
/**
63+
* Constructs a rename command.
64+
*
65+
* Supported options:
66+
*
67+
* * session (MongoDB\Driver\Session): Client session.
68+
*
69+
* Sessions are not supported for server versions < 3.6.
70+
*
71+
* * typeMap (array): Type map for BSON deserialization. This will be used
72+
* for the returned command result document.
73+
*
74+
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
75+
*
76+
* * dropTarget (boolean): If true, mongod will drop the target of
77+
* renameCollection prior to renaming the collection.
78+
*
79+
* This is not supported for server versions < 3.4 and will result in an
80+
* exception at execution time if used.
81+
*
82+
* @param string $databaseName Database name
83+
* @param string $collectionName Collection name
84+
* @param array $options Command options
85+
* @throws InvalidArgumentException for parameter/option parsing errors
86+
*/
87+
public function __construct($databaseName, $collectionName, $newCollectionName, array $options = [])
88+
{
89+
$newCollectionName = (string) $newCollectionName;
90+
91+
if ($newCollectionName === '') {
92+
throw new InvalidArgumentException('$newCollectionName cannot be empty');
93+
}
94+
95+
if (isset($options['session']) && ! $options['session'] instanceof Session) {
96+
throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class);
97+
}
98+
99+
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
100+
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
101+
}
102+
103+
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
104+
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
105+
}
106+
107+
if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) {
108+
unset($options['writeConcern']);
109+
}
110+
111+
if (isset($options['dropTarget']) && ! is_bool($options['dropTarget'])) {
112+
throw InvalidArgumentException::invalidType('"dropTarget" option', $options['dropTarget'], 'boolean');
113+
}
114+
115+
$this->databaseName = (string) $databaseName;
116+
$this->collectionName = (string) $collectionName;
117+
$this->newCollectionName = (string) $newCollectionName;
118+
$this->options = $options;
119+
}
120+
121+
/**
122+
* Execute the operation.
123+
*
124+
* @see Executable::execute()
125+
* @param Server $server
126+
* @return array|object Command result document
127+
* @throws UnsupportedException if writeConcern is used and unsupported
128+
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
129+
*/
130+
public function execute(Server $server)
131+
{
132+
if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) {
133+
throw UnsupportedException::writeConcernNotSupported();
134+
}
135+
136+
$inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction();
137+
if ($inTransaction && isset($this->options['writeConcern'])) {
138+
throw UnsupportedException::writeConcernNotSupportedInTransaction();
139+
}
140+
141+
$command = new Command([
142+
'renameCollection' => $this->collectionName,
143+
'to' => $this->newCollectionName,
144+
]);
145+
146+
try {
147+
$cursor = $server->executeWriteCommand($this->databaseName, $command, $this->createOptions());
148+
} catch (CommandException $e) {
149+
/* The server may return an error if the collection does not exist.
150+
* Check for an error code (or message for pre-3.2 servers) and
151+
* return the command reply instead of throwing. */
152+
if ($e->getCode() === self::$errorCodeNamespaceNotFound ||
153+
$e->getMessage() === self::$errorMessageNamespaceNotFound) {
154+
return $e->getResultDocument();
155+
}
156+
157+
throw $e;
158+
}
159+
160+
if (isset($this->options['typeMap'])) {
161+
$cursor->setTypeMap($this->options['typeMap']);
162+
}
163+
164+
return current($cursor->toArray());
165+
}
166+
167+
/**
168+
* Create options for executing the command.
169+
*
170+
* @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
171+
* @return array
172+
*/
173+
private function createOptions()
174+
{
175+
$options = [];
176+
177+
if (isset($this->options['session'])) {
178+
$options['session'] = $this->options['session'];
179+
}
180+
181+
if (isset($this->options['writeConcern'])) {
182+
$options['writeConcern'] = $this->options['writeConcern'];
183+
}
184+
185+
if (isset($this->options['dropTarget'])) {
186+
$options['dropTarget'] = $this->options['dropTarget'];
187+
}
188+
189+
return $options;
190+
}
191+
}

0 commit comments

Comments
 (0)