| Current Path : /home/rtorresani/www/vendor/magento/module-catalog/Ui/DataProvider/Product/Form/Modifier/ |
| Current File : //home/rtorresani/www/vendor/magento/module-catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php |
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Catalog\Ui\DataProvider\Product\Form\Modifier;
use Magento\Catalog\Api\Data\ProductAttributeInterface;
use Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface;
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
use Magento\Catalog\Model\Attribute\ScopeOverriddenValue;
use Magento\Catalog\Model\Locator\LocatorInterface;
use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\Product\Type as ProductType;
use Magento\Catalog\Model\ResourceModel\Eav\Attribute as EavAttribute;
use Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory as EavAttributeFactory;
use Magento\Catalog\Ui\DataProvider\CatalogEavValidationRules;
use Magento\Eav\Api\Data\AttributeGroupInterface;
use Magento\Eav\Api\Data\AttributeInterface;
use Magento\Eav\Model\Config;
use Magento\Eav\Model\Entity\Attribute\Source\SpecificSourceInterface;
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\CollectionFactory as GroupCollectionFactory;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Api\SortOrderBuilder;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\AuthorizationInterface;
use Magento\Framework\Filter\Translit;
use Magento\Framework\Stdlib\ArrayManager;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Ui\Component\Form\Element\Wysiwyg as WysiwygElement;
use Magento\Ui\Component\Form\Field;
use Magento\Ui\Component\Form\Fieldset;
use Magento\Ui\DataProvider\Mapper\FormElement as FormElementMapper;
use Magento\Ui\DataProvider\Mapper\MetaProperties as MetaPropertiesMapper;
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Eav\CompositeConfigProcessor;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Eav\Model\ResourceModel\Entity\Attribute\CollectionFactory as AttributeCollectionFactory;
/**
* Class Eav data provider for product editing form
*
* @api
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.TooManyFields)
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
* @SuppressWarnings(PHPMD.ExcessiveClassLength)
* @since 101.0.0
*/
class Eav extends AbstractModifier
{
public const SORT_ORDER_MULTIPLIER = 10;
/**
* @var LocatorInterface
* @since 101.0.0
*/
protected $locator;
/**
* @var Config
* @since 101.0.0
*/
protected $eavConfig;
/**
* @var CatalogEavValidationRules
* @since 101.0.0
*/
protected $catalogEavValidationRules;
/**
* @var RequestInterface
* @since 101.0.0
*/
protected $request;
/**
* @var GroupCollectionFactory
* @since 101.0.0
*/
protected $groupCollectionFactory;
/**
* @var StoreManagerInterface
* @since 101.0.0
*/
protected $storeManager;
/**
* @var FormElementMapper
* @since 101.0.0
*/
protected $formElementMapper;
/**
* @var MetaPropertiesMapper
* @since 101.0.0
*/
protected $metaPropertiesMapper;
/**
* @var ProductAttributeGroupRepositoryInterface
* @since 101.0.0
*/
protected $attributeGroupRepository;
/**
* @var SearchCriteriaBuilder
* @since 101.0.0
*/
protected $searchCriteriaBuilder;
/**
* @var ProductAttributeRepositoryInterface
* @since 101.0.0
*/
protected $attributeRepository;
/**
* @var SortOrderBuilder
* @since 101.0.0
*/
protected $sortOrderBuilder;
/**
* @var EavAttributeFactory
* @since 101.0.0
*/
protected $eavAttributeFactory;
/**
* @var Translit
* @since 101.0.0
*/
protected $translitFilter;
/**
* @var ArrayManager
* @since 101.0.0
*/
protected $arrayManager;
/**
* @var ScopeOverriddenValue
*/
private $scopeOverriddenValue;
/**
* @var array
*/
private $attributesToDisable;
/**
* @var array
* @since 101.0.0
*/
protected $attributesToEliminate;
/**
* @var DataPersistorInterface
* @since 101.0.0
*/
protected $dataPersistor;
/**
* @var EavAttribute[]
*/
private $attributes = [];
/**
* @var AttributeGroupInterface[]
*/
private $attributeGroups = [];
/**
* @var array
*/
private $canDisplayUseDefault = [];
/**
* @var array
*/
private $bannedInputTypes = ['media_image'];
/**
* @var array
*/
private $prevSetAttributes;
/**
* @var array
*/
private $attributesCache = [];
/**
* @var AttributeCollectionFactory
*/
private $attributeCollectionFactory;
/**
* @var CompositeConfigProcessor
*/
private $wysiwygConfigProcessor;
/**
* @var ScopeConfigInterface
*/
private $scopeConfig;
/**
* @var AuthorizationInterface
*/
private $auth;
/**
* Eav constructor.
* @param LocatorInterface $locator
* @param CatalogEavValidationRules $catalogEavValidationRules
* @param Config $eavConfig
* @param RequestInterface $request
* @param GroupCollectionFactory $groupCollectionFactory
* @param StoreManagerInterface $storeManager
* @param FormElementMapper $formElementMapper
* @param MetaPropertiesMapper $metaPropertiesMapper
* @param ProductAttributeGroupRepositoryInterface $attributeGroupRepository
* @param ProductAttributeRepositoryInterface $attributeRepository
* @param SearchCriteriaBuilder $searchCriteriaBuilder
* @param SortOrderBuilder $sortOrderBuilder
* @param EavAttributeFactory $eavAttributeFactory
* @param Translit $translitFilter
* @param ArrayManager $arrayManager
* @param ScopeOverriddenValue $scopeOverriddenValue
* @param DataPersistorInterface $dataPersistor
* @param array $attributesToDisable
* @param array $attributesToEliminate
* @param CompositeConfigProcessor|null $wysiwygConfigProcessor
* @param ScopeConfigInterface|null $scopeConfig
* @param AttributeCollectionFactory $attributeCollectionFactory
* @param AuthorizationInterface|null $auth
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
LocatorInterface $locator,
CatalogEavValidationRules $catalogEavValidationRules,
Config $eavConfig,
RequestInterface $request,
GroupCollectionFactory $groupCollectionFactory,
StoreManagerInterface $storeManager,
FormElementMapper $formElementMapper,
MetaPropertiesMapper $metaPropertiesMapper,
ProductAttributeGroupRepositoryInterface $attributeGroupRepository,
ProductAttributeRepositoryInterface $attributeRepository,
SearchCriteriaBuilder $searchCriteriaBuilder,
SortOrderBuilder $sortOrderBuilder,
EavAttributeFactory $eavAttributeFactory,
Translit $translitFilter,
ArrayManager $arrayManager,
ScopeOverriddenValue $scopeOverriddenValue,
DataPersistorInterface $dataPersistor,
$attributesToDisable = [],
$attributesToEliminate = [],
CompositeConfigProcessor $wysiwygConfigProcessor = null,
ScopeConfigInterface $scopeConfig = null,
AttributeCollectionFactory $attributeCollectionFactory = null,
?AuthorizationInterface $auth = null
) {
$this->locator = $locator;
$this->catalogEavValidationRules = $catalogEavValidationRules;
$this->eavConfig = $eavConfig;
$this->request = $request;
$this->groupCollectionFactory = $groupCollectionFactory;
$this->storeManager = $storeManager;
$this->formElementMapper = $formElementMapper;
$this->metaPropertiesMapper = $metaPropertiesMapper;
$this->attributeGroupRepository = $attributeGroupRepository;
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
$this->attributeRepository = $attributeRepository;
$this->sortOrderBuilder = $sortOrderBuilder;
$this->eavAttributeFactory = $eavAttributeFactory;
$this->translitFilter = $translitFilter;
$this->arrayManager = $arrayManager;
$this->scopeOverriddenValue = $scopeOverriddenValue;
$this->dataPersistor = $dataPersistor;
$this->attributesToDisable = $attributesToDisable;
$this->attributesToEliminate = $attributesToEliminate;
$this->wysiwygConfigProcessor = $wysiwygConfigProcessor
?: ObjectManager::getInstance()->get(CompositeConfigProcessor::class);
$this->scopeConfig = $scopeConfig ?: ObjectManager::getInstance()->get(ScopeConfigInterface::class);
$this->attributeCollectionFactory = $attributeCollectionFactory
?: ObjectManager::getInstance()->get(AttributeCollectionFactory::class);
$this->auth = $auth ?? ObjectManager::getInstance()->get(AuthorizationInterface::class);
}
/**
* @inheritdoc
* @since 101.0.0
*/
public function modifyMeta(array $meta)
{
$sortOrder = 0;
foreach ($this->getGroups() as $groupCode => $group) {
$attributes = !empty($this->getAttributes()[$groupCode]) ? $this->getAttributes()[$groupCode] : [];
if ($attributes) {
$meta[$groupCode]['children'] = $this->getAttributesMeta($attributes, $groupCode);
$meta[$groupCode]['arguments']['data']['config']['componentType'] = Fieldset::NAME;
$meta[$groupCode]['arguments']['data']['config']['label'] = __($group->getAttributeGroupName());
$meta[$groupCode]['arguments']['data']['config']['collapsible'] = true;
$meta[$groupCode]['arguments']['data']['config']['dataScope'] = self::DATA_SCOPE_PRODUCT;
$meta[$groupCode]['arguments']['data']['config']['sortOrder'] =
$sortOrder * self::SORT_ORDER_MULTIPLIER;
}
$sortOrder++;
}
return $meta;
}
/**
* Get attributes meta
*
* @param ProductAttributeInterface[] $attributes
* @param string $groupCode
* @return array
* @throws \Magento\Framework\Exception\LocalizedException
*/
private function getAttributesMeta(array $attributes, $groupCode)
{
$meta = [];
foreach ($attributes as $sortOrder => $attribute) {
if (in_array($attribute->getFrontendInput(), $this->bannedInputTypes)) {
continue;
}
if (in_array($attribute->getAttributeCode(), $this->attributesToEliminate)) {
continue;
}
if (!($attributeContainer = $this->setupAttributeContainerMeta($attribute))) {
continue;
}
$attributeContainer = $this->addContainerChildren($attributeContainer, $attribute, $groupCode, $sortOrder);
$meta[static::CONTAINER_PREFIX . $attribute->getAttributeCode()] = $attributeContainer;
}
return $meta;
}
/**
* Add container children
*
* @param array $attributeContainer
* @param ProductAttributeInterface $attribute
* @param string $groupCode
* @param int $sortOrder
* @return array
* @since 101.0.0
*/
public function addContainerChildren(
array $attributeContainer,
ProductAttributeInterface $attribute,
$groupCode,
$sortOrder
) {
foreach ($this->getContainerChildren($attribute, $groupCode, $sortOrder) as $childCode => $child) {
$attributeContainer['children'][$childCode] = $child;
}
$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];
}
/**
* @inheritdoc
* @since 101.0.0
*/
public function modifyData(array $data)
{
if (!$this->locator->getProduct()->getId() && $this->dataPersistor->get('catalog_product')) {
return $this->resolvePersistentData($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] : [];
foreach ($attributes as $attribute) {
if (null !== ($attributeValue = $this->setupAttributeData($attribute))) {
if ($this->isPriceAttribute($attribute, $attributeValue)) {
$attributeValue = $this->formatPrice($attributeValue);
}
$data[$productId][self::DATA_SOURCE_DEFAULT][$attribute->getAttributeCode()] = $attributeValue;
}
}
}
return $data;
}
/**
* Obtain if given attribute is a price
*
* @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute
* @param string|integer $attributeValue
* @return bool
*/
private function isPriceAttribute(ProductAttributeInterface $attribute, $attributeValue)
{
return $attribute->getFrontendInput() === 'price'
&& is_scalar($attributeValue)
&& !$this->isBundleSpecialPrice($attribute);
}
/**
* Obtain if current product is bundle and given attribute is special_price
*
* @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute
* @return bool
*/
private function isBundleSpecialPrice(ProductAttributeInterface $attribute)
{
return $this->locator->getProduct()->getTypeId() === ProductType::TYPE_BUNDLE
&& $attribute->getAttributeCode() === ProductAttributeInterface::CODE_SPECIAL_PRICE;
}
/**
* Resolve data persistence
*
* @param array $data
* @return array
*/
private function resolvePersistentData(array $data)
{
$persistentData = (array)$this->dataPersistor->get('catalog_product');
$this->dataPersistor->clear('catalog_product');
$productId = $this->locator->getProduct()->getId();
if (empty($data[$productId][self::DATA_SOURCE_DEFAULT])) {
$data[$productId][self::DATA_SOURCE_DEFAULT] = [];
}
$data[$productId] = array_replace_recursive(
$data[$productId][self::DATA_SOURCE_DEFAULT],
$persistentData
);
return $data;
}
/**
* Get product type
*
* @return null|string
*/
private function getProductType()
{
return (string)$this->request->getParam('type', $this->locator->getProduct()->getTypeId());
}
/**
* Return prev set id
*
* @return int
*/
private function getPreviousSetId()
{
return (int)$this->request->getParam('prev_set_id', 0);
}
/**
* Retrieve groups
*
* @return AttributeGroupInterface[]
*/
private function getGroups()
{
if (!$this->attributeGroups) {
$searchCriteria = $this->prepareGroupSearchCriteria()->create();
$attributeGroupSearchResult = $this->attributeGroupRepository->getList($searchCriteria);
foreach ($attributeGroupSearchResult->getItems() as $group) {
$this->attributeGroups[$this->calculateGroupCode($group)] = $group;
}
}
return $this->attributeGroups;
}
/**
* Initialize attribute group search criteria with filters.
*
* @return SearchCriteriaBuilder
*/
private function prepareGroupSearchCriteria()
{
return $this->searchCriteriaBuilder->addFilter(
AttributeGroupInterface::ATTRIBUTE_SET_ID,
$this->getAttributeSetId()
);
}
/**
* Return current attribute set id
*
* @return int|null
*/
private function getAttributeSetId()
{
return $this->locator->getProduct()->getAttributeSetId();
}
/**
* Retrieve attributes
*
* @return ProductAttributeInterface[]
*/
private function getAttributes()
{
if (!$this->attributes) {
$this->attributes = $this->loadAttributesForGroups($this->getGroups());
}
return $this->attributes;
}
/**
* Loads attributes for specified groups at once
*
* @param AttributeGroupInterface[] $groups
* @return ProductAttributeInterface[]
*/
private function loadAttributesForGroups(array $groups)
{
$attributes = [];
$groupIds = [];
foreach ($groups as $group) {
$groupIds[$group->getAttributeGroupId()] = $this->calculateGroupCode($group);
$attributes[$this->calculateGroupCode($group)] = [];
}
$collection = $this->attributeCollectionFactory->create();
$collection->setAttributeGroupFilter(array_keys($groupIds));
$mapAttributeToGroup = [];
foreach ($collection->getItems() as $attribute) {
$mapAttributeToGroup[$attribute->getAttributeId()] = $attribute->getAttributeGroupId();
}
$sortOrder = $this->sortOrderBuilder
->setField('sort_order')
->setAscendingDirection()
->create();
$searchCriteria = $this->searchCriteriaBuilder
->addFilter(AttributeGroupInterface::GROUP_ID, array_keys($groupIds), 'in')
->addFilter(ProductAttributeInterface::IS_VISIBLE, 1)
->addSortOrder($sortOrder)
->create();
$groupAttributes = $this->attributeRepository->getList($searchCriteria)->getItems();
$productType = $this->getProductType();
foreach ($groupAttributes as $attribute) {
$applyTo = $attribute->getApplyTo();
$isRelated = !$applyTo || in_array($productType, $applyTo);
if ($isRelated) {
$attributeGroupId = $mapAttributeToGroup[$attribute->getAttributeId()];
$attributeGroupCode = $groupIds[$attributeGroupId];
$attributes[$attributeGroupCode][] = $attribute;
}
}
return $attributes;
}
/**
* Get attribute codes of prev set
*
* @return array
* @throws \Magento\Framework\Exception\LocalizedException
*/
private function getPreviousSetAttributes()
{
if ($this->prevSetAttributes === null) {
$searchCriteria = $this->searchCriteriaBuilder
->addFilter('attribute_set_id', $this->getPreviousSetId())
->create();
$attributes = $this->attributeRepository->getList($searchCriteria)->getItems();
$this->prevSetAttributes = [];
foreach ($attributes as $attribute) {
$this->prevSetAttributes[] = $attribute->getAttributeCode();
}
}
return $this->prevSetAttributes;
}
/**
* Check is product already new or we trying to create one
*
* @return bool
*/
private function isProductExists()
{
return (bool) $this->locator->getProduct()->getId();
}
/**
* Initial meta setup
*
* @param ProductAttributeInterface $attribute
* @param string $groupCode
* @param int $sortOrder
* @return array
* @throws \Magento\Framework\Exception\LocalizedException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function setupAttributeMeta(ProductAttributeInterface $attribute, $groupCode, $sortOrder)
{
$configPath = ltrim(static::META_CONFIG_PATH, ArrayManager::DEFAULT_PATH_DELIMITER);
$attributeCode = $attribute->getAttributeCode();
$meta = $this->arrayManager->set(
$configPath,
[],
[
'dataType' => $attribute->getFrontendInput(),
'formElement' => $this->getFormElementsMapValue($attribute->getFrontendInput()),
'visible' => $attribute->getIsVisible(),
'required' => $attribute->getIsRequired(),
'notice' => $attribute->getNote() === null ? null : __($attribute->getNote()),
'default' => (!$this->isProductExists()) ? $this->getAttributeDefaultValue($attribute) : null,
'label' => __($attribute->getDefaultFrontendLabel()),
'code' => $attributeCode,
'source' => $groupCode,
'scopeLabel' => $this->getScopeLabel($attribute),
'globalScope' => $this->isScopeGlobal($attribute),
'sortOrder' => $sortOrder * self::SORT_ORDER_MULTIPLIER,
]
);
$product = $this->locator->getProduct();
// TODO: Refactor to $attribute->getOptions() when MAGETWO-48289 is done
$attributeModel = $this->getAttributeModel($attribute);
if ($attributeModel->usesSource()) {
$source = $attributeModel->getSource();
if ($source instanceof SpecificSourceInterface) {
$options = $source->getOptionsFor($product);
} else {
$options = $source->getAllOptions(true, true);
}
foreach ($options as &$option) {
$option['__disableTmpl'] = true;
}
$meta = $this->arrayManager->merge(
$configPath,
$meta,
['options' => $this->convertOptionsValueToString($options)]
);
}
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($attributeCode, $this->attributesToDisable)
|| $product->isLockedAttribute($attributeCode)) {
$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->catalogEavValidationRules->build($this->getAttributeModel($attribute), $childData)) {
$meta = $this->arrayManager->merge($configPath, $meta, ['validation' => $rules]);
}
$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" section
$meta = [];
break;
case 'datetime':
$meta = $this->customizeDatetimeAttribute($meta);
break;
}
//Checking access to design config.
$designDesignGroups = ['design', 'schedule-design-update'];
if (in_array($groupCode, $designDesignGroups, true)) {
if (!$this->auth->isAllowed('Magento_Catalog::edit_product_design')) {
$meta = $this->arrayManager->merge(
$configPath,
$meta,
[
'disabled' => true,
'validation' => ['required' => false],
'required' => false,
'serviceDisabled' => true,
]
);
}
}
return $meta;
}
/**
* Returns attribute default value, based on db setting or setting in the system configuration.
*
* @param ProductAttributeInterface $attribute
* @return null|string
*/
private function getAttributeDefaultValue(ProductAttributeInterface $attribute)
{
if ($attribute->getAttributeCode() === 'page_layout') {
$defaultValue = $this->scopeConfig->getValue(
'web/default_layouts/default_product_layout',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
$this->storeManager->getStore()
);
if ($defaultValue !== null) {
$attribute->setDefaultValue($defaultValue);
}
}
return $attribute->getDefaultValue();
}
/**
* Convert options value to string.
*
* @param array $options
* @return array
*/
private function convertOptionsValueToString(array $options) : array
{
array_walk(
$options,
function (&$value) {
if (isset($value['value']) && is_scalar($value['value'])) {
$value['value'] = (string)$value['value'];
}
}
);
return $options;
}
/**
* Adds 'use default value' checkbox.
*
* @param ProductAttributeInterface $attribute
* @param array $meta
* @return array
*/
private function addUseDefaultValueCheckbox(ProductAttributeInterface $attribute, array $meta)
{
$canDisplayService = $this->canDisplayUseDefault($attribute);
if ($canDisplayService) {
$meta['arguments']['data']['config']['service'] = [
'template' => 'ui/form/element/helper/service',
];
$meta['arguments']['data']['config']['disabled'] = !$this->scopeOverriddenValue->containsValue(
\Magento\Catalog\Api\Data\ProductInterface::class,
$this->locator->getProduct(),
$attribute->getAttributeCode(),
$this->locator->getStore()->getId()
);
}
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',
'label' => false,
'required' => false,
]
);
}
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->getPreviousSetId();
$notUsed = !$prevSetId
|| ($prevSetId && !in_array($attribute->getAttributeCode(), $this->getPreviousSetAttributes()));
if ($productId && $notUsed) {
return $this->getValue($attribute);
}
return null;
}
/**
* Customize checkboxes
*
* @param ProductAttributeInterface $attribute
* @param array $meta
* @return array
*/
private function customizeCheckbox(ProductAttributeInterface $attribute, array $meta)
{
if ($attribute->getFrontendInput() === 'boolean') {
$meta['arguments']['data']['config']['prefer'] = 'toggle';
$meta['arguments']['data']['config']['valueMap'] = [
'true' => '1',
'false' => '0',
];
}
return $meta;
}
/**
* Customize attribute that has price type
*
* @param ProductAttributeInterface $attribute
* @param array $meta
* @return array
*/
private function customizePriceAttribute(ProductAttributeInterface $attribute, array $meta)
{
if ($attribute->getFrontendInput() === 'price') {
$meta['arguments']['data']['config']['addbefore'] = $this->locator->getStore()
->getBaseCurrency()
->getCurrencySymbol();
}
return $meta;
}
/**
* Add wysiwyg properties
*
* @param ProductAttributeInterface $attribute
* @param array $meta
* @return array
*/
private function customizeWysiwyg(ProductAttributeInterface $attribute, array $meta)
{
if (!$attribute->getIsWysiwygEnabled()) {
return $meta;
}
$meta['arguments']['data']['config']['formElement'] = WysiwygElement::NAME;
$meta['arguments']['data']['config']['wysiwyg'] = true;
$meta['arguments']['data']['config']['wysiwygConfigData'] = $this->wysiwygConfigProcessor->process($attribute);
return $meta;
}
/**
* Customize datetime attribute
*
* @param array $meta
* @return array
*/
private function customizeDatetimeAttribute(array $meta): array
{
$meta['arguments']['data']['config']['options']['showsTime'] = 1;
return $meta;
}
/**
* Retrieve form element
*
* @param string $value
* @return mixed
*/
private function getFormElementsMapValue($value)
{
$valueMap = $this->formElementMapper->getMappings();
return $valueMap[$value] ?? $value;
}
/**
* Retrieve attribute value
*
* @param ProductAttributeInterface $attribute
* @return mixed
*/
private function getValue(ProductAttributeInterface $attribute)
{
/** @var Product $product */
$product = $this->locator->getProduct();
return $product->getData($attribute->getAttributeCode());
}
/**
* Retrieve scope label
*
* @param ProductAttributeInterface $attribute
* @return \Magento\Framework\Phrase|string
*/
private function getScopeLabel(ProductAttributeInterface $attribute)
{
if ($this->storeManager->isSingleStoreMode()
|| $attribute->getFrontendInput() === AttributeInterface::FRONTEND_INPUT
) {
return '';
}
switch ($attribute->getScope()) {
case ProductAttributeInterface::SCOPE_GLOBAL_TEXT:
return __('[GLOBAL]');
case ProductAttributeInterface::SCOPE_WEBSITE_TEXT:
return __('[WEBSITE]');
case ProductAttributeInterface::SCOPE_STORE_TEXT:
return __('[STORE VIEW]');
}
return '';
}
/**
* Whether attribute can have default value
*
* @param ProductAttributeInterface $attribute
* @return bool
*/
private function canDisplayUseDefault(ProductAttributeInterface $attribute)
{
$attributeCode = $attribute->getAttributeCode();
/** @var Product $product */
$product = $this->locator->getProduct();
if ($product->isLockedAttribute($attributeCode)) {
return false;
}
if (isset($this->canDisplayUseDefault[$attributeCode])) {
return $this->canDisplayUseDefault[$attributeCode];
}
return $this->canDisplayUseDefault[$attributeCode] = (
($attribute->getScope() != ProductAttributeInterface::SCOPE_GLOBAL_TEXT)
&& $product
&& $product->getId()
&& $product->getStoreId()
);
}
/**
* Check if attribute scope is global.
*
* @param ProductAttributeInterface $attribute
* @return bool
*/
private function isScopeGlobal($attribute)
{
return $attribute->getScope() === ProductAttributeInterface::SCOPE_GLOBAL_TEXT;
}
/**
* Load attribute model by attribute data object.
*
* TODO: This method should be eliminated when all missing service methods are implemented
*
* @param ProductAttributeInterface $attribute
* @return EavAttribute
*/
private function getAttributeModel($attribute)
{
// The statement below solves performance issue related to loading same attribute options on different models
if ($attribute instanceof EavAttribute) {
return $attribute;
}
$attributeId = $attribute->getAttributeId();
if (!array_key_exists($attributeId, $this->attributesCache)) {
$this->attributesCache[$attributeId] = $this->eavAttributeFactory->create()->load($attributeId);
}
return $this->attributesCache[$attributeId];
}
/**
* Calculate group code based on group name.
*
* TODO: This logic is copy-pasted from \Magento\Eav\Model\Entity\Attribute\Group::beforeSave
* TODO: and should be moved to a separate service, which will allow two-way conversion groupName <=> groupCode
* TODO: Remove after MAGETWO-48290 is complete
*
* @param AttributeGroupInterface $group
* @return string
*/
private function calculateGroupCode(AttributeGroupInterface $group)
{
$attributeGroupCode = $group->getAttributeGroupCode();
if ($attributeGroupCode === 'images') {
$attributeGroupCode = 'image-management';
}
return $attributeGroupCode;
}
}