Skip to content

Commit

Permalink
PHPLIB-1568 Add GridFS\Bucket::deleteByName(filename) and `renameBy…
Browse files Browse the repository at this point in the history
…Name(filename, newFilename)` (#1504)
  • Loading branch information
GromNaN authored Oct 31, 2024
1 parent a6396a4 commit 7781e75
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 5 deletions.
11 changes: 11 additions & 0 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,20 @@
</MixedArgumentTypeCoercion>
</file>
<file src="src/GridFS/CollectionWrapper.php">
<InvalidNullableReturnType>
<code><![CDATA[int]]></code>
<code><![CDATA[int]]></code>
</InvalidNullableReturnType>
<MixedAssignment>
<code><![CDATA[$ids[]]]></code>
</MixedAssignment>
<NullableReturnStatement>
<code><![CDATA[$count]]></code>
<code><![CDATA[$this->filesCollection->updateMany(
['filename' => $filename],
['$set' => ['filename' => $newFilename]],
)->getMatchedCount()]]></code>
</NullableReturnStatement>
</file>
<file src="src/GridFS/ReadableStream.php">
<MixedArgument>
Expand Down
35 changes: 35 additions & 0 deletions src/GridFS/Bucket.php
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,23 @@ public function delete(mixed $id)
}
}

/**
* Delete all the revisions of a file name from the GridFS bucket.
*
* @param string $filename Filename
*
* @throws FileNotFoundException if no file could be selected
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function deleteByName(string $filename): void
{
$count = $this->collectionWrapper->deleteFileAndChunksByFilename($filename);

if ($count === 0) {
throw FileNotFoundException::byFilename($filename);
}
}

/**
* Writes the contents of a GridFS file to a writable stream.
*
Expand Down Expand Up @@ -648,6 +665,24 @@ public function rename(mixed $id, string $newFilename)
}
}

/**
* Renames all the revisions of a file name in the GridFS bucket.
*
* @param string $filename Filename
* @param string $newFilename New filename
*
* @throws FileNotFoundException if no file could be selected
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
*/
public function renameByName(string $filename, string $newFilename): void
{
$count = $this->collectionWrapper->updateFilenameForFilename($filename, $newFilename);

if ($count === 0) {
throw FileNotFoundException::byFilename($filename);
}
}

/**
* Writes the contents of a readable stream to a GridFS file.
*
Expand Down
7 changes: 2 additions & 5 deletions src/GridFS/CollectionWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public function deleteChunksByFilesId(mixed $id): void
/**
* Delete all GridFS files and chunks for a given filename.
*/
public function deleteFileAndChunksByFilename(string $filename): ?int
public function deleteFileAndChunksByFilename(string $filename): int
{
/** @var iterable<array{_id: mixed}> $files */
$files = $this->findFiles(['filename' => $filename], [
Expand Down Expand Up @@ -150,9 +150,6 @@ public function findChunksByFileId(mixed $id, int $fromChunk = 0)
*/
public function findFileByFilenameAndRevision(string $filename, int $revision): ?object
{
$filename = $filename;
$revision = $revision;

if ($revision < 0) {
$skip = abs($revision) - 1;
$sortOrder = -1;
Expand Down Expand Up @@ -266,7 +263,7 @@ public function insertFile(array|object $file): void
/**
* Updates the filename field in the file document for all the files with a given filename.
*/
public function updateFilenameForFilename(string $filename, string $newFilename): ?int
public function updateFilenameForFilename(string $filename, string $newFilename): int
{
return $this->filesCollection->updateMany(
['filename' => $filename],
Expand Down
46 changes: 46 additions & 0 deletions tests/GridFS/BucketFunctionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,34 @@ public function testDeleteStillRemovesChunksIfFileDoesNotExist($input, $expected
$this->assertCollectionCount($this->chunksCollection, 0);
}

public function testDeleteByName(): void
{
$this->bucket->uploadFromStream('filename', self::createStream('foobar1'));
$this->bucket->uploadFromStream('filename', self::createStream('foobar2'));
$this->bucket->uploadFromStream('filename', self::createStream('foobar3'));

$this->bucket->uploadFromStream('other', self::createStream('foobar'));

$this->assertCollectionCount($this->filesCollection, 4);
$this->assertCollectionCount($this->chunksCollection, 4);

$this->bucket->deleteByName('filename');

$this->assertCollectionCount($this->filesCollection, 1);
$this->assertCollectionCount($this->chunksCollection, 1);

$this->bucket->deleteByName('other');

$this->assertCollectionCount($this->filesCollection, 0);
$this->assertCollectionCount($this->chunksCollection, 0);
}

public function testDeleteByNameShouldRequireFileToExist(): void
{
$this->expectException(FileNotFoundException::class);
$this->bucket->deleteByName('nonexistent-name');
}

public function testDownloadingFileWithMissingChunk(): void
{
$id = $this->bucket->uploadFromStream('filename', self::createStream('foobar'));
Expand Down Expand Up @@ -723,6 +751,24 @@ public function testRenameShouldRequireFileToExist(): void
$this->bucket->rename('nonexistent-id', 'b');
}

public function testRenameByName(): void
{
$this->bucket->uploadFromStream('filename', self::createStream('foo'));
$this->bucket->uploadFromStream('filename', self::createStream('foo'));
$this->bucket->uploadFromStream('filename', self::createStream('foo'));

$this->bucket->renameByName('filename', 'newname');

$this->assertNull($this->bucket->findOne(['filename' => 'filename']), 'No file has the old name');
$this->assertStreamContents('foo', $this->bucket->openDownloadStreamByName('newname'));
}

public function testRenameByNameShouldRequireFileToExist(): void
{
$this->expectException(FileNotFoundException::class);
$this->bucket->renameByName('nonexistent-name', 'b');
}

public function testUploadFromStream(): void
{
$options = [
Expand Down
14 changes: 14 additions & 0 deletions tests/UnifiedSpecTests/Operation.php
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,12 @@ private function executeForBucket(Bucket $bucket)

return $bucket->delete($args['id']);

case 'deleteByName':
assertArrayHasKey('filename', $args);
assertIsString($args['filename']);

return $bucket->deleteByName($args['filename']);

case 'downloadByName':
assertArrayHasKey('filename', $args);
assertIsString($args['filename']);
Expand All @@ -812,6 +818,14 @@ private function executeForBucket(Bucket $bucket)

return null;

case 'renameByName':
assertArrayHasKey('filename', $args);
assertArrayHasKey('newFilename', $args);
assertIsString($args['filename']);
assertIsString($args['newFilename']);

return $bucket->renameByName($args['filename'], $args['newFilename']);

case 'uploadWithId':
assertArrayHasKey('id', $args);
$args['_id'] = $args['id'];
Expand Down
2 changes: 2 additions & 0 deletions tests/UnifiedSpecTests/Util.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,11 @@ final class Util
],
Bucket::class => [
'delete' => ['id'],
'deleteByName' => ['filename'],
'downloadByName' => ['filename', 'revision'],
'download' => ['id'],
'rename' => ['id', 'newFilename'],
'renameByName' => ['filename', 'newFilename'],
'uploadWithId' => ['id', 'filename', 'source', 'chunkSizeBytes', 'disableMD5', 'contentType', 'metadata'],
'upload' => ['filename', 'source', 'chunkSizeBytes', 'disableMD5', 'contentType', 'metadata'],
],
Expand Down

0 comments on commit 7781e75

Please sign in to comment.