diff --git a/Component/Attributes.php b/Component/Attributes.php index 914dd2f..8ddb830 100644 --- a/Component/Attributes.php +++ b/Component/Attributes.php @@ -9,6 +9,7 @@ use Magento\Eav\Api\AttributeRepositoryInterface; use Magento\Eav\Setup\EavSetup; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Catalog\Model\ResourceModel\Eav\Attribute; /** * @SuppressWarnings(PHPMD.LongVariable) @@ -40,6 +41,16 @@ class Attributes implements ComponentInterface */ private $log; + /** + * @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory + */ + protected $attrOptionCollectionFactory; + + /** + * @var \Magento\Eav\Model\Config + */ + protected $eavConfig; + /** * @var array */ @@ -88,20 +99,31 @@ class Attributes implements ComponentInterface */ protected $attributeExists = false; + /** + * @var array + */ + protected $swatchMap = []; + /** * Attributes constructor. * @param EavSetup $eavSetup * @param AttributeRepositoryInterface $attributeRepository * @param LoggerInterface $log + * @param \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory $attrOptionCollectionFactory + * @param \Magento\Eav\Model\Config $eavConfig */ public function __construct( EavSetup $eavSetup, AttributeRepositoryInterface $attributeRepository, - LoggerInterface $log + LoggerInterface $log, + \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory $attrOptionCollectionFactory, + \Magento\Eav\Model\Config $eavConfig ) { $this->eavSetup = $eavSetup; $this->attributeRepository = $attributeRepository; $this->log = $log; + $this->attrOptionCollectionFactory = $attrOptionCollectionFactory; + $this->eavConfig = $eavConfig; } /** @@ -149,7 +171,14 @@ protected function processAttribute($attributeCode, array $attributeConfig) if (isset($attributeConfig['product_types'])) { $attributeConfig['apply_to'] = implode(',', $attributeConfig['product_types']); } - + //swatch functionality + $swatch = false; + if (in_array($attributeConfig['input'], ['swatch_text', 'swatch_visual'])){ + $swatch = $attributeConfig['input']; + $attributeConfig['input'] = 'select'; + $this->swatchMap = $attributeConfig['swatch'] ?? []; + } + //swatch functionality $this->eavSetup->addAttribute( $this->entityTypeId, $attributeCode, @@ -160,6 +189,16 @@ protected function processAttribute($attributeCode, array $attributeConfig) $this->log->logInfo(sprintf('Attribute %s updated.', $attributeCode)); return; } + //swatch functionality + if ($swatch) { + if ($swatch === 'swatch_text'){ + $this->convertToTextSwatch($attributeCode, $attributeConfig); + } else { + $this->convertToVisualSwatch($attributeCode, $attributeConfig); + + } + } + //swatch functionality $this->log->logInfo(sprintf('Attribute %s created.', $attributeCode)); } @@ -275,4 +314,132 @@ public function getDescription() { return $this->description; } + + /** + * @param string $attributeName + * @param array $attributeConfig + * @return void + */ + public function convertToVisualSwatch(string $attributeName, array $attributeConfig) + { + $attribute = $this->eavConfig->getAttribute('catalog_product', $attributeName); + if (!$attribute) { + return; + } + $attributeData['option'] = $this->addExistingOptions($attribute); + $attributeData['frontend_input'] = 'select'; + $attributeData['swatch_input_type'] = 'visual'; + $attributeData['update_product_preview_image'] = 1; + $attributeData['use_product_image_for_swatch'] = 0; + $attributeData['optionvisual'] = $this->getOptionSwatch($attributeData, $attributeConfig['option']['values']); + $attributeData['swatchvisual'] = $this->getOptionSwatchVisual($attributeData); + $attribute->addData($attributeData); + $attribute->save(); + } + + /** + * @param string $attributeName + * @param array $attributeConfig + * @return void + */ + public function convertToTextSwatch(string $attributeName, array $attributeConfig) + { + $attribute = $this->eavConfig->getAttribute('catalog_product', $attributeName); + if (!$attribute) { + return; + } + $attributeData['option'] = $this->addExistingOptions($attribute); + $attributeData['frontend_input'] = 'select'; + $attributeData['swatch_input_type'] = 'text'; + $attributeData['update_product_preview_image'] = 1; + $attributeData['use_product_image_for_swatch'] = 0; + $attributeData['optiontext'] = $this->getOptionSwatch($attributeData, $attributeConfig['option']['values']); + $attributeData['swatchtext'] = $this->getOptionSwatchText($attributeData); + $attribute->addData($attributeData); + $attribute->save(); + } + + + /** + * @param array $attributeData + * @return array + */ + private function getOptionSwatchVisual(array $attributeData): array + { + $optionSwatch = ['value' => []]; + foreach ($attributeData['option'] as $optionKey => $optionValue) { + if (substr($optionValue, 0, 1) == '#' && strlen($optionValue) == 7) { + $optionSwatch['value'][$optionKey] = $optionValue; + } else if (!empty($this->swatchMap[$optionKey])) { + $optionSwatch['value'][$optionKey] = $this->swatchMap[$optionKey]; + } else { + $optionSwatch['value'][$optionKey] = null; + } + } + return $optionSwatch; + } + + /** + * @param array $attributeData + * @param array $attributeOptions + * @return array + */ + protected function getOptionSwatch(array $attributeData, array $attributeOptions): array + { + $optionSwatch = ['order' => [], 'value' => [], 'delete' => []]; + $i = 0; + foreach ($attributeData['option'] as $optionKey => $optionValue) { + $label = array_search($optionValue, $attributeOptions) ?? $optionValue; + $optionSwatch['delete'][$optionKey] = ''; + $optionSwatch['order'][$optionKey] = (string)$i++; + $optionSwatch['value'][$optionKey] = [$label, '']; + } + return $optionSwatch; + } + + /** + * @param array $attributeData + * @return array + */ + private function getOptionSwatchText(array $attributeData): array + { + $optionSwatch = ['value' => []]; + foreach ($attributeData['option'] as $optionKey => $optionValue) { + $optionSwatch['value'][$optionKey] = [$optionValue, '']; + } + return $optionSwatch; + } + + /** + * @param $attributeId + * @return void + */ + private function loadOptionCollection($attributeId) + { + if (empty($this->optionCollection[$attributeId])) { + $this->optionCollection[$attributeId] = $this->attrOptionCollectionFactory->create() + ->setAttributeFilter($attributeId) + ->setPositionOrder('asc', true) + ->load(); + } + } + + /** + * @param Attribute $attribute + * @return array + */ + private function addExistingOptions(Attribute $attribute): array + { + $options = []; + $attributeId = $attribute->getId(); + if ($attributeId) { + $this->loadOptionCollection($attributeId); + /** @var \Magento\Eav\Model\Entity\Attribute\Option $option */ + foreach ($this->optionCollection[$attributeId] as $option) { + $options[$option->getId()] = $option->getValue(); + } + } + + return $options; + } } diff --git a/Component/CustomerAttributes.php b/Component/CustomerAttributes.php index 355b5d4..fb716e4 100644 --- a/Component/CustomerAttributes.php +++ b/Component/CustomerAttributes.php @@ -75,9 +75,11 @@ public function __construct( AttributeRepository $attributeRepository, CustomerSetupFactory $customerSetupFactory, Attribute $attributeResource, - LoggerInterface $log + LoggerInterface $log, + \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory $attrOptionCollectionFactory, + \Magento\Eav\Model\Config $eavConfig ) { - parent::__construct($eavSetup, $attributeRepository, $log); + parent::__construct($eavSetup, $attributeRepository, $log, $attrOptionCollectionFactory, $eavConfig); $this->attributeConfigMap = array_merge($this->attributeConfigMap, $this->customerConfigMap); $this->customerSetup = $customerSetupFactory; $this->attributeResource = $attributeResource; diff --git a/Samples/Components/Attributes/attributes.yaml b/Samples/Components/Attributes/attributes.yaml index 5bee1fb..0ea518a 100644 --- a/Samples/Components/Attributes/attributes.yaml +++ b/Samples/Components/Attributes/attributes.yaml @@ -34,3 +34,61 @@ attributes: product_types: - bundle - simple + colour_with_swatches: + global: 1 + label: Colour + type: int + input: swatch_visual + visible_on_front: 1 + filterable: 1 + filterable_in_search: 1 + required: 0 + searchable: 1 + visible_in_advanced_search: 1 + used_for_promo_rules: 0 + used_in_product_listing: 1 + position: 20 + product_types: + - simple + - configurable + option: + values: + 'Aqua blue': '#A1DAD7' + 'Aqua marine': '#7FFFD4' + 'Black': '#000000' + 'Blue': '#0000FF' + 'Bottle green': '#093624' + 'Bright blue': '#2EFFFA' + 'Brown': '#964B00' + 'Cerise pink': '#DA3287' + 'Cinnabar': '#E34234' + 'Dark brown': '#5F1811' + 'Dark green': '#105B10' + 'Dark grey': '#484747' + 'Dark purple': '#3A0156' + 'Denim blue': '#1560BD' + 'Forest green': '#228B22' + 'French navy': '#005280' + 'Grape': '#381A51' + 'Green': '#00FF00' + 'Grey': '#808080' + 'Indigo denim': '#3752B3' + 'Khaki': '#F0E68C' + 'Lemon yellow': '#FDE910' + 'Light blue': '#D6E6FF' + 'Light green': '#D6FFD8' + 'Light grey': '#DEDEDE' + 'Lime green': '#BFFF00' + 'Mustard yellow': '#FFDB58' + 'Navy blue': '#000080' + 'Orange': '#FF681F' + 'Pale Green': '#72836E' + 'Pink': '#FFC0CB' + 'Purple': '#660099' + 'Red': '#FF0000' + 'Sky blue': '#76D7EA' + 'Slate grey': '#708090' + 'Tomato red': '#FF3100' + 'Turquoise': '#30D5C8' + 'White': '#FFFFFF' + 'Yellow': '#FFFF00' \ No newline at end of file