Skip to content

Commit

Permalink
Improve diagnostics with count of thumbs that can be regenerated (#2200)
Browse files Browse the repository at this point in the history
  • Loading branch information
ildyria committed Jan 16, 2024
1 parent e1faf33 commit 26ad321
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 102 deletions.
2 changes: 2 additions & 0 deletions app/Actions/Diagnostics/Errors.php
Expand Up @@ -14,6 +14,7 @@
use App\Actions\Diagnostics\Pipes\Checks\IniSettingsCheck;
use App\Actions\Diagnostics\Pipes\Checks\MigrationCheck;
use App\Actions\Diagnostics\Pipes\Checks\PHPVersionCheck;
use App\Actions\Diagnostics\Pipes\Checks\SmallMediumExistsCheck;
use App\Actions\Diagnostics\Pipes\Checks\TimezoneCheck;
use App\Actions\Diagnostics\Pipes\Checks\UpdatableCheck;
use Illuminate\Pipeline\Pipeline;
Expand All @@ -40,6 +41,7 @@ class Errors
UpdatableCheck::class,
ForeignKeyListInfo::class,
DBIntegrityCheck::class,
SmallMediumExistsCheck::class,
];

/**
Expand Down
135 changes: 135 additions & 0 deletions app/Actions/Diagnostics/Pipes/Checks/SmallMediumExistsCheck.php
@@ -0,0 +1,135 @@
<?php

namespace App\Actions\Diagnostics\Pipes\Checks;

use App\Contracts\DiagnosticPipe;
use App\Enum\SizeVariantType;
use App\Image\SizeVariantDimensionHelpers;
use App\Models\SizeVariant;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

/**
* Check if there are some small or medium that could be generated.
*/
class SmallMediumExistsCheck implements DiagnosticPipe
{
public const NUM_SMALL = 'num_small';
public const NUM_MEDIUM = 'num_medium';
public const NUM_SMALL2X = 'num_small2x';
public const NUM_MEDIUM2X = 'num_medium2x';
public const MAX_NUM_SMALL = 'max_num_small';
public const MAX_NUM_MEDIUM = 'max_num_medium';
public const MAX_NUM_SMALL2X = 'max_num_small2x';
public const MAX_NUM_MEDIUM2X = 'max_num_medium2x';
public const INFO_MSG = 'Info: Found %d %s that could be generated.';
public const INFO_LINE = ' You can use `php artisan lychee:generate_thumbs %s %d` to generate them.';

/**
* {@inheritDoc}
*/
public function handle(array &$data, \Closure $next): array
{
if (!Schema::hasTable('configs') || !Schema::hasTable('size_variants')) {
// @codeCoverageIgnoreStart
return $next($data);
// @codeCoverageIgnoreEnd
}

$svHelpers = new SizeVariantDimensionHelpers();

/** @var object{num_small:int,num_medium:int,num_small2x:int,num_medium2x:int,max_num_small:int,max_num_medium:int,max_num_small2x:int,max_num_medium2x:int} $result */
$result = DB::query()
->selectSub(
SizeVariant::query()
->selectRaw('COUNT(*)')
->where('type', '=', SizeVariantType::SMALL),
self::NUM_SMALL
)
->selectSub(
SizeVariant::query()
->selectRaw('COUNT(*)')
->where('type', '=', SizeVariantType::SMALL2X),
self::NUM_SMALL2X
)
->selectSub(
SizeVariant::query()
->selectRaw('COUNT(*)')
->where('type', '=', SizeVariantType::MEDIUM),
self::NUM_MEDIUM
)
->selectSub(
SizeVariant::query()
->selectRaw('COUNT(*)')
->where('type', '=', SizeVariantType::MEDIUM2X),
self::NUM_MEDIUM2X
)
->selectSub(
SizeVariant::query()
->selectRaw('COUNT(*)')
->where(fn ($q) => $q
->when($svHelpers->getMaxWidth(SizeVariantType::SMALL) !== 0, fn ($q1) => $q1->where('width', '>', $svHelpers->getMaxWidth(SizeVariantType::SMALL)))
->when($svHelpers->getMaxHeight(SizeVariantType::SMALL) !== 0, fn ($q2) => $q2->orWhere('height', '>', $svHelpers->getMaxHeight(SizeVariantType::SMALL)))
)
->where('type', '=', SizeVariantType::ORIGINAL),
self::MAX_NUM_SMALL
)
->selectSub(
SizeVariant::query()
->selectRaw('COUNT(*)')
->where(fn ($q) => $q
->when($svHelpers->getMaxWidth(SizeVariantType::SMALL2X) !== 0, fn ($q1) => $q1->where('width', '>', $svHelpers->getMaxWidth(SizeVariantType::SMALL2X)))
->when($svHelpers->getMaxHeight(SizeVariantType::SMALL2X) !== 0, fn ($q2) => $q2->orWhere('height', '>', $svHelpers->getMaxHeight(SizeVariantType::SMALL2X)))
)
->where('type', '=', SizeVariantType::ORIGINAL),
self::MAX_NUM_SMALL2X
)
->selectSub(
SizeVariant::query()
->selectRaw('COUNT(*)')
->where(fn ($q) => $q
->when($svHelpers->getMaxWidth(SizeVariantType::MEDIUM) !== 0, fn ($q1) => $q1->where('width', '>', $svHelpers->getMaxWidth(SizeVariantType::MEDIUM)))
->when($svHelpers->getMaxHeight(SizeVariantType::MEDIUM) !== 0, fn ($q2) => $q2->orWhere('height', '>', $svHelpers->getMaxHeight(SizeVariantType::MEDIUM)))
)
->where('type', '=', SizeVariantType::ORIGINAL),
self::MAX_NUM_MEDIUM
)
->selectSub(
SizeVariant::query()
->selectRaw('COUNT(*)')
->where(fn ($q) => $q
->when($svHelpers->getMaxWidth(SizeVariantType::MEDIUM2X) !== 0, fn ($q1) => $q1->where('width', '>', $svHelpers->getMaxWidth(SizeVariantType::MEDIUM2X)))
->when($svHelpers->getMaxHeight(SizeVariantType::MEDIUM2X) !== 0, fn ($q2) => $q2->orWhere('height', '>', $svHelpers->getMaxHeight(SizeVariantType::MEDIUM2X)))
)
->where('type', '=', SizeVariantType::ORIGINAL),
self::MAX_NUM_MEDIUM2X
)
->first();

$num = $result->{self::MAX_NUM_SMALL} - $result->{self::NUM_SMALL}; // @phpstan-ignore-line
if ($num > 0) {
$data[] = sprintf(self::INFO_MSG, $num, SizeVariantType::SMALL->name());
$data[] = sprintf(self::INFO_LINE, SizeVariantType::SMALL->name(), $num);
}

$num = $result->{self::MAX_NUM_SMALL2X} - $result->{self::NUM_SMALL2X}; // @phpstan-ignore-line
if ($num > 0 && $svHelpers->isEnabledByConfiguration(SizeVariantType::SMALL2X)) {
$data[] = sprintf(self::INFO_MSG, $num, SizeVariantType::SMALL2X->name());
$data[] = sprintf(self::INFO_LINE, SizeVariantType::SMALL2X->name(), $num);
}

$num = $result->{self::MAX_NUM_MEDIUM} - $result->{self::NUM_MEDIUM}; // @phpstan-ignore-line
if ($num > 0) {
$data[] = sprintf(self::INFO_MSG, $num, SizeVariantType::MEDIUM->name());
$data[] = sprintf(self::INFO_LINE, SizeVariantType::MEDIUM->name(), $num);
}

$num = $result->{self::MAX_NUM_MEDIUM2X} - $result->{self::NUM_MEDIUM2X}; // @phpstan-ignore-line
if ($num > 0 && $svHelpers->isEnabledByConfiguration(SizeVariantType::MEDIUM2X)) {
$data[] = sprintf(self::INFO_MSG, $num, SizeVariantType::MEDIUM2X->name());
$data[] = sprintf(self::INFO_LINE, SizeVariantType::MEDIUM2X->name(), $num);
}

return $next($data);
}
}
108 changes: 6 additions & 102 deletions app/Image/SizeVariantDefaultFactory.php
Expand Up @@ -19,7 +19,6 @@
use App\Image\Files\TemporaryLocalFile;
use App\Image\Handlers\ImageHandler;
use App\Image\Handlers\VideoHandler;
use App\Models\Configs;
use App\Models\Photo;
use App\Models\SizeVariant;
use Illuminate\Contracts\Container\BindingResolutionException;
Expand All @@ -34,12 +33,15 @@ class SizeVariantDefaultFactory implements SizeVariantFactory
protected ImageHandlerInterface $referenceImage;
protected ?Photo $photo = null;
protected ?AbstractSizeVariantNamingStrategy $namingStrategy = null;
protected ?SizeVariantDimensionHelpers $svDimensionHelpers = null;

/**
* {@inheritDoc}
*/
public function init(Photo $photo, ?ImageHandlerInterface $referenceImage = null, ?AbstractSizeVariantNamingStrategy $namingStrategy = null): void
{
$this->svDimensionHelpers = new SizeVariantDimensionHelpers();

try {
$this->photo = $photo;
if ($referenceImage !== null && $referenceImage->isLoaded()) {
Expand Down Expand Up @@ -130,7 +132,7 @@ public function createSizeVariantCond(SizeVariantType $sizeVariant): ?SizeVarian
if ($sizeVariant === SizeVariantType::ORIGINAL) {
throw new InvalidSizeVariantException('createSizeVariantCond() must not be used to create original size');
}
if (!$this->isEnabledByConfiguration($sizeVariant)) {
if (!$this->svDimensionHelpers->isEnabledByConfiguration($sizeVariant)) {
return null;
}
// Don't generate medium size variants for videos, because the current web front-end has no use for it. Let's save some storage space.
Expand All @@ -142,16 +144,10 @@ public function createSizeVariantCond(SizeVariantType $sizeVariant): ?SizeVarian
return null;
}

$maxDim = $this->getMaxDimensions($sizeVariant);
$maxDim = $this->svDimensionHelpers->getMaxDimensions($sizeVariant);
$realDim = $this->referenceImage->getDimensions();

$isLargeEnough = match ($sizeVariant) {
SizeVariantType::THUMB => true,
SizeVariantType::THUMB2X => $realDim->width >= $maxDim->width && $realDim->height >= $maxDim->height,
default => ($realDim->width >= $maxDim->width && $maxDim->width !== 0) || ($realDim->height >= $maxDim->height && $maxDim->height !== 0)
};

return $isLargeEnough ?
return $this->svDimensionHelpers->isLargeEnough($realDim, $maxDim, $sizeVariant) ?
$this->createSizeVariantInternal($sizeVariant, $maxDim) :
null;
}
Expand Down Expand Up @@ -194,96 +190,4 @@ private function createSizeVariantInternal(SizeVariantType $sizeVariant, ImageDi
$svFile->getFilesize()
);
}

/**
* Determines the maximum dimensions of the designated size variant.
*
* @param SizeVariantType $sizeVariant the size variant
*
* @return ImageDimension
*
* @throws InvalidSizeVariantException
*/
protected function getMaxDimensions(SizeVariantType $sizeVariant): ImageDimension
{
$maxWidth = $this->getMaxWidth($sizeVariant);
$maxHeight = $this->getMaxHeight($sizeVariant);

return new ImageDimension($maxWidth, $maxHeight);
}

/**
* Checks whether the requested size variant is enabled by configuration.
*
* This function always returns true, for size variants which are not
* configurable and are always enabled (e.g. a thumb).
* Hence, it is safe to call this function for all size variants.
* For size variants which may be enabled/disabled through configuration at
* runtime, the method only returns true, if
*
* 1. the size variant is enabled, and
* 2. the allowed maximum width or maximum height is not zero.
*
* In other words, even if a size variant is enabled, this function
* still returns false, if both the allowed maximum width and height
* equal zero.
*
* @param SizeVariantType $sizeVariant the indicated size variant
*
* @return bool true, if the size variant is enabled and the allowed width
* or height is unequal to zero
*
* @throws InvalidSizeVariantException
*/
protected function isEnabledByConfiguration(SizeVariantType $sizeVariant): bool
{
$maxDim = $this->getMaxDimensions($sizeVariant);
if ($maxDim->width === 0 && $maxDim->height === 0) {
return false;
}

return match ($sizeVariant) {
SizeVariantType::MEDIUM2X => Configs::getValueAsBool('medium_2x'),
SizeVariantType::SMALL2X => Configs::getValueAsBool('small_2x'),
SizeVariantType::THUMB2X => Configs::getValueAsBool('thumb_2x'),
SizeVariantType::SMALL, SizeVariantType::MEDIUM, SizeVariantType::THUMB => true,
default => throw new InvalidSizeVariantException('unknown size variant: ' . $sizeVariant->value),
};
}

/**
* Return the max width for the SizeVariant.
*
* @return int
*/
protected function getMaxWidth(SizeVariantType $sizeVariant): int
{
return match ($sizeVariant) {
SizeVariantType::MEDIUM2X => 2 * Configs::getValueAsInt('medium_max_width'),
SizeVariantType::MEDIUM => Configs::getValueAsInt('medium_max_width'),
SizeVariantType::SMALL2X => 2 * Configs::getValueAsInt('small_max_width'),
SizeVariantType::SMALL => Configs::getValueAsInt('small_max_width'),
SizeVariantType::THUMB2X => self::THUMBNAIL2X_DIM,
SizeVariantType::THUMB => self::THUMBNAIL_DIM,
default => throw new InvalidSizeVariantException('No applicable for original'),
};
}

/**
* Return the max height for the SizeVariant.
*
* @return int
*/
protected function getMaxHeight(SizeVariantType $sizeVariant): int
{
return match ($sizeVariant) {
SizeVariantType::MEDIUM2X => 2 * Configs::getValueAsInt('medium_max_height'),
SizeVariantType::MEDIUM => Configs::getValueAsInt('medium_max_height'),
SizeVariantType::SMALL2X => 2 * Configs::getValueAsInt('small_max_height'),
SizeVariantType::SMALL => Configs::getValueAsInt('small_max_height'),
SizeVariantType::THUMB2X => self::THUMBNAIL2X_DIM,
SizeVariantType::THUMB => self::THUMBNAIL_DIM,
default => throw new InvalidSizeVariantException('unknown size variant: ' . $sizeVariant->value),
};
}
}

0 comments on commit 26ad321

Please sign in to comment.