15 use Magento\Customer\Api\Data\ValidationResultsInterfaceFactory;
27 use Magento\Framework\DataObjectFactory as ObjectFactory;
52 use Psr\Log\LoggerInterface as PsrLogger;
55 use Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory;
174 private $customerFactory;
179 private $validationResultsDataFactory;
184 private $eventManager;
189 private $storeManager;
204 private $addressRepository;
209 private $customerMetadataService;
224 private $customerRegistry;
229 private $configShare;
239 private $customerRepository;
244 private $scopeConfig;
249 private $transportBuilder;
254 private $sessionManager;
259 private $saveHandler;
264 private $visitorCollectionFactory;
309 private $emailNotification;
314 private $eavValidator;
319 private $credentialsValidator;
324 private $dateTimeFactory;
329 private $accountConfirmation;
334 private $searchCriteriaBuilder;
370 CustomerFactory $customerFactory,
375 ValidationResultsInterfaceFactory $validationResultsDataFactory,
380 Encryptor $encryptor,
381 ConfigShare $configShare,
398 CollectionFactory $visitorCollectionFactory =
null,
402 $this->eventManager = $eventManager;
404 $this->mathRandom = $mathRandom;
405 $this->validator = $validator;
406 $this->validationResultsDataFactory = $validationResultsDataFactory;
408 $this->customerMetadataService = $customerMetadataService;
412 $this->configShare = $configShare;
415 $this->scopeConfig = $scopeConfig;
416 $this->transportBuilder = $transportBuilder;
424 $this->credentialsValidator =
428 ->get(AccountConfirmation::class);
429 $this->sessionManager = $sessionManager
431 $this->saveHandler = $saveHandler
433 $this->visitorCollectionFactory = $visitorCollectionFactory
435 $this->searchCriteriaBuilder = $searchCriteriaBuilder
444 private function getAuthentication()
447 return \Magento\Framework\App\ObjectManager::getInstance()->get(
466 $this->getEmailNotification()->newAccount(
468 self::NEW_ACCOUNT_EMAIL_CONFIRMATION,
470 $this->storeManager->getStore()->getId()
474 $this->logger->critical($e);
484 return $this->activateCustomer(
$customer, $confirmationKey);
493 return $this->activateCustomer(
$customer, $confirmationKey);
505 private function activateCustomer(
$customer, $confirmationKey)
512 if (
$customer->getConfirmation() !== $confirmationKey) {
513 throw new InputMismatchException(
__(
'The confirmation token is invalid. Verify the token and try again.'));
517 $this->customerRepository->save(
$customer);
518 $this->getEmailNotification()->newAccount(
522 $this->storeManager->getStore()->getId()
533 $customer = $this->customerRepository->get($username);
539 if ($this->getAuthentication()->isLocked(
$customerId)) {
543 $this->getAuthentication()->authenticate(
$customerId, $password);
552 $this->eventManager->dispatch(
553 'customer_customer_authenticated',
557 $this->eventManager->dispatch(
'customer_data_object_login', [
'customer' =>
$customer]);
567 $this->validateResetPasswordToken(
$customerId, $resetPasswordLinkToken);
577 $websiteId = $this->storeManager->getStore()->getWebsiteId();
582 $newPasswordToken = $this->mathRandom->getUniqueHash();
588 $this->getEmailNotification()->passwordReminder(
$customer);
591 $this->getEmailNotification()->passwordResetConfirmation(
$customer);
600 $this->logger->critical($e);
617 $this->searchCriteriaBuilder->addFilter(
621 $this->searchCriteriaBuilder->setPageSize(1);
622 $found = $this->customerRepository->getList(
623 $this->searchCriteriaBuilder->create()
625 if ($found->getTotalCount() > 1) {
628 new Phrase(
'Reset password token expired.')
631 if ($found->getTotalCount() === 0) {
639 return $found->getItems()[0];
648 private function handleUnknownTemplate(
$template)
650 throw new InputException(
__(
651 'Invalid value of "%value" provided for the %fieldName field. Possible values: %template1 or %template2.',
654 'fieldName' =>
'template',
667 $customer = $this->matchCustomerByRpToken($resetToken);
673 $this->validateResetPasswordToken(
$customer->getId(), $resetToken);
674 $this->credentialsValidator->checkPasswordDifferentFromEmail(
680 $customerSecure = $this->customerRegistry->retrieveSecureData(
$customer->getId());
681 $customerSecure->setRpToken(
null);
682 $customerSecure->setRpTokenCreatedAt(
null);
684 $this->sessionManager->destroy();
685 $this->destroyCustomerSessions(
$customer->getId());
686 $this->customerRepository->save(
$customer);
700 $length = $this->stringHelper->strlen($password);
701 if ($length > self::MAX_PASSWORD_LENGTH) {
704 'Please enter a password with at most %1 characters.',
705 self::MAX_PASSWORD_LENGTH
710 if ($length < $configMinPasswordLength) {
713 'The password needs at least %1 characters. Create a new password and try again.',
714 $configMinPasswordLength
718 if ($this->stringHelper->strlen(trim($password)) != $length) {
720 __(
"The password can't begin or end with a space. Verify the password and try again.")
725 if ($requiredCharactersCheck !== 0) {
728 'Minimum of different classes of characters in password is %1.' .
729 ' Classes of characters: Lower Case, Upper Case, Digits, Special Characters.',
730 $requiredCharactersCheck
745 $requiredNumber = $this->scopeConfig->getValue(self::XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER);
748 if (preg_match(
'/[0-9]+/', $password)) {
751 if (preg_match(
'/[A-Z]+/', $password)) {
754 if (preg_match(
'/[a-z]+/', $password)) {
757 if (preg_match(
'/[^a-zA-Z0-9]+/', $password)) {
761 if ($counter < $requiredNumber) {
762 $return = $requiredNumber;
775 return $this->scopeConfig->getValue(self::XML_PATH_MINIMUM_PASSWORD_LENGTH);
799 if ($password !==
null) {
803 $this->credentialsValidator->checkPasswordDifferentFromEmail(
$customerEmail, $password);
806 __(
"The password can't be the same as the email address. Create a new password and try again.")
830 throw new InputException(
__(
'This customer already exists in this store.'));
838 $storeId = $this->storeManager->getWebsite(
$customer->getWebsiteId())->getDefaultStore()->getId();
840 $this->storeManager->setCurrentStore(
null);
841 $storeId = $this->storeManager->getStore()->getId();
863 $customerAddresses =
$customer->getAddresses() ?: [];
870 __(
'A customer with the same email address already exists in an associated website.')
876 foreach ($customerAddresses as
$address) {
879 $newAddress->setId(
null);
880 $newAddress->setCustomerId(
$customer->getId());
881 $this->addressRepository->save($newAddress);
884 $this->addressRepository->save(
$address);
887 $this->customerRegistry->remove(
$customer->getId());
889 $this->customerRepository->delete(
$customer);
893 $newLinkToken = $this->mathRandom->getUniqueHash();
938 $this->logger->critical($e);
939 }
catch (\UnexpectedValueException $e) {
940 $this->logger->error($e);
954 return $this->changePasswordForCustomer(
$customer, $currentPassword, $newPassword);
967 return $this->changePasswordForCustomer(
$customer, $currentPassword, $newPassword);
981 private function changePasswordForCustomer(
$customer, $currentPassword, $newPassword)
984 $this->getAuthentication()->authenticate(
$customer->getId(), $currentPassword);
985 }
catch (InvalidEmailOrPasswordException $e) {
986 throw new InvalidEmailOrPasswordException(
987 __(
"The password doesn't match this account. Verify the password and try again.")
991 $this->credentialsValidator->checkPasswordDifferentFromEmail(
$customerEmail, $newPassword);
992 $customerSecure = $this->customerRegistry->retrieveSecureData(
$customer->getId());
993 $customerSecure->setRpToken(
null);
994 $customerSecure->setRpTokenCreatedAt(
null);
997 $this->destroyCustomerSessions(
$customer->getId());
998 $this->customerRepository->save(
$customer);
1011 return $this->encryptor->getHash($password,
true);
1019 private function getEavValidator()
1021 if ($this->eavValidator ===
null) {
1024 return $this->eavValidator;
1032 $validationResults = $this->validationResultsDataFactory->create();
1034 $oldAddresses =
$customer->getAddresses();
1041 if (
$result ===
false && is_array($this->getEavValidator()->getMessages())) {
1042 return $validationResults->setIsValid(
false)->setMessages(
1043 call_user_func_array(
1045 $this->getEavValidator()->getMessages()
1049 return $validationResults->setIsValid(
true)->setMessages([]);
1059 $websiteId = $this->storeManager->getStore()->getWebsiteId();
1074 if ((
bool)$this->configShare->isWebsiteScope()) {
1075 $ids = $this->storeManager->getWebsite($customerWebsiteId)->getStoreIds();
1077 foreach ($this->storeManager->getStores() as
$store) {
1078 $ids[] =
$store->getId();
1097 private function validateResetPasswordToken(
$customerId, $resetPasswordLinkToken)
1102 'Invalid value of "%value" provided for the %fieldName field.',
1103 [
'value' =>
$customerId,
'fieldName' =>
'customerId']
1110 $customerId = $this->matchCustomerByRpToken($resetPasswordLinkToken)
1113 if (!is_string($resetPasswordLinkToken) || empty($resetPasswordLinkToken)) {
1114 $params = [
'fieldName' =>
'resetPasswordLinkToken'];
1115 throw new InputException(
__(
'"%fieldName" is required. Enter and try again.',
$params));
1117 $customerSecureData = $this->customerRegistry->retrieveSecureData(
$customerId);
1118 $rpToken = $customerSecureData->getRpToken();
1119 $rpTokenCreatedAt = $customerSecureData->getRpTokenCreatedAt();
1121 throw new InputMismatchException(
__(
'The password token is mismatched. Reset and try again.'));
1123 throw new ExpiredException(
__(
'The password token is expired. Reset and try again.'));
1156 $type = self::NEW_ACCOUNT_EMAIL_REGISTERED,
1159 $sendemailStoreId =
null 1163 if (!isset($types[
$type])) {
1165 __(
'The transactional account email type is incorrect. Verify and try again.')
1180 self::XML_PATH_REGISTER_EMAIL_IDENTITY,
1181 [
'customer' => $customerEmailData,
'back_url' => $backUrl,
'store' =>
$store],
1211 if (
$customer->getWebsiteId() != 0 && empty($defaultStoreId)) {
1212 $storeIds = $this->storeManager->getWebsite(
$customer->getWebsiteId())->getStoreIds();
1214 $defaultStoreId = current($storeIds);
1216 return $defaultStoreId;
1261 $templateParams = [],
1267 ScopeInterface::SCOPE_STORE,
1274 $transport = $this->transportBuilder->setTemplateIdentifier(
$templateId)
1276 ->setTemplateVars($templateParams)
1277 ->setFrom($this->scopeConfig->getValue(
1279 ScopeInterface::SCOPE_STORE,
1282 ->addTo(
$email, $this->customerViewHelper->getCustomerName(
$customer))
1285 $transport->sendMessage();
1300 return $this->accountConfirmation->isConfirmationRequired(
1324 $skipConfirmationIfEmail = $this->registry->registry(
"skip_confirmation_if_email");
1325 if (!$skipConfirmationIfEmail) {
1329 return strtolower($skipConfirmationIfEmail) === strtolower(
$customer->getEmail());
1341 if (empty($rpToken) || empty($rpTokenCreatedAt)) {
1345 $expirationPeriod = $this->customerModel->getResetPasswordLinkExpirationPeriod();
1347 $currentTimestamp = $this->dateTimeFactory->create()->getTimestamp();
1348 $tokenTimestamp = $this->dateTimeFactory->create($rpTokenCreatedAt)->getTimestamp();
1349 if ($tokenTimestamp > $currentTimestamp) {
1353 $hourDifference = floor(($currentTimestamp - $tokenTimestamp) / (60 * 60));
1354 if ($hourDifference >= $expirationPeriod) {
1373 if (!is_string($passwordLinkToken) || empty($passwordLinkToken)) {
1376 'Invalid value of "%value" provided for the %fieldName field.',
1377 [
'value' => $passwordLinkToken,
'fieldName' =>
'password reset token']
1381 if (is_string($passwordLinkToken) && !empty($passwordLinkToken)) {
1382 $customerSecure = $this->customerRegistry->retrieveSecureData(
$customer->getId());
1383 $customerSecure->setRpToken($passwordLinkToken);
1384 $customerSecure->setRpTokenCreatedAt(
1387 $this->customerRepository->save(
$customer);
1401 $storeId = $this->storeManager->getStore()->getId();
1410 self::XML_PATH_REMIND_EMAIL_TEMPLATE,
1411 self::XML_PATH_FORGOT_EMAIL_IDENTITY,
1412 [
'customer' => $customerEmailData,
'store' => $this->storeManager->getStore(
$storeId)],
1428 $storeId = $this->storeManager->getStore()->getId();
1437 self::XML_PATH_FORGOT_EMAIL_TEMPLATE,
1438 self::XML_PATH_FORGOT_EMAIL_IDENTITY,
1439 [
'customer' => $customerEmailData,
'store' => $this->storeManager->getStore(
$storeId)],
1456 if (
$address->getId() == $addressId) {
1474 $mergedCustomerData = $this->customerRegistry->retrieveSecureData(
$customer->getId());
1480 $mergedCustomerData->setData(
'name', $this->customerViewHelper->getCustomerName(
$customer));
1481 return $mergedCustomerData;
1492 return $this->encryptor->getHash($password);
1501 private function getEmailNotification()
1504 return \Magento\Framework\App\ObjectManager::getInstance()->get(
1505 EmailNotificationInterface::class
1508 return $this->emailNotification;
1520 private function destroyCustomerSessions(
$customerId)
1522 $sessionLifetime = $this->scopeConfig->getValue(
1523 \
Magento\Framework\Session\Config::XML_PATH_COOKIE_LIFETIME,
1524 \
Magento\Store\Model\ScopeInterface::SCOPE_STORE
1526 $dateTime = $this->dateTimeFactory->create();
1527 $activeSessionsTime =
$dateTime->setTimestamp(
$dateTime->getTimestamp() - $sessionLifetime)
1530 $visitorCollection = $this->visitorCollectionFactory->create();
1531 $visitorCollection->addFieldToFilter(
'customer_id',
$customerId);
1532 $visitorCollection->addFieldToFilter(
'last_visit_at', [
'from' => $activeSessionsTime]);
1533 $visitorCollection->addFieldToFilter(
'session_id', [
'neq' => $this->sessionManager->getSessionId()]);
1535 foreach ($visitorCollection->getItems() as $visitor) {
1536 $sessionId = $visitor->getSessionId();
1537 $this->saveHandler->destroy($sessionId);
initiatePasswordReset($email, $template, $websiteId=null)
createPasswordHash($password)
const DATETIME_PHP_FORMAT
__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, CustomerModel $customerModel, ObjectFactory $objectFactory, ExtensibleDataObjectConverter $extensibleDataObjectConverter, CredentialsValidator $credentialsValidator=null, DateTimeFactory $dateTimeFactory=null, AccountConfirmation $accountConfirmation=null, SessionManagerInterface $sessionManager=null, SaveHandlerInterface $saveHandler=null, CollectionFactory $visitorCollectionFactory=null, SearchCriteriaBuilder $searchCriteriaBuilder=null)
const NEW_ACCOUNT_EMAIL_CONFIRMATION
sendEmailConfirmation(CustomerInterface $customer, $redirectUrl)
const XML_PATH_REGISTER_EMAIL_TEMPLATE
elseif(isset( $params[ 'redirect_parent']))
const XML_PATH_FORGOT_EMAIL_TEMPLATE
isEmailAvailable($customerEmail, $websiteId=null)
sendPasswordResetNotificationEmail($customer)
getPasswordHash($password)
createAccount(CustomerInterface $customer, $password=null, $redirectUrl='')
const XML_PATH_RESET_PASSWORD_TEMPLATE
isCustomerInStore($customerWebsiteId, $storeId)
const ACCOUNT_CONFIRMATION_NOT_REQUIRED
createAccountWithPasswordHash(CustomerInterface $customer, $hash, $redirectUrl='')
changePassword($email, $currentPassword, $newPassword)
getFullCustomerObject($customer)
static singleField($fieldName, $fieldValue)
changePasswordById($customerId, $currentPassword, $newPassword)
const MIN_PASSWORD_LENGTH
getAddressById(CustomerInterface $customer, $addressId)
changeResetPasswordLinkToken($customer, $passwordLinkToken)
isResetPasswordLinkTokenExpired($rpToken, $rpTokenCreatedAt)
const XML_PATH_CONFIRM_EMAIL_TEMPLATE
isConfirmationRequired($customer)
sendNewAccountEmail( $customer, $type=self::NEW_ACCOUNT_EMAIL_REGISTERED, $backUrl='', $storeId='0', $sendemailStoreId=null)
sendEmailTemplate( $customer, $template, $sender, $templateParams=[], $storeId=null, $email=null)
const NEW_ACCOUNT_EMAIL_REGISTERED
getDefaultShippingAddress($customerId)
validateResetPasswordLinkToken($customerId, $resetPasswordLinkToken)
const NEW_ACCOUNT_EMAIL_REGISTERED_NO_PASSWORD
const XML_PATH_REGISTER_EMAIL_IDENTITY
authenticate($username, $password)
activate($email, $confirmationKey)
const ACCOUNT_CONFIRMATION_REQUIRED
resendConfirmation($email, $websiteId=null, $redirectUrl='')
const XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER
activateById($customerId, $confirmationKey)
static compareStrings($expected, $actual)
makeRequiredCharactersCheck($password)
$extensibleDataObjectConverter
const XML_PATH_IS_CONFIRM
validate(CustomerInterface $customer)
const XML_PATH_CONFIRMED_EMAIL_TEMPLATE
const NEW_ACCOUNT_EMAIL_CONFIRMED
getWebsiteStoreId($customer, $defaultStoreId=null)
sendPasswordReminderEmail($customer)
getConfirmationStatus($customerId)
const XML_PATH_REGISTER_NO_PASSWORD_EMAIL_TEMPLATE
$params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE]
sendPasswordResetConfirmationEmail($customer)
resetPassword($email, $resetToken, $newPassword)
const XML_PATH_FORGOT_EMAIL_IDENTITY
const XML_PATH_REMIND_EMAIL_TEMPLATE
checkPasswordStrength($password)
canSkipConfirmation($customer)
getDefaultBillingAddress($customerId)
const XML_PATH_MINIMUM_PASSWORD_LENGTH