gallery-api/src/App/Service/GalleryService.php
2017-08-15 23:05:11 +02:00

207 lines
5.8 KiB
PHP

<?php
namespace App\Service;
use App\Entity\Image;
use Doctrine\ORM\EntityManager;
use Imagine\Gd\Imagine;
use Imagine\Image\Box;
use Imagine\Image\ImageInterface;
use Symfony\Component\Yaml\Parser;
use Zend\Config\Reader\Yaml;
class GalleryService
{
const CONFIG_FILE = 'data/galleries/config.yaml';
const IMAGE_BASEDIR = 'data/galleries/%s/';
const EXPORT_DIR = 'data/export/';
const THUMBNAIL_SIZE = 500;
protected $contentTypeMap = [
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'png' => 'image/png',
];
protected $config;
/**
* @var EntityManager
*/
protected $em;
public function __construct(EntityManager $entityManager)
{
$this->em = $entityManager;
}
public function getExportFileName(string $slug)
{
$config = $this->getConfig();
if (!isset($config['galleries'][$slug])) {
return false;
}
$dir = $config['galleries'][$slug]['dir'];
return $this->ensureExportFileExists($dir, "{$slug}.zip");
}
private function ensureExportFileExists(string $dir, string $filename)
{
$exportName = self::EXPORT_DIR . $filename;
if(file_exists($exportName)) {
return $exportName;
}
$exportLock = sprintf("data/tmp/%s.lock", $dir);
if(file_exists($exportLock)) {
return false;
}
$images = array_map('basename', glob($this->getImageDir($dir) . "*.{jpg,jpeg,png}", GLOB_BRACE));
$zipName = tempnam("data/tmp", "export");
touch($exportLock);
$zipArchive = new \ZipArchive();
$zipArchive->open($zipName, \ZipArchive::CREATE);
foreach ($images as $image) {
ini_set("max_execution_time", 60);
$zipArchive->addFile(
sprintf(self::IMAGE_BASEDIR,$dir) . $image,
"{$dir}/{$image}"
);
}
$zipArchive->close();
rename($zipName, $exportName);
unlink($exportLock);
return $exportName;
}
public function loadGalleryData($includeHidden = false)
{
$config = $this->getConfig();
$albums = [];
foreach ($config['galleries'] as $id => $data) {
if ($includeHidden || $data['public']) {
$galleryImages = $this->loadGalleryImages($data['dir']);
$albums[] = [
'slug' => $id,
'name' => $data['name'],
'coverImage' => isset($data['cover'])
? $this->getCoverImage($galleryImages, $data['cover'])
: null,
'date' => $this->getGalleryDate($data['dir']),
'type' => $data['type'],
'isNew' => $data['new'],
'isPublic' => $data['public'],
'images' => $galleryImages,
];
}
}
return $albums;
}
private function getCoverImage(array &$images, string $coverFileName): Image
{
$filtered = array_values(array_filter($images, function(Image $image) use ($coverFileName) {
return $image->getPath() == $coverFileName;
}));
return array_pop($filtered);
}
private function getGalleryDate(string $dir): string
{
$timestamp = sprintf("@%s", filemtime($this->getImageDir($dir)));
$date = new \DateTime($timestamp);
return $date->format("Y-m-d");
}
/**
* @param string $dir
* @return Image[]
* @todo implement label for image in some way
*/
private function loadGalleryImages(string $dir): array
{
$images = array_map('basename', glob(
sprintf(self::IMAGE_BASEDIR . "*.{jpg,jpeg,png}", $dir),
GLOB_BRACE
));
$imagine = new Imagine();
return array_map(function ($imagePath) use ($dir, $imagine) {
$imageEntity = $this->em->getRepository(Image::class)->findOneBy([
'dir' => $dir,
'path' => $imagePath,
]);
$this->ensureThumbnailExists($dir, $imagePath);
if (null === $imageEntity) {
$image = $imagine->open($this->getImageDir($dir) . $imagePath);
$imageSize = $image->getSize();
unset($image);
$thumb = $imagine->open($this->getThumbDir($dir) . $imagePath);
$thumbSize = $thumb->getSize();
unset($thumb);
$imageEntity = new Image();
$imageEntity->setLabel("")
->setDir($dir)
->setPath($imagePath)
->setWidth($imageSize->getWidth())
->setHeight($imageSize->getHeight())
->setThumbWidth($thumbSize->getWidth())
->setThumbHeight($thumbSize->getHeight())
;
$this->em->persist($imageEntity);
$this->em->flush();
}
return $imageEntity;
}, $images);
}
private function ensureThumbnailExists(string $dir, string $imageName) {
$imageDir = $this->getImageDir($dir);
$thumbPath = $imageDir . "thumb_" . self::THUMBNAIL_SIZE;
@mkdir($thumbPath);
$thumbImageName = $thumbPath . "/" . $imageName;
if (!file_exists($thumbImageName)) {
$thumbSize = new Box(self::THUMBNAIL_SIZE, self::THUMBNAIL_SIZE * 10);
$imagine = new Imagine();
$image = $imagine->open($imageDir . $imageName)
->thumbnail($thumbSize, ImageInterface::THUMBNAIL_INSET);
$image->effects()->sharpen();
$image->save($thumbImageName);
}
return $thumbImageName;
}
public function getImageFileName(string $slug, string $image, $isThumbnail = false): string
{
$config = $this->getConfig();
$dir = $config['galleries'][$slug]['dir'];
$this->ensureThumbnailExists($config['galleries'][$slug]['dir'], $image);
return $isThumbnail
? ($this->getThumbDir($dir) . $image)
: ($this->getImageDir($dir) . $image);
}
private function getImageDir($dir): string {
return sprintf(self::IMAGE_BASEDIR, $dir);
}
private function getThumbDir($dir): string {
return sprintf(self::IMAGE_BASEDIR, "{$dir}/thumb_" . self::THUMBNAIL_SIZE);
}
private function getConfig()
{
if (null === $this->config) {
$parser = new Parser();
$configReader = new Yaml([$parser, 'parse']);
$this->config = $configReader->fromFile(self::CONFIG_FILE);
}
return $this->config;
}
}