-
Notifications
You must be signed in to change notification settings - Fork 266
PHPLIB-1220: Support codec option for GridFS buckets #1149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6651e3b
66ac79b
d4cfa08
f1d4d29
bf8e887
ed114f1
f3a3be3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,8 @@ | |
namespace MongoDB\GridFS; | ||
|
||
use Iterator; | ||
use MongoDB\BSON\Document; | ||
use MongoDB\Codec\DocumentCodec; | ||
use MongoDB\Collection; | ||
use MongoDB\Driver\CursorInterface; | ||
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; | ||
|
@@ -35,6 +37,7 @@ | |
use MongoDB\Operation\Find; | ||
|
||
use function array_intersect_key; | ||
use function array_key_exists; | ||
use function assert; | ||
use function fopen; | ||
use function get_resource_type; | ||
|
@@ -75,6 +78,8 @@ class Bucket | |
|
||
private const STREAM_WRAPPER_PROTOCOL = 'gridfs'; | ||
|
||
private ?DocumentCodec $codec = null; | ||
|
||
private CollectionWrapper $collectionWrapper; | ||
|
||
private string $databaseName; | ||
|
@@ -142,6 +147,10 @@ public function __construct(Manager $manager, string $databaseName, array $optio | |
throw new InvalidArgumentException(sprintf('Expected "chunkSizeBytes" option to be >= 1, %d given', $options['chunkSizeBytes'])); | ||
} | ||
|
||
if (isset($options['codec']) && ! $options['codec'] instanceof DocumentCodec) { | ||
throw InvalidArgumentException::invalidType('"codec" option', $options['codec'], DocumentCodec::class); | ||
} | ||
|
||
if (! is_bool($options['disableMD5'])) { | ||
throw InvalidArgumentException::invalidType('"disableMD5" option', $options['disableMD5'], 'boolean'); | ||
} | ||
|
@@ -162,10 +171,15 @@ public function __construct(Manager $manager, string $databaseName, array $optio | |
throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); | ||
} | ||
|
||
if (isset($options['codec']) && isset($options['typeMap'])) { | ||
throw InvalidArgumentException::cannotCombineCodecAndTypeMap(); | ||
} | ||
|
||
$this->manager = $manager; | ||
$this->databaseName = $databaseName; | ||
$this->bucketName = $options['bucketName']; | ||
$this->chunkSizeBytes = $options['chunkSizeBytes']; | ||
$this->codec = $options['codec'] ?? null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand your explanation for not injecting Bucket uses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The main problem with the In an ideal world, we'd be handling everything as raw BSON data internally and only decoding it using typeMap or codec when necessary to do so. However, I believe this goes beyond the scope of what we want to do here. I'd be in favour of revisiting this when we make changes to our GridFS API to accommodate the recent request to make the stream protocol available to consumers. The refactoring necessary to accommodate this would also allow us to change the |
||
$this->disableMD5 = $options['disableMD5']; | ||
$this->readConcern = $options['readConcern'] ?? $this->manager->getReadConcern(); | ||
$this->readPreference = $options['readPreference'] ?? $this->manager->getReadPreference(); | ||
|
@@ -188,6 +202,7 @@ public function __debugInfo() | |
{ | ||
return [ | ||
'bucketName' => $this->bucketName, | ||
'codec' => $this->codec, | ||
'databaseName' => $this->databaseName, | ||
'disableMD5' => $this->disableMD5, | ||
'manager' => $this->manager, | ||
|
@@ -309,6 +324,10 @@ public function drop() | |
*/ | ||
public function find($filter = [], array $options = []) | ||
{ | ||
if ($this->codec && ! array_key_exists('codec', $options)) { | ||
$options['codec'] = $this->codec; | ||
} | ||
|
||
return $this->collectionWrapper->findFiles($filter, $options); | ||
} | ||
|
||
|
@@ -326,6 +345,10 @@ public function find($filter = [], array $options = []) | |
*/ | ||
public function findOne($filter = [], array $options = []) | ||
{ | ||
if ($this->codec && ! array_key_exists('codec', $options)) { | ||
$options['codec'] = $this->codec; | ||
} | ||
|
||
return $this->collectionWrapper->findOneFile($filter, $options); | ||
} | ||
|
||
|
@@ -381,6 +404,10 @@ public function getFileDocumentForStream($stream) | |
{ | ||
$file = $this->getRawFileDocumentForStream($stream); | ||
|
||
if ($this->codec) { | ||
return $this->codec->decode(Document::fromPHP($file)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here you re-create a BSON document that have already been decoded into PHP? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately, yes: the document may not have come from the database but may be stored by the |
||
} | ||
|
||
// Filter the raw document through the specified type map | ||
return apply_type_map_to_document($file, $this->typeMap); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?php | ||
|
||
namespace MongoDB\Tests\Fixtures\Codec; | ||
|
||
use DateTimeImmutable; | ||
use MongoDB\BSON\Document; | ||
use MongoDB\BSON\UTCDateTime; | ||
use MongoDB\Codec\DecodeIfSupported; | ||
use MongoDB\Codec\DocumentCodec; | ||
use MongoDB\Codec\EncodeIfSupported; | ||
use MongoDB\Exception\UnsupportedValueException; | ||
use MongoDB\Tests\Fixtures\Document\TestFile; | ||
|
||
use function assert; | ||
|
||
final class TestFileCodec implements DocumentCodec | ||
{ | ||
use DecodeIfSupported; | ||
use EncodeIfSupported; | ||
|
||
public function canDecode($value): bool | ||
{ | ||
return $value instanceof Document; | ||
} | ||
|
||
public function decode($value): TestFile | ||
{ | ||
if (! $value instanceof Document) { | ||
throw UnsupportedValueException::invalidDecodableValue($value); | ||
} | ||
|
||
$fileObject = new TestFile(); | ||
$fileObject->id = $value->get('_id'); | ||
$fileObject->length = (int) $value->get('length'); | ||
$fileObject->chunkSize = (int) $value->get('chunkSize'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the purpose of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we're operating on raw BSON, we may get There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That was my assumption. Thanks for confirming! |
||
$fileObject->filename = (string) $value->get('filename'); | ||
|
||
$uploadDate = $value->get('uploadDate'); | ||
if ($uploadDate instanceof UTCDateTime) { | ||
$fileObject->uploadDate = DateTimeImmutable::createFromMutable($uploadDate->toDateTime()); | ||
} | ||
|
||
if ($value->has('metadata')) { | ||
$metadata = $value->get('metadata'); | ||
assert($metadata instanceof Document); | ||
$fileObject->metadata = $metadata->toPHP(); | ||
} | ||
|
||
return $fileObject; | ||
} | ||
|
||
public function canEncode($value): bool | ||
{ | ||
return $value instanceof TestFile; | ||
} | ||
|
||
public function encode($value): Document | ||
{ | ||
if (! $value instanceof TestFile) { | ||
throw UnsupportedValueException::invalidEncodableValue($value); | ||
} | ||
|
||
return Document::fromPHP([ | ||
'_id' => $value->id, | ||
'length' => $value->length, | ||
'chunkSize' => $value->chunkSize, | ||
'uploadDate' => new UTCDateTime($value->uploadDate), | ||
'filename' => $value->filename, | ||
]); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?php | ||
/* | ||
* Copyright 2023-present MongoDB, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
namespace MongoDB\Tests\Fixtures\Document; | ||
|
||
use DateTimeImmutable; | ||
use stdClass; | ||
|
||
final class TestFile | ||
{ | ||
public $id; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noted that GridFS permits custom |
||
public int $length; | ||
public int $chunkSize; | ||
public ?DateTimeImmutable $uploadDate = null; | ||
public string $filename; | ||
public ?stdClass $metadata = null; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.