Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- namespace DBTech\eCommerce\Service\Product;
- use DBTech\eCommerce\Entity\Product;
- use XF\App;
- use XF\Http\Upload;
- use XF\Image\Imagick;
- use XF\Phrase;
- use XF\PrintableException;
- use XF\Repository\IpRepository;
- use XF\Service\AbstractService;
- use XF\Util\File;
- class IconService extends AbstractService
- {
- protected Product $product;
- protected bool $logIp = true;
- protected ?string $fileName = null;
- protected string $extension;
- protected int $width;
- protected int $height;
- protected int $type;
- protected ?Phrase $error = null;
- protected array $allowedTypes = [IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_WEBP];
- /**
- * @param App $app
- * @param Product $product
- */
- public function __construct(App $app, Product $product)
- {
- parent::__construct($app);
- $this->product = $product;
- }
- /**
- * @return Product
- */
- public function getProduct(): Product
- {
- return $this->product;
- }
- /**
- * @param bool $logIp
- */
- public function logIp(bool $logIp): void
- {
- $this->logIp = $logIp;
- }
- /**
- * @return Phrase|null
- */
- public function getError(): ?Phrase
- {
- return $this->error;
- }
- /**
- * @param string $fileName
- *
- * @return bool
- * @throws \InvalidArgumentException
- */
- public function setImage(string $fileName): bool
- {
- if (!$this->validateImageAsIcon($fileName, $error))
- {
- $this->error = $error;
- $this->fileName = null;
- return false;
- }
- $this->fileName = $fileName;
- return true;
- }
- /**
- * @param string $fileName
- *
- * @return bool
- */
- public function setSvgImage(string $fileName): bool
- {
- $this->_setImageBypass($fileName);
- return true;
- }
- /**
- * @param string $fileName
- *
- * @return bool
- */
- public function setWebpImage(string $fileName): bool
- {
- $this->_setImageBypass($fileName);
- return true;
- }
- /**
- * @param string $fileName
- *
- * @return void
- */
- protected function _setImageBypass(string $fileName): void
- {
- $this->width = \XF::app()->options()->dbtechEcommerceProductIconMaxDimensions['width'] ?:
- \XF::app()->container('avatarSizeMap')['l'];
- $this->height = \XF::app()->options()->dbtechEcommerceProductIconMaxDimensions['height'] ?:
- \XF::app()->container('avatarSizeMap')['l'];
- $this->fileName = $fileName;
- }
- /**
- * @param Upload $upload
- *
- * @return bool
- * @throws \InvalidArgumentException
- */
- public function setImageFromUpload(Upload $upload): bool
- {
- $this->extension = strtolower($upload->getExtension());
- if ($this->extension === 'svg')
- {
- return $this->setSvgImage($upload->getTempFile());
- }
- else if ($this->extension === 'webp' && !\XF::isAddOnActive('DBTech/WebP'))
- {
- return $this->setWebpImage($upload->getTempFile());
- }
- else
- {
- $upload->requireImage();
- if (!$upload->isValid($errors))
- {
- $this->error = reset($errors);
- return false;
- }
- return $this->setImage($upload->getTempFile());
- }
- }
- public function setImageFromExisting(): bool
- {
- $this->extension = $this->product->icon_extension;
- $path = $this->product->getAbstractedIconPath(null, $this->extension);
- if (!\XF::app()->fs()->has($path))
- {
- throw new \InvalidArgumentException(
- "Product does not have an icon ({$path})"
- );
- }
- $tempFile = File::copyAbstractedPathToTempFile($path);
- return $this->setImage($tempFile);
- }
- /**
- * @param string $fileName
- * @param null $error
- *
- * @return bool
- * @throws \InvalidArgumentException
- */
- public function validateImageAsIcon(string $fileName, &$error = null): bool
- {
- $error = null;
- if (!file_exists($fileName))
- {
- throw new \InvalidArgumentException("Invalid file '$fileName' passed to icon service");
- }
- if (!is_readable($fileName))
- {
- throw new \InvalidArgumentException("'$fileName' passed to icon service is not readable");
- }
- $imageInfo = filesize($fileName) ? getimagesize($fileName) : false;
- if (!$imageInfo)
- {
- $error = \XF::phrase('provided_file_is_not_valid_image');
- return false;
- }
- $type = $imageInfo[2];
- if (!in_array($type, $this->allowedTypes))
- {
- $error = \XF::phrase('provided_file_is_not_valid_image');
- return false;
- }
- [$width, $height] = $imageInfo;
- if (!\XF::app()->imageManager()->canResize($width, $height))
- {
- $error = \XF::phrase('uploaded_image_is_too_big');
- return false;
- }
- $this->width = $width;
- $this->height = $height;
- return true;
- }
- // This function has been edited by MYCODE
- public function updateIcon(): bool
- {
- if (!$this->fileName) {
- throw new \LogicException('No source file for icon set');
- }
- $imageManager = \XF::app()->imageManager();
- $targetWidth = \XF::app()->options()->dbtechEcommerceProductIconMaxDimensions['width'] ?:
- \XF::app()->container('avatarSizeMap')['l'];
- $targetHeight = \XF::app()->options()->dbtechEcommerceProductIconMaxDimensions['height'] ?:
- \XF::app()->container('avatarSizeMap')['l'];
- $outputFile = null;
- if ($this->extension === 'svg') {
- // Handle SVG specifically
- $svgContent = file_get_contents($this->fileName);
- if (!$svgContent) {
- throw new \RuntimeException('Failed to read SVG file');
- }
- // Basic validation for SVG content
- if (strpos($svgContent, '<svg') === false) {
- throw new \InvalidArgumentException('File is not a valid SVG');
- }
- // Optimize SVG if necessary (you might need an SVG optimization library like SVGO)
- // This is a placeholder for SVG optimization
- if ($this->app->options()->imageOptimization === 'optimize') {
- // Here you would implement SVG optimization. For now, it's just kept as a comment.
- // $optimizedSvg = // optimize svg content here
- }
- // Assuming no changes needed for SVG content in this context, keep original
- $outputFile = $this->fileName; // Use original SVG file directly
- // Unlike raster images, vector SVGs don't need resizing in the same way
- } else {
- // Handle non-SVG (raster) images
- $baseImage = $imageManager->imageFromFile($this->fileName);
- if (!$baseImage) {
- throw new \RuntimeException('Failed to load image from file');
- }
- $isOptimized = $baseImage->getType() === IMAGETYPE_WEBP;
- unset($baseImage);
- if ($this->width != $targetWidth || $this->height != $targetHeight) {
- $image = $imageManager->imageFromFile($this->fileName);
- if (!$image) {
- throw new \RuntimeException('Failed to load image from file for resizing');
- }
- $image->resizeAndCrop($targetWidth, $targetHeight);
- $newTempFile = File::getTempFile();
- if ($newTempFile && $image->save($newTempFile)) {
- $outputFile = $newTempFile;
- }
- } else {
- $outputFile = $this->fileName;
- }
- }
- if (!$outputFile) {
- throw new \RuntimeException('Failed to save image to temporary file; check internal_data/data permissions');
- }
- $dataFile = $this->product->getAbstractedIconPath(null, $this->extension);
- File::copyFileToAbstractedPath($outputFile, $dataFile);
- $this->product->icon_date = \XF::$time;
- $this->product->icon_extension = $this->extension;
- $this->product->icon_optimized = $this->extension === 'svg' || $isOptimized;
- $this->product->save();
- if ($this->logIp) {
- $ip = ($this->logIp === true ? \XF::app()->request()->getIp() : $this->logIp);
- $this->writeIpLog('update', $ip);
- }
- return true;
- }
- /**
- * @return void
- * @throws PrintableException
- */
- public function optimizeExistingIcon(): void
- {
- if ($this->app->options()->imageOptimization !== 'optimize')
- {
- return;
- }
- $this->setImageFromExisting();
- $imageManager = $this->app->imageManager();
- $image = $imageManager->imageFromFile($this->fileName);
- if (!$image)
- {
- return;
- }
- $success = $image->optimizeImage($this->fileName);
- if ($success)
- {
- // We can change extension to webp
- $this->extension = 'webp';
- $this->updateIcon();
- }
- }
- /**
- * @return bool
- * @throws \LogicException
- * @throws \Exception
- * @throws PrintableException
- */
- public function deleteIcon(): bool
- {
- $this->deleteIconFiles();
- $this->product->icon_date = 0;
- $this->product->icon_optimized = false;
- $this->product->save();
- if ($this->logIp)
- {
- $ip = ($this->logIp === true ? \XF::app()->request()->getIp() : $this->logIp);
- $this->writeIpLog('delete', $ip);
- }
- return true;
- }
- /**
- * @return bool
- */
- public function deleteIconForProductDelete(): bool
- {
- $this->deleteIconFiles();
- return true;
- }
- /**
- *
- */
- protected function deleteIconFiles(): void
- {
- if ($this->product->icon_date)
- {
- File::deleteFromAbstractedPath($this->product->getAbstractedIconPath());
- }
- }
- /**
- * @param string $action
- * @param string $ip
- */
- protected function writeIpLog(string $action, string $ip): void
- {
- $product = $this->product;
- $ipRepo = \XF::app()->repository(IpRepository::class);
- $ipRepo->logIp(
- \XF::visitor()->user_id,
- $ip,
- 'dbtech_ecommerce_product',
- $product->product_id,
- 'icon_' . $action
- );
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement