зеркало из https://github.com/nextcloud/cookbook.git
Create image generation class to save thumbnails
Added test for complete coverage Added dropping of thumbnails Prevent accidential removal of primary image Signed-off-by: Christian Wolf <github@christianwolf.email>
This commit is contained in:
Родитель
10a1e78c15
Коммит
247b166e33
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace OCA\Cookbook\Helper\ImageService;
|
||||
|
||||
use OCP\Files\File;
|
||||
use OCP\Files\Folder;
|
||||
use OCA\Cookbook\Service\ThumbnailService;
|
||||
|
||||
/**
|
||||
* This class provides heler function to generate appropriate thumbnails according to the needs.
|
||||
*/
|
||||
class ImageGenerationHelper {
|
||||
private const MAP = [
|
||||
ImageSize::PRIMARY_IMAGE => '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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace OCA\Cookbook\Helper\ImageService;
|
||||
|
||||
class ImageSize {
|
||||
public const PRIMARY_IMAGE = 1;
|
||||
public const THUMBNAIL = 2;
|
||||
public const MINI_THUMBNAIL = 3;
|
||||
|
||||
public const NAME_MAP = [
|
||||
self::PRIMARY_IMAGE => 'full.jpg',
|
||||
self::THUMBNAIL => 'thumb.jpg',
|
||||
self::MINI_THUMBNAIL => 'thumb16.jpg',
|
||||
];
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
namespace OCA\Cookbook\tests\Unit\Helper\ImageService;
|
||||
|
||||
use OCA\Cookbook\Helper\ImageService\ImageGenerationHelper;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use OCA\Cookbook\Helper\ImageService\ImageSize;
|
||||
use OCA\Cookbook\Service\ThumbnailService;
|
||||
use OCP\Files\File;
|
||||
use OCP\Files\Folder;
|
||||
use OCP\Files\NotFoundException;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\MockObject\Stub;
|
||||
|
||||
/**
|
||||
* @covers OCA\Cookbook\Helper\ImageService\ImageGenerationHelper
|
||||
*/
|
||||
class ImageGenerationHelperTest extends TestCase {
|
||||
|
||||
/**
|
||||
* @var ThumbnailService|MockObject
|
||||
*/
|
||||
private $thumbnailService;
|
||||
|
||||
/**
|
||||
* @var ImageGenerationHelper
|
||||
*/
|
||||
private $dut;
|
||||
|
||||
protected function setUp(): void {
|
||||
$this->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');
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче