18
18
namespace MongoDB ;
19
19
20
20
use Iterator ;
21
- use MongoDB \BSON \Binary ;
22
21
use MongoDB \Driver \ClientEncryption ;
23
22
use MongoDB \Driver \Cursor ;
24
23
use MongoDB \Driver \Exception \RuntimeException as DriverRuntimeException ;
36
35
use MongoDB \Model \CollectionInfoIterator ;
37
36
use MongoDB \Operation \Aggregate ;
38
37
use MongoDB \Operation \CreateCollection ;
39
- use MongoDB \Operation \CreateIndexes ;
38
+ use MongoDB \Operation \CreateEncryptedCollection ;
40
39
use MongoDB \Operation \DatabaseCommand ;
41
40
use MongoDB \Operation \DropCollection ;
42
41
use MongoDB \Operation \DropDatabase ;
45
44
use MongoDB \Operation \ModifyCollection ;
46
45
use MongoDB \Operation \RenameCollection ;
47
46
use MongoDB \Operation \Watch ;
47
+ use Throwable ;
48
48
use Traversable ;
49
- use Exception ;
50
49
51
- use function array_key_exists ;
52
50
use function is_array ;
53
- use function is_object ;
54
- use function property_exists ;
55
51
use function strlen ;
56
52
57
53
class Database
@@ -263,7 +259,13 @@ public function command($command, array $options = [])
263
259
/**
264
260
* Create a new collection explicitly.
265
261
*
262
+ * If the "encryptedFields" option is specified, this method additionally
263
+ * creates related metadata collections and an index on the encrypted
264
+ * collection.
265
+ *
266
266
* @see CreateCollection::__construct() for supported options
267
+ * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#create-collection-helper
268
+ * @see https://www.mongodb.com/docs/manual/core/queryable-encryption/fundamentals/manage-collections/
267
269
* @return array|object Command result document
268
270
* @throws UnsupportedException if options are not supported by the selected server
269
271
* @throws InvalidArgumentException for parameter/option parsing errors
@@ -275,90 +277,62 @@ public function createCollection(string $collectionName, array $options = [])
275
277
$ options ['typeMap ' ] = $ this ->typeMap ;
276
278
}
277
279
278
- $ server = select_server ($ this ->manager , $ options );
279
-
280
280
if (! isset ($ options ['writeConcern ' ]) && ! is_in_transaction ($ options )) {
281
281
$ options ['writeConcern ' ] = $ this ->writeConcern ;
282
282
}
283
283
284
- $ encryptedFields = $ options ['encryptedFields ' ]
285
- ?? get_encrypted_fields_from_driver ($ this ->databaseName , $ collectionName , $ this ->manager )
286
- ?? null ;
287
-
288
- if ($ encryptedFields !== null ) {
289
- // encryptedFields is passed to the create command
290
- $ options ['encryptedFields ' ] = $ encryptedFields ;
291
-
292
- $ encryptedFields = (array ) $ encryptedFields ;
293
- $ enxcolOptions = ['clusteredIndex ' => ['key ' => ['_id ' => 1 ], 'unique ' => true ]];
294
- (new CreateCollection ($ this ->databaseName , $ encryptedFields ['escCollection ' ] ?? 'enxcol_. ' . $ collectionName . '.esc ' , $ enxcolOptions ))->execute ($ server );
295
- (new CreateCollection ($ this ->databaseName , $ encryptedFields ['eccCollection ' ] ?? 'enxcol_. ' . $ collectionName . '.ecc ' , $ enxcolOptions ))->execute ($ server );
296
- (new CreateCollection ($ this ->databaseName , $ encryptedFields ['ecocCollection ' ] ?? 'enxcol_. ' . $ collectionName . '.ecoc ' , $ enxcolOptions ))->execute ($ server );
284
+ if (! isset ($ options ['encryptedFields ' ])) {
285
+ $ options ['encryptedFields ' ] = get_encrypted_fields_from_driver ($ this ->databaseName , $ collectionName , $ this ->manager );
297
286
}
298
287
299
- $ operation = new CreateCollection ($ this ->databaseName , $ collectionName , $ options );
288
+ $ operation = isset ($ options ['encryptedFields ' ])
289
+ ? new CreateEncryptedCollection ($ this ->databaseName , $ collectionName , $ options )
290
+ : new CreateCollection ($ this ->databaseName , $ collectionName , $ options );
300
291
301
- $ result = $ operation ->execute ($ server );
302
-
303
- if ($ encryptedFields !== null ) {
304
- (new CreateIndexes ($ this ->databaseName , $ collectionName , [['key ' => ['__safeContent__ ' => 1 ]]]))->execute ($ server );
305
- }
292
+ $ server = select_server ($ this ->manager , $ options );
306
293
307
- return $ result ;
294
+ return $ operation -> execute ( $ server ) ;
308
295
}
309
296
310
297
/**
311
298
* Create a new encrypted collection explicitly.
312
299
*
313
- * This function will automatically create data keys for any encrypted
314
- * fields where the "keyId" option is null. This function will return a copy
315
- * of the modified "encryptedFields" option in addition to the result from
316
- * createCollection(). The "encryptedFields" option is required.
300
+ * The "encryptedFields" option is required.
301
+ *
302
+ * This method will automatically create data keys for any encrypted fields
303
+ * where "keyId" is null. A copy of the modified "encryptedFields" option
304
+ * will be returned in addition to the result from creating the collection.
317
305
*
318
- * If any error is encountered while creating data keys or invoking
319
- * createCollection(), a CreateEncryptedCollectionException will be thrown.
320
- * The original exception and modified "encryptedFields" option can be
321
- * accessed via the getPrevious() and getEncryptedFields() methods,
322
- * respectively.
306
+ * If any error is encountered while creating data keys or creating the
307
+ * collection, a CreateEncryptedCollectionException will be thrown. The
308
+ * original exception and modified "encryptedFields" option can be accessed
309
+ * via the getPrevious() and getEncryptedFields() methods, respectively.
323
310
*
324
311
* @see CreateCollection::__construct() for supported options
325
- * @return array A tuple consisting of the createCollection() result and modified "encryptedFields" option
312
+ * @return array A tuple consisting of the result from creating the collection and the modified "encryptedFields" option
326
313
* @throws InvalidArgumentException for parameter/option parsing errors
327
- * @throws CreateEncryptedCollectionException for any errors creating data keys or invoking createCollection()
314
+ * @throws CreateEncryptedCollectionException for any errors creating data keys or creating the collection
328
315
*/
329
316
public function createEncryptedCollection (string $ collectionName , ClientEncryption $ clientEncryption , string $ kmsProvider , ?array $ masterKey , array $ options ): array
330
317
{
331
- if (! isset ($ options ['encryptedFields ' ]) || ! is_array ( $ options [ ' encryptedFields ' ]) && ! is_object ( $ options [ ' encryptedFields ' ])) {
332
- throw InvalidArgumentException:: invalidType ( ' "encryptedFields" option ' , $ options ['encryptedFields ' ] ?? null , [ ' array ' , ' object ' ]) ;
318
+ if (! isset ($ options ['typeMap ' ])) {
319
+ $ options ['typeMap ' ] = $ this -> typeMap ;
333
320
}
334
321
335
- /** @var array{fields: list<array{keyId: ?Binary}|object{keyId: ?Binary}>} */
336
- $ encryptedFields = (array ) recursive_copy ($ options ['encryptedFields ' ]);
322
+ if (! isset ($ options ['writeConcern ' ]) && ! is_in_transaction ($ options )) {
323
+ $ options ['writeConcern ' ] = $ this ->writeConcern ;
324
+ }
337
325
338
- $ createDataKeyArgs = [
339
- $ kmsProvider ,
340
- isset ($ masterKey ) ? ['masterKey ' => $ masterKey ] : [],
341
- ];
326
+ $ operation = new CreateEncryptedCollection ($ this ->databaseName , $ collectionName , $ options );
327
+ $ server = select_server ($ this ->manager , $ options );
342
328
343
329
try {
344
- /** @psalm-suppress RedundantConditionGivenDocblockType */
345
- if (isset ($ encryptedFields ['fields ' ]) && is_array ($ encryptedFields ['fields ' ])) {
346
- foreach ($ encryptedFields ['fields ' ] as &$ field ) {
347
- if (is_array ($ field ) && array_key_exists ('keyId ' , $ field ) && $ field ['keyId ' ] === null ) {
348
- $ field ['keyId ' ] = $ clientEncryption ->createDataKey (...$ createDataKeyArgs );
349
- } elseif (is_object ($ field ) && property_exists ($ field , 'keyId ' ) && $ field ->keyId === null ) {
350
- $ field ->keyId = $ clientEncryption ->createDataKey (...$ createDataKeyArgs );
351
- }
352
- }
353
-
354
- $ options ['encryptedFields ' ] = $ encryptedFields ;
355
- }
356
-
357
- $ result = $ this ->createCollection ($ collectionName , $ options );
330
+ $ operation ->createDataKeys ($ clientEncryption , $ kmsProvider , $ masterKey , $ encryptedFields );
331
+ $ result = $ operation ->execute ($ server );
358
332
359
333
return [$ result , $ encryptedFields ];
360
- } catch (Exception $ e ) {
361
- throw new CreateEncryptedCollectionException ($ e , $ encryptedFields );
334
+ } catch (Throwable $ e ) {
335
+ throw new CreateEncryptedCollectionException ($ e , $ encryptedFields ?? [] );
362
336
}
363
337
}
364
338
0 commit comments