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; } }