Skip to content

Commit cc0d5a2

Browse files
authored
feat(storage): add deleteSourceObjects option to Bucket::compose() (#9211)
1 parent 474203e commit cc0d5a2

4 files changed

Lines changed: 164 additions & 0 deletions

File tree

Storage/src/Bucket.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,8 @@ public function update(array $options = [])
11451145
* matches the given value.
11461146
* @type string $ifMetagenerationMatch Makes the operation conditional on whether the object's current
11471147
* metageneration matches the given value.
1148+
* @type bool $deleteSourceObjects If true, the source objects will be
1149+
* deleted after a successful compose operation.
11481150
* }
11491151
* @return StorageObject
11501152
* @throws \InvalidArgumentException

Storage/src/Connection/ServiceDefinition/storage-v1.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,10 @@
897897
"$ref": "Object",
898898
"description": "Properties of the resulting object."
899899
},
900+
"deleteSourceObjects": {
901+
"type": "boolean",
902+
"description": "If true, the source objects will be deleted after a successful compose operation."
903+
},
900904
"kind": {
901905
"type": "string",
902906
"description": "The kind of item this is.",

Storage/tests/System/ManageObjectsTest.php

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,84 @@ public function testComposeObjects($object)
597597
return $composedObject;
598598
}
599599

600+
public function testComposeObjectsWithDeleteSourceObjects()
601+
{
602+
$source1 = self::$bucket->upload('content1', ['name' => uniqid(self::TESTING_PREFIX) . '-s1.txt']);
603+
$source2 = self::$bucket->upload('content2', ['name' => uniqid(self::TESTING_PREFIX) . '-s2.txt']);
604+
605+
$this->assertTrue($source1->exists());
606+
$this->assertTrue($source2->exists());
607+
608+
$name = uniqid(self::TESTING_PREFIX) . '-composed.txt';
609+
$composedObject = self::$bucket->compose(
610+
[$source1, $source2],
611+
$name,
612+
['deleteSourceObjects' => true]
613+
);
614+
615+
$this->assertEquals($name, $composedObject->name());
616+
$this->assertEquals('content1content2', $composedObject->downloadAsString());
617+
618+
$this->assertFalse($source1->exists());
619+
$this->assertFalse($source2->exists());
620+
621+
$composedObject->delete();
622+
}
623+
624+
public function testComposeObjectsWithDeleteSourceObjectsFalse()
625+
{
626+
$source1 = self::$bucket->upload('content1', ['name' => uniqid(self::TESTING_PREFIX) . '-s1.txt']);
627+
$source2 = self::$bucket->upload('content2', ['name' => uniqid(self::TESTING_PREFIX) . '-s2.txt']);
628+
629+
$this->assertTrue($source1->exists());
630+
$this->assertTrue($source2->exists());
631+
632+
$name = uniqid(self::TESTING_PREFIX) . '-composed.txt';
633+
$composedObject = self::$bucket->compose(
634+
[$source1, $source2],
635+
$name,
636+
['deleteSourceObjects' => false]
637+
);
638+
639+
$this->assertEquals($name, $composedObject->name());
640+
$this->assertEquals('content1content2', $composedObject->downloadAsString());
641+
642+
// Source objects should still exist because deleteSourceObjects is false
643+
$this->assertTrue($source1->exists());
644+
$this->assertTrue($source2->exists());
645+
646+
$source1->delete();
647+
$source2->delete();
648+
$composedObject->delete();
649+
}
650+
651+
public function testComposeObjectsWithDeleteSourceObjectsNull()
652+
{
653+
$source1 = self::$bucket->upload('content1', ['name' => uniqid(self::TESTING_PREFIX) . '-s1.txt']);
654+
$source2 = self::$bucket->upload('content2', ['name' => uniqid(self::TESTING_PREFIX) . '-s2.txt']);
655+
656+
$this->assertTrue($source1->exists());
657+
$this->assertTrue($source2->exists());
658+
659+
$name = uniqid(self::TESTING_PREFIX) . '-composed.txt';
660+
$composedObject = self::$bucket->compose(
661+
[$source1, $source2],
662+
$name,
663+
['deleteSourceObjects' => null]
664+
);
665+
666+
$this->assertEquals($name, $composedObject->name());
667+
$this->assertEquals('content1content2', $composedObject->downloadAsString());
668+
669+
// Source objects should still exist because deleteSourceObjects is null
670+
$this->assertTrue($source1->exists());
671+
$this->assertTrue($source2->exists());
672+
673+
$source1->delete();
674+
$source2->delete();
675+
$composedObject->delete();
676+
}
677+
600678
public function testSoftDeleteObject()
601679
{
602680
$softDeleteBucketName = "soft-delete-bucket-" . uniqid();

Storage/tests/Unit/BucketTest.php

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,86 @@ public function testComposesObjects(
419419
$this->assertEquals($destinationObject, $object->name());
420420
}
421421

422+
public function testComposeWithDeleteSourceObjects()
423+
{
424+
$acl = 'private';
425+
$destinationObject = 'combined-files.txt';
426+
$this->connection->composeObject([
427+
'destinationBucket' => self::BUCKET_NAME,
428+
'destinationObject' => $destinationObject,
429+
'destinationPredefinedAcl' => $acl,
430+
'destination' => ['contentType' => 'text/plain'],
431+
'sourceObjects' => [['name' => 'file1.txt'], ['name' => 'file2.txt']],
432+
'deleteSourceObjects' => true,
433+
])
434+
->willReturn([
435+
'name' => $destinationObject,
436+
'generation' => 1
437+
])
438+
->shouldBeCalledTimes(1);
439+
440+
$bucket = $this->getBucket();
441+
442+
$object = $bucket->compose(['file1.txt', 'file2.txt'], $destinationObject, [
443+
'predefinedAcl' => $acl,
444+
'deleteSourceObjects' => true
445+
]);
446+
447+
$this->assertEquals($destinationObject, $object->name());
448+
}
449+
450+
public function testComposeWithDeleteSourceObjectsFalse()
451+
{
452+
$acl = 'private';
453+
$destinationObject = 'combined-files.txt';
454+
$this->connection->composeObject([
455+
'destinationBucket' => self::BUCKET_NAME,
456+
'destinationObject' => $destinationObject,
457+
'destinationPredefinedAcl' => $acl,
458+
'destination' => ['contentType' => 'text/plain'],
459+
'sourceObjects' => [['name' => 'file1.txt'], ['name' => 'file2.txt']],
460+
])
461+
->willReturn([
462+
'name' => $destinationObject,
463+
'generation' => 1
464+
])
465+
->shouldBeCalledTimes(1);
466+
$bucket = $this->getBucket();
467+
468+
$object = $bucket->compose(['file1.txt', 'file2.txt'], $destinationObject, [
469+
'predefinedAcl' => $acl,
470+
'deleteSourceObjects' => false
471+
]);
472+
473+
$this->assertEquals($destinationObject, $object->name());
474+
}
475+
476+
public function testComposeWithDeleteSourceObjectsNull()
477+
{
478+
$acl = 'private';
479+
$destinationObject = 'combined-files.txt';
480+
$this->connection->composeObject([
481+
'destinationBucket' => self::BUCKET_NAME,
482+
'destinationObject' => $destinationObject,
483+
'destinationPredefinedAcl' => $acl,
484+
'destination' => ['contentType' => 'text/plain'],
485+
'sourceObjects' => [['name' => 'file1.txt'], ['name' => 'file2.txt']],
486+
])
487+
->willReturn([
488+
'name' => $destinationObject,
489+
'generation' => 1
490+
])
491+
->shouldBeCalledTimes(1);
492+
$bucket = $this->getBucket();
493+
494+
$object = $bucket->compose(['file1.txt', 'file2.txt'], $destinationObject, [
495+
'predefinedAcl' => $acl,
496+
'deleteSourceObjects' => null
497+
]);
498+
499+
$this->assertEquals($destinationObject, $object->name());
500+
}
501+
422502
public function composeProvider()
423503
{
424504
$object1 = $this->prophesize(StorageObject::class);

0 commit comments

Comments
 (0)