diff --git a/Model/Component/AttributeSets.php b/Model/Component/AttributeSets.php new file mode 100644 index 0000000..9bca925 --- /dev/null +++ b/Model/Component/AttributeSets.php @@ -0,0 +1,148 @@ +eavSetup = $eavSetup; + $this->attributeSetRepository = $attributeSetRepository; + } + + /** + * @param array $attributeConfigurationData + */ + protected function processData($attributeConfigurationData = null) + { + try { + foreach ($attributeConfigurationData['attribute_sets'] as $attributeSetConfiguration) { + $this->processAttributeSet($attributeSetConfiguration); + } + } catch (ComponentException $e) { + $this->log->logError($e->getMessage()); + } + } + + /** + * @param array $attributeSetConfig + */ + protected function processAttributeSet(array $attributeSetConfig) + { + $this->eavSetup->addAttributeSet(Product::ENTITY, $attributeSetConfig['name']); + + $attributeSetId = $this->eavSetup->getAttributeSetId(Product::ENTITY, $attributeSetConfig['name']); + $attributeSetEntity = $this->attributeSetRepository->get($attributeSetId); + if (array_key_exists('inherit', $attributeSetConfig)) { + $attributeSetEntity->initFromSkeleton($this->getAttributeSetId($attributeSetConfig['inherit'])); + $this->attributeSetRepository->save($attributeSetEntity); + } + + if (array_key_exists('groups', $attributeSetConfig) && count($attributeSetConfig['groups']) > 0) { + $this->addAttributeGroups($attributeSetEntity, $attributeSetConfig['groups']); + $this->addAttributeGroupAssociations($attributeSetEntity, $attributeSetConfig['groups']); + } + } + + /** + * @param AttributeSetInterface $attributeSetEntity + * @param array $attributeGroupData + */ + protected function addAttributeGroups(AttributeSetInterface $attributeSetEntity, array $attributeGroupData) + { + /* if ($attributeSetEntity->getDefaultGroupId()) { + $this->eavSetup->removeAttributeGroup( + Product::ENTITY, + $attributeSetEntity->getId(), + $attributeSetEntity->getDefaultGroupId() + ); + }*/ + + foreach ($attributeGroupData as $group) { + $attributeSetName = $attributeSetEntity->getAttributeSetName(); + $this->eavSetup->addAttributeGroup(Product::ENTITY, $attributeSetName, $group['name']); + } + } + + /** + * @param AttributeSetInterface $attributeSetEntity + * @param array $attributeGroupData + */ + protected function addAttributeGroupAssociations( + AttributeSetInterface $attributeSetEntity, + array $attributeGroupData + ) { + foreach ($attributeGroupData as $group) { + foreach ($group['attributes'] as $attributeCode) { + $attributeData = $this->eavSetup->getAttribute(Product::ENTITY, $attributeCode); + + if (count($attributeData) === 0) { + throw new ComponentException("Attribute '{$attributeCode}' does not exist."); + } + + $this->eavSetup->addAttributeToGroup( + Product::ENTITY, + $attributeSetEntity->getId(), + $group['name'], + $attributeCode + ); + } + } + } + + /** + * @param $attributeSetName + * @return string + */ + protected function getAttributeSetId($attributeSetName) + { + $attributeSetData = $this->eavSetup->getAttributeSet(Product::ENTITY, $attributeSetName); + if (array_key_exists('attribute_set_id', $attributeSetData)) { + return $attributeSetData['attribute_set_id']; + } + + throw new ComponentException('Could not find attribute set name.'); + } +} diff --git a/Model/Component/Attributes.php b/Model/Component/Attributes.php new file mode 100644 index 0000000..17fb261 --- /dev/null +++ b/Model/Component/Attributes.php @@ -0,0 +1,192 @@ +eavSetup = $eavSetup; + $this->productAttributeRepository = $repository; + } + + /** + * @param array $attributeConfigurationData + */ + protected function processData($attributeConfigurationData = null) + { + try { + foreach ($attributeConfigurationData['attributes'] as $attributeCode => $attributeConfiguration) { + $this->processAttribute($attributeCode, $attributeConfiguration); + } + } catch (ComponentException $e) { + $this->log->logError($e->getMessage()); + } + } + + /** + * @param $attributeCode + * @param $attributeConfig + */ + protected function processAttribute($attributeCode, array $attributeConfig) + { + $updateAttribute = true; + $attributeExists = false; + $attributeArray = $this->eavSetup->getAttribute(Product::ENTITY, $attributeCode); + if ($attributeArray && $attributeArray['attribute_id']) { + $attributeExists = true; + $this->log->logComment(sprintf('Attribute %s exists. Checking for updates.', $attributeCode)); + $updateAttribute = $this->checkForAttributeUpdates($attributeCode, $attributeArray, $attributeConfig); + + if (isset($attributeConfig['option'])) { + $newAttributeOptions = $this->manageAttributeOptions($attributeCode, $attributeConfig['option']); + $attributeConfig['option']['values'] = $newAttributeOptions; + } + } + + if ($updateAttribute) { + + $attributeConfig['user_defined'] = 1; + + if (isset($attributeConfig['product_types'])) { + $attributeConfig['apply_to'] = implode(',', $attributeConfig['product_types']); + } + + $this->eavSetup->addAttribute( + Product::ENTITY, + $attributeCode, + $attributeConfig + ); + + if ($attributeExists) { + $this->log->logInfo(sprintf('Attribute %s updated.', $attributeCode)); + return; + } + + $this->log->logInfo(sprintf('Attribute %s created.', $attributeCode)); + } + } + + protected function checkForAttributeUpdates($attributeCode, $attributeArray, $attributeConfig) + { + $requiresUpdate = false; + $nest = 1; + foreach ($attributeConfig as $name => $value) { + + if ($name == "product_types") { + $value = implode(',', $value); + } + + $name = $this->mapAttributeConfig($name); + + if ($name == 'option') { + continue; + } + + if (!isset($attributeArray[$name])) { + $this->log->logError(sprintf( + 'Attribute %s type %s does not exist or is not mapped', + $attributeCode, + $name + ), $nest); + continue; + } + + if ($attributeArray[$name] != $value) { + $this->log->logInfo(sprintf( + 'Update required for %s as %s is "%s" but should be "%s"', + $attributeCode, + $name, + $attributeArray[$name], + $value + ), $nest); + + $requiresUpdate = true; + + continue; + } + + $this->log->logComment(sprintf( + 'No Update required for %s as %s is still "%s"', + $attributeCode, + $name, + $value + ), $nest); + } + + return $requiresUpdate; + } + + protected function mapAttributeConfig($name) + { + if ($name == 'label') { + $name = 'frontend_label'; + } + + if ($name == 'type') { + $name = 'backend_type'; + } + + if ($name == 'input') { + $name = 'frontend_input'; + } + + if ($name == 'product_types') { + $name = 'apply_to'; + } + return $name; + } + + private function manageAttributeOptions($attributeCode, $option) + { + $attributeOptions = $this->productAttributeRepository->get($attributeCode)->getOptions(); + + // Loop through existing attributes options + $existingAttributeOptions = array(); + foreach ($attributeOptions as $attributeOption) { + $value = $attributeOption->getLabel(); + $existingAttributeOptions[] = $value; + } + + $optionsToAdd = array_diff($option['values'], $existingAttributeOptions); + //$optionsToRemove = array_diff($existingAttributeOptions, $option['values']); + + return $optionsToAdd; + } +} diff --git a/README.md b/README.md index 060e30c..43c511b 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ Do also include sample files with your component that works | System Configuration | :white_check_mark: | :grey_exclamation: | :white_check_mark: | | Categories | :white_check_mark: | :grey_exclamation: | :white_check_mark: | | Products | :white_check_mark: | :grey_exclamation: | :white_check_mark: | +| Attributes | :white_check_mark: | :grey_exclamation: | :white_check_mark: | | Blocks | :white_check_mark: | :grey_exclamation: | :white_check_mark: | | Admin Roles | :white_check_mark: | :grey_exclamation: | :white_check_mark: | | Admin Users | :white_check_mark: | :grey_exclamation: | :white_check_mark: | @@ -56,7 +57,6 @@ Do also include sample files with your component that works | Tax Rules | :white_check_mark: | :grey_exclamation: | :white_check_mark: | | Tax Rates | :x: | :x: | :x: | | Attribute Sets | :x: | :x: | :x: | -| Attributes | :x: | :x: | :x: | | Customers | :x: | :x: | :x: | | Related Products | :x: | :x: | :x: | | SQL | :x: | :x: | :x: | diff --git a/Samples/Components/Attributes/attribute_sets.yaml b/Samples/Components/Attributes/attribute_sets.yaml new file mode 100644 index 0000000..3cd7b13 --- /dev/null +++ b/Samples/Components/Attributes/attribute_sets.yaml @@ -0,0 +1,39 @@ +attribute_sets: +- + name: Shirts + inherit: Default + groups: + - + name: General + attributes: + - colour + - color + - + name: Prices + attributes: + - rrp + - test_attr +- + name: Example Attribute Set 2 + inherit: Default + groups: + - + name: Prices + attributes: + - rrp +- + name: Matthew Attribute Set + inherit: Default + groups: + - + name: Prices + attributes: + - rrp +- + name: Matthew Attribute Set 2 + groups: + - + name: Prices + attributes: + - rrp + diff --git a/Samples/Components/Attributes/attributes.yaml b/Samples/Components/Attributes/attributes.yaml new file mode 100644 index 0000000..17196e2 --- /dev/null +++ b/Samples/Components/Attributes/attributes.yaml @@ -0,0 +1,36 @@ +attributes: + test_attr: + is_global: 1 + label: Test Attribute + type: text + input: select + is_visible_on_front: 1 + is_filterable: 1 + is_searchable: 1 + is_visible_in_advanced_search: 0 + product_types: + - simple + option: + values: + - Red + - Green + - Yellow + - Blue + - Purple + - Pink + - Orange + - Brown + rrp: + frontend_label: Recommended Retail Price + frontend_input: price + used_in_product_listing: 1 + product_types: + - bundle + - simple + colour: + frontend_label: Colour + frontend_input: text + used_in_product_listing: 1 + product_types: + - bundle + - simple diff --git a/Samples/master.yaml b/Samples/master.yaml index e6495fa..c690a77 100644 --- a/Samples/master.yaml +++ b/Samples/master.yaml @@ -106,4 +106,14 @@ media: enabled: 1 method: code sources: - - ../configurator/Media/media.yaml \ No newline at end of file + - ../configurator/Media/media.yaml +attributes: + enabled: 1 + method: code + sources: + - ../configurator/Attributes/attributes.yaml +attribute_sets: + enabled: 1 + method: code + sources: + - ../configurator/Attributes/attribute_sets.yaml diff --git a/Test/Unit/Component/AttributeSetsTest.php b/Test/Unit/Component/AttributeSetsTest.php new file mode 100644 index 0000000..5c4af17 --- /dev/null +++ b/Test/Unit/Component/AttributeSetsTest.php @@ -0,0 +1,31 @@ +getMock(EavSetup::class, [], [], '', false); + $attributeSetsRepositoryInterface = $this->getMock(AttributeSetRepositoryInterface::class); + + $this->component = new AttributeSets( + $this->logInterface, + $this->objectManager, + $eavSetup, + $attributeSetsRepositoryInterface + ); + + $this->className = AttributeSets::class; + } +} diff --git a/Test/Unit/Component/AttributesTest.php b/Test/Unit/Component/AttributesTest.php new file mode 100644 index 0000000..6670625 --- /dev/null +++ b/Test/Unit/Component/AttributesTest.php @@ -0,0 +1,19 @@ +getMock(EavSetup::class, [], [], '', false); + $attributeRepository = $this->getMock(ProductAttributeRepository::class, [], [], '', false); + $this->component = new Attributes($this->logInterface, $this->objectManager, $eavSetup, $attributeRepository); + $this->className = Attributes::class; + } +} diff --git a/composer.json b/composer.json index c4f1f00..4a7bb36 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "satooshi/php-coveralls": "^1.0", "phpunit/phpunit": "4.1.0" }, - "version": "0.11.0-dev", + "version": "0.12.0-dev", "autoload": { "files": [ "registration.php" ], "psr-4": { diff --git a/etc/configurator.xml b/etc/configurator.xml index 1037ae0..faa013b 100644 --- a/etc/configurator.xml +++ b/etc/configurator.xml @@ -14,4 +14,6 @@ + + \ No newline at end of file