Skip to content

Commit 8117675

Browse files
committed
Merge pull request #290
2 parents 79e1221 + f0090c8 commit 8117675

14 files changed

+250
-25
lines changed

docs/includes/apiargs-MongoDBDatabase-method-selectGridFSBucket-option.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ replacement:
3131
resource: "bucket"
3232
parent: "database"
3333
---
34+
source:
35+
file: apiargs-common-option.yaml
36+
ref: typeMap
37+
replacement:
38+
parent: "database"
39+
---
3440
source:
3541
file: apiargs-common-option.yaml
3642
ref: writeConcern

docs/includes/apiargs-MongoDBGridFSBucket-method-construct-option.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ replacement:
3131
resource: "bucket"
3232
parent: "database"
3333
---
34+
source:
35+
file: apiargs-MongoDBClient-method-construct-driverOptions.yaml
36+
ref: typeMap
37+
---
3438
source:
3539
file: apiargs-common-option.yaml
3640
ref: writeConcern
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
source:
2+
file: apiargs-MongoDBCollection-method-find-option.yaml
3+
ref: projection
4+
---
5+
source:
6+
file: apiargs-MongoDBCollection-method-find-option.yaml
7+
ref: sort
8+
---
9+
source:
10+
file: apiargs-MongoDBCollection-method-find-option.yaml
11+
ref: skip
12+
---
13+
source:
14+
file: apiargs-MongoDBCollection-common-option.yaml
15+
ref: collation
16+
---
17+
source:
18+
file: apiargs-MongoDBCollection-method-find-option.yaml
19+
ref: comment
20+
---
21+
source:
22+
file: apiargs-common-option.yaml
23+
ref: maxTimeMS
24+
---
25+
source:
26+
file: apiargs-MongoDBCollection-method-find-option.yaml
27+
ref: readConcern
28+
---
29+
source:
30+
file: apiargs-MongoDBGridFSBucket-method-find-option.yaml
31+
ref: readPreference
32+
---
33+
source:
34+
file: apiargs-MongoDBGridFSBucket-method-find-option.yaml
35+
ref: typeMap
36+
post: |
37+
This will be used for the returned result document.
38+
---
39+
source:
40+
file: apiargs-MongoDBCollection-method-find-option.yaml
41+
ref: modifiers
42+
...

docs/reference/class/MongoDBGridFSBucket.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Methods
4040
/reference/method/MongoDBGridFSBucket-downloadToStreamByName
4141
/reference/method/MongoDBGridFSBucket-drop
4242
/reference/method/MongoDBGridFSBucket-find
43+
/reference/method/MongoDBGridFSBucket-findOne
4344
/reference/method/MongoDBGridFSBucket-getBucketName
4445
/reference/method/MongoDBGridFSBucket-getDatabaseName
4546
/reference/method/MongoDBGridFSBucket-getFileDocumentForStream

docs/reference/method/MongoDBCollection-findOne.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ Definition
3232
Return Values
3333
-------------
3434

35-
An array or object for the :term:`first document <natural order>` document that
36-
matched the query, or ``null`` if no document matched the query. The return type
37-
will depend on the ``typeMap`` option.
35+
An array or object for the :term:`first document <natural order>` that matched
36+
the query, or ``null`` if no document matched the query. The return type will
37+
depend on the ``typeMap`` option.
3838

3939
Errors/Exceptions
4040
-----------------

docs/reference/method/MongoDBDatabase-selectGridFSBucket.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ Errors/Exceptions
4242
Behavior
4343
--------
4444

45-
The selected bucket inherits options such as read preference and write concern
46-
from the :phpclass:`Database <MongoDB\\Database>` object. Options may be
45+
The selected bucket inherits options such as read preference and type
46+
mapping from the :phpclass:`Database <MongoDB\\Database>` object. Options may be
4747
overridden via the ``$options`` parameter.
4848

4949
Example

docs/reference/method/MongoDBGridFSBucket-find.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ See Also
4040
--------
4141

4242
- :phpmethod:`MongoDB\\Collection::find()`
43+
- :phpmethod:`MongoDB\\GridFS\\Bucket::findOne()`
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
==================================
2+
MongoDB\\GridFS\\Bucket::findOne()
3+
==================================
4+
5+
.. default-domain:: mongodb
6+
7+
.. contents:: On this page
8+
:local:
9+
:backlinks: none
10+
:depth: 1
11+
:class: singlecol
12+
13+
Definition
14+
----------
15+
16+
.. phpmethod:: MongoDB\\GridFS\\Bucket::findOne()
17+
18+
Finds a single document from the GridFS bucket's files collection matching
19+
the query.
20+
21+
.. code-block:: php
22+
23+
function findOne($filter = [], array $options = []): array|object|null
24+
25+
This method has the following parameters:
26+
27+
.. include:: /includes/apiargs/MongoDBCollection-method-findOne-param.rst
28+
29+
The ``$options`` parameter supports the following options:
30+
31+
.. include:: /includes/apiargs/MongoDBGridFSBucket-method-findOne-option.rst
32+
33+
Return Values
34+
-------------
35+
36+
An array or object for the :term:`first document <natural order>` that matched
37+
the query, or ``null`` if no document matched the query. The return type will
38+
depend on the ``typeMap`` option.
39+
40+
.. todo: add examples
41+
42+
See Also
43+
--------
44+
45+
- :phpmethod:`MongoDB\\Collection::findOne()`
46+
- :phpmethod:`MongoDB\\GridFS\\Bucket::find()`

docs/reference/method/MongoDBGridFSBucket-getFileDocumentForStream.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Definition
1919

2020
.. code-block:: php
2121

22-
function getFileDocumentForStream($stream): object
22+
function getFileDocumentForStream($stream): array|object
2323

2424
This method has the following parameters:
2525

@@ -28,7 +28,8 @@ Definition
2828
Return Values
2929
-------------
3030

31-
The metadata document associated with the GridFS stream.
31+
The metadata document associated with the GridFS stream. The return type will
32+
depend on the bucket's ``typeMap`` option.
3233

3334
.. todo: add examples
3435

docs/reference/method/MongoDBGridFSBucket-getFileIdForStream.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ Definition
2828
Return Values
2929
-------------
3030

31-
The ``_id`` field of the metadata document associated with the GridFS
32-
stream.
31+
The ``_id`` field of the metadata document associated with the GridFS stream.
32+
The return type will depend on the bucket's ``typeMap`` option.
3333

3434
.. todo: add examples
3535

src/Database.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ public function selectGridFSBucket(array $options = [])
317317
$options += [
318318
'readConcern' => $this->readConcern,
319319
'readPreference' => $this->readPreference,
320+
'typeMap' => $this->typeMap,
320321
'writeConcern' => $this->writeConcern,
321322
];
322323

src/GridFS/Bucket.php

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ class Bucket
2323
{
2424
private static $defaultBucketName = 'fs';
2525
private static $defaultChunkSizeBytes = 261120;
26+
private static $defaultTypeMap = [
27+
'array' => 'MongoDB\Model\BSONArray',
28+
'document' => 'MongoDB\Model\BSONDocument',
29+
'root' => 'MongoDB\Model\BSONDocument',
30+
];
2631
private static $streamWrapperProtocol = 'gridfs';
2732

2833
private $collectionWrapper;
@@ -32,6 +37,7 @@ class Bucket
3237
private $chunkSizeBytes;
3338
private $readConcern;
3439
private $readPreference;
40+
private $typeMap;
3541
private $writeConcern;
3642

3743
/**
@@ -49,6 +55,8 @@ class Bucket
4955
*
5056
* * readPreference (MongoDB\Driver\ReadPreference): Read preference.
5157
*
58+
* * typeMap (array): Default type map for cursors and BSON documents.
59+
*
5260
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
5361
*
5462
* @param Manager $manager Manager instance from the driver
@@ -79,6 +87,10 @@ public function __construct(Manager $manager, $databaseName, array $options = []
7987
throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
8088
}
8189

90+
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
91+
throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array');
92+
}
93+
8294
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
8395
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
8496
}
@@ -89,9 +101,10 @@ public function __construct(Manager $manager, $databaseName, array $options = []
89101
$this->chunkSizeBytes = $options['chunkSizeBytes'];
90102
$this->readConcern = isset($options['readConcern']) ? $options['readConcern'] : $this->manager->getReadConcern();
91103
$this->readPreference = isset($options['readPreference']) ? $options['readPreference'] : $this->manager->getReadPreference();
104+
$this->typeMap = isset($options['typeMap']) ? $options['typeMap'] : self::$defaultTypeMap;
92105
$this->writeConcern = isset($options['writeConcern']) ? $options['writeConcern'] : $this->manager->getWriteConcern();
93106

94-
$collectionOptions = array_intersect_key($options, ['readConcern' => 1, 'readPreference' => 1, 'writeConcern' => 1]);
107+
$collectionOptions = array_intersect_key($options, ['readConcern' => 1, 'readPreference' => 1, 'typeMap' => 1, 'writeConcern' => 1]);
95108

96109
$this->collectionWrapper = new CollectionWrapper($manager, $databaseName, $options['bucketName'], $collectionOptions);
97110
$this->registerStreamWrapper();
@@ -112,6 +125,7 @@ public function __debugInfo()
112125
'chunkSizeBytes' => $this->chunkSizeBytes,
113126
'readConcern' => $this->readConcern,
114127
'readPreference' => $this->readPreference,
128+
'typeMap' => $this->typeMap,
115129
'writeConcern' => $this->writeConcern,
116130
];
117131
}
@@ -204,11 +218,25 @@ public function drop()
204218
* @param array $options Additional options
205219
* @return Cursor
206220
*/
207-
public function find($filter, array $options = [])
221+
public function find($filter = [], array $options = [])
208222
{
209223
return $this->collectionWrapper->findFiles($filter, $options);
210224
}
211225

226+
/**
227+
* Finds a single document from the GridFS bucket's files collection
228+
* matching the query.
229+
*
230+
* @see FindOne::__construct() for supported options
231+
* @param array|object $filter Query by which to filter documents
232+
* @param array $options Additional options
233+
* @return array|object|null
234+
*/
235+
public function findOne($filter = [], array $options = [])
236+
{
237+
return $this->collectionWrapper->findOneFile($filter, $options);
238+
}
239+
212240
/**
213241
* Return the bucket name.
214242
*
@@ -233,22 +261,15 @@ public function getDatabaseName()
233261
* Gets the file document of the GridFS file associated with a stream.
234262
*
235263
* @param resource $stream GridFS stream
236-
* @return stdClass
264+
* @return array|object
237265
* @throws InvalidArgumentException
238266
*/
239267
public function getFileDocumentForStream($stream)
240268
{
241-
if ( ! is_resource($stream) || get_resource_type($stream) != "stream") {
242-
throw InvalidArgumentException::invalidType('$stream', $stream, 'resource');
243-
}
269+
$file = $this->getRawFileDocumentForStream($stream);
244270

245-
$metadata = stream_get_meta_data($stream);
246-
247-
if (!$metadata['wrapper_data'] instanceof StreamWrapper) {
248-
throw InvalidArgumentException::invalidType('$stream wrapper data', $metadata['wrapper_data'], 'MongoDB\Driver\GridFS\StreamWrapper');
249-
}
250-
251-
return $metadata['wrapper_data']->getFile();
271+
// Filter the raw document through the specified type map
272+
return \MongoDB\BSON\toPHP(\MongoDB\BSON\fromPHP($file), $this->typeMap);
252273
}
253274

254275
/**
@@ -261,7 +282,13 @@ public function getFileDocumentForStream($stream)
261282
*/
262283
public function getFileIdForStream($stream)
263284
{
264-
$file = $this->getFileDocumentForStream($stream);
285+
$file = $this->getRawFileDocumentForStream($stream);
286+
287+
/* Filter the raw document through the specified type map, but override
288+
* the root type so we can reliably access the ID.
289+
*/
290+
$typeMap = ['root' => 'stdClass'] + $this->typeMap;
291+
$file = \MongoDB\BSON\toPHP(\MongoDB\BSON\fromPHP($file), $typeMap);
265292

266293
if ( ! isset($file->_id) && ! property_exists($file, '_id')) {
267294
throw new CorruptFileException('file._id does not exist');
@@ -466,6 +493,31 @@ private function getFilesNamespace()
466493
return sprintf('%s.%s.files', $this->databaseName, $this->bucketName);
467494
}
468495

496+
/**
497+
* Gets the file document of the GridFS file associated with a stream.
498+
*
499+
* This returns the raw document from the StreamWrapper, which does not
500+
* respect the Bucket's type map.
501+
*
502+
* @param resource $stream GridFS stream
503+
* @return stdClass
504+
* @throws InvalidArgumentException
505+
*/
506+
private function getRawFileDocumentForStream($stream)
507+
{
508+
if ( ! is_resource($stream) || get_resource_type($stream) != "stream") {
509+
throw InvalidArgumentException::invalidType('$stream', $stream, 'resource');
510+
}
511+
512+
$metadata = stream_get_meta_data($stream);
513+
514+
if (!$metadata['wrapper_data'] instanceof StreamWrapper) {
515+
throw InvalidArgumentException::invalidType('$stream wrapper data', $metadata['wrapper_data'], 'MongoDB\Driver\GridFS\StreamWrapper');
516+
}
517+
518+
return $metadata['wrapper_data']->getFile();
519+
}
520+
469521
/**
470522
* Opens a readable stream for the GridFS file.
471523
*

src/GridFS/CollectionWrapper.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ public function deleteFileAndChunksById($id)
6868
*/
6969
public function dropCollections()
7070
{
71-
$this->filesCollection->drop();
72-
$this->chunksCollection->drop();
71+
$this->filesCollection->drop(['typeMap' => []]);
72+
$this->chunksCollection->drop(['typeMap' => []]);
7373
}
7474

7575
/**
@@ -140,6 +140,18 @@ public function findFiles($filter, array $options = [])
140140
return $this->filesCollection->find($filter, $options);
141141
}
142142

143+
/**
144+
* Finds a single document from the GridFS bucket's files collection.
145+
*
146+
* @param array|object $filter Query by which to filter documents
147+
* @param array $options Additional options
148+
* @return array|object|null
149+
*/
150+
public function findOneFile($filter, array $options = [])
151+
{
152+
return $this->filesCollection->findOne($filter, $options);
153+
}
154+
143155
/**
144156
* Return the bucket name.
145157
*
@@ -284,6 +296,7 @@ private function isFilesCollectionEmpty()
284296
return null === $this->filesCollection->findOne([], [
285297
'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY),
286298
'projection' => ['_id' => 1],
299+
'typeMap' => [],
287300
]);
288301
}
289302
}

0 commit comments

Comments
 (0)