Advertisement
Guest User

Untitled

a guest
May 26th, 2018
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 48.23 KB | None | 0 0
  1. <?php
  2. /**
  3.  * Copyright © Magento, Inc. All rights reserved.
  4.  * See COPYING.txt for license details.
  5.  */
  6. namespace Magento\Customer\Model;
  7.  
  8. use Magento\Customer\Api\AccountManagementInterface;
  9. use Magento\Customer\Api\AddressRepositoryInterface;
  10. use Magento\Customer\Api\CustomerMetadataInterface;
  11. use Magento\Customer\Api\CustomerRepositoryInterface;
  12. use Magento\Customer\Api\Data\AddressInterface;
  13. use Magento\Customer\Api\Data\CustomerInterface;
  14. use Magento\Customer\Api\Data\ValidationResultsInterfaceFactory;
  15. use Magento\Customer\Helper\View as CustomerViewHelper;
  16. use Magento\Customer\Model\Config\Share as ConfigShare;
  17. use Magento\Customer\Model\Customer as CustomerModel;
  18. use Magento\Customer\Model\Customer\CredentialsValidator;
  19. use Magento\Customer\Model\Metadata\Validator;
  20. use Magento\Eav\Model\Validator\Attribute\Backend;
  21. use Magento\Framework\Api\ExtensibleDataObjectConverter;
  22. use Magento\Framework\App\Area;
  23. use Magento\Framework\App\Config\ScopeConfigInterface;
  24. use Magento\Framework\App\ObjectManager;
  25. use Magento\Framework\DataObjectFactory as ObjectFactory;
  26. use Magento\Framework\Encryption\EncryptorInterface as Encryptor;
  27. use Magento\Framework\Encryption\Helper\Security;
  28. use Magento\Framework\Event\ManagerInterface;
  29. use Magento\Framework\Exception\AlreadyExistsException;
  30. use Magento\Framework\Exception\EmailNotConfirmedException;
  31. use Magento\Framework\Exception\InputException;
  32. use Magento\Framework\Exception\InvalidEmailOrPasswordException;
  33. use Magento\Framework\Exception\LocalizedException;
  34. use Magento\Framework\Exception\MailException;
  35. use Magento\Framework\Exception\NoSuchEntityException;
  36. use Magento\Framework\Exception\State\ExpiredException;
  37. use Magento\Framework\Exception\State\InputMismatchException;
  38. use Magento\Framework\Exception\State\InvalidTransitionException;
  39. use Magento\Framework\Exception\State\UserLockedException;
  40. use Magento\Framework\Intl\DateTimeFactory;
  41. use Magento\Framework\Mail\Template\TransportBuilder;
  42. use Magento\Framework\Math\Random;
  43. use Magento\Framework\Reflection\DataObjectProcessor;
  44. use Magento\Framework\Registry;
  45. use Magento\Framework\Stdlib\DateTime;
  46. use Magento\Framework\Stdlib\StringUtils as StringHelper;
  47. use Magento\Store\Model\ScopeInterface;
  48. use Magento\Store\Model\StoreManagerInterface;
  49. use Psr\Log\LoggerInterface as PsrLogger;
  50. use Magento\Framework\Session\SessionManagerInterface;
  51. use Magento\Framework\Session\SaveHandlerInterface;
  52. use Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory;
  53.  
  54. /**
  55.  * Handle various customer account actions
  56.  *
  57.  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  58.  * @SuppressWarnings(PHPMD.TooManyFields)
  59.  * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
  60.  */
  61. class AccountManagement implements AccountManagementInterface
  62. {
  63.     /**
  64.      * Configuration paths for email templates and identities
  65.      *
  66.      * @deprecated
  67.      */
  68.     const XML_PATH_REGISTER_EMAIL_TEMPLATE = 'customer/create_account/email_template';
  69.  
  70.     /**
  71.      * @deprecated
  72.      */
  73.     const XML_PATH_REGISTER_NO_PASSWORD_EMAIL_TEMPLATE = 'customer/create_account/email_no_password_template';
  74.  
  75.     /**
  76.      * @deprecated
  77.      */
  78.     const XML_PATH_REGISTER_EMAIL_IDENTITY = 'customer/create_account/email_identity';
  79.  
  80.     /**
  81.      * @deprecated
  82.      */
  83.     const XML_PATH_REMIND_EMAIL_TEMPLATE = 'customer/password/remind_email_template';
  84.  
  85.     /**
  86.      * @deprecated
  87.      */
  88.     const XML_PATH_FORGOT_EMAIL_TEMPLATE = 'customer/password/forgot_email_template';
  89.  
  90.     /**
  91.      * @deprecated
  92.      */
  93.     const XML_PATH_FORGOT_EMAIL_IDENTITY = 'customer/password/forgot_email_identity';
  94.  
  95.     const XML_PATH_IS_CONFIRM = 'customer/create_account/confirm';
  96.  
  97.     /**
  98.      * @deprecated
  99.      */
  100.     const XML_PATH_CONFIRM_EMAIL_TEMPLATE = 'customer/create_account/email_confirmation_template';
  101.  
  102.     /**
  103.      * @deprecated
  104.      */
  105.     const XML_PATH_CONFIRMED_EMAIL_TEMPLATE = 'customer/create_account/email_confirmed_template';
  106.  
  107.     /**
  108.      * Constants for the type of new account email to be sent
  109.      *
  110.      * @deprecated
  111.      */
  112.     const NEW_ACCOUNT_EMAIL_REGISTERED = 'registered';
  113.  
  114.     /**
  115.      * Welcome email, when password setting is required
  116.      *
  117.      * @deprecated
  118.      */
  119.     const NEW_ACCOUNT_EMAIL_REGISTERED_NO_PASSWORD = 'registered_no_password';
  120.  
  121.     /**
  122.      * Welcome email, when confirmation is enabled
  123.      *
  124.      * @deprecated
  125.      */
  126.     const NEW_ACCOUNT_EMAIL_CONFIRMATION = 'confirmation';
  127.  
  128.     /**
  129.      * Confirmation email, when account is confirmed
  130.      *
  131.      * @deprecated
  132.      */
  133.     const NEW_ACCOUNT_EMAIL_CONFIRMED = 'confirmed';
  134.  
  135.     /**
  136.      * Constants for types of emails to send out.
  137.      * pdl:
  138.      * forgot, remind, reset email templates
  139.      */
  140.     const EMAIL_REMINDER = 'email_reminder';
  141.  
  142.     const EMAIL_RESET = 'email_reset';
  143.  
  144.     /**
  145.      * Configuration path to customer password minimum length
  146.      */
  147.     const XML_PATH_MINIMUM_PASSWORD_LENGTH = 'customer/password/minimum_password_length';
  148.  
  149.     /**
  150.      * Configuration path to customer password required character classes number
  151.      */
  152.     const XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER = 'customer/password/required_character_classes_number';
  153.  
  154.     /**
  155.      * @deprecated
  156.      */
  157.     const XML_PATH_RESET_PASSWORD_TEMPLATE = 'customer/password/reset_password_template';
  158.  
  159.     /**
  160.      * @deprecated
  161.      */
  162.     const MIN_PASSWORD_LENGTH = 6;
  163.  
  164.     /**
  165.      * @var CustomerFactory
  166.      */
  167.     private $customerFactory;
  168.  
  169.     /**
  170.      * @var \Magento\Customer\Api\Data\ValidationResultsInterfaceFactory
  171.      */
  172.     private $validationResultsDataFactory;
  173.  
  174.     /**
  175.      * @var ManagerInterface
  176.      */
  177.     private $eventManager;
  178.  
  179.     /**
  180.      * @var \Magento\Store\Model\StoreManagerInterface
  181.      */
  182.     private $storeManager;
  183.  
  184.     /**
  185.      * @var Random
  186.      */
  187.     private $mathRandom;
  188.  
  189.     /**
  190.      * @var Validator
  191.      */
  192.     private $validator;
  193.  
  194.     /**
  195.      * @var AddressRepositoryInterface
  196.      */
  197.     private $addressRepository;
  198.  
  199.     /**
  200.      * @var CustomerMetadataInterface
  201.      */
  202.     private $customerMetadataService;
  203.  
  204.     /**
  205.      * @var PsrLogger
  206.      */
  207.     protected $logger;
  208.  
  209.     /**
  210.      * @var Encryptor
  211.      */
  212.     private $encryptor;
  213.  
  214.     /**
  215.      * @var CustomerRegistry
  216.      */
  217.     private $customerRegistry;
  218.  
  219.     /**
  220.      * @var ConfigShare
  221.      */
  222.     private $configShare;
  223.  
  224.     /**
  225.      * @var StringHelper
  226.      */
  227.     protected $stringHelper;
  228.  
  229.     /**
  230.      * @var CustomerRepositoryInterface
  231.      */
  232.     private $customerRepository;
  233.  
  234.     /**
  235.      * @var ScopeConfigInterface
  236.      */
  237.     private $scopeConfig;
  238.  
  239.     /**
  240.      * @var TransportBuilder
  241.      */
  242.     private $transportBuilder;
  243.  
  244.     /**
  245.      * @var SessionManagerInterface
  246.      */
  247.     private $sessionManager;
  248.  
  249.     /**
  250.      * @var SaveHandlerInterface
  251.      */
  252.     private $saveHandler;
  253.  
  254.     /**
  255.      * @var CollectionFactory
  256.      */
  257.     private $visitorCollectionFactory;
  258.  
  259.     /**
  260.      * @var DataObjectProcessor
  261.      */
  262.     protected $dataProcessor;
  263.  
  264.     /**
  265.      * @var \Magento\Framework\Registry
  266.      */
  267.     protected $registry;
  268.  
  269.     /**
  270.      * @var CustomerViewHelper
  271.      */
  272.     protected $customerViewHelper;
  273.  
  274.     /**
  275.      * @var DateTime
  276.      */
  277.     protected $dateTime;
  278.  
  279.     /**
  280.      * @var ObjectFactory
  281.      */
  282.     protected $objectFactory;
  283.  
  284.     /**
  285.      * @var \Magento\Framework\Api\ExtensibleDataObjectConverter
  286.      */
  287.     protected $extensibleDataObjectConverter;
  288.  
  289.     /**
  290.      * @var CustomerModel
  291.      */
  292.     protected $customerModel;
  293.  
  294.     /**
  295.      * @var AuthenticationInterface
  296.      */
  297.     protected $authentication;
  298.  
  299.     /**
  300.      * @var EmailNotificationInterface
  301.      */
  302.     private $emailNotification;
  303.  
  304.     /**
  305.      * @var \Magento\Eav\Model\Validator\Attribute\Backend
  306.      */
  307.     private $eavValidator;
  308.  
  309.     /**
  310.      * @var CredentialsValidator
  311.      */
  312.     private $credentialsValidator;
  313.  
  314.     /**
  315.      * @var DateTimeFactory
  316.      */
  317.     private $dateTimeFactory;
  318.  
  319.     /**
  320.      * @param CustomerFactory $customerFactory
  321.      * @param ManagerInterface $eventManager
  322.      * @param StoreManagerInterface $storeManager
  323.      * @param Random $mathRandom
  324.      * @param Validator $validator
  325.      * @param ValidationResultsInterfaceFactory $validationResultsDataFactory
  326.      * @param AddressRepositoryInterface $addressRepository
  327.      * @param CustomerMetadataInterface $customerMetadataService
  328.      * @param CustomerRegistry $customerRegistry
  329.      * @param PsrLogger $logger
  330.      * @param Encryptor $encryptor
  331.      * @param ConfigShare $configShare
  332.      * @param StringHelper $stringHelper
  333.      * @param CustomerRepositoryInterface $customerRepository
  334.      * @param ScopeConfigInterface $scopeConfig
  335.      * @param TransportBuilder $transportBuilder
  336.      * @param DataObjectProcessor $dataProcessor
  337.      * @param Registry $registry
  338.      * @param CustomerViewHelper $customerViewHelper
  339.      * @param DateTime $dateTime
  340.      * @param CustomerModel $customerModel
  341.      * @param ObjectFactory $objectFactory
  342.      * @param ExtensibleDataObjectConverter $extensibleDataObjectConverter
  343.      * @param CredentialsValidator|null $credentialsValidator
  344.      * @param DateTimeFactory $dateTimeFactory
  345.      * @param SessionManagerInterface|null $sessionManager
  346.      * @param SaveHandlerInterface|null $saveHandler
  347.      * @param CollectionFactory|null $visitorCollectionFactory
  348.      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  349.      */
  350.     public function __construct(
  351.         CustomerFactory $customerFactory,
  352.         ManagerInterface $eventManager,
  353.         StoreManagerInterface $storeManager,
  354.         Random $mathRandom,
  355.         Validator $validator,
  356.         ValidationResultsInterfaceFactory $validationResultsDataFactory,
  357.         AddressRepositoryInterface $addressRepository,
  358.         CustomerMetadataInterface $customerMetadataService,
  359.         CustomerRegistry $customerRegistry,
  360.         PsrLogger $logger,
  361.         Encryptor $encryptor,
  362.         ConfigShare $configShare,
  363.         StringHelper $stringHelper,
  364.         CustomerRepositoryInterface $customerRepository,
  365.         ScopeConfigInterface $scopeConfig,
  366.         TransportBuilder $transportBuilder,
  367.         DataObjectProcessor $dataProcessor,
  368.         Registry $registry,
  369.         CustomerViewHelper $customerViewHelper,
  370.         DateTime $dateTime,
  371.         CustomerModel $customerModel,
  372.         ObjectFactory $objectFactory,
  373.         ExtensibleDataObjectConverter $extensibleDataObjectConverter,
  374.         CredentialsValidator $credentialsValidator = null,
  375.         DateTimeFactory $dateTimeFactory = null,
  376.         SessionManagerInterface $sessionManager = null,
  377.         SaveHandlerInterface $saveHandler = null,
  378.         CollectionFactory $visitorCollectionFactory = null
  379.     ) {
  380.         $this->customerFactory = $customerFactory;
  381.         $this->eventManager = $eventManager;
  382.         $this->storeManager = $storeManager;
  383.         $this->mathRandom = $mathRandom;
  384.         $this->validator = $validator;
  385.         $this->validationResultsDataFactory = $validationResultsDataFactory;
  386.         $this->addressRepository = $addressRepository;
  387.         $this->customerMetadataService = $customerMetadataService;
  388.         $this->customerRegistry = $customerRegistry;
  389.         $this->logger = $logger;
  390.         $this->encryptor = $encryptor;
  391.         $this->configShare = $configShare;
  392.         $this->stringHelper = $stringHelper;
  393.         $this->customerRepository = $customerRepository;
  394.         $this->scopeConfig = $scopeConfig;
  395.         $this->transportBuilder = $transportBuilder;
  396.         $this->dataProcessor = $dataProcessor;
  397.         $this->registry = $registry;
  398.         $this->customerViewHelper = $customerViewHelper;
  399.         $this->dateTime = $dateTime;
  400.         $this->customerModel = $customerModel;
  401.         $this->objectFactory = $objectFactory;
  402.         $this->extensibleDataObjectConverter = $extensibleDataObjectConverter;
  403.         $this->credentialsValidator =
  404.             $credentialsValidator ?: ObjectManager::getInstance()->get(CredentialsValidator::class);
  405.         $this->dateTimeFactory = $dateTimeFactory ?: ObjectManager::getInstance()->get(DateTimeFactory::class);
  406.         $this->sessionManager = $sessionManager
  407.             ?: ObjectManager::getInstance()->get(SessionManagerInterface::class);
  408.         $this->saveHandler = $saveHandler
  409.             ?: ObjectManager::getInstance()->get(SaveHandlerInterface::class);
  410.         $this->visitorCollectionFactory = $visitorCollectionFactory
  411.             ?: ObjectManager::getInstance()->get(CollectionFactory::class);
  412.     }
  413.  
  414.     /**
  415.      * Get authentication
  416.      *
  417.      * @return AuthenticationInterface
  418.      */
  419.     private function getAuthentication()
  420.     {
  421.         if (!($this->authentication instanceof AuthenticationInterface)) {
  422.             return \Magento\Framework\App\ObjectManager::getInstance()->get(
  423.                 \Magento\Customer\Model\AuthenticationInterface::class
  424.             );
  425.         } else {
  426.             return $this->authentication;
  427.         }
  428.     }
  429.  
  430.     /**
  431.      * {@inheritdoc}
  432.      */
  433.     public function resendConfirmation($email, $websiteId = null, $redirectUrl = '')
  434.     {
  435.         $customer = $this->customerRepository->get($email, $websiteId);
  436.         if (!$customer->getConfirmation()) {
  437.             throw new InvalidTransitionException(__('No confirmation needed.'));
  438.         }
  439.  
  440.         try {
  441.             $this->getEmailNotification()->newAccount(
  442.                 $customer,
  443.                 self::NEW_ACCOUNT_EMAIL_CONFIRMATION,
  444.                 $redirectUrl,
  445.                 $this->storeManager->getStore()->getId()
  446.             );
  447.         } catch (MailException $e) {
  448.             // If we are not able to send a new account email, this should be ignored
  449.             $this->logger->critical($e);
  450.         }
  451.     }
  452.  
  453.     /**
  454.      * {@inheritdoc}
  455.      */
  456.     public function activate($email, $confirmationKey)
  457.     {
  458.         $customer = $this->customerRepository->get($email);
  459.         return $this->activateCustomer($customer, $confirmationKey);
  460.     }
  461.  
  462.     /**
  463.      * {@inheritdoc}
  464.      */
  465.     public function activateById($customerId, $confirmationKey)
  466.     {
  467.         $customer = $this->customerRepository->getById($customerId);
  468.         return $this->activateCustomer($customer, $confirmationKey);
  469.     }
  470.  
  471.     /**
  472.      * Activate a customer account using a key that was sent in a confirmation email.
  473.      *
  474.      * @param \Magento\Customer\Api\Data\CustomerInterface $customer
  475.      * @param string $confirmationKey
  476.      * @return \Magento\Customer\Api\Data\CustomerInterface
  477.      * @throws \Magento\Framework\Exception\State\InvalidTransitionException
  478.      * @throws \Magento\Framework\Exception\State\InputMismatchException
  479.      */
  480.     private function activateCustomer($customer, $confirmationKey)
  481.     {
  482.         // check if customer is inactive
  483.         if (!$customer->getConfirmation()) {
  484.             throw new InvalidTransitionException(__('Account already active'));
  485.         }
  486.  
  487.         if ($customer->getConfirmation() !== $confirmationKey) {
  488.             throw new InputMismatchException(__('Invalid confirmation token'));
  489.         }
  490.  
  491.         $customer->setConfirmation(null);
  492.         $this->customerRepository->save($customer);
  493.         $this->getEmailNotification()->newAccount($customer, 'confirmed', '', $this->storeManager->getStore()->getId());
  494.         return $customer;
  495.     }
  496.  
  497.     /**
  498.      * {@inheritdoc}
  499.      */
  500.     public function authenticate($username, $password)
  501.     {
  502.         try {
  503.             $customer = $this->customerRepository->get($username);
  504.         } catch (NoSuchEntityException $e) {
  505.             throw new InvalidEmailOrPasswordException(__('Invalid login or password.'));
  506.         }
  507.  
  508.         $customerId = $customer->getId();
  509.         if ($this->getAuthentication()->isLocked($customerId)) {
  510.             throw new UserLockedException(__('The account is locked.'));
  511.         }
  512.         try {
  513.             $this->getAuthentication()->authenticate($customerId, $password);
  514.         } catch (InvalidEmailOrPasswordException $e) {
  515.             throw new InvalidEmailOrPasswordException(__('Invalid login or password.'));
  516.         }
  517.         if ($customer->getConfirmation() && $this->isConfirmationRequired($customer)) {
  518.             throw new EmailNotConfirmedException(__('This account is not confirmed.'));
  519.         }
  520.  
  521.         $customerModel = $this->customerFactory->create()->updateData($customer);
  522.         $this->eventManager->dispatch(
  523.             'customer_customer_authenticated',
  524.             ['model' => $customerModel, 'password' => $password]
  525.         );
  526.  
  527.         $this->eventManager->dispatch('customer_data_object_login', ['customer' => $customer]);
  528.  
  529.         return $customer;
  530.     }
  531.  
  532.     /**
  533.      * {@inheritdoc}
  534.      */
  535.     public function validateResetPasswordLinkToken($customerId, $resetPasswordLinkToken)
  536.     {
  537.         $this->validateResetPasswordToken($customerId, $resetPasswordLinkToken);
  538.         return true;
  539.     }
  540.  
  541.     /**
  542.      * {@inheritdoc}
  543.      */
  544.     public function initiatePasswordReset($email, $template, $websiteId = null)
  545.     {
  546.         if ($websiteId === null) {
  547.             $websiteId = $this->storeManager->getStore()->getWebsiteId();
  548.         }
  549.         // load customer by email
  550.         $customer = $this->customerRepository->get($email, $websiteId);
  551.  
  552.         $newPasswordToken = $this->mathRandom->getUniqueHash();
  553.         $this->changeResetPasswordLinkToken($customer, $newPasswordToken);
  554.  
  555.         try {
  556.             switch ($template) {
  557.                 case AccountManagement::EMAIL_REMINDER:
  558.                     $this->getEmailNotification()->passwordReminder($customer);
  559.                     break;
  560.                 case AccountManagement::EMAIL_RESET:
  561.                     $this->getEmailNotification()->passwordResetConfirmation($customer);
  562.                     break;
  563.                 default:
  564.                     throw new InputException(__(
  565.                         'Invalid value of "%value" provided for the %fieldName field. '.
  566.                         'Possible values: %template1 or %template2.',
  567.                         [
  568.                             'value' => $template,
  569.                             'fieldName' => 'template',
  570.                             'template1' => AccountManagement::EMAIL_REMINDER,
  571.                             'template2' => AccountManagement::EMAIL_RESET
  572.                         ]
  573.                     ));
  574.             }
  575.  
  576.             return true;
  577.         } catch (MailException $e) {
  578.             // If we are not able to send a reset password email, this should be ignored
  579.             $this->logger->critical($e);
  580.         }
  581.  
  582.         return false;
  583.     }
  584.  
  585.     /**
  586.      * {@inheritdoc}
  587.      */
  588.     public function resetPassword($email, $resetToken, $newPassword)
  589.     {
  590.         $customer = $this->customerRepository->get($email);
  591.         //Validate Token and new password strength
  592.         $this->validateResetPasswordToken($customer->getId(), $resetToken);
  593.         $this->checkPasswordStrength($newPassword);
  594.         //Update secure data
  595.         $customerSecure = $this->customerRegistry->retrieveSecureData($customer->getId());
  596.         $customerSecure->setRpToken(null);
  597.         $customerSecure->setRpTokenCreatedAt(null);
  598.         $customerSecure->setPasswordHash($this->createPasswordHash($newPassword));
  599.         $this->sessionManager->destroy();
  600.         $this->destroyCustomerSessions($customer->getId());
  601.         $this->customerRepository->save($customer);
  602.  
  603.         return true;
  604.     }
  605.  
  606.     /**
  607.      * Make sure that password complies with minimum security requirements.
  608.      *
  609.      * @param string $password
  610.      * @return void
  611.      * @throws InputException
  612.      */
  613.     protected function checkPasswordStrength($password)
  614.     {
  615.         $length = $this->stringHelper->strlen($password);
  616.         if ($length > self::MAX_PASSWORD_LENGTH) {
  617.             throw new InputException(
  618.                 __(
  619.                     'Please enter a password with at most %1 characters.',
  620.                     self::MAX_PASSWORD_LENGTH
  621.                 )
  622.             );
  623.         }
  624.         $configMinPasswordLength = $this->getMinPasswordLength();
  625.         if ($length < $configMinPasswordLength) {
  626.             throw new InputException(
  627.                 __(
  628.                     'Please enter a password with at least %1 characters.',
  629.                     $configMinPasswordLength
  630.                 )
  631.             );
  632.         }
  633.         if ($this->stringHelper->strlen(trim($password)) != $length) {
  634.             throw new InputException(__('The password can\'t begin or end with a space.'));
  635.         }
  636.  
  637.         $requiredCharactersCheck = $this->makeRequiredCharactersCheck($password);
  638.         if ($requiredCharactersCheck !== 0) {
  639.             throw new InputException(
  640.                 __(
  641.                     'Minimum of different classes of characters in password is %1.' .
  642.                     ' Classes of characters: Lower Case, Upper Case, Digits, Special Characters.',
  643.                     $requiredCharactersCheck
  644.                 )
  645.             );
  646.         }
  647.     }
  648.  
  649.     /**
  650.      * Check password for presence of required character sets
  651.      *
  652.      * @param string $password
  653.      * @return int
  654.      */
  655.     protected function makeRequiredCharactersCheck($password)
  656.     {
  657.         $counter = 0;
  658.         $requiredNumber = $this->scopeConfig->getValue(self::XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER);
  659.         $return = 0;
  660.  
  661.         if (preg_match('/[0-9]+/', $password)) {
  662.             $counter++;
  663.         }
  664.         if (preg_match('/[A-Z]+/', $password)) {
  665.             $counter++;
  666.         }
  667.         if (preg_match('/[a-z]+/', $password)) {
  668.             $counter++;
  669.         }
  670.         if (preg_match('/[^a-zA-Z0-9]+/', $password)) {
  671.             $counter++;
  672.         }
  673.  
  674.         if ($counter < $requiredNumber) {
  675.             $return = $requiredNumber;
  676.         }
  677.  
  678.         return $return;
  679.     }
  680.  
  681.     /**
  682.      * Retrieve minimum password length
  683.      *
  684.      * @return int
  685.      */
  686.     protected function getMinPasswordLength()
  687.     {
  688.         return $this->scopeConfig->getValue(self::XML_PATH_MINIMUM_PASSWORD_LENGTH);
  689.     }
  690.  
  691.     /**
  692.      * {@inheritdoc}
  693.      */
  694.     public function getConfirmationStatus($customerId)
  695.     {
  696.         // load customer by id
  697.         $customer = $this->customerRepository->getById($customerId);
  698.         if ($this->isConfirmationRequired($customer)) {
  699.             if (!$customer->getConfirmation()) {
  700.                 return self::ACCOUNT_CONFIRMED;
  701.             }
  702.             return self::ACCOUNT_CONFIRMATION_REQUIRED;
  703.         }
  704.         return self::ACCOUNT_CONFIRMATION_NOT_REQUIRED;
  705.     }
  706.  
  707.     /**
  708.      * {@inheritdoc}
  709.      */
  710.     public function createAccount(CustomerInterface $customer, $password = null, $redirectUrl = '')
  711.     {
  712.         if ($password !== null) {
  713.             $this->checkPasswordStrength($password);
  714.             $customerEmail = $customer->getEmail();
  715.             try {
  716.                 $this->credentialsValidator->checkPasswordDifferentFromEmail($customerEmail, $password);
  717.             } catch (InputException $e) {
  718.                 throw new LocalizedException(__('Password cannot be the same as email address.'));
  719.             }
  720.             $hash = $this->createPasswordHash($password);
  721.         } else {
  722.             $hash = null;
  723.         }
  724.         return $this->createAccountWithPasswordHash($customer, $hash, $redirectUrl);
  725.     }
  726.  
  727.     /**
  728.      * {@inheritdoc}
  729.      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  730.      * @SuppressWarnings(PHPMD.NPathComplexity)
  731.      */
  732.     public function createAccountWithPasswordHash(CustomerInterface $customer, $hash, $redirectUrl = '')
  733.     {
  734.         // This logic allows an existing customer to be added to a different store.  No new account is created.
  735.         // The plan is to move this logic into a new method called something like 'registerAccountWithStore'
  736.         if ($customer->getId()) {
  737.             $customer = $this->customerRepository->get($customer->getEmail());
  738.             $websiteId = $customer->getWebsiteId();
  739.  
  740.             if ($this->isCustomerInStore($websiteId, $customer->getStoreId())) {
  741.                 throw new InputException(__('This customer already exists in this store.'));
  742.             }
  743.             // Existing password hash will be used from secured customer data registry when saving customer
  744.         }
  745.  
  746.         // Make sure we have a storeId to associate this customer with.
  747.         if (!$customer->getStoreId()) {
  748.             if ($customer->getWebsiteId()) {
  749.                 $storeId = $this->storeManager->getWebsite($customer->getWebsiteId())->getDefaultStore()->getId();
  750.             } else {
  751.                 $storeId = $this->storeManager->getStore()->getId();
  752.             }
  753.             $customer->setStoreId($storeId);
  754.         }
  755.  
  756.         // Associate website_id with customer
  757.         if (!$customer->getWebsiteId()) {
  758.             $websiteId = $this->storeManager->getStore($customer->getStoreId())->getWebsiteId();
  759.             $customer->setWebsiteId($websiteId);
  760.         }
  761.  
  762.         // Update 'created_in' value with actual store name
  763.         if ($customer->getId() === null) {
  764.             $storeName = $this->storeManager->getStore($customer->getStoreId())->getName();
  765.             $customer->setCreatedIn($storeName);
  766.         }
  767.  
  768.         $customerAddresses = $customer->getAddresses() ?: [];
  769.         $customer->setAddresses(null);
  770.         try {
  771.             // If customer exists existing hash will be used by Repository
  772.             $customer = $this->customerRepository->save($customer, $hash);
  773.         } catch (AlreadyExistsException $e) {
  774.             throw new InputMismatchException(
  775.                 __('A customer with the same email already exists in an associated website.')
  776.             );
  777.         } catch (LocalizedException $e) {
  778.             throw $e;
  779.         }
  780.         try {
  781.             foreach ($customerAddresses as $address) {
  782.                 if ($address->getId()) {
  783.                     $newAddress = clone $address;
  784.                     $newAddress->setId(null);
  785.                     $newAddress->setCustomerId($customer->getId());
  786.                     $this->addressRepository->save($newAddress);
  787.                 } else {
  788.                     $address->setCustomerId($customer->getId());
  789.                     $this->addressRepository->save($address);
  790.                 }
  791.             }
  792.             $this->customerRegistry->remove($customer->getId());
  793.         } catch (InputException $e) {
  794.             $this->customerRepository->delete($customer);
  795.             throw $e;
  796.         }
  797.         $customer = $this->customerRepository->getById($customer->getId());
  798.         $newLinkToken = $this->mathRandom->getUniqueHash();
  799.         $this->changeResetPasswordLinkToken($customer, $newLinkToken);
  800.         $this->sendEmailConfirmation($customer, $redirectUrl);
  801.  
  802.         return $customer;
  803.     }
  804.  
  805.     /**
  806.      * {@inheritdoc}
  807.      */
  808.     public function getDefaultBillingAddress($customerId)
  809.     {
  810.         $customer = $this->customerRepository->getById($customerId);
  811.         return $this->getAddressById($customer, $customer->getDefaultBilling());
  812.     }
  813.  
  814.     /**
  815.      * {@inheritdoc}
  816.      */
  817.     public function getDefaultShippingAddress($customerId)
  818.     {
  819.         $customer = $this->customerRepository->getById($customerId);
  820.         return $this->getAddressById($customer, $customer->getDefaultShipping());
  821.     }
  822.  
  823.     /**
  824.      * Send either confirmation or welcome email after an account creation
  825.      *
  826.      * @param CustomerInterface $customer
  827.      * @param string $redirectUrl
  828.      * @return void
  829.      */
  830.     protected function sendEmailConfirmation(CustomerInterface $customer, $redirectUrl)
  831.     {
  832.         try {
  833.             $hash = $this->customerRegistry->retrieveSecureData($customer->getId())->getPasswordHash();
  834.             $templateType = self::NEW_ACCOUNT_EMAIL_REGISTERED;
  835.             if ($this->isConfirmationRequired($customer) && $hash != '') {
  836.                 $templateType = self::NEW_ACCOUNT_EMAIL_CONFIRMATION;
  837.             } elseif ($hash == '') {
  838.                 $templateType = self::NEW_ACCOUNT_EMAIL_REGISTERED_NO_PASSWORD;
  839.             }
  840.             $this->getEmailNotification()->newAccount($customer, $templateType, $redirectUrl, $customer->getStoreId());
  841.         } catch (MailException $e) {
  842.             // If we are not able to send a new account email, this should be ignored
  843.             $this->logger->critical($e);
  844.         }
  845.     }
  846.  
  847.     /**
  848.      * {@inheritdoc}
  849.      */
  850.     public function changePassword($email, $currentPassword, $newPassword)
  851.     {
  852.         try {
  853.             $customer = $this->customerRepository->get($email);
  854.         } catch (NoSuchEntityException $e) {
  855.             throw new InvalidEmailOrPasswordException(__('Invalid login or password.'));
  856.         }
  857.         return $this->changePasswordForCustomer($customer, $currentPassword, $newPassword);
  858.     }
  859.  
  860.     /**
  861.      * {@inheritdoc}
  862.      */
  863.     public function changePasswordById($customerId, $currentPassword, $newPassword)
  864.     {
  865.         try {
  866.             $customer = $this->customerRepository->getById($customerId);
  867.         } catch (NoSuchEntityException $e) {
  868.             throw new InvalidEmailOrPasswordException(__('Invalid login or password.'));
  869.         }
  870.         return $this->changePasswordForCustomer($customer, $currentPassword, $newPassword);
  871.     }
  872.  
  873.     /**
  874.      * Change customer password
  875.      *
  876.      * @param CustomerInterface $customer
  877.      * @param string $currentPassword
  878.      * @param string $newPassword
  879.      * @return bool true on success
  880.      * @throws InputException
  881.      * @throws InvalidEmailOrPasswordException
  882.      * @throws UserLockedException
  883.      */
  884.     private function changePasswordForCustomer($customer, $currentPassword, $newPassword)
  885.     {
  886.         try {
  887.             $this->getAuthentication()->authenticate($customer->getId(), $currentPassword);
  888.         } catch (InvalidEmailOrPasswordException $e) {
  889.             throw new InvalidEmailOrPasswordException(__('The password doesn\'t match this account.'));
  890.         }
  891.         $customerEmail = $customer->getEmail();
  892.         $this->credentialsValidator->checkPasswordDifferentFromEmail($customerEmail, $newPassword);
  893.         $customerSecure = $this->customerRegistry->retrieveSecureData($customer->getId());
  894.         $customerSecure->setRpToken(null);
  895.         $customerSecure->setRpTokenCreatedAt(null);
  896.         $this->checkPasswordStrength($newPassword);
  897.         $customerSecure->setPasswordHash($this->createPasswordHash($newPassword));
  898.         $this->destroyCustomerSessions($customer->getId());
  899.         $this->customerRepository->save($customer);
  900.  
  901.         return true;
  902.     }
  903.  
  904.     /**
  905.      * Create a hash for the given password
  906.      *
  907.      * @param string $password
  908.      * @return string
  909.      */
  910.     protected function createPasswordHash($password)
  911.     {
  912.         return $this->encryptor->getHash($password, true);
  913.     }
  914.  
  915.     /**
  916.      * @return Backend
  917.      */
  918.     private function getEavValidator()
  919.     {
  920.         if ($this->eavValidator === null) {
  921.             $this->eavValidator = ObjectManager::getInstance()->get(Backend::class);
  922.         }
  923.         return $this->eavValidator;
  924.     }
  925.  
  926.     /**
  927.      * {@inheritdoc}
  928.      */
  929.     public function validate(CustomerInterface $customer)
  930.     {
  931.         $validationResults = $this->validationResultsDataFactory->create();
  932.  
  933.         $oldAddresses = $customer->getAddresses();
  934.         $customerModel = $this->customerFactory->create()->updateData(
  935.             $customer->setAddresses([])
  936.         );
  937.         $customer->setAddresses($oldAddresses);
  938.  
  939.         $result = $this->getEavValidator()->isValid($customerModel);
  940.         if ($result === false && is_array($this->getEavValidator()->getMessages())) {
  941.             return $validationResults->setIsValid(false)->setMessages(
  942.                 call_user_func_array(
  943.                     'array_merge',
  944.                     $this->getEavValidator()->getMessages()
  945.                 )
  946.             );
  947.         }
  948.         return $validationResults->setIsValid(true)->setMessages([]);
  949.     }
  950.  
  951.     /**
  952.      * {@inheritdoc}
  953.      */
  954.     public function isEmailAvailable($customerEmail, $websiteId = null)
  955.     {
  956.         try {
  957.             if ($websiteId === null) {
  958.                 $websiteId = $this->storeManager->getStore()->getWebsiteId();
  959.             }
  960.             $this->customerRepository->get($customerEmail, $websiteId);
  961.             return false;
  962.         } catch (NoSuchEntityException $e) {
  963.             return true;
  964.         }
  965.     }
  966.  
  967.     /**
  968.      * {@inheritDoc}
  969.      */
  970.     public function isCustomerInStore($customerWebsiteId, $storeId)
  971.     {
  972.         $ids = [];
  973.         if ((bool)$this->configShare->isWebsiteScope()) {
  974.             $ids = $this->storeManager->getWebsite($customerWebsiteId)->getStoreIds();
  975.         } else {
  976.             foreach ($this->storeManager->getStores() as $store) {
  977.                 $ids[] = $store->getId();
  978.             }
  979.         }
  980.  
  981.         return in_array($storeId, $ids);
  982.     }
  983.  
  984.     /**
  985.      * Validate the Reset Password Token for a customer.
  986.      *
  987.      * @param int $customerId
  988.      * @param string $resetPasswordLinkToken
  989.      * @return bool
  990.      * @throws \Magento\Framework\Exception\State\InputMismatchException If token is mismatched
  991.      * @throws \Magento\Framework\Exception\State\ExpiredException If token is expired
  992.      * @throws \Magento\Framework\Exception\InputException If token or customer id is invalid
  993.      * @throws \Magento\Framework\Exception\NoSuchEntityException If customer doesn't exist
  994.      */
  995.     private function validateResetPasswordToken($customerId, $resetPasswordLinkToken)
  996.     {
  997.         if (empty($customerId) || $customerId < 0) {
  998.             throw new InputException(
  999.                 __(
  1000.                     'Invalid value of "%value" provided for the %fieldName field.',
  1001.                     ['value' => $customerId, 'fieldName' => 'customerId']
  1002.                 )
  1003.             );
  1004.         }
  1005.         if (!is_string($resetPasswordLinkToken) || empty($resetPasswordLinkToken)) {
  1006.             $params = ['fieldName' => 'resetPasswordLinkToken'];
  1007.             throw new InputException(__('%fieldName is a required field.', $params));
  1008.         }
  1009.  
  1010.         $customerSecureData = $this->customerRegistry->retrieveSecureData($customerId);
  1011.         $rpToken = $customerSecureData->getRpToken();
  1012.         $rpTokenCreatedAt = $customerSecureData->getRpTokenCreatedAt();
  1013.  
  1014.         if (!Security::compareStrings($rpToken, $resetPasswordLinkToken)) {
  1015.             throw new InputMismatchException(__('Reset password token mismatch.'));
  1016.         } elseif ($this->isResetPasswordLinkTokenExpired($rpToken, $rpTokenCreatedAt)) {
  1017.             throw new ExpiredException(__('Reset password token expired.'));
  1018.         }
  1019.  
  1020.         return true;
  1021.     }
  1022.  
  1023.     /**
  1024.      * Check if customer can be deleted.
  1025.      *
  1026.      * @param int $customerId
  1027.      * @return bool
  1028.      * @throws \Magento\Framework\Exception\NoSuchEntityException If group is not found
  1029.      * @throws LocalizedException
  1030.      */
  1031.     public function isReadonly($customerId)
  1032.     {
  1033.         $customer = $this->customerRegistry->retrieveSecureData($customerId);
  1034.         return !$customer->getDeleteable();
  1035.     }
  1036.  
  1037.     /**
  1038.      * Send email with new account related information
  1039.      *
  1040.      * @param CustomerInterface $customer
  1041.      * @param string $type
  1042.      * @param string $backUrl
  1043.      * @param string $storeId
  1044.      * @param string $sendemailStoreId
  1045.      * @return $this
  1046.      * @throws LocalizedException
  1047.      * @deprecated 100.1.0
  1048.      */
  1049.     protected function sendNewAccountEmail(
  1050.         $customer,
  1051.         $type = self::NEW_ACCOUNT_EMAIL_REGISTERED,
  1052.         $backUrl = '',
  1053.         $storeId = '0',
  1054.         $sendemailStoreId = null
  1055.     ) {
  1056.         $types = $this->getTemplateTypes();
  1057.  
  1058.         if (!isset($types[$type])) {
  1059.             throw new LocalizedException(__('Please correct the transactional account email type.'));
  1060.         }
  1061.  
  1062.         if (!$storeId) {
  1063.             $storeId = $this->getWebsiteStoreId($customer, $sendemailStoreId);
  1064.         }
  1065.  
  1066.         $store = $this->storeManager->getStore($customer->getStoreId());
  1067.  
  1068.         $customerEmailData = $this->getFullCustomerObject($customer);
  1069.  
  1070.         $this->sendEmailTemplate(
  1071.             $customer,
  1072.             $types[$type],
  1073.             self::XML_PATH_REGISTER_EMAIL_IDENTITY,
  1074.             ['customer' => $customerEmailData, 'back_url' => $backUrl, 'store' => $store],
  1075.             $storeId
  1076.         );
  1077.  
  1078.         return $this;
  1079.     }
  1080.  
  1081.     /**
  1082.      * Send email to customer when his password is reset
  1083.      *
  1084.      * @param CustomerInterface $customer
  1085.      * @return $this
  1086.      * @deprecated 100.1.0
  1087.      */
  1088.     protected function sendPasswordResetNotificationEmail($customer)
  1089.     {
  1090.         return $this->sendPasswordResetConfirmationEmail($customer);
  1091.     }
  1092.  
  1093.     /**
  1094.      * Get either first store ID from a set website or the provided as default
  1095.      *
  1096.      * @param CustomerInterface $customer
  1097.      * @param int|string|null $defaultStoreId
  1098.      * @return int
  1099.      * @deprecated 100.1.0
  1100.      */
  1101.     protected function getWebsiteStoreId($customer, $defaultStoreId = null)
  1102.     {
  1103.         if ($customer->getWebsiteId() != 0 && empty($defaultStoreId)) {
  1104.             $storeIds = $this->storeManager->getWebsite($customer->getWebsiteId())->getStoreIds();
  1105.             reset($storeIds);
  1106.             $defaultStoreId = current($storeIds);
  1107.         }
  1108.         return $defaultStoreId;
  1109.     }
  1110.  
  1111.     /**
  1112.      * @return array
  1113.      * @deprecated 100.1.0
  1114.      */
  1115.     protected function getTemplateTypes()
  1116.     {
  1117.         /**
  1118.          * self::NEW_ACCOUNT_EMAIL_REGISTERED               welcome email, when confirmation is disabled
  1119.          *                                                  and password is set
  1120.          * self::NEW_ACCOUNT_EMAIL_REGISTERED_NO_PASSWORD   welcome email, when confirmation is disabled
  1121.          *                                                  and password is not set
  1122.          * self::NEW_ACCOUNT_EMAIL_CONFIRMED                welcome email, when confirmation is enabled
  1123.          *                                                  and password is set
  1124.          * self::NEW_ACCOUNT_EMAIL_CONFIRMATION             email with confirmation link
  1125.          */
  1126.         $types = [
  1127.             self::NEW_ACCOUNT_EMAIL_REGISTERED             => self::XML_PATH_REGISTER_EMAIL_TEMPLATE,
  1128.             self::NEW_ACCOUNT_EMAIL_REGISTERED_NO_PASSWORD => self::XML_PATH_REGISTER_NO_PASSWORD_EMAIL_TEMPLATE,
  1129.             self::NEW_ACCOUNT_EMAIL_CONFIRMED              => self::XML_PATH_CONFIRMED_EMAIL_TEMPLATE,
  1130.             self::NEW_ACCOUNT_EMAIL_CONFIRMATION           => self::XML_PATH_CONFIRM_EMAIL_TEMPLATE,
  1131.         ];
  1132.         return $types;
  1133.     }
  1134.  
  1135.     /**
  1136.      * Send corresponding email template
  1137.      *
  1138.      * @param CustomerInterface $customer
  1139.      * @param string $template configuration path of email template
  1140.      * @param string $sender configuration path of email identity
  1141.      * @param array $templateParams
  1142.      * @param int|null $storeId
  1143.      * @param string $email
  1144.      * @return $this
  1145.      * @deprecated 100.1.0
  1146.      */
  1147.     protected function sendEmailTemplate(
  1148.         $customer,
  1149.         $template,
  1150.         $sender,
  1151.         $templateParams = [],
  1152.         $storeId = null,
  1153.         $email = null
  1154.     ) {
  1155.         $templateId = $this->scopeConfig->getValue($template, ScopeInterface::SCOPE_STORE, $storeId);
  1156.         if ($email === null) {
  1157.             $email = $customer->getEmail();
  1158.         }
  1159.  
  1160.         $transport = $this->transportBuilder->setTemplateIdentifier($templateId)->setTemplateOptions(
  1161.             ['area' => Area::AREA_FRONTEND, 'store' => $storeId]
  1162.         )->setTemplateVars($templateParams)->setFrom(
  1163.             $this->scopeConfig->getValue($sender, ScopeInterface::SCOPE_STORE, $storeId)
  1164.         )->addTo($email, $this->customerViewHelper->getCustomerName($customer))->getTransport();
  1165.  
  1166.         $transport->sendMessage();
  1167.  
  1168.         return $this;
  1169.     }
  1170.  
  1171.     /**
  1172.      * Check if accounts confirmation is required in config
  1173.      *
  1174.      * @param CustomerInterface $customer
  1175.      * @return bool
  1176.      */
  1177.     protected function isConfirmationRequired($customer)
  1178.     {
  1179.         if ($this->canSkipConfirmation($customer)) {
  1180.             return false;
  1181.         }
  1182.  
  1183.         return (bool)$this->scopeConfig->getValue(
  1184.             self::XML_PATH_IS_CONFIRM,
  1185.             ScopeInterface::SCOPE_WEBSITES,
  1186.             $customer->getWebsiteId()
  1187.         );
  1188.     }
  1189.  
  1190.     /**
  1191.      * Check whether confirmation may be skipped when registering using certain email address
  1192.      *
  1193.      * @param CustomerInterface $customer
  1194.      * @return bool
  1195.      */
  1196.     protected function canSkipConfirmation($customer)
  1197.     {
  1198.         if (!$customer->getId()) {
  1199.             return false;
  1200.         }
  1201.  
  1202.         /* If an email was used to start the registration process and it is the same email as the one
  1203.            used to register, then this can skip confirmation.
  1204.            */
  1205.         $skipConfirmationIfEmail = $this->registry->registry("skip_confirmation_if_email");
  1206.         if (!$skipConfirmationIfEmail) {
  1207.             return false;
  1208.         }
  1209.  
  1210.         return strtolower($skipConfirmationIfEmail) === strtolower($customer->getEmail());
  1211.     }
  1212.  
  1213.     /**
  1214.      * Check if rpToken is expired
  1215.      *
  1216.      * @param string $rpToken
  1217.      * @param string $rpTokenCreatedAt
  1218.      * @return bool
  1219.      */
  1220.     public function isResetPasswordLinkTokenExpired($rpToken, $rpTokenCreatedAt)
  1221.     {
  1222.         if (empty($rpToken) || empty($rpTokenCreatedAt)) {
  1223.             return true;
  1224.         }
  1225.  
  1226.         $expirationPeriod = $this->customerModel->getResetPasswordLinkExpirationPeriod();
  1227.  
  1228.         $currentTimestamp = $this->dateTimeFactory->create()->getTimestamp();
  1229.         $tokenTimestamp = $this->dateTimeFactory->create($rpTokenCreatedAt)->getTimestamp();
  1230.         if ($tokenTimestamp > $currentTimestamp) {
  1231.             return true;
  1232.         }
  1233.  
  1234.         $hourDifference = floor(($currentTimestamp - $tokenTimestamp) / (60 * 60));
  1235.         if ($hourDifference >= $expirationPeriod) {
  1236.             return true;
  1237.         }
  1238.  
  1239.         return false;
  1240.     }
  1241.  
  1242.     /**
  1243.      * Change reset password link token
  1244.      *
  1245.      * Stores new reset password link token
  1246.      *
  1247.      * @param CustomerInterface $customer
  1248.      * @param string $passwordLinkToken
  1249.      * @return bool
  1250.      * @throws InputException
  1251.      */
  1252.     public function changeResetPasswordLinkToken($customer, $passwordLinkToken)
  1253.     {
  1254.         if (!is_string($passwordLinkToken) || empty($passwordLinkToken)) {
  1255.             throw new InputException(
  1256.                 __(
  1257.                     'Invalid value of "%value" provided for the %fieldName field.',
  1258.                     ['value' => $passwordLinkToken, 'fieldName' => 'password reset token']
  1259.                 )
  1260.             );
  1261.         }
  1262.         if (is_string($passwordLinkToken) && !empty($passwordLinkToken)) {
  1263.             $customerSecure = $this->customerRegistry->retrieveSecureData($customer->getId());
  1264.             $customerSecure->setRpToken($passwordLinkToken);
  1265.             $customerSecure->setRpTokenCreatedAt(
  1266.                 $this->dateTimeFactory->create()->format(DateTime::DATETIME_PHP_FORMAT)
  1267.             );
  1268.             $this->customerRepository->save($customer);
  1269.         }
  1270.         return true;
  1271.     }
  1272.  
  1273.     /**
  1274.      * Send email with new customer password
  1275.      *
  1276.      * @param CustomerInterface $customer
  1277.      * @return $this
  1278.      * @deprecated 100.1.0
  1279.      */
  1280.     public function sendPasswordReminderEmail($customer)
  1281.     {
  1282.         $storeId = $this->storeManager->getStore()->getId();
  1283.         if (!$storeId) {
  1284.             $storeId = $this->getWebsiteStoreId($customer);
  1285.         }
  1286.  
  1287.         $customerEmailData = $this->getFullCustomerObject($customer);
  1288.  
  1289.         $this->sendEmailTemplate(
  1290.             $customer,
  1291.             self::XML_PATH_REMIND_EMAIL_TEMPLATE,
  1292.             self::XML_PATH_FORGOT_EMAIL_IDENTITY,
  1293.             ['customer' => $customerEmailData, 'store' => $this->storeManager->getStore($storeId)],
  1294.             $storeId
  1295.         );
  1296.  
  1297.         return $this;
  1298.     }
  1299.  
  1300.     /**
  1301.      * Send email with reset password confirmation link
  1302.      *
  1303.      * @param CustomerInterface $customer
  1304.      * @return $this
  1305.      * @deprecated 100.1.0
  1306.      */
  1307.     public function sendPasswordResetConfirmationEmail($customer)
  1308.     {
  1309.         $storeId = $this->storeManager->getStore()->getId();
  1310.         if (!$storeId) {
  1311.             $storeId = $this->getWebsiteStoreId($customer);
  1312.         }
  1313.  
  1314.         $customerEmailData = $this->getFullCustomerObject($customer);
  1315.  
  1316.         $this->sendEmailTemplate(
  1317.             $customer,
  1318.             self::XML_PATH_FORGOT_EMAIL_TEMPLATE,
  1319.             self::XML_PATH_FORGOT_EMAIL_IDENTITY,
  1320.             ['customer' => $customerEmailData, 'store' => $this->storeManager->getStore($storeId)],
  1321.             $storeId
  1322.         );
  1323.  
  1324.         return $this;
  1325.     }
  1326.  
  1327.     /**
  1328.      * Get address by id
  1329.      *
  1330.      * @param CustomerInterface $customer
  1331.      * @param int $addressId
  1332.      * @return AddressInterface|null
  1333.      */
  1334.     protected function getAddressById(CustomerInterface $customer, $addressId)
  1335.     {
  1336.         foreach ($customer->getAddresses() as $address) {
  1337.             if ($address->getId() == $addressId) {
  1338.                 return $address;
  1339.             }
  1340.         }
  1341.         return null;
  1342.     }
  1343.  
  1344.     /**
  1345.      * Create an object with data merged from Customer and CustomerSecure
  1346.      *
  1347.      * @param CustomerInterface $customer
  1348.      * @return Data\CustomerSecure
  1349.      * @deprecated 100.1.0
  1350.      */
  1351.     protected function getFullCustomerObject($customer)
  1352.     {
  1353.         // No need to flatten the custom attributes or nested objects since the only usage is for email templates and
  1354.         // object passed for events
  1355.         $mergedCustomerData = $this->customerRegistry->retrieveSecureData($customer->getId());
  1356.         $customerData =
  1357.             $this->dataProcessor->buildOutputDataArray($customer, \Magento\Customer\Api\Data\CustomerInterface::class);
  1358.         $mergedCustomerData->addData($customerData);
  1359.         $mergedCustomerData->setData('name', $this->customerViewHelper->getCustomerName($customer));
  1360.         return $mergedCustomerData;
  1361.     }
  1362.  
  1363.     /**
  1364.      * Return hashed password, which can be directly saved to database.
  1365.      *
  1366.      * @param string $password
  1367.      * @return string
  1368.      */
  1369.     public function getPasswordHash($password)
  1370.     {
  1371.         return $this->encryptor->getHash($password);
  1372.     }
  1373.  
  1374.     /**
  1375.      * Get email notification
  1376.      *
  1377.      * @return EmailNotificationInterface
  1378.      * @deprecated 100.1.0
  1379.      */
  1380.     private function getEmailNotification()
  1381.     {
  1382.         if (!($this->emailNotification instanceof EmailNotificationInterface)) {
  1383.             return \Magento\Framework\App\ObjectManager::getInstance()->get(
  1384.                 EmailNotificationInterface::class
  1385.             );
  1386.         } else {
  1387.             return $this->emailNotification;
  1388.         }
  1389.     }
  1390.  
  1391.     /**
  1392.      * Destroy all active customer sessions by customer id (current session will not be destroyed).
  1393.      * Customer sessions which should be deleted are collecting  from the "customer_visitor" table considering
  1394.      * configured session lifetime.
  1395.      *
  1396.      * @param string|int $customerId
  1397.      * @return void
  1398.      */
  1399.     private function destroyCustomerSessions($customerId)
  1400.     {
  1401.         $sessionLifetime = $this->scopeConfig->getValue(
  1402.             \Magento\Framework\Session\Config::XML_PATH_COOKIE_LIFETIME,
  1403.             \Magento\Store\Model\ScopeInterface::SCOPE_STORE
  1404.         );
  1405.         $dateTime = $this->dateTimeFactory->create();
  1406.         $activeSessionsTime = $dateTime->setTimestamp($dateTime->getTimestamp() - $sessionLifetime)
  1407.             ->format(DateTime::DATETIME_PHP_FORMAT);
  1408.         /** @var \Magento\Customer\Model\ResourceModel\Visitor\Collection $visitorCollection */
  1409.         $visitorCollection = $this->visitorCollectionFactory->create();
  1410.         $visitorCollection->addFieldToFilter('customer_id', $customerId);
  1411.         $visitorCollection->addFieldToFilter('last_visit_at', ['from' => $activeSessionsTime]);
  1412.         $visitorCollection->addFieldToFilter('session_id', ['neq' => $this->sessionManager->getSessionId()]);
  1413.         /** @var \Magento\Customer\Model\Visitor $visitor */
  1414.         foreach ($visitorCollection->getItems() as $visitor) {
  1415.             $sessionId = $visitor->getSessionId();
  1416.             $this->sessionManager->start();
  1417.             $this->saveHandler->destroy($sessionId);
  1418.             $this->sessionManager->writeClose();
  1419.         }
  1420.     }
  1421. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement