11 use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory;
14 use Magento\Eav\Model\ResourceModel\Entity\Attribute\CollectionFactory;
19 use Symfony\Component\Console\Output\OutputInterface;
87 private $searchConfig;
92 private $dataGenerator;
97 private $attributeSetsFixture;
102 private $attributePattern;
107 private $productGenerator;
112 private $attributeCollectionFactory;
117 private $configurableProductGenerator;
122 private $productCollectionFactory;
127 private $productStartIndex;
132 private $productsAmountProvider;
137 private $categoryResolver;
142 private $websiteCategoryProvider;
147 private $priceProvider;
152 private $swatchesGenerator;
177 \
Magento\Setup\Fixtures\AttributeSet\AttributeSetFixture $attributeSetsFixture,
178 \
Magento\Setup\Fixtures\AttributeSet\Pattern $attributePattern,
180 CollectionFactory $attributeCollectionFactory,
182 ProductCollectionFactory $collectionFactory,
187 \
Magento\Setup\Fixtures\AttributeSet\SwatchesGenerator $swatchesGenerator,
191 $this->attributeSetsFixture = $attributeSetsFixture;
192 $this->attributePattern = $attributePattern;
193 $this->productGenerator = $productGenerator;
194 $this->attributeCollectionFactory = $attributeCollectionFactory;
195 $this->configurableProductGenerator = $configurableProductGenerator;
196 $this->productCollectionFactory = $collectionFactory;
197 $this->productsAmountProvider = $productsAmountProvider;
198 $this->categoryResolver = $categoryResolver;
199 $this->websiteCategoryProvider = $websiteCategoryProvider;
200 $this->priceProvider = $priceProvider;
201 $this->swatchesGenerator = $swatchesGenerator;
211 if (!$this->fixtureModel->getValue(
'configurable_products', [])) {
214 $simpleProductsCount = $this->fixtureModel->getValue(
'simple_products', 0);
215 $maxAmountOfWordsDescription = $this->getSearchConfigValue(
'max_amount_of_words_description');
216 $maxAmountOfWordsShortDescription = $this->getSearchConfigValue(
'max_amount_of_words_short_description');
217 $minAmountOfWordsDescription = $this->getSearchConfigValue(
'min_amount_of_words_description');
218 $minAmountOfWordsShortDescription = $this->getSearchConfigValue(
'min_amount_of_words_short_description');
220 foreach ($this->getConfigurableProductConfig() as $configurableConfig) {
221 $configurableSku = $configurableConfig[
'sku'];
222 $productAmount = $this->productsAmountProvider->getAmount(
223 $configurableConfig[
'products'],
226 if (!$productAmount) {
229 $searchTerms = $this->getSearchTerms();
230 $shortDescriptionClosure = $this->getDescriptionClosure(
232 $simpleProductsCount,
234 $maxAmountOfWordsShortDescription,
235 $minAmountOfWordsShortDescription,
238 $descriptionClosure = $this->getDescriptionClosure(
240 $simpleProductsCount,
242 $maxAmountOfWordsDescription,
243 $minAmountOfWordsDescription,
246 $variationCount = $configurableConfig[
'variationCount'];
248 $variationSkuClosure =
function (
$productId, $entityNumber) use ($configurableSku, $variationCount) {
249 $variationIndex = $this->getConfigurableVariationIndex($entityNumber, $variationCount);
250 $productId = $this->getConfigurableProductIndex($entityNumber, $variationCount);
252 return sprintf($this->getConfigurableOptionSkuPattern($configurableSku),
$productId, $variationIndex);
255 'name' => $variationSkuClosure,
256 'sku' => $variationSkuClosure,
257 'price' =>
function (
$index, $entityNumber) {
258 return $this->priceProvider->getPrice($entityNumber);
260 'website_ids' =>
function (
$index, $entityNumber) use ($variationCount) {
261 $configurableIndex = $this->getConfigurableProductIndex($entityNumber, $variationCount);
263 return $this->websiteCategoryProvider->getWebsiteIds($configurableIndex);
266 'additional_attributes' => $this->getAdditionalAttributesClosure(
272 $this->productGenerator->generate($productAmount * $variationCount, $fixture);
274 $skuClosure =
function (
$productId, $entityNumber) use ($configurableSku) {
275 return sprintf($configurableSku, $entityNumber + $this->getNewProductStartIndex());
278 '_variation_sku_pattern' => $this->getFirstVariationSkuPattern($configurableConfig),
280 '_variation_count' => $variationCount,
283 'name' => $skuClosure,
284 'sku' => $skuClosure,
285 'description' => $descriptionClosure,
286 'short_description' => $shortDescriptionClosure,
288 'website_ids' => $this->getConfigurableWebsiteIdsClosure(),
289 'category_ids' => $configurableConfig[
'category'],
290 'meta_keyword' => $skuClosure,
291 'meta_title' => $skuClosure,
294 $this->configurableProductGenerator->generate($productAmount, $fixture);
302 private function getConfigurableWebsiteIdsClosure()
304 return function (
$index, $entityNumber) {
305 return $this->websiteCategoryProvider->getWebsiteIds($entityNumber + $this->getNewProductStartIndex());
316 private function getDefaultAttributeSetsConfig(array $defaultAttributeSets, $configurableProductsCount)
318 $attributeSetClosure =
function (
$index) use ($defaultAttributeSets) {
319 $attributeSetAmount = count(array_keys($defaultAttributeSets));
322 return $attributeSetAmount > (
$index - 1) % (
int)$this->fixtureModel->getValue(
'categories', 30)
323 ? array_keys($defaultAttributeSets)[mt_rand(0, $attributeSetAmount - 1)]
326 $productsPerSet = [];
327 for (
$i = 1;
$i <= $configurableProductsCount;
$i++) {
334 $configurableConfig = [];
335 foreach ($defaultAttributeSets as $attributeSetName =>
$attributeSet) {
336 $skuSuffix = $attributeSetName ===
'Default' ?
'' :
' - ' . $attributeSetName;
337 $configurableConfig[] = [
338 'attributeSet' => $attributeSetName,
339 'products' => $productsPerSet[$attributeSetName],
340 'sku' =>
'Configurable Product %s' . $skuSuffix,
344 return $configurableConfig;
354 private function getFirstVariationSkuPattern($configurableConfig)
356 $productIndex = $this->getConfigurableProductIndex(0, $configurableConfig[
'variationCount']);
358 return sprintf($this->getConfigurableOptionSkuPattern($configurableConfig[
'sku']), $productIndex, 1);
366 private function getNewProductStartIndex()
368 if (
null === $this->productStartIndex) {
369 $this->productStartIndex = $this->productCollectionFactory->create()
374 return $this->productStartIndex;
384 private function getConfigurableProductIndex($entityNumber, $variationCount)
386 return floor($entityNumber / $variationCount) + $this->getNewProductStartIndex();
396 private function getConfigurableVariationIndex($entityNumber, $variationCount)
398 return $entityNumber % $variationCount + 1;
406 return 'Generating configurable products';
423 if (!$this->fixtureModel->getValue(
'configurable_products', [])) {
427 $configurableProductConfig = $this->prepareConfigurableConfig(
428 $this->getDefaultAttributeSetsWithAttributes()
430 $generalAmount = array_sum(array_column($configurableProductConfig,
'products'));
432 $output->writeln(sprintf(
'<info> |- Configurable products: %s</info>', $generalAmount));
441 private function getDefaultAttributeSetsWithAttributes()
443 $attributeSets = $this->fixtureModel->getValue(
'attribute_sets',
null);
446 if ($attributeSets !==
null && array_key_exists(
'attribute_set', $attributeSets)) {
468 $attributeOptions = range(1, $this->getConfigurableProductsVariationsValue());
471 function (&
$item, $key) {
472 $item =
'option ' . ($key + 1);
479 'name' =>
'configurable_variation',
480 'values' => $attributeOptions
495 private function getConfigurableProductConfig()
497 $defaultAttributeSets = $this->getDefaultAttributeSetsWithAttributes();
498 $configurableProductConfig = $this->prepareConfigurableConfig($defaultAttributeSets);
500 $configurableProductConfig = array_map(
function (
$config) {
503 'attributeSet' =>
null,
504 'attributes' =>
null,
512 }, $configurableProductConfig);
515 foreach ($configurableProductConfig as
$i => &
$config) {
540 unset($configurableProductConfig[
$i]);
553 if (count($skuPull) !== count(array_unique($skuPull))) {
554 throw new ValidatorException(
555 __(
"The configurable product's SKU pattern must be unique in an attribute set.")
559 return $configurableProductConfig;
570 private function prepareConfigurableConfig($defaultAttributeSets)
572 $configurableConfigs = $this->fixtureModel->getValue(
'configurable_products', []);
573 $configurableConfigs = is_array($configurableConfigs) ? $configurableConfigs : (int)$configurableConfigs;
574 if (is_int($configurableConfigs)) {
575 $configurableConfigs = $this->getDefaultAttributeSetsConfig($defaultAttributeSets, $configurableConfigs);
576 }
elseif (isset($configurableConfigs[
'config'])) {
577 if (!isset($configurableConfigs[
'config'][0])) {
579 $configurableConfigs = [$configurableConfigs[
'config']];
581 $configurableConfigs = $configurableConfigs[
'config'];
584 foreach ($configurableConfigs as &
$config) {
585 if (isset(
$config[
'attributes']) && is_array(
$config[
'attributes'])) {
586 if (!isset(
$config[
'attributes'][
'attribute'][0])) {
594 throw new ValidatorException(
595 __(
'The configurable product config is invalid. Verify the product and try again.')
599 return $configurableConfigs;
606 private function getConfigurableCategory(
$config)
608 if (isset(
$config[
'category'])) {
610 $websiteClosure = $this->getConfigurableWebsiteIdsClosure();
613 return $this->categoryResolver->getCategory(
619 return function (
$index, $entityNumber) {
620 return $this->websiteCategoryProvider->getCategoryId($entityNumber);
630 private function getConfigurableSkuPattern(
$config, $attributeSetName)
634 $sku =
'Configurable Product ' . $attributeSetName .
' %s';
636 if (
false === strpos($sku,
'%s')) {
649 private function getCustomAttributeSet(array
$attributes)
651 $attributeSetHash = crc32($this->serializer->serialize(
$attributes));
652 $attributeSetName = sprintf(
'Dynamic Attribute Set %s', $attributeSetHash);
654 $pattern = $this->attributePattern->generateAttributeSet(
661 sprintf(
'ca_%s_%s',
$index, $attributeSetHash),
671 $data[
'is_visible_in_advanced_search'] = 1;
672 $data[
'is_searchable'] = 1;
673 $data[
'is_filterable'] = 1;
674 $data[
'is_filterable_in_search'] = 1;
675 $data[
'used_in_product_listing'] = 1;
677 $swatch = $this->swatchesGenerator->generateSwatchData(
679 $attributeSetName .
$index,
684 return array_replace_recursive(
692 return $this->attributeSetsFixture->createAttributeSet(
$pattern);
698 private function getSearchConfig()
700 if (!$this->searchConfig) {
701 $this->searchConfig = $this->fixtureModel->getValue(
'search_config',
null);
703 return $this->searchConfig;
710 private function getSearchConfigValue(
$name)
712 return $this->getSearchConfig() ===
null 713 ? 0 : ($this->getSearchConfig()[
$name] ===
null ? 0 : $this->getSearchConfig()[
$name]);
719 private function getSearchTerms()
721 $searchTerms = $this->fixtureModel->getValue(
'search_terms',
null);
722 if ($searchTerms !==
null) {
723 $searchTerms = array_key_exists(0, $searchTerms[
'search_term'])
724 ? $searchTerms[
'search_term'] : [$searchTerms[
'search_term']];
736 private function getConfigurableProductsVariationsValue()
738 return $this->fixtureModel->getValue(
'configurable_products_variation', 3);
749 private function getAdditionalAttributesClosure(array
$attributes, $variationCount)
752 return count(
$attr[
'values']);
757 $variationIndex = $this->getConfigurableVariationIndex($entityNumber, $variationCount) - 1;
758 if (isset($variationsMatrix[$variationIndex])) {
759 $tempProductData = [];
760 foreach ($variationsMatrix[$variationIndex] as $attributeIndex => $optionIndex) {
765 return $tempProductData;
780 $variationsMatrix =
null;
781 for (
$i = 0;
$i < $attributesPerSet;
$i++) {
784 return $this->generateVariations($variationsMatrix);
792 private function generateVariations($variationsMatrix)
794 if (!$variationsMatrix) {
797 $set = array_shift($variationsMatrix);
798 $subset = $this->generateVariations($variationsMatrix);
800 foreach ($set as
$value) {
801 foreach ($subset as $subValue) {
802 array_unshift($subValue,
$value);
815 private function getConfigurableOptionSkuPattern($skuPattern)
817 return $skuPattern .
' - option %s';
829 private function getDescriptionClosure(
831 $simpleProductsCount,
832 $configurableProductsCount,
833 $maxAmountOfWordsDescription,
834 $minAmountOfWordsDescription,
835 $descriptionPrefix =
'description' 837 if (
null === $this->dataGenerator) {
838 $fileName =
__DIR__ . DIRECTORY_SEPARATOR .
'_files' . DIRECTORY_SEPARATOR .
'dictionary.csv';
839 $this->dataGenerator =
new DataGenerator(realpath(
$fileName));
842 return function (
$index) use (
844 $simpleProductsCount,
845 $configurableProductsCount,
846 $maxAmountOfWordsDescription,
847 $minAmountOfWordsDescription,
850 $countSearchTerms = is_array($searchTerms) ? count($searchTerms) : 0;
854 $searchTerms[
$index % $countSearchTerms][
'count'] * (
855 $configurableProductsCount / ($simpleProductsCount + $configurableProductsCount)
859 return $this->dataGenerator->generate(
860 $minAmountOfWordsDescription,
861 $maxAmountOfWordsDescription,
862 $descriptionPrefix .
'-' .
$index 865 $searchTerms[
$index % $countSearchTerms][
'term'] :
'');
875 private function convertAttributesToDBFormat(array
$attributeSet)
elseif(isset( $params[ 'redirect_parent']))
defined('TESTS_BP')||define('TESTS_BP' __DIR__
const ATTRIBUTE_CODE_MAX_LENGTH
__construct(FixtureModel $fixtureModel, \Magento\Setup\Fixtures\AttributeSet\AttributeSetFixture $attributeSetsFixture, \Magento\Setup\Fixtures\AttributeSet\Pattern $attributePattern, ProductGenerator $productGenerator, CollectionFactory $attributeCollectionFactory, ConfigurableProductGenerator $configurableProductGenerator, ProductCollectionFactory $collectionFactory, ProductsAmountProvider $productsAmountProvider, CategoryResolver $categoryResolver, WebsiteCategoryProvider $websiteCategoryProvider, PriceProvider $priceProvider, \Magento\Setup\Fixtures\AttributeSet\SwatchesGenerator $swatchesGenerator, \Magento\Framework\Serialize\SerializerInterface $serializer)
const VISIBILITY_NOT_VISIBLE
printInfo(OutputInterface $output)
if(!isset($_GET['name'])) $name