diff --git a/lib/Helper/ImageService/ImageGenerationHelper.php b/lib/Helper/ImageService/ImageGenerationHelper.php new file mode 100644 index 00000000..56c54529 --- /dev/null +++ b/lib/Helper/ImageService/ImageGenerationHelper.php @@ -0,0 +1,74 @@ + 'full.jpg', + ImageSize::THUMBNAIL => 'thumb.jpg', + ImageSize::MINI_THUMBNAIL => 'thumb16.jpg', + ]; + + /** + * @var ThumbnailService + */ + private $thumbnailService; + + public function __construct( + ThumbnailService $thumbnailService + ) { + $this->thumbnailService = $thumbnailService; + } + + /** + * Calculate the image data of a thumbnail of defined size and store it in the nextcloud server storage. + * + * @param File $fullImage The full-sized image to use as a starting point + * @param int $type The requested size of the thunbmail + * @param File $dstFile The name of the file to store the thumbnail to + * @return void + */ + public function generateThumbnail(File $fullImage, int $type, File $dstFile): void { + if ($type === ImageSize::PRIMARY_IMAGE) { + return; + } + + $fullContent = $fullImage->getContent(); + + $thumbContent = $this->thumbnailService->getThumbnail($fullContent, $type); + + $dstFile->putContent($thumbContent); + $dstFile->touch(); + } + + /** + * Ensure that a thumbnail is not existing in the file system. + * + * This method checks if a certain thumbail size is present in the recipe folder and removes the file accordingly. + * Note: If the thumbnail is not present, this method does nothing. + * + * The main image will not be dropped. + * + * @param Folder $recipeFolder The folder containing the recipe + * @param integer $type The type of the thumbnail to remove + * @return void + */ + public function drop(Folder $recipeFolder, int $type): void { + if ($type === ImageSize::PRIMARY_IMAGE) { + return; + } + + $filename = ImageSize::NAME_MAP[$type]; + + if ($recipeFolder->nodeExists($filename)) { + $recipeFolder->get($filename)->delete(); + } + } +} diff --git a/lib/Helper/ImageService/ImageSize.php b/lib/Helper/ImageService/ImageSize.php new file mode 100644 index 00000000..1488988f --- /dev/null +++ b/lib/Helper/ImageService/ImageSize.php @@ -0,0 +1,15 @@ + 'full.jpg', + self::THUMBNAIL => 'thumb.jpg', + self::MINI_THUMBNAIL => 'thumb16.jpg', + ]; +} diff --git a/tests/Unit/Helper/ImageService/ImageGenerationHelperTest.php b/tests/Unit/Helper/ImageService/ImageGenerationHelperTest.php new file mode 100644 index 00000000..607c8a89 --- /dev/null +++ b/tests/Unit/Helper/ImageService/ImageGenerationHelperTest.php @@ -0,0 +1,152 @@ +thumbnailService = $this->createMock(ThumbnailService::class); + + $this->dut = new ImageGenerationHelper($this->thumbnailService); + } + + public function dpThumbnails() { + yield [ImageSize::THUMBNAIL]; + yield [ImageSize::MINI_THUMBNAIL]; + } + + /** + * @dataProvider dpThumbnails + */ + public function testThumbnailGeneration($type) { + /** + * @var Stub|File $fullImage + */ + $fullImage = $this->createStub(File::class); + /** + * @var MockObject|File + */ + $dstFile = $this->createMock(File::class); + + $fullContent = 'The content of the full image'; + $thumbContent = 'The content of the thumb file'; + + $fullImage->method('getContent')->willReturn($fullContent); + + $fileWasSaved = true; + + $dstFile->expects($this->once())->method('putContent')->with($thumbContent)->will( + $this->returnCallback(function ($content) use (&$fileWasSaved) { + $fileWasSaved = false; + }) + ); + $dstFile->expects($this->once())->method('touch')->will($this->returnCallback( + function () use (&$fileWasSaved) { + $fileWasSaved = true; + } + )); + + $this->thumbnailService->method('getThumbnail')->with($fullContent, $type) + ->willReturn($thumbContent); + + $this->dut->generateThumbnail($fullImage, $type, $dstFile); + + $this->assertTrue($fileWasSaved, 'File was not touched after modifications.'); + } + + public function testFullSizeImage() { + $fullImage = $this->createStub(File::class); + /** + * @var MockObject|File $dstFile + */ + $dstFile = $this->createMock(File::class); + + $dstFile->expects($this->never())->method('putContent'); + + $this->dut->generateThumbnail($fullImage, ImageSize::PRIMARY_IMAGE, $dstFile); + } + + public function dpDropExisting() { + yield [ImageSize::THUMBNAIL, 'thumb.jpg']; + yield [ImageSize::MINI_THUMBNAIL, 'thumb16.jpg']; + } + + /** + * @dataProvider dpDropExisting + */ + public function testDropThumbnailExisting($type, $filename) { + /** + * @var MockObject|Folder $folder + */ + $folder = $this->createMock(Folder::class); + /** + * @var MockObject|File $thumbnail + */ + $thumbnail = $this->createMock(File::class); + + $folder->method('get')->with($filename)->willReturn($thumbnail); + $folder->method('nodeExists')->willReturn(true); + + $thumbnail->expects($this->once())->method('delete'); + + $this->dut->drop($folder, $type); + } + + /** + * @dataProvider dpDropExisting + */ + public function testDropThumbnailNonExisting($type, $filename) { + /** + * @var MockObject|Folder $folder + */ + $folder = $this->createMock(Folder::class); + + $folder->method('get')->with($filename)->willThrowException(new NotFoundException()); + $folder->method('nodeExists')->willReturn(false); + + $this->dut->drop($folder, $type); + $this->assertTrue(true, 'No Exception was thrown'); + } + + public function testDropThumbnailMainImage() { + /** + * @var MockObject|Folder $folder + */ + $folder = $this->createMock(Folder::class); + /** + * @var MockObject|Folder $image + */ + $image = $this->createMock(File::class); + + $folder->method('get')->with('full.jpg')->willReturn($image); + $folder->method('nodeExists')->willReturn(true); + + $image->expects($this->never())->method('delete'); + + $this->dut->drop($folder, ImageSize::PRIMARY_IMAGE); + $this->assertTrue(true, 'No Exception was thrown'); + } +}