Skip to content

Commit

Permalink
Add chunkSizeBytes option to GridFS file mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
alcaeus committed Aug 1, 2018
1 parent 49bd3c5 commit 6f44159
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 19 deletions.
1 change: 1 addition & 0 deletions doctrine-mongo-mapping.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
<xs:attribute name="writeConcern" type="xs:string" />
<xs:attribute name="inheritance-type" type="odm:inheritance-type"/>
<xs:attribute name="change-tracking-policy" type="odm:change-tracking-policy" />
<xs:attribute name="chunk-size-bytes" type="xs:positiveInteger" />
</xs:complexType>

<xs:complexType name="document">
Expand Down
3 changes: 3 additions & 0 deletions lib/Doctrine/ODM/MongoDB/Mapping/Annotations/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,7 @@ final class File extends AbstractDocument

/** @var string|int|null */
public $writeConcern;

/** @var int|null */
public $chunkSizeBytes;
}
18 changes: 18 additions & 0 deletions lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,13 @@ class ClassMetadata implements BaseClassMetadata
*/
public $isFile = false;

/**
* READ-ONLY: The default chunk size in bytes for the file
*
* @var int|null
*/
public $chunkSizeBytes;

/**
* READ-ONLY: The policy used for change-tracking on entities of this class.
*
Expand Down Expand Up @@ -1148,6 +1155,16 @@ public function setBucketName(string $bucketName): void
$this->setCollection($bucketName . '.files');
}

public function getChunkSizeBytes(): ?int
{
return $this->chunkSizeBytes;
}

public function setChunkSizeBytes(int $chunkSizeBytes): void
{
$this->chunkSizeBytes = $chunkSizeBytes;
}

/**
* Get whether or not the documents collection is capped.
*
Expand Down Expand Up @@ -2164,6 +2181,7 @@ public function __sleep()
if ($this->isFile) {
$serialized[] = 'isFile';
$serialized[] = 'bucketName';
$serialized[] = 'chunkSizeBytes';
}

if ($this->isVersioned) {
Expand Down
4 changes: 4 additions & 0 deletions lib/Doctrine/ODM/MongoDB/Mapping/Driver/AnnotationDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ public function loadMetadataForClass($className, \Doctrine\Common\Persistence\Ma
$class->isQueryResultDocument = true;
} elseif ($documentAnnot instanceof ODM\File) {
$class->isFile = true;

if ($documentAnnot->chunkSizeBytes !== null) {
$class->setChunkSizeBytes($documentAnnot->chunkSizeBytes);
}
}

if (isset($documentAnnot->db)) {
Expand Down
4 changes: 4 additions & 0 deletions lib/Doctrine/ODM/MongoDB/Mapping/Driver/XmlDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ public function loadMetadataForClass($className, \Doctrine\Common\Persistence\Ma
$class->isQueryResultDocument = true;
} elseif ($xmlRoot->getName() === 'gridfs-file') {
$class->isFile = true;

if (isset($xmlRoot['chunk-size-bytes'])) {
$class->setChunkSizeBytes((int) $xmlRoot['chunk-size-bytes']);
}
}

if (isset($xmlRoot['db'])) {
Expand Down
24 changes: 14 additions & 10 deletions lib/Doctrine/ODM/MongoDB/Repository/DefaultGridFSRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,27 @@ public function downloadToStream($id, $destination): void
/**
* @see Bucket::openUploadStream
*/
public function openUploadStream(string $filename, $metadata = null)
public function openUploadStream(string $filename, $metadata = null, ?int $chunkSizeBytes = null)
{
$options = $this->prepareMetadataOptions($metadata);
$options = $this->prepareOptions($metadata, $chunkSizeBytes);

return $this->getDocumentBucket()->openUploadStream($filename, $options);
}

/**
* @see Bucket::uploadFromStream
*/
public function uploadFromStream(string $filename, $source, $metadata = null)
public function uploadFromStream(string $filename, $source, $metadata = null, ?int $chunkSizeBytes = null)
{
$options = $this->prepareMetadataOptions($metadata);
$options = $this->prepareOptions($metadata, $chunkSizeBytes);

$databaseIdentifier = $this->getDocumentBucket()->uploadFromStream($filename, $source, $options);
$documentIdentifier = $this->class->getPHPIdentifierValue($databaseIdentifier);

return $this->dm->getReference($this->getClassName(), $documentIdentifier);
}

public function uploadFromFile(string $source, ?string $filename = null, $metadata = null)
public function uploadFromFile(string $source, ?string $filename = null, $metadata = null, ?int $chunkSizeBytes = null)
{
$resource = fopen($source, 'r');
if ($resource === false) {
Expand All @@ -62,7 +62,7 @@ public function uploadFromFile(string $source, ?string $filename = null, $metada
}

try {
return $this->uploadFromStream($filename, $resource, $metadata);
return $this->uploadFromStream($filename, $resource, $metadata, $chunkSizeBytes);
} finally {
fclose($resource);
}
Expand All @@ -76,12 +76,16 @@ private function getDocumentBucket(): Bucket
/**
* @param object|null $metadata
*/
private function prepareMetadataOptions($metadata = null): array
private function prepareOptions($metadata = null, ?int $chunkSizeBytes = null): array
{
if ($metadata === null) {
return [];
$options = [
'chunkSizeBytes' => $chunkSizeBytes ?: $this->class->getChunkSizeBytes(),
];

if ($metadata) {
$options += ['metadata' => (object) $this->uow->getPersistenceBuilder()->prepareInsertData($metadata)];
}

return ['metadata' => (object) $this->uow->getPersistenceBuilder()->prepareInsertData($metadata)];
return $options;
}
}
6 changes: 3 additions & 3 deletions lib/Doctrine/ODM/MongoDB/Repository/GridFSRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function downloadToStream($id, $destination): void;
* @param object|null $metadata
* @return resource
*/
public function openUploadStream(string $filename, $metadata = null);
public function openUploadStream(string $filename, $metadata = null, ?int $chunkSizeBytes = null);

/**
* Writes the contents of a readable stream to a GridFS file.
Expand All @@ -31,7 +31,7 @@ public function openUploadStream(string $filename, $metadata = null);
* @param object|null $metadata
* @return object The newly created GridFS file
*/
public function uploadFromStream(string $filename, $source, $metadata = null);
public function uploadFromStream(string $filename, $source, $metadata = null, ?int $chunkSizeBytes = null);

/**
* Writes the contents of a file to a GridFS file.
Expand All @@ -41,5 +41,5 @@ public function uploadFromStream(string $filename, $source, $metadata = null);
* @param object|null $metadata
* @return object The newly created GridFS file
*/
public function uploadFromFile(string $source, ?string $filename = null, $metadata = null);
public function uploadFromFile(string $source, ?string $filename = null, $metadata = null, ?int $chunkSizeBytes = null);
}
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ public function testGridFSMapping()
$class = $this->loadMetadata(AbstractMappingDriverFile::class);

$this->assertTrue($class->isFile);
$this->assertSame(12345, $class->getChunkSizeBytes());

$this->assertArraySubset([
'name' => '_id',
Expand Down Expand Up @@ -652,7 +653,7 @@ class InvalidMappingDocument
}

/**
* @ODM\File
* @ODM\File(chunkSizeBytes=12345)
*/
class AbstractMappingDriverFile
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
xsi:schemaLocation="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping
http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping.xsd">

<gridfs-file name="Doctrine\ODM\MongoDB\Tests\Mapping\AbstractMappingDriverFile">
<gridfs-file name="Doctrine\ODM\MongoDB\Tests\Mapping\AbstractMappingDriverFile" chunk-size-bytes="12345">
<id />
<length fieldName="size" />
<chunk-size />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,26 @@ public function testOpenUploadStreamReturnsWritableResource(): void

self::assertSame('somefile.txt', $file->getFilename());
self::assertSame(8, $file->getLength());
self::assertInternalType('int', $file->getChunkSize());
self::assertSame(12345, $file->getChunkSize());
self::assertEquals(new \DateTime(), $file->getUploadDate(), '', 1);
self::assertNull($file->getMetadata());
}

public function testOpenUploadStreamUsesChunkSizeFromOptions(): void
{
$uploadStream = $this->getRepository()->openUploadStream('somefile.txt', null, 1234);
self::assertInternalType('resource', $uploadStream);

fwrite($uploadStream, 'contents');
fclose($uploadStream);

/** @var File $file */
$file = $this->getRepository()->findOneBy(['filename' => 'somefile.txt']);
self::assertInstanceOf(File::class, $file);

self::assertSame('somefile.txt', $file->getFilename());
self::assertSame(8, $file->getLength());
self::assertSame(1234, $file->getChunkSize());
self::assertEquals(new \DateTime(), $file->getUploadDate(), '', 1);
self::assertNull($file->getMetadata());
}
Expand All @@ -58,7 +77,40 @@ public function testUploadFromStreamStoresFile(): void

self::assertSame('somefile.txt', $file->getFilename());
self::assertSame($expectedSize, $file->getLength());
self::assertInternalType('int', $file->getChunkSize());
self::assertSame(12345, $file->getChunkSize());
self::assertEquals(new \DateTime(), $file->getUploadDate(), '', 1);
self::assertInstanceOf(FileMetadata::class, $file->getMetadata());

$stream = tmpfile();
$this->getRepository()->downloadToStream($file->getId(), $stream);

fseek($stream, 0);
$stat = fstat($stream);
self::assertSame($expectedSize, $stat['size']);
fclose($stream);
}

public function testUploadFromStreamPassesChunkSize(): void
{
$fileResource = fopen(__FILE__, 'r');

try {
/** @var File $file */
$file = $this->getRepository()->uploadFromStream('somefile.txt', $fileResource, new FileMetadata(), 1234);
} finally {
fclose($fileResource);
}

self::assertInstanceOf(File::class, $file);

$expectedSize = filesize(__FILE__);

// Check if the file is actually there
self::assertInstanceOf(File::class, $this->getRepository()->findOneBy(['filename' => 'somefile.txt']));

self::assertSame('somefile.txt', $file->getFilename());
self::assertSame($expectedSize, $file->getLength());
self::assertSame(1234, $file->getChunkSize());
self::assertEquals(new \DateTime(), $file->getUploadDate(), '', 1);
self::assertInstanceOf(FileMetadata::class, $file->getMetadata());

Expand All @@ -80,6 +132,7 @@ public function testUploadFromFileWithoutFilenamePicksAFilename(): void

self::assertSame('DefaultGridFSRepositoryTest.php', $file->getFilename());
self::assertSame($expectedSize, $file->getLength());
self::assertSame(12345, $file->getChunkSize());

// Check if the file is actually there
self::assertInstanceOf(File::class, $this->getRepository()->findOneBy(['filename' => $file->getFilename()]));
Expand All @@ -88,8 +141,9 @@ public function testUploadFromFileWithoutFilenamePicksAFilename(): void
public function testUploadFromFileUsesProvidedFilename(): void
{
/** @var File $file */
$file = $this->getRepository()->uploadFromFile(__FILE__, 'test.php');
$file = $this->getRepository()->uploadFromFile(__FILE__, 'test.php', null, 1234);
self::assertSame('test.php', $file->getFilename());
self::assertSame(1234, $file->getChunkSize());
}

public function testReadingFileAllowsUpdatingMetadata(): void
Expand Down
2 changes: 1 addition & 1 deletion tests/Documents/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

/** @ODM\File */
/** @ODM\File(chunkSizeBytes=12345) */
class File
{
/** @ODM\Id */
Expand Down

0 comments on commit 6f44159

Please sign in to comment.