1
0
cms11/app/Classes/Traits/Repairs/RepairsImages.php

221 lines
6.4 KiB
PHP

<?php
namespace App\Classes\Traits\Repairs;
use App\Classes\AttachmentsManager;
use App\Exceptions\AttachmentNotFound;
use Carbon\Carbon;
use Illuminate\Support\Str;
use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Laravel\Facades\Image;
use League\Flysystem\StorageAttributes;
/**
* Trait for AttachmentsManager
*/
trait RepairsImages
{
/**
* Repair all attached images
*/
private function repairImages()
{
$this->load();
$files = $this->disk->listContents(
sprintf(
'%s/%s/%s',
$this->bundle->getDataDir(),
$this->attachmentsDir,
AttachmentsManager::Images
),
false
)
->filter(fn (StorageAttributes $attributes) => $attributes->isFile())
->map(fn (StorageAttributes $attributes) => $attributes->path())
->toArray();
foreach ($files as $file) {
$content = $this->disk->get($file);
$filename = sprintf('%s/%s', AttachmentsManager::Images, pathinfo($file, PATHINFO_BASENAME));
$data = [
'contents' => $content,
'filename' => $filename,
];
$this->disk->delete($file);
$this->add($data);
}
foreach ($this->manager->get('files', []) as $ref => $data) {
$this->repairKnownImage($ref, $data);
}
$this->save();
}
/**
* Repair a single image. Move it to appropriate directory and create or
* update variations.
*/
private function repairKnownImage(string $ref, array $data)
{
if (!empty($data['url'])) {
$data['filename'] = $data['url'];
unset($data['url']);
$this->manager->set(sprintf('files.%s', $ref), $data);
}
$extension = pathinfo($data['filename'], PATHINFO_EXTENSION);
$currentFullPath = sprintf('%s%s', $this->bundle->getDataDir(), $data['filename']);
$expectedFullPath = sprintf(
'%s%s/%s/%s/original.%s',
$this->bundle->getDataDir(),
$this->attachmentsDir,
$this->kind,
$ref,
$extension
);
if (!$this->disk->exists($currentFullPath)) {
$this->deleteAttachment($ref);
return;
}
if (empty($data['last_modified'])) {
$data['last_modified'] = Carbon::parse($this->disk->lastModified($currentFullPath))->toIso8601String();
}
if ($currentFullPath !== $expectedFullPath) {
$filename = pathinfo($currentFullPath, PATHINFO_BASENAME);
$tempname = Str::random(6);
$tempPath = str_replace($filename, $tempname, $currentFullPath);
$this->disk->move($currentFullPath, $tempPath);
$this->disk->move($tempPath, $expectedFullPath);
$data['last_modified'] = Carbon::parse($this->disk->lastModified($expectedFullPath))->toIso8601String();
$data['filename'] = sprintf(
'%s/%s/%s/original.%s',
$this->attachmentsDir,
$this->kind,
$ref,
$extension
);
$parentDir = dirname($currentFullPath);
if (empty($this->disk->listContents($parentDir, true))) {
$this->disk->delete($parentDir);
}
}
$this->manager->set(sprintf('files.%s', $ref), $data);
$this->syncImageVariants($ref);
}
/**
* Synchronize image variants (apply pre-defined filters)
*/
private function syncImageVariants(string $ref)
{
$currentVariants = $this->manager->get(sprintf('variants.%s', $ref), []);
$configVariants = array_keys(config('imagefilters'));
// Synchronize or delete currently declared variants
foreach ($currentVariants as $filter => $variantData) {
if (!in_array($filter, $configVariants)) {
$this->deleteVariant($ref, $filter);
continue;
}
$this->syncImageVariant($ref, $filter);
}
// Synchronize variants with the ones expected by configuration
foreach ($configVariants as $filter) {
$this->syncImageVariant($ref, $filter);
}
}
/**
* Synchronize specific image variant
*/
private function syncImageVariant(string $ref, string $filter)
{
try {
$originalData = $this->getAttachmentData($ref);
} catch (AttachmentNotFound $ex) {
$this->deleteAttachment($ref);
return;
}
$variantData = $this->getVariantData($ref, $filter);
$variantFilepath = $this->getVariantFullPath($ref, $filter);
if (!$this->disk->exists($variantFilepath)) {
$this->createImageVariant($ref, $filter);
} else {
$originalLastModified = Carbon::parse($originalData['last_modified']);
$variantLastModified = Carbon::parse($variantData['last_modified'] ?? $this->disk->lastModified($variantFilepath));
if ($originalLastModified->gt($variantLastModified)) {
$this->createImageVariant($ref, $filter);
}
}
}
/**
* Create the variant for specified image and filter
*/
private function createImageVariant(string $ref, string $filter)
{
$filterClass = config(sprintf('imagefilters.%s', $filter));
try {
$original = $this->getAttachmentFullPath($ref);
} catch (AttachmentNotFound $ex) {
$this->deleteAttachment($ref);
return;
}
$target = $this->getVariantFullPath($ref, $filter);
$contents = $this->disk->get($original);
try {
$image = Image::read($contents);
} catch (DecoderException $ex) {
$this->deleteAttachment($ref);
return;
}
$variantData = $this->getVariantData($ref, $filter);
$image->modify(new $filterClass());
if ($image->isAnimated()) {
$contents = (string) $image->toGif();
} else {
$contents = (string) $image->toWebp();
}
$this->disk->put($target, $contents);
$variantData['filename'] = $this->getVariantRelativePath($ref, $filter);
$variantData['last_modified'] = now();
$this->manager->set(sprintf('variants.%s.%s', $ref, $filter), $variantData);
}
}