Skip to content

Instantly share code, notes, and snippets.

@vmasciotta
Created August 22, 2019 14:06
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vmasciotta/f14586a9a41fa4ec999d81bb88e0f2eb to your computer and use it in GitHub Desktop.
Save vmasciotta/f14586a9a41fa4ec999d81bb88e0f2eb to your computer and use it in GitHub Desktop.
Fix error catalog placeholder Magento 2.3 - https://github.com/magento/magento2/issues/19710

magento/magento2#19710

Temporary fix for placeholder issue

Replace the following files:

module-catalog/Model/Product/Image/ParamsBuilder.php
module-media-storage/Service/ImageResize.php
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\MediaStorage\Service;
use Magento\Catalog\Helper\Image as ImageHelper;
use Magento\Catalog\Model\Product\Image\ParamsBuilder;
use Magento\Catalog\Model\View\Asset\ImageFactory as AssertImageFactory;
use Magento\Framework\App\Area;
use Magento\Framework\Exception\NotFoundException;
use Magento\Framework\Filesystem;
use Magento\Framework\Image;
use Magento\Framework\Image\Factory as ImageFactory;
use Magento\Catalog\Model\Product\Media\ConfigInterface as MediaConfig;
use Magento\Framework\App\State;
use Magento\Framework\View\ConfigInterface as ViewConfig;
use \Magento\Catalog\Model\ResourceModel\Product\Image as ProductImage;
use Magento\Theme\Model\Config\Customization as ThemeCustomizationConfig;
use Magento\Theme\Model\ResourceModel\Theme\Collection;
use Magento\Framework\App\Filesystem\DirectoryList;
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class ImageResize
{
/**
* @var State
*/
private $appState;
/**
* @var MediaConfig
*/
private $imageConfig;
/**
* @var ProductImage
*/
private $productImage;
/**
* @var ImageFactory
*/
private $imageFactory;
/**
* @var ParamsBuilder
*/
private $paramsBuilder;
/**
* @var ViewConfig
*/
private $viewConfig;
/**
* @var AssertImageFactory
*/
private $assertImageFactory;
/**
* @var ThemeCustomizationConfig
*/
private $themeCustomizationConfig;
/**
* @var Collection
*/
private $themeCollection;
/**
* @var Filesystem
*/
private $mediaDirectory;
/**
* @var Filesystem
*/
private $filesystem;
/**
* @param State $appState
* @param MediaConfig $imageConfig
* @param ProductImage $productImage
* @param ImageFactory $imageFactory
* @param ParamsBuilder $paramsBuilder
* @param ViewConfig $viewConfig
* @param AssertImageFactory $assertImageFactory
* @param ThemeCustomizationConfig $themeCustomizationConfig
* @param Collection $themeCollection
* @param Filesystem $filesystem
* @internal param ProductImage $gallery
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
State $appState,
MediaConfig $imageConfig,
ProductImage $productImage,
ImageFactory $imageFactory,
ParamsBuilder $paramsBuilder,
ViewConfig $viewConfig,
AssertImageFactory $assertImageFactory,
ThemeCustomizationConfig $themeCustomizationConfig,
Collection $themeCollection,
Filesystem $filesystem,
\Magento\Store\Model\StoreManagerInterface $storeManager
) {
$this->appState = $appState;
$this->imageConfig = $imageConfig;
$this->productImage = $productImage;
$this->imageFactory = $imageFactory;
$this->paramsBuilder = $paramsBuilder;
$this->viewConfig = $viewConfig;
$this->assertImageFactory = $assertImageFactory;
$this->themeCustomizationConfig = $themeCustomizationConfig;
$this->themeCollection = $themeCollection;
$this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
$this->filesystem = $filesystem;
$this->storeManager = $storeManager;
}
/**
* Create resized images of different sizes from an original image
* @param string $originalImageName
* @throws NotFoundException
*/
public function resizeFromImageName(string $originalImageName)
{
$originalImagePath = $this->mediaDirectory->getAbsolutePath(
$this->imageConfig->getMediaPath($originalImageName)
);
if (!$this->mediaDirectory->isFile($originalImagePath)) {
throw new NotFoundException(__('Cannot resize image "%1" - original image not found', $originalImagePath));
}
$storeIds = $this->storeManager->getStores();
foreach($storeIds as $store){
foreach ($this->getViewImages($this->getThemesInUse()) as $viewImage) {
$storeId = $store->getId();
$this->resize($viewImage, $originalImagePath, $originalImageName, $storeId);
}
}
}
/**
* Create resized images of different sizes from themes
* @param array|null $themes
* @return \Generator
* @throws NotFoundException
*/
public function resizeFromThemes(array $themes = null): \Generator
{
$count = $this->productImage->getCountAllProductImages();
if (!$count) {
throw new NotFoundException(__('Cannot resize images - product images not found'));
}
$productImages = $this->productImage->getAllProductImages();
$viewImages = $this->getViewImages($themes ?? $this->getThemesInUse());
foreach ($productImages as $image) {
$originalImageName = $image['filepath'];
$originalImagePath = $this->mediaDirectory->getAbsolutePath(
$this->imageConfig->getMediaPath($originalImageName)
);
foreach ($viewImages as $viewImage) {
$this->resize($viewImage, $originalImagePath, $originalImageName);
}
yield $originalImageName => $count;
}
}
/**
* Search the current theme
* @return array
*/
private function getThemesInUse(): array
{
$themesInUse = [];
$registeredThemes = $this->themeCollection->loadRegisteredThemes();
$storesByThemes = $this->themeCustomizationConfig->getStoresByThemes();
$keyType = is_integer(key($storesByThemes)) ? 'getId' : 'getCode';
foreach ($registeredThemes as $registeredTheme) {
if (array_key_exists($registeredTheme->$keyType(), $storesByThemes)) {
$themesInUse[] = $registeredTheme;
}
}
return $themesInUse;
}
/**
* Get view images data from themes
* @param array $themes
* @return array
*/
private function getViewImages(array $themes): array
{
$viewImages = [];
/** @var \Magento\Theme\Model\Theme $theme */
foreach ($themes as $theme) {
$config = $this->viewConfig->getViewConfig([
'area' => Area::AREA_FRONTEND,
'themeModel' => $theme,
]);
$images = $config->getMediaEntities('Magento_Catalog', ImageHelper::MEDIA_TYPE_CONFIG_NODE);
foreach ($images as $imageId => $imageData) {
$uniqIndex = $this->getUniqueImageIndex($imageData);
$imageData['id'] = $imageId;
$viewImages[$uniqIndex] = $imageData;
}
}
return $viewImages;
}
/**
* Get unique image index
* @param array $imageData
* @return string
*/
private function getUniqueImageIndex(array $imageData): string
{
ksort($imageData);
unset($imageData['type']);
return md5(json_encode($imageData));
}
/**
* Make image
* @param string $originalImagePath
* @param array $imageParams
* @return Image
*/
private function makeImage(string $originalImagePath, array $imageParams): Image
{
$image = $this->imageFactory->create($originalImagePath);
$image->keepAspectRatio($imageParams['keep_aspect_ratio']);
$image->keepFrame($imageParams['keep_frame']);
$image->keepTransparency($imageParams['keep_transparency']);
$image->constrainOnly($imageParams['constrain_only']);
$image->backgroundColor($imageParams['background']);
$image->quality($imageParams['quality']);
return $image;
}
/**
* Resize image
* @param array $viewImage
* @param string $originalImagePath
* @param string $originalImageName
*/
private function resize(array $viewImage, string $originalImagePath, string $originalImageName, string $storeId)
{
$this->paramsBuilder->setStoreId($storeId);
$imageParams = $this->paramsBuilder->build($viewImage);
$image = $this->makeImage($originalImagePath, $imageParams);
$imageAsset = $this->assertImageFactory->create(
[
'miscParams' => $imageParams,
'filePath' => $originalImageName,
]
);
#https://github.com/magento/magento2/commit/c7930eb37b29c3bc14735d048845278092fca053?diff=unified
if (isset($imageParams['watermark_file'])) {
if ($imageParams['watermark_height'] !== null) {
$image->setWatermarkHeight($imageParams['watermark_height']);
}
if ($imageParams['watermark_width'] !== null) {
$image->setWatermarkWidth($imageParams['watermark_width']);
}
if ($imageParams['watermark_position'] !== null) {
$image->setWatermarkPosition($imageParams['watermark_position']);
}
if ($imageParams['watermark_image_opacity'] !== null) {
$image->setWatermarkImageOpacity($imageParams['watermark_image_opacity']);
}
$image->watermark($this->getWatermarkFilePath($imageParams['watermark_file']));
}
#https://github.com/magento/magento2/commit/c7930eb37b29c3bc14735d048845278092fca053?diff=unified
if ($imageParams['image_width'] !== null && $imageParams['image_height'] !== null) {
$image->resize($imageParams['image_width'], $imageParams['image_height']);
}
$image->save($imageAsset->getPath());
}
#https://github.com/magento/magento2/commit/c7930eb37b29c3bc14735d048845278092fca053?diff=unified
/**
* Returns watermark file absolute path
*
* @param string $file
* @return string
*/
private function getWatermarkFilePath($file)
{
$path = $this->imageConfig->getMediaPath('/watermark/' . $file);
return $this->mediaDirectory->getAbsolutePath($path);
}
#https://github.com/magento/magento2/commit/c7930eb37b29c3bc14735d048845278092fca053?diff=unified
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Catalog\Model\Product\Image;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\View\ConfigInterface;
use Magento\Store\Model\ScopeInterface;
/**
* Builds parameters array used to build Image Asset
*/
class ParamsBuilder
{
/**
* @var int
*/
private $defaultQuality = 80;
/**
* @var array
*/
private $defaultBackground = [255, 255, 255];
/**
* @var int|null
*/
private $defaultAngle = null;
/**
* @var bool
*/
private $defaultKeepAspectRatio = true;
/**
* @var bool
*/
private $defaultKeepTransparency = true;
/**
* @var bool
*/
private $defaultConstrainOnly = true;
/**
* @var ScopeConfigInterface
*/
private $scopeConfig;
/**
* @var ConfigInterface
*/
private $viewConfig;
private $storeId;
/**
* @param ScopeConfigInterface $scopeConfig
* @param ConfigInterface $viewConfig
*/
public function __construct(
ScopeConfigInterface $scopeConfig,
ConfigInterface $viewConfig
) {
$this->scopeConfig = $scopeConfig;
$this->viewConfig = $viewConfig;
}
/**
* @param array $imageArguments
* @return array
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function build(array $imageArguments): array
{
$miscParams = [
'image_type' => $imageArguments['type'] ?? null,
'image_height' => $imageArguments['height'] ?? null,
'image_width' => $imageArguments['width'] ?? null,
];
$overwritten = $this->overwriteDefaultValues($imageArguments);
$watermark = isset($miscParams['image_type']) ? $this->getWatermark($miscParams['image_type']) : [];
return array_merge($miscParams, $overwritten, $watermark);
}
public function setStoreId($storeId): void
{
$this->storeId = $storeId;
}
/**
* @param array $imageArguments
* @return array
*/
private function overwriteDefaultValues(array $imageArguments): array
{
$frame = $imageArguments['frame'] ?? $this->hasDefaultFrame();
$constrain = $imageArguments['constrain'] ?? $this->defaultConstrainOnly;
$aspectRatio = $imageArguments['aspect_ratio'] ?? $this->defaultKeepAspectRatio;
$transparency = $imageArguments['transparency'] ?? $this->defaultKeepTransparency;
$background = $imageArguments['background'] ?? $this->defaultBackground;
$angle = $imageArguments['angle'] ?? $this->defaultAngle;
return [
'background' => (array) $background,
'angle' => $angle,
'quality' => $this->defaultQuality,
'keep_aspect_ratio' => (bool) $aspectRatio,
'keep_frame' => (bool) $frame,
'keep_transparency' => (bool) $transparency,
'constrain_only' => (bool) $constrain,
];
}
/**
* @param string $type
* @return array
*/
private function getWatermark(string $type): array
{
$storeId = $this->storeId;
$file = $this->scopeConfig->getValue(
"design/watermark/{$type}_image",
ScopeInterface::SCOPE_STORE
,$storeId
);
if ($file) {
$size = $this->scopeConfig->getValue(
"design/watermark/{$type}_size",
ScopeInterface::SCOPE_STORE
,$storeId
);
$opacity = $this->scopeConfig->getValue(
"design/watermark/{$type}_imageOpacity",
ScopeInterface::SCOPE_STORE
//,$storeId
);
$position = $this->scopeConfig->getValue(
"design/watermark/{$type}_position",
ScopeInterface::SCOPE_STORE
,$storeId
);
$width = !empty($size['width']) ? $size['width'] : null;
$height = !empty($size['height']) ? $size['height'] : null;
return [
'watermark_file' => $file,
'watermark_image_opacity' => $opacity,
'watermark_position' => $position,
'watermark_width' => $width,
'watermark_height' => $height
];
}
return [];
}
/**
* Get frame from product_image_white_borders
* @return bool
*/
private function hasDefaultFrame(): bool
{
return (bool) $this->viewConfig->getViewConfig()->getVarValue(
'Magento_Catalog',
'product_image_white_borders'
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment