diff --git a/src/ImageManipulator.php b/src/ImageManipulator.php index 777009e2..9f85032c 100644 --- a/src/ImageManipulator.php +++ b/src/ImageManipulator.php @@ -17,7 +17,7 @@ class ImageManipulator /** * @var ImageManipulation[] */ - private $variantManipulations = []; + private $variantDefinitions = []; /** * @var FilesystemManager @@ -30,26 +30,43 @@ public function __construct(ImageManager $imageManager, FilesystemManager $files $this->filesystem = $filesystem; } - public function addVariantManipulation( + public function defineVariant( string $variantName, ImageManipulation $manipulation ) { - $this->variantManipulations[$variantName] = $manipulation; + $this->variantDefinitions[$variantName] = $manipulation; + } + + public function hasVariantDefinition(string $variantName): bool + { + return isset($this->variantDefinitions[$variantName]); + } + + /** + * @param string $variantName + * @return ImageManipulation + * @throws ImageManipulationException if Variant is not defined + */ + public function getVariantDefinition(string $variantName): ImageManipulation + { + if (isset($this->variantDefinitions[$variantName])) { + return $this->variantDefinitions[$variantName]; + } + + throw ImageManipulationException::unknownVariant($variantName); } /** - * @param ImageManipulation $manipulation * @param Media $media - * @return StreamInterface + * @param string $variantName + * @return Media * @throws ImageManipulationException */ - public function createVariant(string $variantName, Media $media): Media + public function createImageVariant(Media $media, string $variantName): Media { - if ($media->aggregate_type != Media::TYPE_IMAGE) { - throw ImageManipulationException::invalidMediaType($media->aggregate_type); - } + $this->validateMedia($media); - $manipulation = $this->getVariantManipulation($variantName); + $manipulation = $this->getVariantDefinition($variantName); $outputFormat = $this->determineOutputFormat($manipulation, $media); $image = $this->imageManager->make($media->stream()); @@ -89,20 +106,6 @@ public function createVariant(string $variantName, Media $media): Media return $newMedia; } - /** - * @param string $variantName - * @return ImageManipulation - * @throws ImageManipulationException - */ - private function getVariantManipulation(string $variantName): ImageManipulation - { - if (isset($this->variantManipulations[$variantName])) { - return $this->variantManipulations[$variantName]; - } - - throw ImageManipulationException::unknownVariant($variantName); - } - private function getMimeTypeForOutputFormat(string $outputFormat): string { return ImageManipulation::MIME_TYPE_MAP[$outputFormat]; @@ -112,7 +115,7 @@ private function getMimeTypeForOutputFormat(string $outputFormat): string * @param ImageManipulation $manipulation * @param Media $media * @return string - * @throws ImageManipulationException + * @throws ImageManipulationException If output format cannot be determined */ private function determineOutputFormat( ImageManipulation $manipulation, @@ -143,4 +146,11 @@ private function determineOutputFormat( throw ImageManipulationException::unknownOutputFormat(); } + + public function validateMedia(Media $media) + { + if ($media->aggregate_type != Media::TYPE_IMAGE) { + throw ImageManipulationException::invalidMediaType($media->aggregate_type); + } + } } diff --git a/src/Jobs/CreateImageVariants.php b/src/Jobs/CreateImageVariants.php new file mode 100644 index 00000000..51578fcd --- /dev/null +++ b/src/Jobs/CreateImageVariants.php @@ -0,0 +1,86 @@ +validate($model, $variantNames); + + $this->variantNames = $variantNames; + $this->model = $model; + } + + public function handle() + { + foreach ($this->getVariantNames() as $variantName) { + $this->getImageManipulator()->createImageVariant( + $this->getModel(), + $variantName + ); + } + } + + /** + * @return string[] + */ + public function getVariantNames(): array + { + return $this->variantNames; + } + + /** + * @return Media + */ + public function getModel(): Media + { + return $this->model; + } + + /** + * @param Media $model + * @param array $variantNames + * @throws ImageManipulationException + */ + private function validate(Media $media, array $variantNames): void + { + $imageManipulator = $this->getImageManipulator(); + $imageManipulator->validateMedia($media); + foreach ($variantNames as $variantName) { + $imageManipulator->getVariantDefinition($variantName); + } + } + + private function getImageManipulator(): ImageManipulator + { + return app(ImageManipulator::class); + } +} diff --git a/src/Jobs/ProcessImageVariant.php b/src/Jobs/ProcessImageVariant.php deleted file mode 100644 index c0ba23aa..00000000 --- a/src/Jobs/ProcessImageVariant.php +++ /dev/null @@ -1,55 +0,0 @@ -variantName = $variantName; - $this->model = $model; - } - - public function handle() - { - app(ImageManipulator::class)->createVariant( - $this->getVariantName(), - $this->getModel() - ); - } - - /** - * @return string - */ - public function getVariantName(): string - { - return $this->variantName; - } - - /** - * @return Media - */ - public function getModel(): Media - { - return $this->model; - } -} diff --git a/src/Media.php b/src/Media.php index a5e0118a..528c9a01 100644 --- a/src/Media.php +++ b/src/Media.php @@ -167,6 +167,11 @@ public function getAllVariantsAndSelf(): Collection return $collection; } + public function hasVariant(string $variantName): bool + { + return $this->findVariant($variantName) !== null; + } + public function findVariant(string $variantName): ?Media { $filter = function (Media $media) use ($variantName) { diff --git a/tests/Integration/ImageManipulatorTest.php b/tests/Integration/ImageManipulatorTest.php index 6994ec87..f36b9190 100644 --- a/tests/Integration/ImageManipulatorTest.php +++ b/tests/Integration/ImageManipulatorTest.php @@ -13,15 +13,26 @@ class ImageManipulatorTest extends TestCase { + public function test_it_sets_and_has_variants() + { + $manipulator = $this->getManipulator(); + $this->assertFalse($manipulator->hasVariantDefinition('foo')); + $manipulator->defineVariant( + 'foo', + new ImageManipulation($this->getMockCallable()) + ); + $this->assertTrue($manipulator->hasVariantDefinition('foo')); + } + public function test_it_throws_for_non_image_media() { $this->expectException(ImageManipulationException::class); $this->expectErrorMessage( "Cannot manipulate media with an aggregate type other than 'image', got 'document'." ); - $this->getManipulator()->createVariant( - 'variant', - $this->makeMedia(['aggregate_type' => 'document']) + $this->getManipulator()->createImageVariant( + $this->makeMedia(['aggregate_type' => 'document']), + 'variant' ); } @@ -29,9 +40,9 @@ public function test_it_throws_for_unknown_variants() { $this->expectException(ImageManipulationException::class); $this->expectErrorMessage("Unknown variant 'invalid'."); - $this->getManipulator()->createVariant( - 'invalid', - $this->makeMedia(['aggregate_type' => 'image']) + $this->getManipulator()->createImageVariant( + $this->makeMedia(['aggregate_type' => 'image']), + 'invalid' ); } @@ -54,8 +65,8 @@ function (Image $image) { ); $this->seedFileForMedia($media); $manipulator = $this->getManipulator(); - $manipulator->addVariantManipulation('foo', $manipulation); - $manipulator->createVariant('foo', $media); + $manipulator->defineVariant('foo', $manipulation); + $manipulator->createImageVariant($media, 'foo'); } public function test_it_can_create_a_variant() @@ -75,7 +86,7 @@ public function test_it_can_create_a_variant() ); $this->seedFileForMedia($media, $this->sampleFile()); - $beforeSave = $this->getMockCallback(); + $beforeSave = $this->getMockCallable(); $beforeSave->expects($this->once()) ->method('__invoke') ->with( @@ -95,8 +106,8 @@ function (Image $image) { )->beforeSave($beforeSave); $imageManipulator = $this->getManipulator(); - $imageManipulator->addVariantManipulation('test', $manipulation); - $result = $imageManipulator->createVariant('test', $media); + $imageManipulator->defineVariant('test', $manipulation); + $result = $imageManipulator->createImageVariant($media, 'test'); $this->assertTrue($result->exists); $this->assertEquals('tmp', $result->disk); @@ -137,8 +148,8 @@ function (Image $image) { ); $imageManipulator = $this->getManipulator(); - $imageManipulator->addVariantManipulation('test', $manipulation); - $result = $imageManipulator->createVariant('test', $media); + $imageManipulator->defineVariant('test', $manipulation); + $result = $imageManipulator->createImageVariant($media, 'test'); $this->assertEquals('test', $result->variant_name); $this->assertEquals(19, $result->original_media_id); @@ -183,8 +194,8 @@ function (Image $image) { )->setOutputFormat($format)->setOutputQuality($quality); $imageManipulator = $this->getManipulator(); - $imageManipulator->addVariantManipulation('test', $manipulation); - $result = $imageManipulator->createVariant('test', $media); + $imageManipulator->defineVariant('test', $manipulation); + $result = $imageManipulator->createImageVariant($media, 'test'); $this->assertEquals($format, $result->extension); $this->assertEquals($mime, $result->mime_type); diff --git a/tests/Integration/Jobs/CreateImageVariantsTest.php b/tests/Integration/Jobs/CreateImageVariantsTest.php new file mode 100644 index 00000000..12c2bc05 --- /dev/null +++ b/tests/Integration/Jobs/CreateImageVariantsTest.php @@ -0,0 +1,34 @@ +makeMedia(['aggregate_type' => 'image']); + $variant1 = 'foo'; + $variant2 = 'bar'; + + $manipulator = $this->createMock(ImageManipulator::class); + $manipulator->expects($this->once()) + ->method('validateMedia') + ->with($model); + $manipulator->expects($this->exactly(2)) + ->method('getVariantDefinition') + ->withConsecutive([$variant1], [$variant2]) + ->willReturn($this->createMock(ImageManipulation::class)); + $manipulator->expects($this->exactly(2)) + ->method('createImageVariant') + ->withConsecutive([$model, $variant1], [$model, $variant2]); + app()->instance(ImageManipulator::class, $manipulator); + + $job = new CreateImageVariants($model, [$variant1, $variant2]); + $job->handle(); + } +} diff --git a/tests/Integration/Jobs/ProcessImageVariantTest.php b/tests/Integration/Jobs/ProcessImageVariantTest.php deleted file mode 100644 index b83a7023..00000000 --- a/tests/Integration/Jobs/ProcessImageVariantTest.php +++ /dev/null @@ -1,25 +0,0 @@ -makeMedia([]); - $variant = 'foo'; - $job = new ProcessImageVariant($variant, $model); - - $manipulator = $this->createMock(ImageManipulator::class); - $manipulator->expects($this->once()) - ->method('createVariant') - ->with($variant, $model); - app()->instance(ImageManipulator::class, $manipulator); - - $job->handle(); - } -} diff --git a/tests/Integration/MediaTest.php b/tests/Integration/MediaTest.php index ed0ac4f1..f131ce82 100644 --- a/tests/Integration/MediaTest.php +++ b/tests/Integration/MediaTest.php @@ -678,6 +678,16 @@ public function test_it_can_find_other_variants() $this->assertEquals($media3, $media2->findVariant('bar')); $this->assertEquals($media3, $media3->findVariant('bar')); + $this->assertTrue($media1->hasVariant('foo')); + $this->assertTrue($media2->hasVariant('foo')); + $this->assertTrue($media3->hasVariant('foo')); + $this->assertTrue($media1->hasVariant('bar')); + $this->assertTrue($media2->hasVariant('bar')); + $this->assertTrue($media3->hasVariant('bar')); + $this->assertFalse($media1->hasVariant('original')); + $this->assertFalse($media2->hasVariant('original')); + $this->assertFalse($media3->hasVariant('original')); + $this->assertEquals( new Collection(['foo' => $media2, 'bar' => $media3]), $media1->getAllVariants() diff --git a/tests/Mocks/MockClosure.php b/tests/Mocks/MockCallable.php similarity index 83% rename from tests/Mocks/MockClosure.php rename to tests/Mocks/MockCallable.php index 031630ad..e4d222b6 100644 --- a/tests/Mocks/MockClosure.php +++ b/tests/Mocks/MockCallable.php @@ -2,7 +2,7 @@ namespace Plank\Mediable\Tests\Mocks; -class MockClosure +class MockCallable { public function __invoke() { diff --git a/tests/TestCase.php b/tests/TestCase.php index 08092dac..6fdcf02d 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -8,7 +8,7 @@ use Orchestra\Testbench\TestCase as BaseTestCase; use Plank\Mediable\Media; use Plank\Mediable\MediableServiceProvider; -use Plank\Mediable\Tests\Mocks\MockClosure; +use Plank\Mediable\Tests\Mocks\MockCallable; use ReflectionClass; class TestCase extends BaseTestCase @@ -171,8 +171,8 @@ protected function createMedia(array $attributes = []): Media return factory(Media::class)->create($attributes); } - protected function getMockCallback() + protected function getMockCallable() { - return $this->createPartialMock(MockClosure::class, ['__invoke']); + return $this->createPartialMock(MockCallable::class, ['__invoke']); } }