Skip to content

Commit ca43b05

Browse files
committed
Use DriverOptions value object in Client
1 parent d1cd2f1 commit ca43b05

File tree

2 files changed

+30
-147
lines changed

2 files changed

+30
-147
lines changed

psalm-baseline.xml

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -217,28 +217,6 @@
217217
<code><![CDATA[$query::NAME]]></code>
218218
</UndefinedConstant>
219219
</file>
220-
<file src="src/Client.php">
221-
<MixedArgument>
222-
<code><![CDATA[$driverOptions['driver'] ?? []]]></code>
223-
<code><![CDATA[$pipeline]]></code>
224-
</MixedArgument>
225-
<MixedArrayAssignment>
226-
<code><![CDATA[$options['kmsProviders'][$name]]]></code>
227-
</MixedArrayAssignment>
228-
<MixedAssignment>
229-
<code><![CDATA[$mergedDriver['platform']]]></code>
230-
<code><![CDATA[$provider]]></code>
231-
</MixedAssignment>
232-
<MixedPropertyTypeCoercion>
233-
<code><![CDATA[$driverOptions['builderEncoder'] ?? new BuilderEncoder()]]></code>
234-
</MixedPropertyTypeCoercion>
235-
<NamedArgumentNotAllowed>
236-
<code><![CDATA[$pipeline]]></code>
237-
</NamedArgumentNotAllowed>
238-
<PossiblyInvalidArgument>
239-
<code><![CDATA[$pipeline]]></code>
240-
</PossiblyInvalidArgument>
241-
</file>
242220
<file src="src/ClientBulkWrite.php">
243221
<PossiblyInvalidArgument>
244222
<code><![CDATA[$document]]></code>

src/Client.php

Lines changed: 30 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,10 @@
1717

1818
namespace MongoDB;
1919

20-
use Composer\InstalledVersions;
2120
use Iterator;
22-
use MongoDB\BSON\Document;
23-
use MongoDB\BSON\PackedArray;
24-
use MongoDB\Builder\BuilderEncoder;
2521
use MongoDB\Builder\Pipeline;
26-
use MongoDB\Codec\Encoder;
22+
use MongoDB\Builder\Stage;
23+
use MongoDB\Builder\Type\StageInterface;
2724
use MongoDB\Driver\BulkWriteCommand;
2825
use MongoDB\Driver\BulkWriteCommandResult;
2926
use MongoDB\Driver\ClientEncryption;
@@ -38,36 +35,26 @@
3835
use MongoDB\Exception\InvalidArgumentException;
3936
use MongoDB\Exception\UnexpectedValueException;
4037
use MongoDB\Exception\UnsupportedException;
41-
use MongoDB\Model\BSONArray;
42-
use MongoDB\Model\BSONDocument;
38+
use MongoDB\Model\AutoEncryptionOptions;
4339
use MongoDB\Model\DatabaseInfo;
40+
use MongoDB\Model\DriverOptions;
4441
use MongoDB\Operation\ClientBulkWriteCommand;
4542
use MongoDB\Operation\DropDatabase;
4643
use MongoDB\Operation\ListDatabaseNames;
4744
use MongoDB\Operation\ListDatabases;
4845
use MongoDB\Operation\Watch;
4946
use stdClass;
5047
use Stringable;
51-
use Throwable;
5248

5349
use function array_diff_key;
54-
use function is_array;
55-
use function is_string;
5650

51+
/**
52+
* @psalm-type stage = StageInterface|array<string,mixed>|stdClass
53+
*/
5754
class Client implements Stringable
5855
{
5956
public const DEFAULT_URI = 'mongodb://127.0.0.1/';
6057

61-
private const DEFAULT_TYPE_MAP = [
62-
'array' => BSONArray::class,
63-
'document' => BSONDocument::class,
64-
'root' => BSONDocument::class,
65-
];
66-
67-
private const HANDSHAKE_SEPARATOR = '/';
68-
69-
private static ?string $version = null;
70-
7158
private Manager $manager;
7259

7360
private ReadConcern $readConcern;
@@ -76,14 +63,9 @@ class Client implements Stringable
7663

7764
private string $uri;
7865

79-
private array $typeMap;
80-
81-
/** @psalm-var Encoder<array|stdClass|Document|PackedArray, mixed> */
82-
private readonly Encoder $builderEncoder;
83-
8466
private WriteConcern $writeConcern;
8567

86-
private bool $autoEncryptionEnabled;
68+
private DriverOptions $driverOptions;
8769

8870
/**
8971
* Constructs a new Client instance.
@@ -113,32 +95,11 @@ class Client implements Stringable
11395
*/
11496
public function __construct(?string $uri = null, array $uriOptions = [], array $driverOptions = [])
11597
{
116-
$driverOptions += ['typeMap' => self::DEFAULT_TYPE_MAP];
117-
118-
if (! is_array($driverOptions['typeMap'])) {
119-
throw InvalidArgumentException::invalidType('"typeMap" driver option', $driverOptions['typeMap'], 'array');
120-
}
121-
122-
if (isset($driverOptions['autoEncryption']) && is_array($driverOptions['autoEncryption'])) {
123-
$driverOptions['autoEncryption'] = $this->prepareEncryptionOptions($driverOptions['autoEncryption']);
124-
}
125-
126-
if (isset($driverOptions['builderEncoder']) && ! $driverOptions['builderEncoder'] instanceof Encoder) {
127-
throw InvalidArgumentException::invalidType('"builderEncoder" option', $driverOptions['builderEncoder'], Encoder::class);
128-
}
129-
130-
$driverOptions['driver'] = $this->mergeDriverInfo($driverOptions['driver'] ?? []);
98+
$this->driverOptions = DriverOptions::fromArray($driverOptions);
13199

132100
$this->uri = $uri ?? self::DEFAULT_URI;
133-
$this->builderEncoder = $driverOptions['builderEncoder'] ?? new BuilderEncoder();
134-
$this->typeMap = $driverOptions['typeMap'];
135-
136-
/* Database and Collection objects may need to know whether auto
137-
* encryption is enabled for dropping collections. Track this via an
138-
* internal option until PHPC-2615 is implemented. */
139-
$this->autoEncryptionEnabled = isset($driverOptions['autoEncryption']['keyVaultNamespace']);
140101

141-
$driverOptions = array_diff_key($driverOptions, ['builderEncoder' => 1, 'typeMap' => 1]);
102+
$driverOptions = array_diff_key($this->driverOptions->toArray(), ['builderEncoder' => 1, 'typeMap' => 1]);
142103

143104
$this->manager = new Manager($uri, $uriOptions, $driverOptions);
144105

@@ -157,8 +118,8 @@ public function __debugInfo(): array
157118
return [
158119
'manager' => $this->manager,
159120
'uri' => $this->uri,
160-
'typeMap' => $this->typeMap,
161-
'builderEncoder' => $this->builderEncoder,
121+
'typeMap' => $this->driverOptions->typeMap,
122+
'builderEncoder' => $this->driverOptions->builderEncoder,
162123
'writeConcern' => $this->writeConcern,
163124
];
164125
}
@@ -226,13 +187,13 @@ public function bulkWrite(BulkWriteCommand|ClientBulkWrite $bulk, array $options
226187
/**
227188
* Returns a ClientEncryption instance for explicit encryption and decryption
228189
*
229-
* @param array $options Encryption options
190+
* @param array{kmsProviders?: stdClass|array<string, array>, keyVaultClient?: Client|Manager} $options
230191
*/
231192
public function createClientEncryption(array $options): ClientEncryption
232193
{
233-
$options = $this->prepareEncryptionOptions($options);
194+
$options = AutoEncryptionOptions::fromArray($options);
234195

235-
return $this->manager->createClientEncryption($options);
196+
return $this->manager->createClientEncryption($options->toArray());
236197
}
237198

238199
/**
@@ -269,7 +230,11 @@ public function dropDatabase(string $databaseName, array $options = []): void
269230
*/
270231
public function getCollection(string $databaseName, string $collectionName, array $options = []): Collection
271232
{
272-
$options += ['typeMap' => $this->typeMap, 'builderEncoder' => $this->builderEncoder, 'autoEncryptionEnabled' => $this->autoEncryptionEnabled];
233+
$options += [
234+
'typeMap' => $this->driverOptions->typeMap,
235+
'builderEncoder' => $this->driverOptions->builderEncoder,
236+
'autoEncryptionEnabled' => $this->driverOptions->isAutoEncryptionEnabled(),
237+
];
273238

274239
return new Collection($this->manager, $databaseName, $collectionName, $options);
275240
}
@@ -284,7 +249,11 @@ public function getCollection(string $databaseName, string $collectionName, arra
284249
*/
285250
public function getDatabase(string $databaseName, array $options = []): Database
286251
{
287-
$options += ['typeMap' => $this->typeMap, 'builderEncoder' => $this->builderEncoder, 'autoEncryptionEnabled' => $this->autoEncryptionEnabled];
252+
$options += [
253+
'typeMap' => $this->driverOptions->typeMap,
254+
'builderEncoder' => $this->driverOptions->builderEncoder,
255+
'autoEncryptionEnabled' => $this->driverOptions->isAutoEncryptionEnabled(),
256+
];
288257

289258
return new Database($this->manager, $databaseName, $options);
290259
}
@@ -320,7 +289,7 @@ public function getReadPreference(): ReadPreference
320289
*/
321290
public function getTypeMap(): array
322291
{
323-
return $this->typeMap;
292+
return $this->driverOptions->typeMap;
324293
}
325294

326295
/**
@@ -419,7 +388,7 @@ public function startSession(array $options = []): Session
419388
* Create a change stream for watching changes to the cluster.
420389
*
421390
* @see Watch::__construct() for supported options
422-
* @param array $pipeline Aggregation pipeline
391+
* @psalm-param list<stage> $pipeline Aggregation pipeline
423392
* @param array $options Command options
424393
* @throws InvalidArgumentException for parameter/option parsing errors
425394
*/
@@ -429,7 +398,8 @@ public function watch(array $pipeline = [], array $options = []): ChangeStream
429398
$pipeline = new Pipeline(...$pipeline);
430399
}
431400

432-
$pipeline = $this->builderEncoder->encodeIfSupported($pipeline);
401+
/** @var array<array-key, mixed> $pipeline */
402+
$pipeline = $this->driverOptions->builderEncoder->encodeIfSupported($pipeline);
433403

434404
if (! isset($options['readPreference']) && ! is_in_transaction($options)) {
435405
$options['readPreference'] = $this->readPreference;
@@ -442,76 +412,11 @@ public function watch(array $pipeline = [], array $options = []): ChangeStream
442412
}
443413

444414
if (! isset($options['typeMap'])) {
445-
$options['typeMap'] = $this->typeMap;
415+
$options['typeMap'] = $this->driverOptions->typeMap;
446416
}
447417

448418
$operation = new Watch($this->manager, null, null, $pipeline, $options);
449419

450420
return $operation->execute($server);
451421
}
452-
453-
private static function getVersion(): string
454-
{
455-
if (self::$version === null) {
456-
try {
457-
self::$version = InstalledVersions::getPrettyVersion('mongodb/mongodb') ?? 'unknown';
458-
} catch (Throwable) {
459-
self::$version = 'error';
460-
}
461-
}
462-
463-
return self::$version;
464-
}
465-
466-
private function mergeDriverInfo(array $driver): array
467-
{
468-
$mergedDriver = [
469-
'name' => 'PHPLIB',
470-
'version' => self::getVersion(),
471-
];
472-
473-
if (isset($driver['name'])) {
474-
if (! is_string($driver['name'])) {
475-
throw InvalidArgumentException::invalidType('"name" handshake option', $driver['name'], 'string');
476-
}
477-
478-
$mergedDriver['name'] .= self::HANDSHAKE_SEPARATOR . $driver['name'];
479-
}
480-
481-
if (isset($driver['version'])) {
482-
if (! is_string($driver['version'])) {
483-
throw InvalidArgumentException::invalidType('"version" handshake option', $driver['version'], 'string');
484-
}
485-
486-
$mergedDriver['version'] .= self::HANDSHAKE_SEPARATOR . $driver['version'];
487-
}
488-
489-
if (isset($driver['platform'])) {
490-
$mergedDriver['platform'] = $driver['platform'];
491-
}
492-
493-
return $mergedDriver;
494-
}
495-
496-
private function prepareEncryptionOptions(array $options): array
497-
{
498-
if (isset($options['keyVaultClient'])) {
499-
if ($options['keyVaultClient'] instanceof self) {
500-
$options['keyVaultClient'] = $options['keyVaultClient']->manager;
501-
} elseif (! $options['keyVaultClient'] instanceof Manager) {
502-
throw InvalidArgumentException::invalidType('"keyVaultClient" option', $options['keyVaultClient'], [self::class, Manager::class]);
503-
}
504-
}
505-
506-
// The server requires an empty document for automatic credentials.
507-
if (isset($options['kmsProviders']) && is_array($options['kmsProviders'])) {
508-
foreach ($options['kmsProviders'] as $name => $provider) {
509-
if ($provider === []) {
510-
$options['kmsProviders'][$name] = new stdClass();
511-
}
512-
}
513-
}
514-
515-
return $options;
516-
}
517422
}

0 commit comments

Comments
 (0)