Files
stemcell/app/code/Stemcell/Customer/Model/AccountManagement.php
T
2026-09-15 10:26:34 +08:00

214 lines
9.3 KiB
PHP

<?php
namespace Stemcell\Customer\Model;
use Magento\Customer\Api\AddressRepositoryInterface;
use Magento\Customer\Api\CustomerMetadataInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Api\Data\AddressInterface;
use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Customer\Api\Data\ValidationResultsInterfaceFactory;
use Magento\Customer\Api\SessionCleanerInterface;
use Magento\Customer\Helper\View as CustomerViewHelper;
use Magento\Customer\Model\AccountConfirmation;
use Magento\Customer\Model\AddressRegistry;
use Magento\Customer\Model\AuthenticationInterface;
use Magento\Customer\Model\Config\Share as ConfigShare;
use Magento\Customer\Model\Customer;
use Magento\Customer\Model\Customer as CustomerModel;
use Magento\Customer\Model\Customer\CredentialsValidator;
use Magento\Customer\Model\CustomerFactory;
use Magento\Customer\Model\CustomerRegistry;
use Magento\Customer\Model\EmailNotificationInterface;
use Magento\Customer\Model\ForgotPasswordToken\GetCustomerByToken;
use Magento\Customer\Model\Metadata\Validator;
use Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory;
use Magento\Directory\Model\AllowedCountries;
use Magento\Framework\Api\ExtensibleDataObjectConverter;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\AuthorizationInterface;
use Magento\Framework\DataObjectFactory as ObjectFactory;
use Magento\Framework\Encryption\EncryptorInterface as Encryptor;
use Magento\Framework\Encryption\Helper\Security;
use Magento\Framework\Event\ManagerInterface;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Exception\State\ExpiredException;
use Magento\Framework\Exception\State\InputMismatchException;
use Magento\Framework\Intl\DateTimeFactory;
use Magento\Framework\Mail\Template\TransportBuilder;
use Magento\Framework\Math\Random;
use Magento\Framework\Reflection\DataObjectProcessor;
use Magento\Framework\Registry;
use Magento\Framework\Session\SaveHandlerInterface;
use Magento\Framework\Session\SessionManagerInterface;
use Magento\Framework\Stdlib\DateTime;
use Magento\Framework\Stdlib\StringUtils as StringHelper;
use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\StoreManagerInterface;
use Psr\Log\LoggerInterface as PsrLogger;
class AccountManagement extends \Magento\Customer\Model\AccountManagement
{
protected AddressRegistry $addressRegistry;
protected GetCustomerByToken $getByToken;
protected CustomerRegistry $customerRegistry;
protected CredentialsValidator $credentialsValidator;
protected CustomerRepositoryInterface $customerRepository;
protected SessionCleanerInterface $sessionCleaner;
public function __construct(
CustomerFactory $customerFactory,
ManagerInterface $eventManager,
StoreManagerInterface $storeManager,
Random $mathRandom,
Validator $validator,
ValidationResultsInterfaceFactory $validationResultsDataFactory,
AddressRepositoryInterface $addressRepository,
CustomerMetadataInterface $customerMetadataService,
CustomerRegistry $customerRegistry,
PsrLogger $logger,
Encryptor $encryptor,
ConfigShare $configShare,
StringHelper $stringHelper,
CustomerRepositoryInterface $customerRepository,
ScopeConfigInterface $scopeConfig,
TransportBuilder $transportBuilder,
DataObjectProcessor $dataProcessor,
Registry $registry,
CustomerViewHelper $customerViewHelper,
DateTime $dateTime,
Customer $customerModel,
ObjectFactory $objectFactory,
ExtensibleDataObjectConverter $extensibleDataObjectConverter,
CredentialsValidator $credentialsValidator,
DateTimeFactory $dateTimeFactory = null,
AccountConfirmation $accountConfirmation = null,
SessionManagerInterface $sessionManager = null,
SaveHandlerInterface $saveHandler = null,
CollectionFactory $visitorCollectionFactory = null,
SearchCriteriaBuilder $searchCriteriaBuilder = null,
AddressRegistry $addressRegistry,
GetCustomerByToken $getByToken,
AllowedCountries $allowedCountriesReader = null,
SessionCleanerInterface $sessionCleaner,
AuthorizationInterface $authorization = null
) {
parent::__construct($customerFactory, $eventManager, $storeManager, $mathRandom, $validator, $validationResultsDataFactory, $addressRepository, $customerMetadataService, $customerRegistry, $logger, $encryptor, $configShare, $stringHelper, $customerRepository, $scopeConfig, $transportBuilder, $dataProcessor, $registry, $customerViewHelper, $dateTime, $customerModel, $objectFactory, $extensibleDataObjectConverter, $credentialsValidator, $dateTimeFactory, $accountConfirmation, $sessionManager, $saveHandler, $visitorCollectionFactory, $searchCriteriaBuilder, $addressRegistry, $getByToken, $allowedCountriesReader, $sessionCleaner, $authorization);
$this->addressRegistry = $addressRegistry;
$this->getByToken = $getByToken;
$this->customerRegistry = $customerRegistry;
$this->credentialsValidator = $credentialsValidator;
$this->customerRepository = $customerRepository;
$this->sessionCleaner = $sessionCleaner;
}
/**
* Disable Customer Address Validation
*
* @param CustomerInterface $customer
* @throws NoSuchEntityException
*/
protected function disableAddressValidation($customer)
{
foreach ($customer->getAddresses() as $address) {
$addressModel = $this->addressRegistry->retrieve($address->getId());
$addressModel->setShouldIgnoreValidation(true);
}
}
/**
* Set ignore_validation_flag for reset password flow to skip unnecessary address and customer validation
*
* @param Customer $customer
* @return void
*/
protected function setIgnoreValidationFlag($customer)
{
$customer->setData('ignore_validation_flag', true);
}
/**
* Validate the Reset Password Token for a customer.
*
* @param int $customerId
* @param string $resetPasswordLinkToken
*
* @return bool
* @throws ExpiredException If token is expired
* @throws InputException If token or customer id is invalid
* @throws InputMismatchException If token is mismatched
* @throws LocalizedException
* @throws NoSuchEntityException If customer doesn't exist
* @SuppressWarnings(PHPMD.LongVariable)
*/
protected function validateResetPasswordToken($customerId, $resetPasswordLinkToken)
{
if ($customerId !== null && $customerId <= 0) {
throw new InputException(
__(
'Invalid value of "%value" provided for the %fieldName field.',
['value' => $customerId, 'fieldName' => 'customerId']
)
);
}
if ($customerId === null) {
//Looking for the customer.
$customerId = $this->getByToken
->execute($resetPasswordLinkToken)
->getId();
}
if (!is_string($resetPasswordLinkToken) || empty($resetPasswordLinkToken)) {
$params = ['fieldName' => 'resetPasswordLinkToken'];
throw new InputException(__('"%fieldName" is required. Enter and try again.', $params));
}
$customerSecureData = $this->customerRegistry->retrieveSecureData($customerId);
$rpToken = $customerSecureData->getRpToken();
$rpTokenCreatedAt = $customerSecureData->getRpTokenCreatedAt();
if (!Security::compareStrings($rpToken, $resetPasswordLinkToken)) {
throw new InputMismatchException(__('The password token is mismatched. Reset and try again.'));
} elseif ($this->isResetPasswordLinkTokenExpired($rpToken, $rpTokenCreatedAt)) {
throw new ExpiredException(__('The password token is expired. Reset and try again.'));
}
return true;
}
public function resetPassword($email, $resetToken, $newPassword)
{
if (!$email && $resetToken) {
$customer = $this->getByToken->execute($resetToken);
$email = $customer->getEmail();
} else {
$customer = $this->customerRepository->get($email);
}
// No need to validate customer and customer address while saving customer reset password token
$this->disableAddressValidation($customer);
$this->setIgnoreValidationFlag($customer);
//Validate Token and new password strength
if ($resetToken) {
$this->validateResetPasswordToken($customer->getId(), $resetToken);
}
$this->credentialsValidator->checkPasswordDifferentFromEmail(
$email,
$newPassword
);
$this->checkPasswordStrength($newPassword);
//Update secure data
$customerSecure = $this->customerRegistry->retrieveSecureData($customer->getId());
$customerSecure->setRpToken(null);
$customerSecure->setRpTokenCreatedAt(null);
$customerSecure->setPasswordHash($this->createPasswordHash($newPassword));
$this->sessionCleaner->clearFor((int)$customer->getId());
$this->customerRepository->save($customer);
return true;
}
}