Files
kupshop/bundles/KupShop/ContentBundle/Util/ImageLocator.php
2025-08-02 16:30:27 +02:00

247 lines
7.5 KiB
PHP

<?php
namespace KupShop\ContentBundle\Util;
use KupShop\ComponentsBundle\Entity\Thumbnail;
use KupShop\ContentBundle\Entity\Image;
use KupShop\KupShopBundle\Context\LanguageContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\KupShopBundle\Util\StringUtil;
use KupShop\KupShopBundle\Util\System\PathFinder;
use KupShop\KupShopBundle\Util\System\UrlFinder;
use Query\Operator;
use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext;
class ImageLocator
{
/**
* @var PathFinder
*/
private $pathFinder;
/** @var UrlFinder */
protected $urlFinder;
// Default settings
private $default = [
'crop' => true,
'background' => false,
'watermark' => false,
'png' => false,
'svg' => false,
'upscale' => false,
'quality' => null,
'sharpen' => null,
'contrast' => null,
];
public function __construct(PathFinder $pathFinder)
{
$this->pathFinder = $pathFinder;
}
public function getConfig()
{
global $cfg;
return $cfg['Photo'];
}
public function getThumbnailPath(Thumbnail $thumbnail, string $type, string $size): string
{
// TODO: Tady začni generovat cestu bez extension a asi teda i kvůli SEO šovinistům i s názevm souboru :-(
// TODO: A ideálně nějakou custom URL, co se bude zpracovávat v PHP, ale bude na CDN cachovaná.
$config = $this->getTypeConfig($type);
$lang = null;
if (!empty($config['lang'])) {
$lang = Contexts::get(LanguageContext::class)->getActiveId();
}
return $this->getNewPath($thumbnail, $type, $size, $lang);
}
public function getThumbnailUrl(Thumbnail $thumbnail, string $type, string $size)
{
$path = $this->getThumbnailPath($thumbnail, $type, $size);
if (isFunctionalTests()) {
$version = '';
} else {
$version = is_numeric($thumbnail->version) ? $thumbnail->version : strtotime($thumbnail->version);
}
return $this->urlFinder->staticUrl("{$path}?{$version}");
}
public function getNewPath(Thumbnail $thumbnail, string $type, string $version, ?string $lang = null): string
{
$path = "photo/{$type}/{$thumbnail->id}/";
$path .= empty($thumbnail->title) ? 'photo' : StringUtil::slugify($thumbnail->title);
$path .= empty($version) ? '' : ".{$version}";
$path .= empty($lang) ? '' : ".{$lang}";
return $this->pathFinder->shopPath($path);
}
public function getPath($id, $type, $ext = 'jpg', $lang = null, ?string $version = null)
{
$config = $this->getConfig();
if (!is_numeric($type)) {
if (!isset($config['type_to_id'])) {
$config['type_to_id'] = array_flip($config['id_to_type']);
}
$type = $config['type_to_id'][$type];
}
$subFolder = $id % 10;
if ($lang) {
$ext = "{$lang}.{$ext}";
}
$versionString = '';
if ($version && $version !== \Photos::PHOTO_VERSION_DESKTOP && $version !== 'desktop') {
$versionString = "_{$version}";
}
return $this->pathFinder->tmpPath("{$type}/{$subFolder}/{$id}_{$type}{$versionString}.{$ext}");
}
public function getTypeName($type)
{
$config = $this->getConfig();
if (is_numeric($type)) {
$type = getVal($type, $config['id_to_type'], $type);
}
if (!isset($config['types'][$type])) {
throw new \UnexpectedValueException('Neznámý typ obrázku: '.$type);
}
return $type;
}
public function getTypeConfig(&$type)
{
$config = $this->getConfig();
$type = $this->getTypeName($type);
return array_merge($this->default, $config['default'], $config['types'][$type]);
}
public function getImageById(int $id): ?Image
{
$photo = sqlQueryBuilder()
->select('*')
->from('photos')
->where(Operator::equals(['id' => $id]))
->execute()->fetchAssociative();
if (!$photo) {
return null;
}
return $this->getImage($photo);
}
public function getImage(array $photo): Image
{
return (new Image())
->setId((int) $photo['id'])
->setVideoId($photo['id_video'] ?? null)
->setDescription($photo['descr'])
->setSource($photo['source'])
->setImageDesktop($photo['image_2'])
->setImageTablet($photo['image_tablet'])
->setImageMobile($photo['image_mobile'])
->setDate(!empty($photo['date']) ? new \DateTime($photo['date_update']) : null)
->setDateUpdated(new \DateTime($photo['date_update']))
->setData(json_decode($photo['data'] ?? '', true) ?: []);
}
public function getOldImageArray($id, $file, $folder, $type, $desc = '', ?int $dateUpdate = null, ?string $data = null): ?array
{
if (empty($id)) {
return null;
}
$settings = $this->getTypeConfig($type);
// All thumbnails now use `jpg` extension
$ext = 'jpg';
$lang = null;
if (!empty($settings['lang'])) {
$lang = Contexts::get(LanguageContext::class)->getActiveId();
}
$path_large = $this->getPath($id, 0, $ext, $lang);
$path_thumbnail = $this->getPath($id, $type, $ext, $lang);
$ret = [
'id' => $id,
'src' => &$path_thumbnail,
'source' => &$path_thumbnail,
'descr' => $desc,
'width' => $settings['size'][0] ?? 0, // TODO: Revert, responsive types should not be accessed using getOldImageArray
'height' => $settings['size'][1] ?? 0,
'src_big' => &$path_large,
'source_big' => &$path_large,
'date_update' => $dateUpdate,
'type' => $this->getTypeName($type),
];
if ($data) {
$data = json_decode($data, true);
$ret = array_merge($data, $ret);
}
if (($dateUpdate ?? -1) > 0) {
$time_thumbnail = $time_large = (isFunctionalTests()) ? '' : $dateUpdate;
} else {
if (isLocalDevelopment()) {
$logger = ServiceContainer::getService('logger');
$logger->error('getOldImageArray bez data poslední změny '.$type, array_merge($ret, ['exception' => new SilencedErrorContext(1, '', 0, debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 5), 1)]));
}
$time_thumbnail = $time_large = '';
}
$imageVersion = '';
if (!isFunctionalTests()) {
$imageVersion = '_'.(\Settings::getDefault()->image_version ?? '1');
}
$path_thumbnail .= "?{$time_thumbnail}{$imageVersion}";
$path_large .= "?{$time_large}{$imageVersion}";
$path_thumbnail = $this->urlFinder->staticUrl($path_thumbnail);
$path_large = $this->urlFinder->staticUrl($path_large);
return $ret;
}
public function clearThumbnails($image_id, $version = null)
{
foreach ($this->getConfig()['id_to_type'] as $id => $type) {
foreach (glob($this->getPath($image_id, $id, '', null, $version).'*') as $filename) {
@unlink($filename);
}
}
return true;
}
/**
* @required
*/
public function setUrlFinder(UrlFinder $urlFinder): void
{
$this->urlFinder = $urlFinder;
}
}