123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
- <?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\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;
- /**
- * @param AddressHelper $addressHelper
- * @param Session $customerSession
- * @param CustomerRepository $customerRepository
- * @param DirectoryHelper $directoryHelper
- */
- public function __construct(
- AddressHelper $addressHelper,
- Session $customerSession,
- CustomerRepository $customerRepository,
- DirectoryHelper $directoryHelper
- ) {
- $this->addressHelper = $addressHelper;
- $this->customerSession = $customerSession;
- $this->customerRepository = $customerRepository;
- $this->directoryHelper = $directoryHelper;
- $this->topCountryCodes = $directoryHelper->getTopCountryCodes();
- }
- /**
- * 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 = [
- '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
- ? 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') {
- return $this->directoryHelper->getDefaultCountry();
- }
- $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 string $attributeCode
- * @param array $attributeConfig
- * @return array
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
- */
- protected function getFieldOptions($attributeCode, array $attributeConfig)
- {
- return isset($attributeConfig['options']) ? $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);
- }
- }
|