Skip to content

Commit 002fad6

Browse files
Merge v1.21 into v2.1 (#1746)
2 parents 62a321e + 7b97317 commit 002fad6

File tree

6 files changed

+129
-13
lines changed

6 files changed

+129
-13
lines changed

src/Client.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ class Client
8282

8383
private WriteConcern $writeConcern;
8484

85+
private bool $autoEncryptionEnabled;
86+
8587
/**
8688
* Constructs a new Client instance.
8789
*
@@ -133,6 +135,7 @@ public function __construct(?string $uri = null, array $uriOptions = [], array $
133135
$this->uri = $uri ?? self::DEFAULT_URI;
134136
$this->builderEncoder = $driverOptions['builderEncoder'] ?? new BuilderEncoder();
135137
$this->typeMap = $driverOptions['typeMap'];
138+
$this->autoEncryptionEnabled = isset($driverOptions['autoEncryption']['keyVaultNamespace']);
136139

137140
$driverOptions = array_diff_key($driverOptions, ['builderEncoder' => 1, 'typeMap' => 1]);
138141

@@ -270,7 +273,7 @@ public function dropDatabase(string $databaseName, array $options = []): void
270273
*/
271274
public function getCollection(string $databaseName, string $collectionName, array $options = []): Collection
272275
{
273-
$options += ['typeMap' => $this->typeMap, 'builderEncoder' => $this->builderEncoder];
276+
$options += ['typeMap' => $this->typeMap, 'builderEncoder' => $this->builderEncoder, 'autoEncryptionEnabled' => $this->autoEncryptionEnabled];
274277

275278
return new Collection($this->manager, $databaseName, $collectionName, $options);
276279
}
@@ -285,7 +288,7 @@ public function getCollection(string $databaseName, string $collectionName, arra
285288
*/
286289
public function getDatabase(string $databaseName, array $options = []): Database
287290
{
288-
$options += ['typeMap' => $this->typeMap, 'builderEncoder' => $this->builderEncoder];
291+
$options += ['typeMap' => $this->typeMap, 'builderEncoder' => $this->builderEncoder, 'autoEncryptionEnabled' => $this->autoEncryptionEnabled];
289292

290293
return new Database($this->manager, $databaseName, $options);
291294
}

src/Collection.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
use function array_key_exists;
7676
use function current;
7777
use function is_array;
78+
use function is_bool;
7879
use function strlen;
7980

8081
class Collection
@@ -100,6 +101,8 @@ class Collection
100101

101102
private WriteConcern $writeConcern;
102103

104+
private bool $autoEncryptionEnabled;
105+
103106
/**
104107
* Constructs new Collection instance.
105108
*
@@ -167,12 +170,17 @@ public function __construct(private Manager $manager, private string $databaseNa
167170
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
168171
}
169172

173+
if (isset($options['autoEncryptionEnabled']) && ! is_bool($options['autoEncryptionEnabled'])) {
174+
throw InvalidArgumentException::invalidType('"autoEncryptionEnabled" option', $options['autoEncryptionEnabled'], 'boolean');
175+
}
176+
170177
$this->builderEncoder = $options['builderEncoder'] ?? new BuilderEncoder();
171178
$this->codec = $options['codec'] ?? null;
172179
$this->readConcern = $options['readConcern'] ?? $this->manager->getReadConcern();
173180
$this->readPreference = $options['readPreference'] ?? $this->manager->getReadPreference();
174181
$this->typeMap = $options['typeMap'] ?? self::DEFAULT_TYPE_MAP;
175182
$this->writeConcern = $options['writeConcern'] ?? $this->manager->getWriteConcern();
183+
$this->autoEncryptionEnabled = $options['autoEncryptionEnabled'] ?? false;
176184
}
177185

178186
/**
@@ -511,9 +519,9 @@ public function drop(array $options = []): void
511519

512520
$server = select_server_for_write($this->manager, $options);
513521

514-
if (! isset($options['encryptedFields'])) {
522+
if ($this->autoEncryptionEnabled && ! isset($options['encryptedFields'])) {
515523
$options['encryptedFields'] = get_encrypted_fields_from_driver($this->databaseName, $this->collectionName, $this->manager)
516-
?? get_encrypted_fields_from_server($this->databaseName, $this->collectionName, $this->manager, $server);
524+
?? get_encrypted_fields_from_server($this->databaseName, $this->collectionName, $server);
517525
}
518526

519527
$operation = isset($options['encryptedFields'])

src/Database.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
use Throwable;
5555

5656
use function is_array;
57+
use function is_bool;
5758
use function strlen;
5859

5960
class Database
@@ -77,6 +78,8 @@ class Database
7778

7879
private WriteConcern $writeConcern;
7980

81+
private bool $autoEncryptionEnabled;
82+
8083
/**
8184
* Constructs new Database instance.
8285
*
@@ -133,11 +136,16 @@ public function __construct(private Manager $manager, private string $databaseNa
133136
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class);
134137
}
135138

139+
if (isset($options['autoEncryptionEnabled']) && ! is_bool($options['autoEncryptionEnabled'])) {
140+
throw InvalidArgumentException::invalidType('"autoEncryptionEnabled" option', $options['autoEncryptionEnabled'], 'boolean');
141+
}
142+
136143
$this->builderEncoder = $options['builderEncoder'] ?? new BuilderEncoder();
137144
$this->readConcern = $options['readConcern'] ?? $this->manager->getReadConcern();
138145
$this->readPreference = $options['readPreference'] ?? $this->manager->getReadPreference();
139146
$this->typeMap = $options['typeMap'] ?? self::DEFAULT_TYPE_MAP;
140147
$this->writeConcern = $options['writeConcern'] ?? $this->manager->getWriteConcern();
148+
$this->autoEncryptionEnabled = $options['autoEncryptionEnabled'] ?? false;
141149
}
142150

143151
/**
@@ -372,9 +380,9 @@ public function dropCollection(string $collectionName, array $options = []): voi
372380
$options['writeConcern'] = $this->writeConcern;
373381
}
374382

375-
if (! isset($options['encryptedFields'])) {
383+
if ($this->autoEncryptionEnabled && ! isset($options['encryptedFields'])) {
376384
$options['encryptedFields'] = get_encrypted_fields_from_driver($this->databaseName, $collectionName, $this->manager)
377-
?? get_encrypted_fields_from_server($this->databaseName, $collectionName, $this->manager, $server);
385+
?? get_encrypted_fields_from_server($this->databaseName, $collectionName, $server);
378386
}
379387

380388
$operation = isset($options['encryptedFields'])
@@ -401,6 +409,7 @@ public function getCollection(string $collectionName, array $options = []): Coll
401409
'readPreference' => $this->readPreference,
402410
'typeMap' => $this->typeMap,
403411
'writeConcern' => $this->writeConcern,
412+
'autoEncryptionEnabled' => $this->autoEncryptionEnabled,
404413
];
405414

406415
return new Collection($this->manager, $this->databaseName, $collectionName, $options);

src/functions.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,8 @@ function get_encrypted_fields_from_driver(string $databaseName, string $collecti
198198
* @see Collection::drop()
199199
* @see Database::dropCollection()
200200
*/
201-
function get_encrypted_fields_from_server(string $databaseName, string $collectionName, Manager $manager, Server $server): array|object|null
201+
function get_encrypted_fields_from_server(string $databaseName, string $collectionName, Server $server): array|object|null
202202
{
203-
// No-op if the encryptedFieldsMap autoEncryption driver option was omitted
204-
if ($manager->getEncryptedFieldsMap() === null) {
205-
return null;
206-
}
207-
208203
$collectionInfoIterator = (new ListCollections($databaseName, ['filter' => ['name' => $collectionName]]))->execute($server);
209204

210205
foreach ($collectionInfoIterator as $collectionInfo) {
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
namespace MongoDB\Tests\Functions;
4+
5+
use MongoDB\BSON\Binary;
6+
use MongoDB\BSON\Regex;
7+
use MongoDB\Collection;
8+
use MongoDB\Database;
9+
use MongoDB\Driver\ClientEncryption;
10+
use MongoDB\Driver\WriteConcern;
11+
use MongoDB\Tests\FunctionalTestCase;
12+
13+
use function preg_quote;
14+
use function str_repeat;
15+
16+
class GetEncryptedFieldsFromServerFunctionalTest extends FunctionalTestCase
17+
{
18+
private ClientEncryption $clientEncryption;
19+
private Collection $keyVaultCollection;
20+
private Database $database;
21+
22+
public function setUp(): void
23+
{
24+
parent::setUp();
25+
26+
$this->skipIfClientSideEncryptionIsNotSupported();
27+
28+
if ($this->isStandalone()) {
29+
$this->markTestSkipped('Queryable encryption requires replica sets');
30+
}
31+
32+
$this->skipIfServerVersion('<', '7.0.0', 'Queryable encryption requires MongoDB 7.0 or later');
33+
34+
$encryptionOptions = [
35+
'keyVaultNamespace' => 'keyvault.datakeys',
36+
'kmsProviders' => [
37+
'local' => [
38+
'key' => new Binary(str_repeat("\0", 96)), // 96-byte local master key
39+
],
40+
],
41+
];
42+
$client = static::createTestClient(driverOptions: ['autoEncryption' => $encryptionOptions]);
43+
44+
// Ensure the key vault collection is dropped before each test
45+
$this->keyVaultCollection = $client->getCollection('keyvault', 'datakeys', ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]);
46+
$this->keyVaultCollection->drop();
47+
48+
$this->clientEncryption = $client->createClientEncryption($encryptionOptions);
49+
50+
$this->database = $client->getDatabase($this->getDatabaseName());
51+
}
52+
53+
public function tearDown(): void
54+
{
55+
$this->keyVaultCollection?->drop();
56+
}
57+
58+
/** @see https://jira.mongodb.org/browse/PHPLIB-1702 */
59+
public function testDatabaseDropCollectionConsultsEncryptedFieldsFromServer(): void
60+
{
61+
$this->database->createEncryptedCollection(
62+
$this->getCollectionName(),
63+
$this->clientEncryption,
64+
'local',
65+
null,
66+
['encryptedFields' => ['fields' => []]],
67+
);
68+
69+
$this->assertCountCollections(3, $this->getCollectionName(), 'createEncryptedCollection should create three collections');
70+
71+
$this->database->dropCollection($this->getCollectionName());
72+
73+
$this->assertCountCollections(0, $this->getCollectionName());
74+
}
75+
76+
/** @see https://jira.mongodb.org/browse/PHPLIB-1702 */
77+
public function testCollectionDropConsultsEncryptedFieldsFromServer(): void
78+
{
79+
$this->database->createEncryptedCollection(
80+
$this->getCollectionName(),
81+
$this->clientEncryption,
82+
'local',
83+
null,
84+
['encryptedFields' => ['fields' => []]],
85+
);
86+
87+
$this->assertCountCollections(3, $this->getCollectionName(), 'createEncryptedCollection should create three collections');
88+
89+
$this->database->getCollection($this->getCollectionName())->drop();
90+
91+
$this->assertCountCollections(0, $this->getCollectionName());
92+
}
93+
94+
private function assertCountCollections(int $expected, $collectionName, string $message = ''): void
95+
{
96+
$collectionNames = $this->database->listCollectionNames([
97+
'filter' => ['name' => new Regex(preg_quote($collectionName))],
98+
]);
99+
$this->assertCount($expected, $collectionNames, $message);
100+
}
101+
}

tests/drivers-evergreen-tools

0 commit comments

Comments
 (0)