[ENTITY][AttachmentThumbnail] Uncache when deleting, cleanup code and ensure the biggest thumbnail is used when the original is not avaliable

This commit is contained in:
Hugo Sales 2021-11-14 23:20:59 +00:00
parent a3074662b8
commit c509692102
Signed by: someonewithpc
GPG Key ID: 7D0C7EAFC9D835A0

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -59,6 +61,12 @@ class AttachmentThumbnail extends Entity
public const SIZE_MEDIUM = 1; public const SIZE_MEDIUM = 1;
public const SIZE_BIG = 2; public const SIZE_BIG = 2;
public const SIZE_MAP = [
'small' => self::SIZE_SMALL,
'medium' => self::SIZE_MEDIUM,
'big' => self::SIZE_BIG,
];
// {{{ Autocode // {{{ Autocode
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
private int $attachment_id; private int $attachment_id;
@ -67,7 +75,7 @@ class AttachmentThumbnail extends Entity
private string $filename; private string $filename;
private int $width; private int $width;
private int $height; private int $height;
private \DateTimeInterface $modified; private DateTimeInterface $modified;
public function setAttachmentId(int $attachment_id): self public function setAttachmentId(int $attachment_id): self
{ {
@ -149,6 +157,17 @@ class AttachmentThumbnail extends Entity
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
// }}} Autocode // }}} Autocode
public static function sizeIntToStr(?int $size): string
{
$map = array_flip(self::SIZE_MAP);
return $map[$size] ?? $map[self::SIZE_SMALL];
}
public static function sizeStrToInt(string $size)
{
return self::SIZE_MAP[$size] ?? self::SIZE_MAP[self::SIZE_SMALL];
}
private ?Attachment $attachment = null; private ?Attachment $attachment = null;
public function setAttachment(?Attachment $attachment) public function setAttachment(?Attachment $attachment)
@ -158,17 +177,20 @@ class AttachmentThumbnail extends Entity
public function getAttachment() public function getAttachment()
{ {
if (isset($this->attachment) && !is_null($this->attachment)) { if (isset($this->attachment) && !\is_null($this->attachment)) {
return $this->attachment; return $this->attachment;
} else { } else {
return $this->attachment = DB::findOneBy('attachment', ['id' => $this->attachment_id]); return $this->attachment = DB::findOneBy('attachment', ['id' => $this->attachment_id]);
} }
} }
public static function getCacheKey(int $id, int $size)
{
return "thumb-{$id}-{$size}";
}
/** /**
* @param Attachment $attachment * @param ?string $size 'small'|'medium'|'big'
* @param ?string $size 'small'|'medium'|'big'
* @param bool $crop
* *
* @throws ClientException * @throws ClientException
* @throws NotFoundException * @throws NotFoundException
@ -178,26 +200,23 @@ class AttachmentThumbnail extends Entity
*/ */
public static function getOrCreate(Attachment $attachment, ?string $size = null, bool $crop = false): ?self public static function getOrCreate(Attachment $attachment, ?string $size = null, bool $crop = false): ?self
{ {
$size = $size ?? Common::config('thumbnail', 'default_size'); $size ??= Common::config('thumbnail', 'default_size');
$size_int = match ($size) { $size_int = self::sizeStrToInt($size);
'medium' => self::SIZE_MEDIUM,
'big' => self::SIZE_BIG,
default => self::SIZE_SMALL,
};
try { try {
return Cache::get('thumb-' . $attachment->getId() . "-{$size}", return Cache::get(
function () use ($attachment, $size_int) { self::getCacheKey($attachment->getId(), $size_int),
return DB::findOneBy('attachment_thumbnail', ['attachment_id' => $attachment->getId(), 'size' => $size_int]); fn () => DB::findOneBy('attachment_thumbnail', ['attachment_id' => $attachment->getId(), 'size' => $size_int]),
}); );
} catch (NotFoundException) { } catch (NotFoundException) {
if (is_null($attachment->getWidth()) || is_null($attachment->getHeight())) { if (\is_null($attachment->getWidth()) || \is_null($attachment->getHeight())) {
return null; return null;
} }
[$predicted_width, $predicted_height] = self::predictScalingValues($attachment->getWidth(), $attachment->getHeight(), $size, $crop); [$predicted_width, $predicted_height] = self::predictScalingValues($attachment->getWidth(), $attachment->getHeight(), $size, $crop);
if (!file_exists($attachment->getPath())) { if (!file_exists($attachment->getPath())) {
// Before we quit, check if there's any other thumb // Before we quit, check if there's any other thumb
$alternative_thumbs = DB::findBy('attachment_thumbnail', ['attachment_id' => $attachment->getId()]); $alternative_thumbs = DB::findBy('attachment_thumbnail', ['attachment_id' => $attachment->getId()]);
if ($alternative_thumbs === []) { usort($alternative_thumbs, fn ($l, $r) => $r->getSize() <=> $l->getSize());
if (empty($alternative_thumbs)) {
throw new NotStoredLocallyException(); throw new NotStoredLocallyException();
} else { } else {
return $alternative_thumbs[0]; return $alternative_thumbs[0];
@ -237,12 +256,12 @@ class AttachmentThumbnail extends Entity
public function getPath() public function getPath()
{ {
return Common::config('thumbnail', 'dir') . DIRECTORY_SEPARATOR . $this->getFilename(); return Common::config('thumbnail', 'dir') . \DIRECTORY_SEPARATOR . $this->getFilename();
} }
public function getUrl() public function getUrl()
{ {
return Router::url('attachment_thumbnail', ['id' => $this->getAttachmentId(), 'size' => $this->getSize()]); return Router::url('attachment_thumbnail', ['id' => $this->getAttachmentId(), 'size' => self::sizeIntToStr($this->getSize())]);
} }
/** /**
@ -258,6 +277,7 @@ class AttachmentThumbnail extends Entity
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
} }
} }
Cache::delete(self::getCacheKey($this->getAttachmentId(), $this->getSize()));
DB::remove($this); DB::remove($this);
if ($flush) { if ($flush) {
DB::flush(); DB::flush();
@ -270,10 +290,8 @@ class AttachmentThumbnail extends Entity
* Values will scale _up_ to fit max values if cropping is enabled! * Values will scale _up_ to fit max values if cropping is enabled!
* With cropping disabled, the max value of each axis will be respected. * With cropping disabled, the max value of each axis will be respected.
* *
* @param int $existing_width Original width * @param int $existing_width Original width
* @param int $existing_height Original height * @param int $existing_height Original height
* @param string $requested_size
* @param bool $crop
* *
* @return array [predicted width, predicted height] * @return array [predicted width, predicted height]
*/ */
@ -281,7 +299,7 @@ class AttachmentThumbnail extends Entity
int $existing_width, int $existing_width,
int $existing_height, int $existing_height,
string $requested_size, string $requested_size,
bool $crop bool $crop,
): array { ): array {
/** /**
* 1:1 => Square * 1:1 => Square
@ -318,7 +336,7 @@ class AttachmentThumbnail extends Entity
// Binary search the closer allowed aspect ratio // Binary search the closer allowed aspect ratio
$left = 0; $left = 0;
$right = count($allowed_aspect_ratios) - 1; $right = \count($allowed_aspect_ratios) - 1;
while ($left < $right) { while ($left < $right) {
$mid = floor($left + ($right - $left) / 2); $mid = floor($left + ($right - $left) / 2);