![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/magento/magento2-base/setup/src/Magento/Setup/Fixtures/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Setup\Fixtures; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\ValidatorException; use Magento\MediaStorage\Service\ImageResize; use Symfony\Component\Console\Output\OutputInterface; /** * Generate images per each product * Support next format: * <product-images> * <images-count>X</images-count> * <images-per-product>Y</images-per-product> * </product-images> * * Where * X - number of images to be generated * Y - number of images that will be assigned per each product * * note, that probably you would need to run command: * php bin/magento catalog:images:resize * to resize images after generation but be patient with it * because it can take pretty much time * * @see setup/performance-toolkit/profiles/ce/small.xml * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ImagesFixture extends Fixture { /** * @var int */ protected $priority = 51; /** * @var \Magento\Framework\App\ResourceConnection */ private $resourceConnection; /** * @var \Magento\Setup\Fixtures\ImagesGenerator\ImagesGeneratorFactory */ private $imagesGeneratorFactory; /** * @var \Magento\Framework\Filesystem */ private $filesystem; /** * @var \Magento\Catalog\Model\Product\Media\Config */ private $mediaConfig; /** * @var \Magento\Eav\Model\AttributeRepository */ private $attributeRepository; /** * @var \Magento\Framework\DB\Adapter\AdapterInterface */ private $dbConnection; /** * @var \Magento\Framework\DB\Sql\ColumnValueExpressionFactory */ private $expressionFactory; /** * @var \Magento\Setup\Model\BatchInsertFactory */ private $batchInsertFactory; /** * @var \Magento\Framework\EntityManager\MetadataPool */ private $metadataPool; /** * @var array */ private $attributeCodesCache = []; /** * @var int */ private $imagesInsertBatchSize = 1000; /** * @var int */ private $productsSelectBatchSize = 1000; /** * @var int */ private $productsCountCache; /** * @var array */ private $tableCache = []; /** * @var ImageResize */ private $imageResize; /** * @param FixtureModel $fixtureModel * @param \Magento\Framework\App\ResourceConnection $resourceConnection * @param ImagesGenerator\ImagesGeneratorFactory $imagesGeneratorFactory * @param \Magento\Framework\Filesystem $filesystem * @param \Magento\Catalog\Model\Product\Media\Config $mediaConfig * @param \Magento\Eav\Model\AttributeRepository $attributeRepository * @param \Magento\Framework\DB\Sql\ColumnValueExpressionFactory $expressionFactory * @param \Magento\Setup\Model\BatchInsertFactory $batchInsertFactory * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool * @param ImageResize $imageResize */ public function __construct( FixtureModel $fixtureModel, \Magento\Framework\App\ResourceConnection $resourceConnection, \Magento\Setup\Fixtures\ImagesGenerator\ImagesGeneratorFactory $imagesGeneratorFactory, \Magento\Framework\Filesystem $filesystem, \Magento\Catalog\Model\Product\Media\Config $mediaConfig, \Magento\Eav\Model\AttributeRepository $attributeRepository, \Magento\Framework\DB\Sql\ColumnValueExpressionFactory $expressionFactory, \Magento\Setup\Model\BatchInsertFactory $batchInsertFactory, \Magento\Framework\EntityManager\MetadataPool $metadataPool, ImageResize $imageResize ) { parent::__construct($fixtureModel); $this->imagesGeneratorFactory = $imagesGeneratorFactory; $this->resourceConnection = $resourceConnection; $this->filesystem = $filesystem; $this->mediaConfig = $mediaConfig; $this->attributeRepository = $attributeRepository; $this->expressionFactory = $expressionFactory; $this->batchInsertFactory = $batchInsertFactory; $this->metadataPool = $metadataPool; $this->imageResize = $imageResize; } /** * {@inheritdoc} * @throws \Exception */ public function execute() { if (!$this->checkIfImagesExists() && $this->getImagesToGenerate()) { $this->createImageEntities(); $this->assignImagesToProducts(); iterator_to_array($this->imageResize->resizeFromThemes(), false); } } /** * {@inheritdoc} */ public function getActionTitle() { return 'Generating images'; } /** * {@inheritdoc} */ public function introduceParamLabels() { return [ 'product-images' => 'Product Images' ]; } /** * {@inheritdoc} * @throws ValidatorException */ public function printInfo(OutputInterface $output) { $config = $this->fixtureModel->getValue('product-images', []); if (!$config) { return; } if (!isset($config['images-count'])) { throw new ValidatorException( __("The amount of images to generate wasn't specified. Enter the amount and try again.") ); } if (!isset($config['images-per-product'])) { throw new ValidatorException( __("The amount of images per product wasn't specified. Enter the amount and try again.") ); } $output->writeln( sprintf( '<info> |- Product images: %s, %s per product</info>', $config['images-count'], $config['images-per-product'] ) ); } /** * Check if DB already has any images * * @return bool */ private function checkIfImagesExists() { return $this->getImagesCount() > 0; } /** * Create image file and add it to media gallery table in DB * * @return void */ private function createImageEntities() { /** @var \Magento\Setup\Model\BatchInsert $batchInsert */ $batchInsert = $this->batchInsertFactory->create([ 'insertIntoTable' => $this->getTable('catalog_product_entity_media_gallery'), 'batchSize' => $this->imagesInsertBatchSize ]); foreach ($this->generateImageFilesGenerator() as $imageName) { $batchInsert->insert([ 'attribute_id' => $this->getAttributeId('media_gallery'), 'value' => $imageName, ]); } $batchInsert->flush(); } /** * Create generator that creates image files and puts them to appropriate media folder * in memory-safe way * * @return \Generator * @throws \Magento\Framework\Exception\FileSystemException */ private function generateImageFilesGenerator() { /** @var \Magento\Setup\Fixtures\ImagesGenerator\ImagesGenerator $imagesGenerator */ $imagesGenerator = $this->imagesGeneratorFactory->create(); $mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); $productImagesDirectoryPath = $mediaDirectory->getRelativePath($this->mediaConfig->getBaseMediaPath()); for ($i = 1; $i <= $this->getImagesToGenerate(); $i++) { // md5() here is not for cryptographic use. // phpcs:ignore Magento2.Security.InsecureFunction $imageName = md5($i) . '.jpg'; $imageFullName = DIRECTORY_SEPARATOR . substr($imageName, 0, 1) . DIRECTORY_SEPARATOR . substr($imageName, 1, 1) . DIRECTORY_SEPARATOR . $imageName; $imagePath = $imagesGenerator->generate([ 'image-width' => 300, 'image-height' => 300, 'image-name' => $imageName ]); $mediaDirectory->renameFile( $mediaDirectory->getRelativePath($imagePath), $productImagesDirectoryPath . $imageFullName ); yield $imageFullName; } } /** * Assign created images to products according to Y images per each product * * @return void * @throws \Exception */ private function assignImagesToProducts() { /** @var \Magento\Setup\Model\BatchInsert $batchInsertCatalogProductEntityVarchar */ $batchInsertCatalogProductEntityVarchar = $this->batchInsertFactory->create([ 'insertIntoTable' => $this->getTable('catalog_product_entity_varchar'), 'batchSize' => $this->imagesInsertBatchSize ]); /** @var \Magento\Setup\Model\BatchInsert $batchInsertCatalogProductEntityMediaGalleryValue */ $batchInsertCatalogProductEntityMediaGalleryValue = $this->batchInsertFactory->create([ 'insertIntoTable' => $this->getTable('catalog_product_entity_media_gallery_value'), 'batchSize' => $this->imagesInsertBatchSize ]); /** @var \Magento\Setup\Model\BatchInsert $batchInsertCatalogProductEntityMediaGalleryValueToEntity */ $batchInsertCatalogProductEntityMediaGalleryValueToEntity = $this->batchInsertFactory->create([ 'insertIntoTable' => $this->getTable('catalog_product_entity_media_gallery_value_to_entity'), 'batchSize' => $this->imagesInsertBatchSize ]); $imageGenerator = $this->getImagesGenerator(); foreach ($this->getProductGenerator() as $productEntity) { for ($imageNum = 1; $imageNum <= $this->getImagesPerProduct(); $imageNum++) { $image = $imageGenerator->current(); $imageGenerator->next(); if ($imageNum === 1) { $attributes = ['image', 'small_image', 'thumbnail', 'swatch_image']; foreach ($attributes as $attr) { $batchInsertCatalogProductEntityVarchar->insert([ $this->getProductLinkField() => $productEntity[$this->getProductLinkField()], 'attribute_id' => $this->getAttributeId($attr), 'value' => $image['value'], 'store_id' => 0, ]); } } $batchInsertCatalogProductEntityMediaGalleryValueToEntity->insert([ 'value_id' => $image['value_id'], $this->getProductLinkField() => $productEntity[$this->getProductLinkField()] ]); $batchInsertCatalogProductEntityMediaGalleryValue->insert([ 'value_id' => $image['value_id'], 'store_id' => 0, $this->getProductLinkField() => $productEntity[$this->getProductLinkField()], 'position' => $image['value_id'], 'disabled' => 0 ]); } } $batchInsertCatalogProductEntityVarchar->flush(); $batchInsertCatalogProductEntityMediaGalleryValue->flush(); $batchInsertCatalogProductEntityMediaGalleryValueToEntity->flush(); } /** * Returns generator to iterate in memory-safe way over all product entities in DB * * @return \Generator * @throws \Exception */ private function getProductGenerator() { $offset = 0; $products = $this->getProducts($this->productsSelectBatchSize, $offset); $offset += $this->productsSelectBatchSize; while (true) { yield current($products); if (next($products) === false) { $products = $this->getProducts($this->productsSelectBatchSize, $offset); $offset += $this->productsSelectBatchSize; if (empty($products)) { break; } } } } /** * Get products entity ids * * @param int $limit * @param int $offset * @return array * @throws \Exception */ private function getProducts($limit, $offset) { $select = $this->getDbConnection() ->select() ->from(['product_entity' => $this->getTable('catalog_product_entity')], []) ->columns([$this->getProductLinkField()]) ->limit($limit, $offset); return $this->getDbConnection()->fetchAssoc($select); } /** * Creates generator to iterate infinitely over all image entities * * @return \Generator */ private function getImagesGenerator() { $select = $this->getDbConnection() ->select() ->from( $this->getTable('catalog_product_entity_media_gallery'), ['value_id', 'value'] )->order('value_id desc') ->limit($this->getProductsCount() * $this->getImagesPerProduct()); $images = $this->getDbConnection()->fetchAssoc($select); while (true) { yield current($images); if (next($images) === false) { reset($images); } } } /** * Return number of images to create * * @return null|int */ private function getImagesToGenerate() { $config = $this->fixtureModel->getValue('product-images', []); return $config['images-count'] ?? null; } /** * Return number of images to be assigned per each product * * @return null|int */ private function getImagesPerProduct() { $config = $this->fixtureModel->getValue('product-images', []); return $config['images-per-product'] ?? null; } /** * Get amount of existing products * * @return int */ private function getProductsCount() { if ($this->productsCountCache === null) { $select = $select = $this->getDbConnection() ->select() ->from(['product_entity' => $this->getTable('catalog_product_entity')], []) ->columns([ 'count' => $this->expressionFactory->create([ 'expression' => 'COUNT(*)' ]) ]); $this->productsCountCache = (int) $this->getDbConnection()->fetchOne($select); } return $this->productsCountCache; } /** * Get amount of existing images * * @return int */ private function getImagesCount() { $select = $select = $this->getDbConnection() ->select() ->from(['product_entity' => $this->getTable('catalog_product_entity_media_gallery')], []) ->columns([ 'count' => $this->expressionFactory->create([ 'expression' => 'COUNT(*)' ]) ])->where('media_type="image"'); return (int) $this->getDbConnection()->fetchOne($select); } /** * Get eav attribute id by its code * * @param string $attributeCode * @return int * @throws \Magento\Framework\Exception\NoSuchEntityException */ private function getAttributeId($attributeCode) { if (!isset($this->attributeCodesCache[$attributeCode])) { $attribute = $this->attributeRepository->get( 'catalog_product', $attributeCode ); $this->attributeCodesCache[$attributeCode] = $attribute->getAttributeId(); } return $this->attributeCodesCache[$attributeCode]; } /** * Retrieve current connection to DB * * Method is required to eliminate multiple calls to ResourceConnection class * * @return \Magento\Framework\DB\Adapter\AdapterInterface */ private function getDbConnection() { if ($this->dbConnection === null) { $this->dbConnection = $this->resourceConnection->getConnection(); } return $this->dbConnection; } /** * Retrieve real table name * * Method act like a cache for already retrieved table names * is required to eliminate multiple calls to ResourceConnection class * * @param string $tableName * @return string */ private function getTable($tableName) { if (!isset($this->tableCache[$tableName])) { $this->tableCache[$tableName] = $this->resourceConnection->getTableName($tableName); } return $this->tableCache[$tableName]; } /** * Return product id field name - entity_id|row_id * * @return string * @throws \Exception */ private function getProductLinkField() { return $this->metadataPool ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class) ->getLinkField(); } }