diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php index 218507d0dd1457c3d1d6fe2cebc49af8da90b195..1bdad7d3147f56e7f9c0d9450030ec08f8abe855 100644 --- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php @@ -77,7 +77,7 @@ abstract class AbstractModifierTest extends \PHPUnit_Framework_TestCase ->willReturnArgument(1); $this->arrayManagerMock->expects($this->any()) ->method('get') - ->willReturnArgument(3); + ->willReturnArgument(2); $this->arrayManagerMock->expects($this->any()) ->method('set') ->willReturnArgument(1); diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php index 1418967884a5006ff9e340ec12950bb532d4b867..25280559e543a942949d1a89910f94d306171549 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php @@ -122,9 +122,6 @@ class AdvancedPricing extends AbstractModifier { $this->meta = $meta; - $this->preparePriceFields(ProductAttributeInterface::CODE_PRICE); - $this->preparePriceFields(ProductAttributeInterface::CODE_SPECIAL_PRICE); - $this->preparePriceFields(ProductAttributeInterface::CODE_COST); $this->specialPriceDataToInline(); $this->customizeTierPrice(); @@ -182,7 +179,7 @@ class AdvancedPricing extends AbstractModifier $tierPricePath = $this->getElementArrayPath($this->meta, ProductAttributeInterface::CODE_TIER_PRICE); if ($tierPricePath) { - $this->meta = $this->arrayManager->set( + $this->meta = $this->arrayManager->merge( $tierPricePath, $this->meta, $this->getTierPriceStructure($tierPricePath) diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php index 7ae19a786104878d3c47704a9684ce86c9ba434a..9370390ad7bec3fbb6c5ed0c0e95e4848734acd2 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php @@ -20,6 +20,7 @@ use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Framework\Api\SortOrderBuilder; use Magento\Framework\App\RequestInterface; use Magento\Framework\Filter\Translit; +use Magento\Framework\Stdlib\ArrayManager; use Magento\Store\Model\StoreManagerInterface; use Magento\Ui\Component\Form\Field; use Magento\Ui\Component\Form\Fieldset; @@ -129,6 +130,11 @@ class Eav extends AbstractModifier */ private $translitFilter; + /** + * @var ArrayManager + */ + private $arrayManager; + /** * @var ScopeOverriddenValue */ @@ -150,8 +156,6 @@ class Eav extends AbstractModifier private $attributesToEliminate; /** - * Initialize dependencies - * * @param LocatorInterface $locator * @param EavValidationRules $eavValidationRules * @param Config $eavConfig @@ -166,6 +170,7 @@ class Eav extends AbstractModifier * @param SortOrderBuilder $sortOrderBuilder * @param EavAttributeFactory $eavAttributeFactory * @param Translit $translitFilter + * @param ArrayManager $arrayManager * @param ScopeOverriddenValue $scopeOverriddenValue * @param array $attributesToDisable * @param array $attributesToEliminate @@ -186,6 +191,7 @@ class Eav extends AbstractModifier SortOrderBuilder $sortOrderBuilder, EavAttributeFactory $eavAttributeFactory, Translit $translitFilter, + ArrayManager $arrayManager, ScopeOverriddenValue $scopeOverriddenValue, $attributesToDisable = [], $attributesToEliminate = [] @@ -204,6 +210,7 @@ class Eav extends AbstractModifier $this->sortOrderBuilder = $sortOrderBuilder; $this->eavAttributeFactory = $eavAttributeFactory; $this->translitFilter = $translitFilter; + $this->arrayManager = $arrayManager; $this->scopeOverriddenValue = $scopeOverriddenValue; $this->attributesToDisable = $attributesToDisable; $this->attributesToEliminate = $attributesToEliminate; @@ -239,68 +246,75 @@ class Eav extends AbstractModifier * @param string $groupCode * @return array * @throws \Magento\Framework\Exception\LocalizedException - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function getAttributesMeta(array $attributes, $groupCode) { $meta = []; - foreach ($attributes as $sortKey => $attribute) { + foreach ($attributes as $sortOrder => $attribute) { if (in_array($attribute->getFrontendInput(), $this->bannedInputTypes)) { continue; } - $code = $attribute->getAttributeCode(); - if (in_array($code, $this->attributesToEliminate)) { + if (in_array($attribute->getAttributeCode(), $this->attributesToEliminate)) { continue; } - $child = $this->setupMetaProperties($attribute); - $meta[static::CONTAINER_PREFIX . $code] = [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'formElement' => 'container', - 'componentType' => 'container', - 'breakLine' => false, - 'label' => __('%1', $attribute->getDefaultFrontendLabel()), - 'sortOrder' => $sortKey * self::SORT_ORDER_MULTIPLIER, - 'required' => $attribute->getIsRequired(), - 'scopeLabel' => $this->getScopeLabel($attribute), - ], - ], - ], - ]; - - if ($attribute->getIsWysiwygEnabled()) { - $meta[static::CONTAINER_PREFIX . $code]['arguments']['data']['config']['component'] = - 'Magento_Ui/js/form/components/group'; + if (!($attributeContainer = $this->setupAttributeContainerMeta($attribute))) { + continue; } - $child['arguments']['data']['config']['code'] = $code; - $child['arguments']['data']['config']['source'] = $groupCode; - $child['arguments']['data']['config']['scopeLabel'] = $this->getScopeLabel($attribute); - $child['arguments']['data']['config']['globalScope'] = $this->isScopeGlobal($attribute); - $child['arguments']['data']['config']['sortOrder'] = $sortKey * self::SORT_ORDER_MULTIPLIER; + $attributeContainer = $this->addContainerChildren($attributeContainer, $attribute, $groupCode, $sortOrder); - if (!isset($child['arguments']['data']['config']['componentType'])) { - $child['arguments']['data']['config']['componentType'] = Field::NAME; - } + $meta[static::CONTAINER_PREFIX . $attribute->getAttributeCode()] = $attributeContainer; + } - if (in_array($code, $this->attributesToDisable)) { - $child['arguments']['data']['config']['disabled'] = true; - } - // TODO: getAttributeModel() should not be used when MAGETWO-48284 is complete - $childData = $child['arguments']['data']['config']; - if (($rules = $this->eavValidationRules->build($this->getAttributeModel($attribute), $childData))) { - $child['arguments']['data']['config']['validation'] = $rules; - } + return $meta; + } - $meta[static::CONTAINER_PREFIX . $code]['children'][$code] = $child; + /** + * Add container children + * + * @param array $attributeContainer + * @param ProductAttributeInterface $attribute + * @param string $groupCode + * @param int $sortOrder + * @return array + */ + public function addContainerChildren( + array $attributeContainer, + ProductAttributeInterface $attribute, + $groupCode, + $sortOrder + ) { + foreach ($this->getContainerChildren($attribute, $groupCode, $sortOrder) as $childCode => $child) { + $attributeContainer['children'][$childCode] = $child; } - return $meta; + $attributeContainer = $this->arrayManager->merge( + ltrim(static::META_CONFIG_PATH, ArrayManager::DEFAULT_PATH_DELIMITER), + $attributeContainer, + ['sortOrder' => $sortOrder * self::SORT_ORDER_MULTIPLIER] + ); + + return $attributeContainer; + } + + /** + * Retrieve container child fields + * + * @param ProductAttributeInterface $attribute + * @param string $groupCode + * @param int $sortOrder + * @return array + */ + public function getContainerChildren(ProductAttributeInterface $attribute, $groupCode, $sortOrder) + { + if (!($child = $this->setupAttributeMeta($attribute, $groupCode, $sortOrder))) { + return []; + } + + return [$attribute->getAttributeCode() => $child]; } /** @@ -308,13 +322,18 @@ class Eav extends AbstractModifier */ public function modifyData(array $data) { + $productId = $this->locator->getProduct()->getId(); + /** @var string $groupCode */ foreach (array_keys($this->getGroups()) as $groupCode) { + /** @var ProductAttributeInterface[] $attributes */ $attributes = !empty($this->getAttributes()[$groupCode]) ? $this->getAttributes()[$groupCode] : []; - /* @var EavAttribute $attribute */ foreach ($attributes as $attribute) { - $data = $this->setAttributeValueToData($data, $attribute->getAttributeCode()); + if (null !== ($attributeValue = $this->setupAttributeData($attribute))) { + $data[$productId][self::DATA_SOURCE_DEFAULT][$attribute->getAttributeCode()] = $attributeValue; + } + } } @@ -455,43 +474,85 @@ class Eav extends AbstractModifier * Initial meta setup * * @param ProductAttributeInterface $attribute + * @param string $groupCode + * @param int $sortOrder * @return array * @throws \Magento\Framework\Exception\LocalizedException + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ - protected function setupMetaProperties(ProductAttributeInterface $attribute) + public function setupAttributeMeta(ProductAttributeInterface $attribute, $groupCode, $sortOrder) { - $meta = [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'dataType' => $attribute->getFrontendInput(), - 'formElement' => $this->getFormElementsMapValue($attribute->getFrontendInput()), - 'visible' => $attribute->getIsVisible(), - 'required' => $attribute->getIsRequired(), - 'notice' => $attribute->getNote(), - 'default' => $attribute->getDefaultValue(), - 'label' => __('%1', $attribute->getDefaultFrontendLabel()), - ], - ], - ], - ]; - foreach ($meta as $key => $value) { - if ($value === null) { - unset($meta[$key]); - } - } + $configPath = ltrim(static::META_CONFIG_PATH, ArrayManager::DEFAULT_PATH_DELIMITER); + + $meta = $this->arrayManager->set($configPath, [], [ + 'dataType' => $attribute->getFrontendInput(), + 'formElement' => $this->getFormElementsMapValue($attribute->getFrontendInput()), + 'visible' => $attribute->getIsVisible(), + 'required' => $attribute->getIsRequired(), + 'notice' => $attribute->getNote(), + 'default' => $attribute->getDefaultValue(), + 'label' => $attribute->getDefaultFrontendLabel(), + 'code' => $attribute->getAttributeCode(), + 'source' => $groupCode, + 'scopeLabel' => $this->getScopeLabel($attribute), + 'globalScope' => $this->isScopeGlobal($attribute), + 'sortOrder' => $sortOrder * self::SORT_ORDER_MULTIPLIER, + ]); // TODO: Refactor to $attribute->getOptions() when MAGETWO-48289 is done $attributeModel = $this->getAttributeModel($attribute); if ($attributeModel->usesSource()) { - $meta['arguments']['data']['config']['options'] = $attributeModel->getSource()->getAllOptions(); + $meta = $this->arrayManager->merge($configPath, $meta, [ + 'options' => $attributeModel->getSource()->getAllOptions(), + ]); + } + + if ($this->canDisplayUseDefault($attribute)) { + $meta = $this->arrayManager->merge($configPath, $meta, [ + 'service' => [ + 'template' => 'ui/form/element/helper/service', + ] + ]); + } + + if (!$this->arrayManager->exists($configPath . '/componentType', $meta)) { + $meta = $this->arrayManager->merge($configPath, $meta, [ + 'componentType' => Field::NAME, + ]); + } + + if (in_array($attribute->getAttributeCode(), $this->attributesToDisable)) { + $meta = $this->arrayManager->merge($configPath, $meta, [ + 'disabled' => true, + ]); + } + + // TODO: getAttributeModel() should not be used when MAGETWO-48284 is complete + $childData = $this->arrayManager->get($configPath, $meta, []); + if (($rules = $this->eavValidationRules->build($this->getAttributeModel($attribute), $childData))) { + $meta = $this->arrayManager->merge($configPath, $meta, [ + 'validation' => $rules, + ]); } - $meta = $this->addWysiwyg($attribute, $meta); - $meta = $this->customizeCheckbox($attribute, $meta); - $meta = $this->customizePriceAttribute($attribute, $meta); $meta = $this->addUseDefaultValueCheckbox($attribute, $meta); + switch ($attribute->getFrontendInput()) { + case 'boolean': + $meta = $this->customizeCheckbox($attribute, $meta); + break; + case 'textarea': + $meta = $this->customizeWysiwyg($attribute, $meta); + break; + case 'price': + $meta = $this->customizePriceAttribute($attribute, $meta); + break; + case 'gallery': + // Gallery attribute is being handled by "Images And Videos Tab" + $meta = []; + break; + } + return $meta; } @@ -518,6 +579,60 @@ class Eav extends AbstractModifier return $meta; } + /** + * Setup attribute container meta + * + * @param ProductAttributeInterface $attribute + * @return array + */ + public function setupAttributeContainerMeta(ProductAttributeInterface $attribute) + { + $containerMeta = $this->arrayManager->set( + 'arguments/data/config', + [], + [ + 'formElement' => 'container', + 'componentType' => 'container', + 'breakLine' => false, + 'label' => $attribute->getDefaultFrontendLabel(), + 'required' => $attribute->getIsRequired(), + ] + ); + + if ($attribute->getIsWysiwygEnabled()) { + $containerMeta = $this->arrayManager->merge( + 'arguments/data/config', + $containerMeta, + [ + 'component' => 'Magento_Ui/js/form/components/group' + ] + ); + } + + return $containerMeta; + } + + /** + * Setup attribute data + * + * @param ProductAttributeInterface $attribute + * @return mixed|null + */ + public function setupAttributeData(ProductAttributeInterface $attribute) + { + $product = $this->locator->getProduct(); + $productId = $product->getId(); + $prevSetId = $this->getPrevSetId(); + $notUsed = !$prevSetId + || ($prevSetId && !in_array($attribute->getAttributeCode(), $this->getPrevSetAttributes())); + + if ($productId && $notUsed) { + return $this->getValue($attribute); + } + + return null; + } + /** * Customize checkboxes * @@ -563,7 +678,7 @@ class Eav extends AbstractModifier * @param array $meta * @return array */ - private function addWysiwyg(ProductAttributeInterface $attribute, array $meta) + private function customizeWysiwyg(ProductAttributeInterface $attribute, array $meta) { if (!$attribute->getIsWysiwygEnabled()) { return $meta; @@ -588,41 +703,18 @@ class Eav extends AbstractModifier return isset($valueMap[$value]) ? $valueMap[$value] : $value; } - /** - * Set attribute to loaded data - * - * @param array $data - * @param string $attributeCode - * @return $this - */ - protected function setAttributeValueToData(array $data, $attributeCode) - { - $product = $this->locator->getProduct(); - $productId = $product->getId(); - $prevSetId = $this->getPrevSetId(); - $notUsed = !$prevSetId || ($prevSetId && !in_array($attributeCode, $this->getPrevSetAttributes())); - - if ($productId && $notUsed) { - if (null !== ($value = $this->getValue($attributeCode))) { - $data[$productId][self::DATA_SOURCE_DEFAULT][$attributeCode] = $value; - } - } - - return $data; - } - /** * Retrieve attribute value * - * @param string $attributeCode + * @param ProductAttributeInterface $attribute * @return mixed */ - protected function getValue($attributeCode) + protected function getValue(ProductAttributeInterface $attribute) { /** @var Product $product */ $product = $this->locator->getProduct(); - return $product->getData($attributeCode); + return $product->getData($attribute->getAttributeCode()); } /** diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Related.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Related.php index f39c5c69a2be72c7467b62b2ef08218b64d9ca3c..3552ce8a0c20be79186964833e54601c98c275d4 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Related.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Related.php @@ -5,6 +5,8 @@ */ namespace Magento\Catalog\Ui\DataProvider\Product\Form\Modifier; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\Data\ProductLinkInterface; use Magento\Catalog\Api\ProductLinkRepositoryInterface; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Locator\LocatorInterface; @@ -185,18 +187,7 @@ class Related extends AbstractModifier false, $this->locator->getStore()->getId() ); - $data[$productId]['links'][$dataScope][] = [ - 'id' => $linkedProduct->getId(), - 'thumbnail' => $this->imageHelper->init($linkedProduct, 'product_listing_thumbnail')->getUrl(), - 'name' => $linkedProduct->getName(), - 'status' => $this->status->getOptionText($linkedProduct->getStatus()), - 'attribute_set' => $this->attributeSetRepository - ->get($linkedProduct->getAttributeSetId()) - ->getAttributeSetName(), - 'sku' => $linkItem->getLinkedProductSku(), - 'price' => $linkedProduct->getPrice(), - 'position' => $linkItem->getPosition(), - ]; + $data[$productId]['links'][$dataScope][] = $this->fillData($linkedProduct, $linkItem); } } @@ -206,6 +197,29 @@ class Related extends AbstractModifier return $data; } + /** + * Prepare data column + * + * @param ProductInterface $linkedProduct + * @param ProductLinkInterface $linkItem + * @return array + */ + protected function fillData(ProductInterface $linkedProduct, ProductLinkInterface $linkItem) + { + return [ + 'id' => $linkedProduct->getId(), + 'thumbnail' => $this->imageHelper->init($linkedProduct, 'product_listing_thumbnail')->getUrl(), + 'name' => $linkedProduct->getName(), + 'status' => $this->status->getOptionText($linkedProduct->getStatus()), + 'attribute_set' => $this->attributeSetRepository + ->get($linkedProduct->getAttributeSetId()) + ->getAttributeSetName(), + 'sku' => $linkItem->getLinkedProductSku(), + 'price' => $linkedProduct->getPrice(), + 'position' => $linkItem->getPosition(), + ]; + } + /** * Retrieve all data scopes * @@ -529,56 +543,66 @@ class Related extends AbstractModifier ], ], ], - 'children' => [ - 'id' => $this->getTextColumn('id', false, 'ID', 0), - 'thumbnail' => [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'componentType' => Field::NAME, - 'formElement' => Input::NAME, - 'elementTmpl' => 'ui/dynamic-rows/cells/thumbnail', - 'dataType' => Text::NAME, - 'dataScope' => 'thumbnail', - 'fit' => true, - 'label' => __('Thumbnail'), - 'sortOrder' => 10, - ], - ], - ], + 'children' => $this->fillMeta(), + ], + ], + ]; + } + + /** + * Retrieve meta column + * + * @return array + */ + protected function fillMeta() + { + return [ + 'id' => $this->getTextColumn('id', false, __('ID'), 0), + 'thumbnail' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Field::NAME, + 'formElement' => Input::NAME, + 'elementTmpl' => 'ui/dynamic-rows/cells/thumbnail', + 'dataType' => Text::NAME, + 'dataScope' => 'thumbnail', + 'fit' => true, + 'label' => __('Thumbnail'), + 'sortOrder' => 10, ], - 'name' => $this->getTextColumn('name', false, 'Name', 20), - 'status' => $this->getTextColumn('status', true, 'Status', 30), - 'attribute_set' => $this->getTextColumn('attribute_set', false, 'Attribute Set', 40), - 'sku' => $this->getTextColumn('sku', true, 'SKU', 50), - 'price' => $this->getTextColumn('price', true, 'Price', 60), - 'actionDelete' => [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'additionalClasses' => 'data-grid-actions-cell', - 'componentType' => 'actionDelete', - 'dataType' => Text::NAME, - 'label' => __('Actions'), - 'sortOrder' => 70, - 'fit' => true, - ], - ], - ], + ], + ], + ], + 'name' => $this->getTextColumn('name', false, __('Name'), 20), + 'status' => $this->getTextColumn('status', true, __('Status'), 30), + 'attribute_set' => $this->getTextColumn('attribute_set', false, __('Attribute Set'), 40), + 'sku' => $this->getTextColumn('sku', true, __('SKU'), 50), + 'price' => $this->getTextColumn('price', true, __('Price'), 60), + 'actionDelete' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'additionalClasses' => 'data-grid-actions-cell', + 'componentType' => 'actionDelete', + 'dataType' => Text::NAME, + 'label' => __('Actions'), + 'sortOrder' => 70, + 'fit' => true, ], - 'position' => [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'dataType' => Number::NAME, - 'formElement' => Input::NAME, - 'componentType' => Field::NAME, - 'dataScope' => 'position', - 'sortOrder' => 80, - 'visible' => false, - ], - ], - ], + ], + ], + ], + 'position' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => Number::NAME, + 'formElement' => Input::NAME, + 'componentType' => Field::NAME, + 'dataScope' => 'position', + 'sortOrder' => 80, + 'visible' => false, ], ], ], @@ -591,11 +615,11 @@ class Related extends AbstractModifier * * @param string $dataScope * @param bool $fit - * @param string $label + * @param Phrase $label * @param int $sortOrder * @return array */ - protected function getTextColumn($dataScope, $fit, $label, $sortOrder) + protected function getTextColumn($dataScope, $fit, Phrase $label, $sortOrder) { $column = [ 'arguments' => [ diff --git a/app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php b/app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php index 24396c0df730735077ca1671392396168625025b..35b9be0305019f09ede3048ae2e5a38cebf7eb4d 100644 --- a/app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php +++ b/app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php @@ -5,6 +5,8 @@ */ namespace Magento\GroupedProduct\Ui\DataProvider\Product\Form\Modifier; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\Data\ProductLinkInterface; use Magento\Catalog\Model\Locator\LocatorInterface; use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; use Magento\Framework\Phrase; @@ -127,8 +129,6 @@ class Grouped extends AbstractModifier $modelId = $product->getId(); if ($modelId) { $storeId = $this->locator->getStore()->getId(); - /** @var \Magento\Framework\Currency $currency */ - $currency = $this->localeCurrency->getCurrency($this->locator->getBaseCurrencyCode()); $data[$product->getId()]['links'][self::LINK_TYPE] = []; foreach ($this->productLinkRepository->getList($product) as $linkItem) { if ($linkItem->getLinkType() !== self::LINK_TYPE) { @@ -136,26 +136,41 @@ class Grouped extends AbstractModifier } /** @var \Magento\Catalog\Api\Data\ProductInterface $linkedProduct */ $linkedProduct = $this->productRepository->get($linkItem->getLinkedProductSku(), false, $storeId); - $data[$modelId]['links'][self::LINK_TYPE][] = [ - 'id' => $linkedProduct->getId(), - 'name' => $linkedProduct->getName(), - 'sku' => $linkItem->getLinkedProductSku(), - 'price' => $currency->toCurrency(sprintf("%f", $linkedProduct->getPrice())), - 'qty' => $linkItem->getExtensionAttributes()->getQty(), - 'position' => $linkItem->getPosition(), - 'thumbnail' => $this->imageHelper->init($linkedProduct, 'product_listing_thumbnail')->getUrl(), - 'type_id' => $linkedProduct->getTypeId(), - 'status' => $this->status->getOptionText($linkedProduct->getStatus()), - 'attribute_set' => $this->attributeSetRepository - ->get($linkedProduct->getAttributeSetId()) - ->getAttributeSetName(), - ]; + $data[$modelId]['links'][self::LINK_TYPE][] = $this->fillData($linkedProduct, $linkItem); } $data[$modelId][self::DATA_SOURCE_DEFAULT]['current_store_id'] = $storeId; } return $data; } + /** + * Fill data column + * + * @param ProductInterface $linkedProduct + * @param ProductLinkInterface $linkItem + * @return array + */ + protected function fillData(ProductInterface $linkedProduct, ProductLinkInterface $linkItem) + { + /** @var \Magento\Framework\Currency $currency */ + $currency = $this->localeCurrency->getCurrency($this->locator->getBaseCurrencyCode()); + + return [ + 'id' => $linkedProduct->getId(), + 'name' => $linkedProduct->getName(), + 'sku' => $linkItem->getLinkedProductSku(), + 'price' => $currency->toCurrency(sprintf("%f", $linkedProduct->getPrice())), + 'qty' => $linkItem->getExtensionAttributes()->getQty(), + 'position' => $linkItem->getPosition(), + 'thumbnail' => $this->imageHelper->init($linkedProduct, 'product_listing_thumbnail')->getUrl(), + 'type_id' => $linkedProduct->getTypeId(), + 'status' => $this->status->getOptionText($linkedProduct->getStatus()), + 'attribute_set' => $this->attributeSetRepository + ->get($linkedProduct->getAttributeSetId()) + ->getAttributeSetName(), + ]; + } + /** * {@inheritdoc} */ @@ -452,74 +467,84 @@ class Grouped extends AbstractModifier ], ], ], - 'children' => [ - 'id' => $this->getTextColumn('id', true, __('ID'), 10), - 'thumbnail' => [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'componentType' => Form\Field::NAME, - 'formElement' => Form\Element\Input::NAME, - 'elementTmpl' => 'ui/dynamic-rows/cells/thumbnail', - 'dataType' => Form\Element\DataType\Text::NAME, - 'dataScope' => 'thumbnail', - 'fit' => true, - 'label' => __('Thumbnail'), - 'sortOrder' => 20, - ], - ], + 'children' => $this->fillMeta(), + ], + ]; + } + + /** + * Fill meta columns + * + * @return array + */ + protected function fillMeta() + { + return [ + 'id' => $this->getTextColumn('id', true, __('ID'), 10), + 'thumbnail' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Form\Field::NAME, + 'formElement' => Form\Element\Input::NAME, + 'elementTmpl' => 'ui/dynamic-rows/cells/thumbnail', + 'dataType' => Form\Element\DataType\Text::NAME, + 'dataScope' => 'thumbnail', + 'fit' => true, + 'label' => __('Thumbnail'), + 'sortOrder' => 20, ], ], - 'name' => $this->getTextColumn('name', false, __('Name'), 30), - 'attribute_set' => $this->getTextColumn('attribute_set', false, __('Attribute Set'), 40), - 'status' => $this->getTextColumn('status', true, __('Status'), 50), - 'sku' => $this->getTextColumn('sku', false, __('SKU'), 60), - 'price' => $this->getTextColumn('price', true, __('Price'), 70), - 'qty' => [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'dataType' => Form\Element\DataType\Number::NAME, - 'formElement' => Form\Element\Input::NAME, - 'componentType' => Form\Field::NAME, - 'dataScope' => 'qty', - 'label' => __('Default Quantity'), - 'fit' => true, - 'additionalClasses' => 'admin__field-small', - 'sortOrder' => 80, - 'validation' => [ - 'validate-zero-or-greater' => true - ], - ], + ], + ], + 'name' => $this->getTextColumn('name', false, __('Name'), 30), + 'attribute_set' => $this->getTextColumn('attribute_set', false, __('Attribute Set'), 40), + 'status' => $this->getTextColumn('status', true, __('Status'), 50), + 'sku' => $this->getTextColumn('sku', false, __('SKU'), 60), + 'price' => $this->getTextColumn('price', true, __('Price'), 70), + 'qty' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => Form\Element\DataType\Number::NAME, + 'formElement' => Form\Element\Input::NAME, + 'componentType' => Form\Field::NAME, + 'dataScope' => 'qty', + 'label' => __('Default Quantity'), + 'fit' => true, + 'additionalClasses' => 'admin__field-small', + 'sortOrder' => 80, + 'validation' => [ + 'validate-number' => true, ], ], ], - 'actionDelete' => [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'additionalClasses' => 'data-grid-actions-cell', - 'componentType' => 'actionDelete', - 'dataType' => Form\Element\DataType\Text::NAME, - 'label' => __('Actions'), - 'sortOrder' => 90, - 'fit' => true, - ], - ], + ], + ], + 'actionDelete' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'additionalClasses' => 'data-grid-actions-cell', + 'componentType' => 'actionDelete', + 'dataType' => Form\Element\DataType\Text::NAME, + 'label' => __('Actions'), + 'sortOrder' => 90, + 'fit' => true, ], ], - 'position' => [ - 'arguments' => [ - 'data' => [ - 'config' => [ - 'dataType' => Form\Element\DataType\Number::NAME, - 'formElement' => Form\Element\Input::NAME, - 'componentType' => Form\Field::NAME, - 'dataScope' => 'position', - 'sortOrder' => 100, - 'visible' => false, - ], - ], + ], + ], + 'position' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => Form\Element\DataType\Number::NAME, + 'formElement' => Form\Element\Input::NAME, + 'componentType' => Form\Field::NAME, + 'dataScope' => 'position', + 'sortOrder' => 100, + 'visible' => false, ], ], ], diff --git a/lib/internal/Magento/Framework/Stdlib/ArrayManager.php b/lib/internal/Magento/Framework/Stdlib/ArrayManager.php index d759d2a42c778a6a9068dfe51ec69c0726d0f1b9..51897c0edfcf9305924fd443c8b1582c4d503f9c 100644 --- a/lib/internal/Magento/Framework/Stdlib/ArrayManager.php +++ b/lib/internal/Magento/Framework/Stdlib/ArrayManager.php @@ -43,11 +43,11 @@ class ArrayManager * * @param string $path * @param array $data - * @param string $delimiter * @param null $defaultValue + * @param string $delimiter * @return mixed|null */ - public function get($path, array $data, $delimiter = self::DEFAULT_PATH_DELIMITER, $defaultValue = null) + public function get($path, array $data, $defaultValue = null, $delimiter = self::DEFAULT_PATH_DELIMITER) { return $this->find($path, $data, $delimiter) ? $this->parentNode[$this->nodeIndex] : $defaultValue; } @@ -88,6 +88,33 @@ class ArrayManager return $data; } + /** + * Move value from one location to another + * + * @param string $path + * @param string $targetPath + * @param array $data + * @param bool $overwrite + * @param string $delimiter + * @return array + */ + public function move($path, $targetPath, array $data, $overwrite = false, $delimiter = self::DEFAULT_PATH_DELIMITER) + { + if ($this->find($path, $data, $delimiter)) { + $parentNode = &$this->parentNode; + $nodeIndex = &$this->nodeIndex; + + if ((!$this->find($targetPath, $data, $delimiter) || $overwrite) + && $this->find($targetPath, $data, $delimiter, true) + ) { + $this->parentNode[$this->nodeIndex] = $parentNode[$nodeIndex]; + unset($parentNode[$nodeIndex]); + } + } + + return $data; + } + /** * Merge value with node and return modified data * @@ -109,6 +136,21 @@ class ArrayManager return $data; } + /** + * Populate nested array if possible and needed + * + * @param string $path + * @param array $data + * @param string $delimiter + * @return array + */ + public function populate($path, array $data, $delimiter = self::DEFAULT_PATH_DELIMITER) + { + $this->find($path, $data, $delimiter, true); + + return $data; + } + /** * Remove node and return modified data * diff --git a/lib/internal/Magento/Framework/Stdlib/Test/Unit/ArrayManagerTest.php b/lib/internal/Magento/Framework/Stdlib/Test/Unit/ArrayManagerTest.php index 40a3bdacc0e9e6f1d547e436a07bed1e27a48138..8967a6f488b85542172833d4760acb08e97d76c5 100644 --- a/lib/internal/Magento/Framework/Stdlib/Test/Unit/ArrayManagerTest.php +++ b/lib/internal/Magento/Framework/Stdlib/Test/Unit/ArrayManagerTest.php @@ -182,6 +182,56 @@ class ArrayManagerTest extends \PHPUnit_Framework_TestCase ]; } + /** + * @param string $path + * @param string $targetPath + * @param array $data + * @param bool $overwrite + * @param array $result + * @dataProvider moveDataProvider + */ + public function testMove($path, $targetPath, array $data, $overwrite, array $result) + { + $this->assertSame($result, $this->arrayManager->move($path, $targetPath, $data, $overwrite)); + } + + /** + * @return array + */ + public function moveDataProvider() + { + return [ + 0 => [ + 'path' => 'not/valid/path', + 'targetPath' => 'target/path', + 'data' => ['valid' => ['path' => 'value']], + 'overwrite' => false, + 'result' => ['valid' => ['path' => 'value']] + ], + 1 => [ + 'path' => 'valid/path', + 'targetPath' => 'target/path', + 'data' => ['valid' => ['path' => 'value']], + 'overwrite' => false, + 'result' => ['valid' => [], 'target' => ['path' => 'value']] + ], + 2 => [ + 'path' => 'valid/path', + 'targetPath' => 'target/path', + 'data' => ['valid' => ['path' => 'value'], 'target' => ['path' => 'exists']], + 'overwrite' => false, + 'result' => ['valid' => ['path' => 'value'], 'target' => ['path' => 'exists']] + ], + 3 => [ + 'path' => 'valid/path', + 'targetPath' => 'target/path', + 'data' => ['valid' => ['path' => 'value'], 'target' => ['path' => 'exists']], + 'overwrite' => true, + 'result' => ['valid' => [], 'target' => ['path' => 'value']] + ] + ]; + } + /** * @param string $path * @param array $data @@ -221,6 +271,41 @@ class ArrayManagerTest extends \PHPUnit_Framework_TestCase ]; } + /** + * @param string $path + * @param array $data + * @param array $result + * @dataProvider populateDataProvider + */ + public function testPopulate($path, $data, $result) + { + $this->assertSame($result, $this->arrayManager->populate($path, $data)); + } + + /** + * @return array + */ + public function populateDataProvider() + { + return [ + 0 => [ + 'path' => 'some/is/not/array', + 'data' => ['some' => true], + 'result' => ['some' => true] + ], + 1 => [ + 'path' => 0, + 'data' => [], + 'result' => [[]] + ], + 2 => [ + 'path' => 'nested/1/array', + 'data' => ['nested' => [true]], + 'result' => ['nested' => [true, ['array' => []]]] + ] + ]; + } + /** * @param string $path * @param array $data