From c7b587a50d1ab856dce0124c49e1631e16f1b619 Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 29 Sep 2017 10:33:29 +0200 Subject: [PATCH] Update Generator for 2.0 --- Generator/AttributeGenerator.php | 4 +- Generator/FamilyGenerator.php | 8 +- Generator/FamilyVariantGenerator.php | 310 ++++++++++++++++++++++++ Generator/Product/ProductRawBuilder.php | 2 +- Resources/config/generators.yml | 8 + 5 files changed, 325 insertions(+), 7 deletions(-) create mode 100644 Generator/FamilyVariantGenerator.php diff --git a/Generator/AttributeGenerator.php b/Generator/AttributeGenerator.php index 5d27021..28effef 100644 --- a/Generator/AttributeGenerator.php +++ b/Generator/AttributeGenerator.php @@ -114,12 +114,12 @@ public function generate(array $globalConfig, array $entitiesConfig, ProgressBar $attribute['group'] = $this->getRandomAttributeGroupCode(); if (AttributeTypes::OPTION_SIMPLE_SELECT === $type && $minVariantAxes > 0) { - // Configure a minimum set of non localizable and non scopable select axes for variant groups. + // Configure a minimum set of non localizable and non scopable select axes for family variants. $attribute['localizable'] = 0; $attribute['scopable'] = 0; $minVariantAxes--; } elseif (AttributeTypes::TEXT === $type && $minVariantAttributes > 0) { - // Configure a minimum set of non localizable and non scopable text attributes for variant groups. + // Configure a minimum set of non localizable and non scopable text attributes for family variants. $attribute['localizable'] = 0; $attribute['scopable'] = 0; $minVariantAttributes--; diff --git a/Generator/FamilyGenerator.php b/Generator/FamilyGenerator.php index 8c32c10..e3b7034 100644 --- a/Generator/FamilyGenerator.php +++ b/Generator/FamilyGenerator.php @@ -86,10 +86,10 @@ public function generate(array $globalConfig, array $entitiesConfig, ProgressBar for ($i = 0; $i < $count; $i++) { $family = []; - $family['code'] =self::FAMILY_CODE_PREFIX.$i; + $family['code'] = self::FAMILY_CODE_PREFIX . $i; foreach ($this->getLocalizedRandomLabels() as $localeCode => $label) { - $family['label-'.$localeCode] = $label; + $family['label-' . $localeCode] = $label; } $family['attribute_as_label'] = $this->labelAttribute; @@ -105,7 +105,7 @@ public function generate(array $globalConfig, array $entitiesConfig, ProgressBar $attributeReqs = $this->faker->randomElements($nonMediaAttributeCodes, $requirementsCount); $attributeReqs = array_merge([$this->identifierAttribute], $attributeReqs); - $family['requirements-'.$channel->getCode()] = implode(self::ATTRIBUTE_DELIMITER, $attributeReqs); + $family['requirements-' . $channel->getCode()] = implode(self::ATTRIBUTE_DELIMITER, $attributeReqs); } $families[$family['code']] = $family; @@ -123,7 +123,7 @@ public function generate(array $globalConfig, array $entitiesConfig, ProgressBar )) ->write($families); - return []; + return ['families' => $this->getFamilyObjects()]; } /** diff --git a/Generator/FamilyVariantGenerator.php b/Generator/FamilyVariantGenerator.php new file mode 100644 index 0000000..57a9c21 --- /dev/null +++ b/Generator/FamilyVariantGenerator.php @@ -0,0 +1,310 @@ + + * @copyright 2017 Akeneo SAS (http://www.akeneo.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class FamilyVariantGenerator implements GeneratorInterface +{ + // code;family;label-de_DE;label-en_US;label-fr_FR;variant-axes_1;variant-axes_2;variant-attributes_1;variant-attributes_2 + + const TYPE = 'family_variant'; + + const FAMILY_VARIANT_CODE_PREFIX = 'fam_variant_'; + + const FAMILY_VARIANTS_FILENAME = 'family_variants.csv'; + + const ATTRIBUTE_DELIMITER = ','; + + /** @var array */ + protected $locales = []; + + /** @var array */ + protected $channels = []; + + /** @var Generator */ + protected $faker; + + /** @var array */ + protected $familyVariants = []; + + /** @var AttributeInterface[] */ + protected $availableAxes = []; + + /** @var AttributeInterface[] */ + protected $availableAttributes = []; + + /** @var string */ + protected $identifierAttributeCode; + + /** @var array */ + protected $availableFamilies; + + /** @var CsvWriter */ + protected $writer; + + /** + * @param CsvWriter $writer + */ + public function __construct(CsvWriter $writer) + { + $this->writer = $writer; + } + + /** + * {@inheritdoc} + */ + public function generate(array $globalConfig, array $entitiesConfig, ProgressBar $progress, array $options = []) + { + $this->locales = $options['locales']; + $this->channels = $options['channels']; + + $count = (int) $entitiesConfig['count']; + $oneLevelProbability = (float) $entitiesConfig['one_level_probability']; + $twoLevelProbability = (float) $entitiesConfig['two_level_probability']; + $maxAttributesPerAxe = (int) $entitiesConfig['max_attributes_per_axe']; + $this->identifierAttributeCode = $entitiesConfig['identifier_attribute']; + $this->setFamilies($options['families'], $count); + $this->setFaker($globalConfig); + + if (100 !== $oneLevelProbability + $twoLevelProbability) { + throw new \Exception('Addition of one level and two level family variants probability must be equals to 100'); + } + $nbOfOneLevelNeeded = $count * 100 / $oneLevelProbability; + $nbOfTwoLevelNeeded = $count - $nbOfOneLevelNeeded; + + $familyVariants = []; + // code;family;label-de_DE;label-en_US;label-fr_FR;variant-axes_1;variant-axes_2;variant-attributes_1;variant-attributes_2 + foreach ($this->availableFamilies as $code => $parentFamily) { + $family = []; + + $family['code'] = self::FAMILY_VARIANT_CODE_PREFIX . $code; + $family['family'] = $code; + + foreach ($this->getLocalizedRandomLabels() as $localeCode => $label) { + $family['label-' . $localeCode] = $label; + } + + if (count($parentFamily['availableAxes']) >= 2 && 0 < $nbOfTwoLevelNeeded) { + $level = $this->buildLevel($code, $maxAttributesPerAxe, true); + $nbOfTwoLevelNeeded--; + } elseif (0 < $nbOfOneLevelNeeded) { + $level = $this->buildLevel($code, $maxAttributesPerAxe); + $nbOfOneLevelNeeded--; + } + //Array merge + //stop process if count is reach + // Check if we have enough family variants + + $familyVariants[$family['code']] = $family; + $progress->advance(); + } + + $this->familyVariants = $familyVariants; + + $this->writer + ->setFilename(sprintf( + '%s%s%s', + $globalConfig['output_dir'], + DIRECTORY_SEPARATOR, + self::FAMILY_VARIANTS_FILENAME + )) + ->write($familyVariants); + + return []; + } + + /** + * {@inheritdoc} + */ + public function supports($type) + { + return self::TYPE === $type; + } + + /** + * @param string $familyParentCode + * @param int $maxAttributesPerAxe + * @param bool $twoLevels + * + * @return array + */ + protected function buildLevel($familyParentCode, $maxAttributesPerAxe, $twoLevels = false) + { + $chunkSize = count($this->availableFamilies[$familyParentCode]['availableAttributes']) / 2; + $availableAttributes = array_chunk( + $this->availableFamilies[$familyParentCode]['availableAttributes'], + $chunkSize + ); + + $axis1 = array_shift($this->availableFamilies[$familyParentCode]['availableAxes']); + $levels['variant-axes_1'] = [$axis1->getCode()]; + $levels['variant-attributes_1'] = $this->buildAvailableAttributes( + $availableAttributes[0], + $maxAttributesPerAxe + ); + + if ($twoLevels) { + $axis2 = array_shift($this->availableFamilies[$familyParentCode]['availableAxes']); + $levels['variant-axes_2'] = [$axis2->getCode()]; + $levels['variant-attributes_2'] = $this->buildAvailableAttributes( + $availableAttributes[1], + $maxAttributesPerAxe + ); + } + + return $levels; + } + + /** + * @param array $availableAttributes + * @param int $maxAttributes + * + * @return string + */ + protected function buildAvailableAttributes(array $availableAttributes, $maxAttributes) + { + $variantAttributes = []; + while (!empty($availableAttributes) || 0 !== $maxAttributes) { + $attribute = array_shift($availableAttributes); + $variantAttributes[] = $attribute->getCode(); + $maxAttributes--; + } + + return implode(self::ATTRIBUTE_DELIMITER, $variantAttributes); + } + + /** + * Get localized random labels + * + * @return array + */ + protected function getLocalizedRandomLabels() + { + $labels = []; + + foreach ($this->locales as $locale) { + $labels[$locale->getCode()] = $this->faker->sentence(2); + } + + return $labels; + } + + /** + * @param FamilyInterface[] $families + * @param int $count + * + * @throws \Exception if there is not enough families available to create asked number of family variants. + */ + protected function setFamilies(array $families, $count) + { + foreach ($families as $family) { + $attributes = $family->getAttributes(); + + $availableAxes = $this->getAvailableAxis($attributes); + $availableAttributes = $this->getAvailableAttributes($attributes); + + if (0 !== count($availableAxes) && 0 !== count($availableAttributes)) { + $this->availableFamilies[$family->getCode()] = [ + 'family' => $family, + 'availableAxes' => $availableAxes, + 'availableAttributes' => $availableAttributes + ]; + } + } + + if (count($this->availableFamilies) < $count) { + throw new \Exception('There is not enough available families to create family variants.'); + } + } + + /** + * Returns the available attributes to define family variant axes + * (only selects non localizable and non scopable). + * + * @param AttributeInterface[] $attributes + * + * @return AttributeInterface[] + */ + protected function getAvailableAxis(array $attributes) + { + return array_filter($attributes, function ($attribute) { + return in_array($attribute->getAttributeType(), [ + AttributeTypes::OPTION_SIMPLE_SELECT, + AttributeTypes::REFERENCE_DATA_SIMPLE_SELECT + ]) && !$attribute->isLocalizable() && !$attribute->isScopable(); + }); + } + + /** + * Returns the available attributes to define family variant attributes + * (only texts non localizable and non scopable). + * + * @param AttributeInterface[] $attributes + * + * @return AttributeInterface[] + */ + protected function getAvailableAttributes(array $attributes) + { + return array_filter($attributes, function ($attribute) { + return (($attribute->getAttributeType() === AttributeTypes::TEXT) + && !$attribute->isLocalizable() + && !$attribute->isScopable() + ); + }); + } + + /** + * @param array $globalConfig + */ + protected function setFaker(array $globalConfig) + { + $this->faker = Factory::create(); + if (isset($globalConfig['seed'])) { + $this->faker->seed($globalConfig['seed']); + } + } + + /** + * Returns the number of attributes to set. + * + * @param FamilyInterface $family + * @param int $nbAttrBase + * @param int $nbAttrDeviation + * + * @return int + */ + private function getRandomAttributesCount(FamilyInterface $family, $nbAttrBase, $nbAttrDeviation) + { + if ($nbAttrBase > 0) { + if ($nbAttrDeviation > 0) { + $nbAttr = $this->faker->numberBetween( + $nbAttrBase - round($nbAttrDeviation / 2), + $nbAttrBase + round($nbAttrDeviation / 2) + ); + } else { + $nbAttr = $nbAttrBase; + } + } + $familyAttrCount = count($this->getAttributesFromFamily($family)); + + if (!isset($nbAttr) || $nbAttr > $familyAttrCount) { + $nbAttr = $familyAttrCount; + } + + return $nbAttr; + } +} diff --git a/Generator/Product/ProductRawBuilder.php b/Generator/Product/ProductRawBuilder.php index 0baa2b0..4d95bd6 100644 --- a/Generator/Product/ProductRawBuilder.php +++ b/Generator/Product/ProductRawBuilder.php @@ -107,7 +107,7 @@ public function fillInRandomAttributes( $nbAttr, $nbAttrDeviation ); - $attributes = $this->getRandomAttributesFromFamily($family, $randomNbAttr); + $attributes = $this->getRandomAttributesFromFamily($family, $randomNbAttr); foreach ($attributes as $attribute) { $valueData = $this->generateValue($attribute, $forcedAttributes); diff --git a/Resources/config/generators.yml b/Resources/config/generators.yml index fa6a363..0e1273b 100644 --- a/Resources/config/generators.yml +++ b/Resources/config/generators.yml @@ -6,6 +6,7 @@ parameters: pim_data_generator.generator.attribute.class: Pim\Bundle\DataGeneratorBundle\Generator\AttributeGenerator pim_data_generator.generator.attribute_option.class: Pim\Bundle\DataGeneratorBundle\Generator\AttributeOptionGenerator pim_data_generator.generator.family.class: Pim\Bundle\DataGeneratorBundle\Generator\FamilyGenerator + pim_data_generator.generator.family_variant.class: Pim\Bundle\DataGeneratorBundle\Generator\FamilyVariantGenerator pim_data_generator.generator.attribute_group.class: Pim\Bundle\DataGeneratorBundle\Generator\AttributeGroupGenerator pim_data_generator.generator.category.class: Pim\Bundle\DataGeneratorBundle\Generator\CategoryGenerator pim_data_generator.generator.user_group.class: Pim\Bundle\DataGeneratorBundle\Generator\UserGroupGenerator @@ -79,6 +80,13 @@ services: tags: - { name: pim_data_generator.generator } + pim_data_generator.generator.family_variant: + class: '%pim_data_generator.generator.family_variant.class%' + arguments: + - '@pim_data_generator.writer.csv_writer' + tags: + - { name: pim_data_generator.generator } + pim_data_generator.generator.attribute_option: class: '%pim_data_generator.generator.attribute_option.class%' arguments: