Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
ImagesFixture.php
Go to the documentation of this file.
1 <?php
7 namespace Magento\Setup\Fixtures;
8 
11 use Symfony\Component\Console\Output\OutputInterface;
12 
33 class ImagesFixture extends Fixture
34 {
38  protected $priority = 51;
39 
43  private $resourceConnection;
44 
48  private $imagesGeneratorFactory;
49 
53  private $filesystem;
54 
58  private $mediaConfig;
59 
63  private $attributeRepository;
64 
68  private $dbConnection;
69 
73  private $expressionFactory;
74 
78  private $batchInsertFactory;
79 
83  private $metadataPool;
84 
88  private $attributeCodesCache = [];
89 
93  private $imagesInsertBatchSize = 1000;
94 
98  private $productsSelectBatchSize = 1000;
99 
103  private $productsCountCache;
104 
108  private $tableCache = [];
109 
121  public function __construct(
123  \Magento\Framework\App\ResourceConnection $resourceConnection,
124  \Magento\Setup\Fixtures\ImagesGenerator\ImagesGeneratorFactory $imagesGeneratorFactory,
125  \Magento\Framework\Filesystem $filesystem,
126  \Magento\Catalog\Model\Product\Media\Config $mediaConfig,
127  \Magento\Eav\Model\AttributeRepository $attributeRepository,
128  \Magento\Framework\DB\Sql\ColumnValueExpressionFactory $expressionFactory,
129  \Magento\Setup\Model\BatchInsertFactory $batchInsertFactory,
130  \Magento\Framework\EntityManager\MetadataPool $metadataPool
131  ) {
132  parent::__construct($fixtureModel);
133 
134  $this->imagesGeneratorFactory = $imagesGeneratorFactory;
135  $this->resourceConnection = $resourceConnection;
136  $this->filesystem = $filesystem;
137  $this->mediaConfig = $mediaConfig;
138  $this->attributeRepository = $attributeRepository;
139  $this->expressionFactory = $expressionFactory;
140  $this->batchInsertFactory = $batchInsertFactory;
141  $this->metadataPool = $metadataPool;
142  }
143 
148  public function execute()
149  {
150  if (!$this->checkIfImagesExists()) {
151  $this->createImageEntities();
152  $this->assignImagesToProducts();
153  }
154  }
155 
159  public function getActionTitle()
160  {
161  return 'Generating images';
162  }
163 
167  public function introduceParamLabels()
168  {
169  return [
170  'product-images' => 'Product Images'
171  ];
172  }
173 
178  public function printInfo(OutputInterface $output)
179  {
180  $config = $this->fixtureModel->getValue('product-images', []);
181  if (!$config) {
182  return;
183  }
184 
185  if (!isset($config['images-count'])) {
186  throw new ValidatorException(
187  __("The amount of images to generate wasn't specified. Enter the amount and try again.")
188  );
189  }
190 
191  if (!isset($config['images-per-product'])) {
192  throw new ValidatorException(
193  __("The amount of images per product wasn't specified. Enter the amount and try again.")
194  );
195  }
196 
197  $output->writeln(
198  sprintf(
199  '<info> |- Product images: %s, %s per product</info>',
200  $config['images-count'],
201  $config['images-per-product']
202  )
203  );
204  }
205 
211  private function checkIfImagesExists()
212  {
213  return $this->getImagesCount() > 0;
214  }
215 
221  private function createImageEntities()
222  {
224  $batchInsert = $this->batchInsertFactory->create([
225  'insertIntoTable' => $this->getTable('catalog_product_entity_media_gallery'),
226  'batchSize' => $this->imagesInsertBatchSize
227  ]);
228 
229  foreach ($this->generateImageFilesGenerator() as $imageName) {
230  $batchInsert->insert([
231  'attribute_id' => $this->getAttributeId('media_gallery'),
232  'value' => $imageName,
233  ]);
234  }
235 
236  $batchInsert->flush();
237  }
238 
246  private function generateImageFilesGenerator()
247  {
249  $imagesGenerator = $this->imagesGeneratorFactory->create();
250  $mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA);
251  $productImagesDirectoryPath = $mediaDirectory->getRelativePath($this->mediaConfig->getBaseMediaPath());
252 
253  for ($i = 1; $i <= $this->getImagesToGenerate(); $i++) {
254  $imageName = md5($i) . '.jpg';
255  $imageFullName = DIRECTORY_SEPARATOR . substr($imageName, 0, 1)
256  . DIRECTORY_SEPARATOR . substr($imageName, 1, 1)
257  . DIRECTORY_SEPARATOR . $imageName;
258 
259  $imagePath = $imagesGenerator->generate([
260  'image-width' => 300,
261  'image-height' => 300,
262  'image-name' => $imageName
263  ]);
264 
265  $mediaDirectory->renameFile(
266  $mediaDirectory->getRelativePath($imagePath),
267  $productImagesDirectoryPath . $imageFullName
268  );
269 
270  yield $imageFullName;
271  }
272  }
273 
280  private function assignImagesToProducts()
281  {
283  $batchInsertCatalogProductEntityVarchar = $this->batchInsertFactory->create([
284  'insertIntoTable' => $this->getTable('catalog_product_entity_varchar'),
285  'batchSize' => $this->imagesInsertBatchSize
286  ]);
287 
289  $batchInsertCatalogProductEntityMediaGalleryValue = $this->batchInsertFactory->create([
290  'insertIntoTable' => $this->getTable('catalog_product_entity_media_gallery_value'),
291  'batchSize' => $this->imagesInsertBatchSize
292  ]);
293 
295  $batchInsertCatalogProductEntityMediaGalleryValueToEntity = $this->batchInsertFactory->create([
296  'insertIntoTable' => $this->getTable('catalog_product_entity_media_gallery_value_to_entity'),
297  'batchSize' => $this->imagesInsertBatchSize
298  ]);
299 
300  $imageGenerator = $this->getImagesGenerator();
301 
302  foreach ($this->getProductGenerator() as $productEntity) {
303  for ($imageNum = 1; $imageNum <= $this->getImagesPerProduct(); $imageNum++) {
304  $image = $imageGenerator->current();
305  $imageGenerator->next();
306 
307  if ($imageNum === 1) {
308  $attributes = ['image', 'small_image', 'thumbnail', 'swatch_image'];
309  foreach ($attributes as $attr) {
310  $batchInsertCatalogProductEntityVarchar->insert([
311  $this->getProductLinkField() => $productEntity[$this->getProductLinkField()],
312  'attribute_id' => $this->getAttributeId($attr),
313  'value' => $image['value'],
314  'store_id' => 0,
315  ]);
316  }
317  }
318 
319  $batchInsertCatalogProductEntityMediaGalleryValueToEntity->insert([
320  'value_id' => $image['value_id'],
321  $this->getProductLinkField() => $productEntity[$this->getProductLinkField()]
322  ]);
323 
324  $batchInsertCatalogProductEntityMediaGalleryValue->insert([
325  'value_id' => $image['value_id'],
326  'store_id' => 0,
327  $this->getProductLinkField() => $productEntity[$this->getProductLinkField()],
328  'position' => $image['value_id'],
329  'disabled' => 0
330  ]);
331  }
332  }
333 
334  $batchInsertCatalogProductEntityVarchar->flush();
335  $batchInsertCatalogProductEntityMediaGalleryValue->flush();
336  $batchInsertCatalogProductEntityMediaGalleryValueToEntity->flush();
337  }
338 
345  private function getProductGenerator()
346  {
347  $offset = 0;
348 
349  $products = $this->getProducts($this->productsSelectBatchSize, $offset);
350  $offset += $this->productsSelectBatchSize;
351 
352  while (true) {
353  yield current($products);
354 
355  if (next($products) === false) {
356  $products = $this->getProducts($this->productsSelectBatchSize, $offset);
357  $offset += $this->productsSelectBatchSize;
358 
359  if (empty($products)) {
360  break;
361  }
362  }
363  }
364  }
365 
374  private function getProducts($limit, $offset)
375  {
376  $select = $this->getDbConnection()
377  ->select()
378  ->from(['product_entity' => $this->getTable('catalog_product_entity')], [])
379  ->columns([$this->getProductLinkField()])
380  ->limit($limit, $offset);
381 
382  return $this->getDbConnection()->fetchAssoc($select);
383  }
384 
390  private function getImagesGenerator()
391  {
392  $select = $this->getDbConnection()
393  ->select()
394  ->from(
395  $this->getTable('catalog_product_entity_media_gallery'),
396  ['value_id', 'value']
397  )->order('value_id desc')
398  ->limit($this->getProductsCount() * $this->getImagesPerProduct());
399 
400  $images = $this->getDbConnection()->fetchAssoc($select);
401 
402  while (true) {
403  yield current($images);
404 
405  if (next($images) === false) {
406  reset($images);
407  }
408  }
409  }
410 
416  private function getImagesToGenerate()
417  {
418  $config = $this->fixtureModel->getValue('product-images', []);
419 
420  return $config['images-count'] ?? null;
421  }
422 
428  private function getImagesPerProduct()
429  {
430  $config = $this->fixtureModel->getValue('product-images', []);
431 
432  return $config['images-per-product'] ?? null;
433  }
434 
440  private function getProductsCount()
441  {
442  if ($this->productsCountCache === null) {
443  $select = $select = $this->getDbConnection()
444  ->select()
445  ->from(['product_entity' => $this->getTable('catalog_product_entity')], [])
446  ->columns([
447  'count' => $this->expressionFactory->create([
448  'expression' => 'COUNT(*)'
449  ])
450  ]);
451 
452  $this->productsCountCache = (int) $this->getDbConnection()->fetchOne($select);
453  }
454 
455  return $this->productsCountCache;
456  }
457 
463  private function getImagesCount()
464  {
465  $select = $select = $this->getDbConnection()
466  ->select()
467  ->from(['product_entity' => $this->getTable('catalog_product_entity_media_gallery')], [])
468  ->columns([
469  'count' => $this->expressionFactory->create([
470  'expression' => 'COUNT(*)'
471  ])
472  ])->where('media_type="image"');
473 
474  return (int) $this->getDbConnection()->fetchOne($select);
475  }
476 
484  private function getAttributeId($attributeCode)
485  {
486  if (!isset($this->attributeCodesCache[$attributeCode])) {
487  $attribute = $this->attributeRepository->get(
488  'catalog_product',
490  );
491 
492  $this->attributeCodesCache[$attributeCode] = $attribute->getAttributeId();
493  }
494 
495  return $this->attributeCodesCache[$attributeCode];
496  }
497 
505  private function getDbConnection()
506  {
507  if ($this->dbConnection === null) {
508  $this->dbConnection = $this->resourceConnection->getConnection();
509  }
510 
511  return $this->dbConnection;
512  }
513 
523  private function getTable($tableName)
524  {
525  if (!isset($this->tableCache[$tableName])) {
526  $this->tableCache[$tableName] = $this->resourceConnection->getTableName($tableName);
527  }
528 
529  return $this->tableCache[$tableName];
530  }
531 
538  private function getProductLinkField()
539  {
540  return $this->metadataPool
541  ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
542  ->getLinkField();
543  }
544 }
$tableName
Definition: trigger.php:13
$attr
Definition: text.phtml:8
$config
Definition: fraud_order.php:17
__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)
__()
Definition: __.php:13
printInfo(OutputInterface $output)
$attributeCode
Definition: extend.phtml:12
$attributes
Definition: matrix.phtml:13
$mediaDirectory
$filesystem
$i
Definition: gallery.phtml:31
$mediaConfig