Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
QuoteGenerator.php
Go to the documentation of this file.
1 <?php
8 
11 
18 {
24  const BATCH_SIZE = 1000;
25 
31  private $queryTemplates;
32 
38  private $resourceConnections;
39 
43  private $storeManager;
44 
48  private $productRepository;
49 
53  private $optionRepository;
54 
58  private $productCollectionFactory;
59 
63  private $linkManagement;
64 
68  private $serializer;
69 
73  private $productStubData;
74 
78  private $config;
79 
83  private $fixtureModel;
84 
95  public function __construct(
96  \Magento\Store\Model\StoreManagerInterface $storeManager,
97  \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
98  \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
99  \Magento\ConfigurableProduct\Api\OptionRepositoryInterface $optionRepository,
100  \Magento\ConfigurableProduct\Api\LinkManagementInterface $linkManagement,
101  \Magento\Framework\Serialize\SerializerInterface $serializer,
102  QuoteConfiguration $config,
103  \Magento\Setup\Fixtures\FixtureModel $fixtureModel
104  ) {
105  $this->storeManager = $storeManager;
106  $this->productCollectionFactory = $productCollectionFactory;
107  $this->productRepository = $productRepository;
108  $this->optionRepository = $optionRepository;
109  $this->linkManagement = $linkManagement;
110  $this->serializer = $serializer;
111  $this->config = $config;
112  $this->fixtureModel = $fixtureModel;
113  }
114 
121  public function generateQuotes()
122  {
123  $maxItemsPerOrder = $this->config->getSimpleCountTo()
124  + ($this->config->getConfigurableCountTo() + $this->config->getBigConfigurableCountTo()) * 2;
125 
126  $maxItemId = $this->getMaxEntityId(
127  'quote_item',
128  \Magento\Quote\Model\ResourceModel\Quote\Item::class,
129  'item_id'
130  );
132  $itemIdSequence = $this->getItemIdSequence(
133  $maxItemId,
134  $this->config->getRequiredQuoteQuantity(),
135  $maxItemsPerOrder
136  );
137  $this->productStubData = $this->prepareProductsForQuote();
138  $this->prepareQueryTemplates();
139 
140  $entityId = $this->getMaxEntityId('quote', \Magento\Quote\Model\ResourceModel\Quote::class, 'entity_id');
141  $quoteQty = $this->config->getExistsQuoteQuantity();
142  $batchNumber = 0;
143  while ($quoteQty < $this->config->getRequiredQuoteQuantity()) {
144  $entityId++;
145  $batchNumber++;
146  $quoteQty++;
147 
148  try {
149  $this->saveQuoteWithQuoteItems($entityId, $itemIdSequence);
150  } catch (\Exception $lastException) {
151  foreach ($this->resourceConnections as $connection) {
152  if ($connection->getTransactionLevel() > 0) {
153  $connection->rollBack();
154  }
155  }
156  throw $lastException;
157  }
158 
159  if ($batchNumber >= self::BATCH_SIZE) {
160  $this->commitBatch();
161  $batchNumber = 0;
162  }
163  }
164 
165  foreach ($this->resourceConnections as $connection) {
166  if ($connection->getTransactionLevel() > 0) {
167  $connection->commit();
168  }
169  }
170  }
171 
179  private function saveQuoteWithQuoteItems($entityId, \Generator $itemIdSequence)
180  {
181  $productCount = [
182  Type::TYPE_SIMPLE => mt_rand(
183  $this->config->getSimpleCountFrom(),
184  $this->config->getSimpleCountTo()
185  ),
186  Configurable::TYPE_CODE => mt_rand(
187  $this->config->getConfigurableCountFrom(),
188  $this->config->getConfigurableCountTo()
189  ),
191  $this->config->getBigConfigurableCountFrom(),
192  $this->config->getBigConfigurableCountTo()
193  )
194  ];
195  $quote = [
196  '%itemsPerOrder%' => array_sum($productCount),
197  '%orderNumber%' => 100000000 * $this->getStubProductStoreId($entityId) + $entityId,
198  '%email%' => "quote_{$entityId}@example.com",
199  '%time%' => date(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT),
200  '%productStoreId%' => $this->getStubProductStoreId($entityId),
201  '%productStoreName%' => $this->getStubProductStoreName($entityId),
202  '%entityId%' => $entityId,
203  ];
204  $shippingAddress = ['%orderAddressId%' => $entityId * 2 - 1, '%addressType%' => 'shipping'];
205  $billingAddress = ['%orderAddressId%' => $entityId * 2, '%addressType%' => 'billing'];
206  $address = $this->getAddressDataFixture();
207 
208  $this->query('quote', $quote);
209  $this->query('quote_address', $quote, $address, $shippingAddress);
210  $this->query('quote_address', $quote, $address, $billingAddress);
211 
212  for ($i = 0; $i < $productCount[Type::TYPE_SIMPLE]; $i++) {
213  $this->saveItemSimpleData($entityId, $i, $itemIdSequence->current(), $quote);
214  $itemIdSequence->next();
215  }
216 
218  for ($i = 0; $i < $productCount[$type]; $i++) {
219  // Generate parent item
220  $parentItemId = $itemIdSequence->current();
221  $this->saveParentItemConfigurableData($entityId, $i, $parentItemId, $type, $quote);
222  $itemIdSequence->next();
223 
224  // Generate child item
225  $itemId = $itemIdSequence->current();
226  $this->saveChildItemConfigurable($entityId, $i, $itemId, $parentItemId, $type, $quote);
227  $itemIdSequence->next();
228  }
229  }
230  }
231 
241  private function saveItemSimpleData($entityId, $index, $itemId, array $quote)
242  {
243  $itemData = [
244  '%productId%' => $this->getStubProductId($entityId, $index, Type::TYPE_SIMPLE),
245  '%sku%' => $this->getStubProductSku($entityId, $index, Type::TYPE_SIMPLE),
246  '%name%' => $this->getStubProductName($entityId, $index, Type::TYPE_SIMPLE),
247  '%itemId%' => $itemId,
248  '%productType%' => Type::TYPE_SIMPLE,
249  '%productOptions%' => $this->getStubProductBuyRequest($entityId, $index, Type::TYPE_SIMPLE),
250  '%parentItemId%' => 'null',
251  ];
252  $this->query('quote_item', $quote, $itemData);
253  $this->query('quote_item_option', $quote, $itemData, [
254  '%code%' => 'info_buyRequest',
255  '%value%' => $this->serializer->serialize([
256  'product' => $this->getStubProductId($entityId, $index, Type::TYPE_SIMPLE),
257  'qty' => "1",
258  'uenc' => 'aHR0cDovL21hZ2UyLmNvbS9jYXRlZ29yeS0xLmh0bWw'
259  ])
260  ]);
261  }
262 
273  private function saveParentItemConfigurableData($entityId, $index, $parentItemId, $productType, array $quote)
274  {
275  $itemData = [
276  '%productId%' => $this->getStubProductId($entityId, $index, $productType),
277  '%sku%' => $this->getStubProductSku($entityId, $index, $productType),
278  '%name%' => $this->getStubProductName($entityId, $index, $productType),
279  '%productOptions%' => $this->getStubProductBuyRequest($entityId, $index, $productType)['order'],
280  '%itemId%' => $parentItemId,
281  '%parentItemId%' => 'null',
282  '%productType%' => Configurable::TYPE_CODE
283  ];
284  $this->query('quote_item', $quote, $itemData);
285  $this->query('quote_item_option', $quote, $itemData, [
286  '%code%' => 'info_buyRequest',
287  '%value%' => $this->getStubProductBuyRequest($entityId, $index, $productType)['quote']
288  ]);
289  $this->query('quote_item_option', $quote, $itemData, [
290  '%code%' => 'attributes',
291  '%value%' => $this->getStubProductBuyRequest($entityId, $index, $productType)['super_attribute']
292  ]);
293  $itemData['%productId%'] = $this->getStubProductChildId($entityId, $index, $productType);
294  $this->query('quote_item_option', $itemData, [
295  '%code%' => "product_qty_" . $this->getStubProductChildId($entityId, $index, $productType),
296  '%value%' => "1"
297  ]);
298  $this->query('quote_item_option', $itemData, [
299  '%code%' => "simple_product",
300  '%value%' => $this->getStubProductChildId($entityId, $index, $productType)
301  ]);
302  }
303 
315  private function saveChildItemConfigurable($entityId, $index, $itemId, $parentItemId, $productType, array $quote)
316  {
317  $itemData = [
318  '%productId%' => $this->getStubProductChildId($entityId, $index, $productType),
319  '%sku%' => $this->getStubProductSku($entityId, $index, $productType),
320  '%name%' => $this->getStubProductName($entityId, $index, $productType),
321  '%productOptions%' => $this->getStubProductChildBuyRequest($entityId, $index, $productType)['order'],
322  '%itemId%' => $itemId,
323  '%parentItemId%' => $parentItemId,
324  '%productType%' => Type::TYPE_SIMPLE
325  ];
326 
327  $this->query('quote_item', $quote, $itemData);
328  $this->query('quote_item_option', $itemData, [
329  '%code%' => "info_buyRequest",
330  '%value%' => $this->getStubProductChildBuyRequest($entityId, $index, $productType)['quote']
331  ]);
332  $this->query('quote_item_option', $itemData, [
333  '%code%' => "parent_product_id",
334  '%value%' => $this->getStubProductId($entityId, $index, $productType)
335  ]);
336  }
337 
344  private function getStubProductStoreId($entityId)
345  {
346  return $this->productStubData[$this->getProductStubIndex($entityId)][0];
347  }
348 
355  private function getStubProductStoreName($entityId)
356  {
357  return $this->productStubData[$this->getProductStubIndex($entityId)][1];
358  }
359 
368  private function getStubProductId($entityId, $index, $type)
369  {
370  return $this->productStubData[$this->getProductStubIndex($entityId)][2][$type][$index]['id'];
371  }
372 
381  private function getStubProductSku($entityId, $index, $type)
382  {
383  return $this->productStubData[$this->getProductStubIndex($entityId)][2][$type][$index]['sku'];
384  }
385 
394  private function getStubProductName($entityId, $index, $type)
395  {
396  return $this->productStubData[$this->getProductStubIndex($entityId)][2][$type][$index]['name'];
397  }
398 
407  private function getStubProductBuyRequest($entityId, $index, $type)
408  {
409  return $this->productStubData[$this->getProductStubIndex($entityId)][2][$type][$index]['buyRequest'];
410  }
411 
420  private function getStubProductChildBuyRequest($entityId, $index, $type)
421  {
422  return $this->productStubData[$this->getProductStubIndex($entityId)][2][$type][$index]['childBuyRequest'];
423  }
424 
433  private function getStubProductChildId($entityId, $index, $type)
434  {
435  return $this->productStubData[$this->getProductStubIndex($entityId)][2][$type][$index]['childId'];
436  }
437 
444  private function getProductStubIndex($entityId)
445  {
446  $storeCount = count($this->productStubData);
447  $qty = intdiv($this->config->getRequiredQuoteQuantity(), $storeCount);
448  return intdiv($entityId, $qty) % $storeCount;
449  }
450 
456  private function getAddressDataFixture()
457  {
458  return [
459  '%firstName%' => 'First Name',
460  '%lastName%' => 'Last Name',
461  '%company%' => 'Company',
462  '%address%' => 'Address',
463  '%city%' => 'city',
464  '%state%' => 'Alabama',
465  '%country%' => 'US',
466  '%zip%' => '11111',
467  '%phone%' => '911'
468  ];
469  }
470 
476  private function prepareProductsForQuote()
477  {
478  $result = [];
479 
480  foreach ($this->storeManager->getStores() as $store) {
481  $productsResult = [];
482  $this->storeManager->setCurrentStore($store->getId());
483 
484  if ($this->config->getSimpleCountTo() > 0) {
485  $productsResult[Type::TYPE_SIMPLE] = $this->prepareSimpleProducts(
486  $this->getProductIds($store, Type::TYPE_SIMPLE, $this->config->getSimpleCountTo())
487  );
488  }
489  $configurables = [
490  Configurable::TYPE_CODE => $this->config->getConfigurableCountTo(),
491  QuoteConfiguration::BIG_CONFIGURABLE_TYPE => $this->config->getBigConfigurableCountTo(),
492  ];
493 
494  foreach ($configurables as $type => $qty) {
495  if ($qty > 0) {
496  $productsResult[$type] = $this->prepareConfigurableProducts(
497  $this->getProductIds(
498  $store,
499  $type,
500  $qty
501  )
502  );
503  }
504  }
505 
506  $result[] = [
507  $store->getId(),
508  implode(PHP_EOL, [
509  $this->storeManager->getWebsite($store->getWebsiteId())->getName(),
510  $this->storeManager->getGroup($store->getStoreGroupId())->getName(),
511  $store->getName()
512  ]),
513  $productsResult
514  ];
515  }
516 
517  return $result;
518  }
519 
530  private function prepareQueryTemplates()
531  {
532  $fileName = $this->config->getFixtureDataFilename();
533  $templateData = json_decode(file_get_contents(realpath($fileName)), true);
534  foreach ($templateData as $table => $template) {
535  if (isset($template['_table'])) {
536  $table = $template['_table'];
537  unset($template['_table']);
538  }
539  if (isset($template['_resource'])) {
540  $resource = $template['_resource'];
541  unset($template['_resource']);
542  } else {
543  $resource = explode("_", $table);
544  foreach ($resource as &$item) {
545  $item = ucfirst($item);
546  }
547  $resource = "Magento\\"
548  . array_shift($resource)
549  . "\\Model\\ResourceModel\\"
550  . implode("\\", $resource);
551  }
552 
553  $tableName = $this->getTableName($table, $resource);
554 
555  $querySuffix = "";
556  if (isset($template['_query_suffix'])) {
557  $querySuffix = $template['_query_suffix'];
558  unset($template['_query_suffix']);
559  }
560 
561  $fields = implode(', ', array_keys($template));
562  $values = implode(', ', array_values($template));
563 
564  $connection = $this->getConnection($resource);
565  if ($connection->getTransactionLevel() == 0) {
566  $connection->beginTransaction();
567  }
568 
569  $this->queryTemplates[$table] = "INSERT INTO `{$tableName}` ({$fields}) VALUES ({$values}){$querySuffix};";
570  $this->resourceConnections[$table] = $connection;
571  }
572  }
573 
584  protected function query($table, ... $replacements)
585  {
586  $query = $this->queryTemplates[$table];
587  foreach ($replacements as $data) {
588  $query = str_replace(array_keys($data), array_values($data), $query);
589  }
590 
591  $this->resourceConnections[$table]->query($query);
592  }
593 
605  private function getMaxEntityId($tableName, $resourceName, $column = 'entity_id')
606  {
607  $tableName = $this->getTableName($tableName, $resourceName);
608  $connection = $this->getConnection($resourceName);
609  return (int)$connection->query("SELECT MAX(`{$column}`) FROM `{$tableName}`;")->fetchColumn(0);
610  }
611 
620  private function getProductIds(\Magento\Store\Api\Data\StoreInterface $store, $typeId, $limit = null)
621  {
623  $productCollection = $this->productCollectionFactory->create();
624  $productCollection->addStoreFilter($store->getId());
625  $productCollection->addWebsiteFilter($store->getWebsiteId());
626 
627  // "Big%" should be replaced with a configurable value.
629  $productCollection->getSelect()->where(" type_id = '" . Configurable::TYPE_CODE . "' ");
630  $productCollection->getSelect()->where(" sku LIKE 'Big%' ");
631  } else {
632  $productCollection->getSelect()->where(" type_id = '$typeId' ");
633  $productCollection->getSelect()->where(" sku NOT LIKE 'Big%' ");
634  }
635 
636  return $productCollection->getAllIds($limit);
637  }
638 
647  private function prepareSimpleProducts(array $productIds = [])
648  {
649  $productsResult = [];
650  foreach ($productIds as $key => $simpleId) {
651  $simpleProduct = $this->productRepository->getById($simpleId);
652  $productsResult[$key]['id'] = $simpleId;
653  $productsResult[$key]['sku'] = $simpleProduct->getSku();
654  $productsResult[$key]['name'] = $simpleProduct->getName();
655  $productsResult[$key]['buyRequest'] = $this->serializer->serialize([
656  "info_buyRequest" => [
657  "uenc" => "aHR0cDovL21hZ2VudG8uZGV2L2NvbmZpZ3VyYWJsZS1wcm9kdWN0LTEuaHRtbA,,",
658  "product" => $simpleId,
659  "qty" => "1"
660  ]
661  ]);
662  }
663  return $productsResult;
664  }
665 
674  private function prepareConfigurableProducts(array $productIds = [])
675  {
676  $productsResult = [];
677  foreach ($productIds as $key => $configurableId) {
678  $configurableProduct = $this->productRepository->getById($configurableId);
679  $options = $this->optionRepository->getList($configurableProduct->getSku());
680  $configurableChild = $this->linkManagement->getChildren($configurableProduct->getSku())[0];
681  $simpleSku = $configurableChild->getSku();
682  $simpleId = $this->productRepository->get($simpleSku)->getId();
683 
684  $attributesInfo = [];
685  $superAttribute = [];
686  foreach ($options as $option) {
687  $attributesInfo[] = [
688  "label" => $option->getLabel(),
689  "value" => $option['options']['0']['label'],
690  "option_id" => $option->getAttributeId(),
691  "option_value" => $option->getValues()[0]->getValueIndex()
692  ];
693  $superAttribute[$option->getAttributeId()] = $option->getValues()[0]->getValueIndex();
694  }
695 
696  $configurableBuyRequest = [
697  "info_buyRequest" => [
698  "uenc" => "aHR0cDovL21hZ2UyLmNvbS9jYXRlZ29yeS0xLmh0bWw",
699  "product" => $configurableId,
700  "selected_configurable_option" => $simpleId,
701  "related_product" => "",
702  "super_attribute" => $superAttribute,
703  "qty" => 1
704  ],
705  "attributes_info" => $attributesInfo,
706  "simple_name" => $configurableChild->getName(),
707  "simple_sku" => $configurableChild->getSku(),
708  ];
709  $simpleBuyRequest = [
710  "info_buyRequest" => [
711  "uenc" => "aHR0cDovL21hZ2VudG8uZGV2L2NvbmZpZ3VyYWJsZS1wcm9kdWN0LTEuaHRtbA,,",
712  "product" => $configurableId,
713  "selected_configurable_option" => $simpleId,
714  "related_product" => "",
715  "super_attribute" => $superAttribute,
716  "qty" => "1"
717  ]
718  ];
719 
720  $quoteConfigurableBuyRequest = $configurableBuyRequest['info_buyRequest'];
721  $quoteSimpleBuyRequest = $simpleBuyRequest['info_buyRequest'];
722  unset($quoteConfigurableBuyRequest['selected_configurable_option']);
723  unset($quoteSimpleBuyRequest['selected_configurable_option']);
724 
725  $productsResult[$key]['id'] = $configurableId;
726  $productsResult[$key]['sku'] = $simpleSku;
727  $productsResult[$key]['name'] = $configurableProduct->getName();
728  $productsResult[$key]['childId'] = $simpleId;
729  $productsResult[$key]['buyRequest'] = [
730  'order' => $this->serializer->serialize($configurableBuyRequest),
731  'quote' => $this->serializer->serialize($quoteConfigurableBuyRequest),
732  'super_attribute' => $this->serializer->serialize($superAttribute)
733  ];
734  $productsResult[$key]['childBuyRequest'] = [
735  'order' => $this->serializer->serialize($simpleBuyRequest),
736  'quote' => $this->serializer->serialize($quoteSimpleBuyRequest),
737  ];
738  }
739  return $productsResult;
740  }
741 
749  private function commitBatch()
750  {
751  foreach ($this->resourceConnections as $connection) {
752  if ($connection->getTransactionLevel() > 0) {
753  $connection->commit();
754  $connection->beginTransaction();
755  }
756  }
757  }
758 
767  private function getItemIdSequence($maxItemId, $requestedOrders, $maxItemsPerOrder)
768  {
769  $requestedItems = $maxItemId + ($requestedOrders + 1) * $maxItemsPerOrder;
770  for ($i = $maxItemId + 1; $i <= $requestedItems; $i++) {
771  yield $i;
772  }
773  }
774 
783  private function getTableName($tableName, $resourceName)
784  {
786  $resource = $this->fixtureModel->getObjectManager()->get($resourceName);
787  return $this->getConnection($resourceName)->getTableName($resource->getTable($tableName));
788  }
789 
796  private function getConnection($resourceName)
797  {
798  $resource = $this->fixtureModel->getObjectManager()->get($resourceName);
799  return $resource->getConnection();
800  }
801 }
$tableName
Definition: trigger.php:13
$billingAddress
Definition: order.php:25
$config
Definition: fraud_order.php:17
$quote
$shippingAddress
Definition: order.php:40
$fields
Definition: details.phtml:14
$storeManager
$values
Definition: options.phtml:88
$resource
Definition: bulk.php:12
$address
Definition: customer.php:38
$type
Definition: item.phtml:13
$fileName
Definition: translate.phtml:15
$simpleId
$connection
Definition: bulk.php:13
__construct(\Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory, \Magento\Catalog\Api\ProductRepositoryInterface $productRepository, \Magento\ConfigurableProduct\Api\OptionRepositoryInterface $optionRepository, \Magento\ConfigurableProduct\Api\LinkManagementInterface $linkManagement, \Magento\Framework\Serialize\SerializerInterface $serializer, QuoteConfiguration $config, \Magento\Setup\Fixtures\FixtureModel $fixtureModel)
$table
Definition: trigger.php:14
$i
Definition: gallery.phtml:31
$index
Definition: list.phtml:44
$templateData
$template
Definition: export.php:12