Skip to content

Commit 821dbed

Browse files
authored
Merge pull request #5347 from magento-tsg/2.3.5-develop-pr109
[TSG] Fixes for 2.3 (pr109) (2.3.5-develop)
2 parents 5f4aa3c + f64add2 commit 821dbed

File tree

19 files changed

+526
-180
lines changed

19 files changed

+526
-180
lines changed

app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Save.php

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@
77
namespace Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute;
88

99
use Magento\AsynchronousOperations\Api\Data\OperationInterface;
10+
use Magento\Catalog\Model\ProductFactory;
1011
use Magento\Eav\Model\Config;
1112
use Magento\Framework\App\Action\HttpPostActionInterface;
1213
use Magento\Backend\App\Action;
1314
use Magento\Framework\App\ObjectManager;
15+
use Magento\Framework\Exception\LocalizedException;
1416
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
1517

1618
/**
17-
* Class Save
19+
* Class responsible for saving product attributes.
1820
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1921
*/
2022
class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute implements HttpPostActionInterface
@@ -59,6 +61,11 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribut
5961
*/
6062
private $eavConfig;
6163

64+
/**
65+
* @var ProductFactory
66+
*/
67+
private $productFactory;
68+
6269
/**
6370
* @param Action\Context $context
6471
* @param \Magento\Catalog\Helper\Product\Edit\Action\Attribute $attributeHelper
@@ -70,6 +77,7 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribut
7077
* @param int $bulkSize
7178
* @param TimezoneInterface $timezone
7279
* @param Config $eavConfig
80+
* @param ProductFactory $productFactory
7381
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
7482
*/
7583
public function __construct(
@@ -82,7 +90,8 @@ public function __construct(
8290
\Magento\Authorization\Model\UserContextInterface $userContext,
8391
int $bulkSize = 100,
8492
TimezoneInterface $timezone = null,
85-
Config $eavConfig = null
93+
Config $eavConfig = null,
94+
ProductFactory $productFactory = null
8695
) {
8796
parent::__construct($context, $attributeHelper);
8897
$this->bulkManagement = $bulkManagement;
@@ -95,6 +104,7 @@ public function __construct(
95104
->get(TimezoneInterface::class);
96105
$this->eavConfig = $eavConfig ?: ObjectManager::getInstance()
97106
->get(Config::class);
107+
$this->productFactory = $productFactory ?? ObjectManager::getInstance()->get(ProductFactory::class);
98108
}
99109

100110
/**
@@ -120,9 +130,10 @@ public function execute()
120130
$attributesData = $this->sanitizeProductAttributes($attributesData);
121131

122132
try {
133+
$this->validateProductAttributes($attributesData);
123134
$this->publish($attributesData, $websiteRemoveData, $websiteAddData, $storeId, $websiteId, $productIds);
124135
$this->messageManager->addSuccessMessage(__('Message is added to queue'));
125-
} catch (\Magento\Framework\Exception\LocalizedException $e) {
136+
} catch (LocalizedException $e) {
126137
$this->messageManager->addErrorMessage($e->getMessage());
127138
} catch (\Exception $e) {
128139
$this->messageManager->addExceptionMessage(
@@ -147,10 +158,12 @@ private function sanitizeProductAttributes($attributesData)
147158

148159
foreach ($attributesData as $attributeCode => $value) {
149160
$attribute = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode);
161+
150162
if (!$attribute->getAttributeId()) {
151163
unset($attributesData[$attributeCode]);
152164
continue;
153165
}
166+
154167
if ($attribute->getBackendType() === 'datetime') {
155168
if (!empty($value)) {
156169
$filterInput = new \Zend_Filter_LocalizedToNormalized(['date_format' => $dateFormat]);
@@ -178,6 +191,25 @@ private function sanitizeProductAttributes($attributesData)
178191
return $attributesData;
179192
}
180193

194+
/**
195+
* Validate product attributes data.
196+
*
197+
* @param array $attributesData
198+
*
199+
* @return void
200+
* @throws LocalizedException
201+
*/
202+
private function validateProductAttributes(array $attributesData): void
203+
{
204+
$product = $this->productFactory->create();
205+
$product->setData($attributesData);
206+
207+
foreach (array_keys($attributesData) as $attributeCode) {
208+
$attribute = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode);
209+
$attribute->getBackend()->validate($product);
210+
}
211+
}
212+
181213
/**
182214
* Schedule new bulk
183215
*
@@ -187,7 +219,7 @@ private function sanitizeProductAttributes($attributesData)
187219
* @param int $storeId
188220
* @param int $websiteId
189221
* @param array $productIds
190-
* @throws \Magento\Framework\Exception\LocalizedException
222+
* @throws LocalizedException
191223
*
192224
* @return void
193225
*/
@@ -241,7 +273,7 @@ private function publish(
241273
$this->userContext->getUserId()
242274
);
243275
if (!$result) {
244-
throw new \Magento\Framework\Exception\LocalizedException(
276+
throw new LocalizedException(
245277
__('Something went wrong while processing the request.')
246278
);
247279
}

app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ public function execute()
221221
return $this->returnResult('catalog/*/', [], ['error' => true]);
222222
}
223223
// entity type check
224-
if ($model->getEntityTypeId() != $this->_entityTypeId) {
224+
if ($model->getEntityTypeId() != $this->_entityTypeId || array_key_exists('backend_model', $data)) {
225225
$this->messageManager->addErrorMessage(__('We can\'t update the attribute.'));
226226
$this->_session->setAttributeData($data);
227227
return $this->returnResult('catalog/*/', [], ['error' => true]);
@@ -258,6 +258,8 @@ public function execute()
258258
unset($data['apply_to']);
259259
}
260260

261+
unset($data['entity_type_id']);
262+
261263
$model->addData($data);
262264

263265
if (!$attributeId) {

app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
use Magento\Catalog\Model\Attribute\LockValidatorInterface;
1010
use Magento\Framework\Api\AttributeValueFactory;
11+
use Magento\Framework\Exception\LocalizedException;
1112
use Magento\Framework\Stdlib\DateTime\DateTimeFormatterInterface;
1213

1314
/**
@@ -180,7 +181,7 @@ protected function _construct()
180181
* Processing object before save data
181182
*
182183
* @return \Magento\Framework\Model\AbstractModel
183-
* @throws \Magento\Framework\Exception\LocalizedException
184+
* @throws LocalizedException
184185
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
185186
*/
186187
public function beforeSave()
@@ -193,13 +194,14 @@ public function beforeSave()
193194
if ($this->_data[self::KEY_IS_GLOBAL] != $this->_origData[self::KEY_IS_GLOBAL]) {
194195
try {
195196
$this->attrLockValidator->validate($this);
196-
} catch (\Magento\Framework\Exception\LocalizedException $exception) {
197-
throw new \Magento\Framework\Exception\LocalizedException(
197+
} catch (LocalizedException $exception) {
198+
throw new LocalizedException(
198199
__('Do not change the scope. %1', $exception->getMessage())
199200
);
200201
}
201202
}
202203
}
204+
203205
if ($this->getFrontendInput() == 'price') {
204206
if (!$this->getBackendModel()) {
205207
$this->setBackendModel(\Magento\Catalog\Model\Product\Attribute\Backend\Price::class);
@@ -285,7 +287,7 @@ protected function _isOriginalEnabledInFlat()
285287
* Register indexing event before delete catalog eav attribute
286288
*
287289
* @return $this
288-
* @throws \Magento\Framework\Exception\LocalizedException
290+
* @throws LocalizedException
289291
*/
290292
public function beforeDelete()
291293
{
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Customer\Api;
9+
10+
/**
11+
* Interface for cleaning customer session data.
12+
*/
13+
interface SessionCleanerInterface
14+
{
15+
/**
16+
* Destroy all active customer sessions related to given customer id, including current session.
17+
*
18+
* @param int $customerId
19+
* @return void
20+
*/
21+
public function clearFor(int $customerId): void;
22+
}

app/code/Magento/Customer/Model/AccountManagement.php

Lines changed: 16 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Magento\Customer\Api\Data\AddressInterface;
1414
use Magento\Customer\Api\Data\CustomerInterface;
1515
use Magento\Customer\Api\Data\ValidationResultsInterfaceFactory;
16+
use Magento\Customer\Api\SessionCleanerInterface;
1617
use Magento\Customer\Helper\View as CustomerViewHelper;
1718
use Magento\Customer\Model\Config\Share as ConfigShare;
1819
use Magento\Customer\Model\Customer as CustomerModel;
@@ -200,6 +201,7 @@ class AccountManagement implements AccountManagementInterface
200201
* Minimum password length
201202
*
202203
* @deprecated Get rid of Helpers in Password Security Management
204+
* @see \Magento\Customer\Model\AccountManagement::XML_PATH_MINIMUM_PASSWORD_LENGTH
203205
*/
204206
const MIN_PASSWORD_LENGTH = 6;
205207

@@ -283,21 +285,6 @@ class AccountManagement implements AccountManagementInterface
283285
*/
284286
private $transportBuilder;
285287

286-
/**
287-
* @var SessionManagerInterface
288-
*/
289-
private $sessionManager;
290-
291-
/**
292-
* @var SaveHandlerInterface
293-
*/
294-
private $saveHandler;
295-
296-
/**
297-
* @var CollectionFactory
298-
*/
299-
private $visitorCollectionFactory;
300-
301288
/**
302289
* @var DataObjectProcessor
303290
*/
@@ -383,6 +370,11 @@ class AccountManagement implements AccountManagementInterface
383370
*/
384371
private $getByToken;
385372

373+
/**
374+
* @var SessionCleanerInterface
375+
*/
376+
private $sessionCleaner;
377+
386378
/**
387379
* @param CustomerFactory $customerFactory
388380
* @param ManagerInterface $eventManager
@@ -417,10 +409,12 @@ class AccountManagement implements AccountManagementInterface
417409
* @param AddressRegistry|null $addressRegistry
418410
* @param GetCustomerByToken|null $getByToken
419411
* @param AllowedCountries|null $allowedCountriesReader
412+
* @param SessionCleanerInterface|null $sessionCleaner
420413
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
421414
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
422415
* @SuppressWarnings(PHPMD.NPathComplexity)
423416
* @SuppressWarnings(PHPMD.LongVariable)
417+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
424418
*/
425419
public function __construct(
426420
CustomerFactory $customerFactory,
@@ -455,7 +449,8 @@ public function __construct(
455449
SearchCriteriaBuilder $searchCriteriaBuilder = null,
456450
AddressRegistry $addressRegistry = null,
457451
GetCustomerByToken $getByToken = null,
458-
AllowedCountries $allowedCountriesReader = null
452+
AllowedCountries $allowedCountriesReader = null,
453+
SessionCleanerInterface $sessionCleaner = null
459454
) {
460455
$this->customerFactory = $customerFactory;
461456
$this->eventManager = $eventManager;
@@ -486,12 +481,6 @@ public function __construct(
486481
$this->dateTimeFactory = $dateTimeFactory ?: $objectManager->get(DateTimeFactory::class);
487482
$this->accountConfirmation = $accountConfirmation ?: $objectManager
488483
->get(AccountConfirmation::class);
489-
$this->sessionManager = $sessionManager
490-
?: $objectManager->get(SessionManagerInterface::class);
491-
$this->saveHandler = $saveHandler
492-
?: $objectManager->get(SaveHandlerInterface::class);
493-
$this->visitorCollectionFactory = $visitorCollectionFactory
494-
?: $objectManager->get(CollectionFactory::class);
495484
$this->searchCriteriaBuilder = $searchCriteriaBuilder
496485
?: $objectManager->get(SearchCriteriaBuilder::class);
497486
$this->addressRegistry = $addressRegistry
@@ -500,6 +489,7 @@ public function __construct(
500489
?: $objectManager->get(GetCustomerByToken::class);
501490
$this->allowedCountriesReader = $allowedCountriesReader
502491
?: $objectManager->get(AllowedCountries::class);
492+
$this->sessionCleaner = $sessionCleaner ?? $objectManager->get(SessionCleanerInterface::class);
503493
}
504494

505495
/**
@@ -538,6 +528,8 @@ public function resendConfirmation($email, $websiteId = null, $redirectUrl = '')
538528
} catch (MailException $e) {
539529
// If we are not able to send a new account email, this should be ignored
540530
$this->logger->critical($e);
531+
532+
return false;
541533
}
542534
return true;
543535
}
@@ -725,7 +717,7 @@ public function resetPassword($email, $resetToken, $newPassword)
725717
$customerSecure->setRpToken(null);
726718
$customerSecure->setRpTokenCreatedAt(null);
727719
$customerSecure->setPasswordHash($this->createPasswordHash($newPassword));
728-
$this->destroyCustomerSessions($customer->getId());
720+
$this->sessionCleaner->clearFor((int)$customer->getId());
729721
$this->customerRepository->save($customer);
730722

731723
return true;
@@ -1050,7 +1042,7 @@ private function changePasswordForCustomer($customer, $currentPassword, $newPass
10501042
$customerSecure->setRpTokenCreatedAt(null);
10511043
$this->checkPasswordStrength($newPassword);
10521044
$customerSecure->setPasswordHash($this->createPasswordHash($newPassword));
1053-
$this->destroyCustomerSessions($customer->getId());
1045+
$this->sessionCleaner->clearFor((int)$customer->getId());
10541046
$this->disableAddressValidation($customer);
10551047
$this->customerRepository->save($customer);
10561048

@@ -1619,36 +1611,6 @@ private function getEmailNotification()
16191611
}
16201612
}
16211613

1622-
/**
1623-
* Destroy all active customer sessions by customer id (current session will not be destroyed).
1624-
*
1625-
* Customer sessions which should be deleted are collecting from the "customer_visitor" table considering
1626-
* configured session lifetime.
1627-
*
1628-
* @param string|int $customerId
1629-
* @return void
1630-
*/
1631-
private function destroyCustomerSessions($customerId)
1632-
{
1633-
$sessionLifetime = $this->scopeConfig->getValue(
1634-
\Magento\Framework\Session\Config::XML_PATH_COOKIE_LIFETIME,
1635-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
1636-
);
1637-
$dateTime = $this->dateTimeFactory->create();
1638-
$activeSessionsTime = $dateTime->setTimestamp($dateTime->getTimestamp() - $sessionLifetime)
1639-
->format(DateTime::DATETIME_PHP_FORMAT);
1640-
/** @var \Magento\Customer\Model\ResourceModel\Visitor\Collection $visitorCollection */
1641-
$visitorCollection = $this->visitorCollectionFactory->create();
1642-
$visitorCollection->addFieldToFilter('customer_id', $customerId);
1643-
$visitorCollection->addFieldToFilter('last_visit_at', ['from' => $activeSessionsTime]);
1644-
$visitorCollection->addFieldToFilter('session_id', ['neq' => $this->sessionManager->getSessionId()]);
1645-
/** @var \Magento\Customer\Model\Visitor $visitor */
1646-
foreach ($visitorCollection->getItems() as $visitor) {
1647-
$sessionId = $visitor->getSessionId();
1648-
$this->saveHandler->destroy($sessionId);
1649-
}
1650-
}
1651-
16521614
/**
16531615
* Set ignore_validation_flag for reset password flow to skip unnecessary address and customer validation
16541616
*

0 commit comments

Comments
 (0)