| Current Path : /var/www/clients/client3/web2/web/vendor/magento/module-checkout/Block/Checkout/ |
| Current File : /var/www/clients/client3/web2/web/vendor/magento/module-checkout/Block/Checkout/AttributeMerger.php |
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Checkout\Block\Checkout;
use Magento\Customer\Api\CustomerRepositoryInterface as CustomerRepository;
use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Customer\Helper\Address as AddressHelper;
use Magento\Customer\Model\Session;
use Magento\Directory\Helper\Data as DirectoryHelper;
use Magento\Directory\Model\AllowedCountries;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
/**
* Fields attribute merger.
*
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class AttributeMerger
{
/**
* Map form element
*
* @var array
*/
protected $formElementMap = [
'checkbox' => 'Magento_Ui/js/form/element/select',
'select' => 'Magento_Ui/js/form/element/select',
'textarea' => 'Magento_Ui/js/form/element/textarea',
'multiline' => 'Magento_Ui/js/form/components/group',
'multiselect' => 'Magento_Ui/js/form/element/multiselect',
'image' => 'Magento_Ui/js/form/element/media',
'file' => 'Magento_Ui/js/form/element/media',
];
/**
* Map template
*
* @var array
*/
protected $templateMap = [
'image' => 'media',
'file' => 'media',
];
/**
* Map input_validation and validation rule from js
*
* @var array
*/
protected $inputValidationMap = [
'alpha' => 'validate-alpha',
'numeric' => 'validate-number',
'alphanumeric' => 'validate-alphanum',
'alphanum-with-spaces' => 'validate-alphanum-with-spaces',
'url' => 'validate-url',
'email' => 'email2',
'length' => 'validate-length',
];
/**
* @var AddressHelper
*/
private $addressHelper;
/**
* @var Session
*/
private $customerSession;
/**
* @var CustomerRepository
*/
private $customerRepository;
/**
* @var CustomerInterface
*/
private $customer;
/**
* @var \Magento\Directory\Helper\Data
*/
private $directoryHelper;
/**
* List of codes of countries that must be shown on the top of country list
*
* @var array
*/
private $topCountryCodes;
/**
* @var AllowedCountries|null
*/
private $allowedCountryReader;
/**
* @param AddressHelper $addressHelper
* @param Session $customerSession
* @param CustomerRepository $customerRepository
* @param DirectoryHelper $directoryHelper
* @param AllowedCountries $allowedCountryReader
*/
public function __construct(
AddressHelper $addressHelper,
Session $customerSession,
CustomerRepository $customerRepository,
DirectoryHelper $directoryHelper,
?AllowedCountries $allowedCountryReader = null
) {
$this->addressHelper = $addressHelper;
$this->customerSession = $customerSession;
$this->customerRepository = $customerRepository;
$this->directoryHelper = $directoryHelper;
$this->topCountryCodes = $directoryHelper->getTopCountryCodes();
$this->allowedCountryReader =
$allowedCountryReader ?: ObjectManager::getInstance()->get(AllowedCountries::class);
}
/**
* Merge additional address fields for given provider
*
* @param array $elements
* @param string $providerName name of the storage container used by UI component
* @param string $dataScopePrefix
* @param array $fields
* @return array
*/
public function merge($elements, $providerName, $dataScopePrefix, array $fields = [])
{
foreach ($elements as $attributeCode => $attributeConfig) {
$additionalConfig = isset($fields[$attributeCode]) ? $fields[$attributeCode] : [];
if (!$this->isFieldVisible($attributeCode, $attributeConfig, $additionalConfig)) {
continue;
}
$fields[$attributeCode] = $this->getFieldConfig(
$attributeCode,
$attributeConfig,
$additionalConfig,
$providerName,
$dataScopePrefix
);
}
return $fields;
}
/**
* Retrieve UI field configuration for given attribute
*
* @param string $attributeCode
* @param array $attributeConfig
* @param array $additionalConfig field configuration provided via layout XML
* @param string $providerName name of the storage container used by UI component
* @param string $dataScopePrefix
* @return array
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
protected function getFieldConfig(
$attributeCode,
array $attributeConfig,
array $additionalConfig,
$providerName,
$dataScopePrefix
) {
// street attribute is unique in terms of configuration, so it has its own configuration builder
if (isset($attributeConfig['validation']['input_validation'])) {
$validationRule = $attributeConfig['validation']['input_validation'];
$attributeConfig['validation'][$this->inputValidationMap[$validationRule]] = true;
unset($attributeConfig['validation']['input_validation']);
}
if ($attributeConfig['formElement'] == 'multiline') {
return $this->getMultilineFieldConfig($attributeCode, $attributeConfig, $providerName, $dataScopePrefix);
}
$uiComponent = isset($this->formElementMap[$attributeConfig['formElement']])
? $this->formElementMap[$attributeConfig['formElement']]
: 'Magento_Ui/js/form/element/abstract';
$elementTemplate = isset($this->templateMap[$attributeConfig['formElement']])
? 'ui/form/element/' . $this->templateMap[$attributeConfig['formElement']]
: 'ui/form/element/' . $attributeConfig['formElement'];
$element = [
'component' => isset($additionalConfig['component']) ? $additionalConfig['component'] : $uiComponent,
'config' => $this->mergeConfigurationNode(
'config',
$additionalConfig,
[
'config' => [
// customScope is used to group elements within a single
// form (e.g. they can be validated separately)
'customScope' => $dataScopePrefix,
'template' => 'ui/form/field',
'elementTmpl' => $elementTemplate,
],
]
),
'dataScope' => $dataScopePrefix . '.' . $attributeCode,
'label' => $attributeConfig['label'],
'provider' => $providerName,
'sortOrder' => isset($additionalConfig['sortOrder'])
? $additionalConfig['sortOrder']
: $attributeConfig['sortOrder'],
'validation' => $this->mergeConfigurationNode('validation', $additionalConfig, $attributeConfig),
'options' => $this->getFieldOptions($attributeCode, $attributeConfig),
'filterBy' => isset($additionalConfig['filterBy']) ? $additionalConfig['filterBy'] : null,
'customEntry' => isset($additionalConfig['customEntry']) ? $additionalConfig['customEntry'] : null,
'visible' => isset($additionalConfig['visible']) ? $additionalConfig['visible'] : true,
];
if ($attributeCode === 'region_id' || $attributeCode === 'country_id') {
unset($element['options']);
$element['deps'] = [$providerName];
$element['imports'] = [
'initialOptions' => 'index = ' . $providerName . ':dictionaries.' . $attributeCode,
'setOptions' => 'index = ' . $providerName . ':dictionaries.' . $attributeCode
];
}
if (isset($attributeConfig['value']) && $attributeConfig['value'] != null) {
$element['value'] = $attributeConfig['value'];
} elseif (isset($attributeConfig['default']) && $attributeConfig['default'] != null) {
$element['value'] = $attributeConfig['default'];
} else {
$defaultValue = $this->getDefaultValue($attributeCode);
if (null !== $defaultValue) {
$element['value'] = $defaultValue;
}
}
return $element;
}
/**
* Merge two configuration nodes recursively
*
* @param string $nodeName
* @param array $mainSource
* @param array $additionalSource
* @return array
*/
protected function mergeConfigurationNode($nodeName, array $mainSource, array $additionalSource)
{
$mainData = isset($mainSource[$nodeName]) ? $mainSource[$nodeName] : [];
$additionalData = isset($additionalSource[$nodeName]) ? $additionalSource[$nodeName] : [];
return array_replace_recursive($additionalData, $mainData);
}
/**
* Check if address attribute is visible on frontend
*
* @param string $attributeCode
* @param array $attributeConfig
* @param array $additionalConfig field configuration provided via layout XML
* @return bool
*/
protected function isFieldVisible($attributeCode, array $attributeConfig, array $additionalConfig = [])
{
// TODO move this logic to separate model so it can be customized
if ($attributeConfig['visible'] == false
|| (isset($additionalConfig['visible']) && $additionalConfig['visible'] == false)
) {
return false;
}
if ($attributeCode == 'vat_id' && !$this->addressHelper->isVatAttributeVisible()) {
return false;
}
return true;
}
/**
* Retrieve field configuration for street address attribute
*
* @param string $attributeCode
* @param array $attributeConfig
* @param string $providerName name of the storage container used by UI component
* @param string $dataScopePrefix
* @return array
*/
protected function getMultilineFieldConfig($attributeCode, array $attributeConfig, $providerName, $dataScopePrefix)
{
$lines = [];
unset($attributeConfig['validation']['required-entry']);
for ($lineIndex = 0; $lineIndex < (int)$attributeConfig['size']; $lineIndex++) {
$isFirstLine = $lineIndex === 0;
$line = [
'label' => __("%1: Line %2", $attributeConfig['label'], $lineIndex + 1),
'component' => 'Magento_Ui/js/form/element/abstract',
'config' => [
// customScope is used to group elements within a single form e.g. they can be validated separately
'customScope' => $dataScopePrefix,
'template' => 'ui/form/field',
'elementTmpl' => 'ui/form/element/input'
],
'dataScope' => $lineIndex,
'provider' => $providerName,
'validation' => $isFirstLine
// phpcs:ignore Magento2.Performance.ForeachArrayMerge
? array_merge(
['required-entry' => (bool)$attributeConfig['required']],
$attributeConfig['validation']
)
: $attributeConfig['validation'],
'additionalClasses' => $isFirstLine ? 'field' : 'additional'
];
if ($isFirstLine && isset($attributeConfig['default']) && $attributeConfig['default'] != null) {
$line['value'] = $attributeConfig['default'];
}
$lines[] = $line;
}
return [
'component' => 'Magento_Ui/js/form/components/group',
'label' => $attributeConfig['label'],
'required' => (bool)$attributeConfig['required'],
'dataScope' => $dataScopePrefix . '.' . $attributeCode,
'provider' => $providerName,
'sortOrder' => $attributeConfig['sortOrder'],
'type' => 'group',
'config' => [
'template' => 'ui/group/group',
'additionalClasses' => $attributeCode
],
'children' => $lines,
];
}
/**
* Returns default attribute value.
*
* @param string $attributeCode
* @throws NoSuchEntityException
* @throws LocalizedException
* @return null|string
*/
protected function getDefaultValue($attributeCode): ?string
{
if ($attributeCode === 'country_id') {
$defaultCountryId = $this->directoryHelper->getDefaultCountry();
if (!in_array($defaultCountryId, $this->allowedCountryReader->getAllowedCountries())) {
$defaultCountryId = null;
}
return $defaultCountryId;
}
$customer = $this->getCustomer();
if ($customer === null) {
return null;
}
$attributeValue = null;
switch ($attributeCode) {
case 'prefix':
$attributeValue = $customer->getPrefix();
break;
case 'firstname':
$attributeValue = $customer->getFirstname();
break;
case 'middlename':
$attributeValue = $customer->getMiddlename();
break;
case 'lastname':
$attributeValue = $customer->getLastname();
break;
case 'suffix':
$attributeValue = $customer->getSuffix();
break;
}
return $attributeValue;
}
/**
* Returns logged customer.
*
* @throws NoSuchEntityException
* @throws LocalizedException
* @return CustomerInterface|null
*/
protected function getCustomer(): ?CustomerInterface
{
if (!$this->customer) {
if ($this->customerSession->isLoggedIn()) {
$this->customer = $this->customerRepository->getById($this->customerSession->getCustomerId());
} else {
return null;
}
}
return $this->customer;
}
/**
* Retrieve field options from attribute configuration
*
* @param mixed $attributeCode
* @param array $attributeConfig
* @return array
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function getFieldOptions($attributeCode, array $attributeConfig)
{
return $attributeConfig['options'] ?? [];
}
/**
* Order country options. Move top countries to the beginning of the list.
*
* @param array $countryOptions
* @return array
* @deprecated 100.1.7
*/
protected function orderCountryOptions(array $countryOptions)
{
if (empty($this->topCountryCodes)) {
return $countryOptions;
}
$headOptions = [];
$tailOptions = [[
'value' => 'delimiter',
'label' => '──────────',
'disabled' => true,
]];
foreach ($countryOptions as $countryOption) {
if (empty($countryOption['value']) || in_array($countryOption['value'], $this->topCountryCodes)) {
$headOptions[] = $countryOption;
} else {
$tailOptions[] = $countryOption;
}
}
return array_merge($headOptions, $tailOptions);
}
}