mirror of
https://github.com/bdnugget/magento2.git
synced 2026-11-07 09:17:35 +00:00
459 lines
15 KiB
PHP
459 lines
15 KiB
PHP
<?php
|
|
/**
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
declare(strict_types=1);
|
|
|
|
namespace Magento\Customer\Model;
|
|
|
|
use Magento\Framework\App\Config\ScopeConfigInterface;
|
|
use Magento\Framework\App\ObjectManager;
|
|
use Magento\Framework\Exception\MailException;
|
|
use Magento\Framework\Exception\NoSuchEntityException;
|
|
use Magento\Framework\Mail\Template\SenderResolverInterface;
|
|
use Magento\Store\Model\App\Emulation;
|
|
use Magento\Store\Model\StoreManagerInterface;
|
|
use Magento\Framework\Mail\Template\TransportBuilder;
|
|
use Magento\Customer\Helper\View as CustomerViewHelper;
|
|
use Magento\Customer\Api\Data\CustomerInterface;
|
|
use Magento\Framework\Reflection\DataObjectProcessor;
|
|
use Magento\Framework\Exception\LocalizedException;
|
|
use Magento\Store\Model\ScopeInterface;
|
|
use Magento\Customer\Model\Data\CustomerSecure;
|
|
|
|
/**
|
|
* Customer email notification
|
|
*
|
|
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
|
*/
|
|
class EmailNotification implements EmailNotificationInterface
|
|
{
|
|
/**#@+
|
|
* Configuration paths for email templates and identities
|
|
*/
|
|
public const XML_PATH_FORGOT_EMAIL_IDENTITY = 'customer/password/forgot_email_identity';
|
|
|
|
public const XML_PATH_RESET_PASSWORD_TEMPLATE = 'customer/password/reset_password_template';
|
|
|
|
public const XML_PATH_CHANGE_EMAIL_TEMPLATE = 'customer/account_information/change_email_template';
|
|
|
|
public const XML_PATH_CHANGE_EMAIL_AND_PASSWORD_TEMPLATE =
|
|
'customer/account_information/change_email_and_password_template';
|
|
|
|
public const XML_PATH_FORGOT_EMAIL_TEMPLATE = 'customer/password/forgot_email_template';
|
|
|
|
public const XML_PATH_REMIND_EMAIL_TEMPLATE = 'customer/password/remind_email_template';
|
|
|
|
public const XML_PATH_REGISTER_EMAIL_IDENTITY = 'customer/create_account/email_identity';
|
|
|
|
public const XML_PATH_REGISTER_EMAIL_TEMPLATE = 'customer/create_account/email_template';
|
|
|
|
public const XML_PATH_REGISTER_NO_PASSWORD_EMAIL_TEMPLATE = 'customer/create_account/email_no_password_template';
|
|
|
|
public const XML_PATH_CONFIRM_EMAIL_TEMPLATE = 'customer/create_account/email_confirmation_template';
|
|
|
|
public const XML_PATH_CONFIRMED_EMAIL_TEMPLATE = 'customer/create_account/email_confirmed_template';
|
|
|
|
/**
|
|
* self::NEW_ACCOUNT_EMAIL_REGISTERED welcome email, when confirmation is disabled
|
|
* and password is set
|
|
* self::NEW_ACCOUNT_EMAIL_REGISTERED_NO_PASSWORD welcome email, when confirmation is disabled
|
|
* and password is not set
|
|
* self::NEW_ACCOUNT_EMAIL_CONFIRMED welcome email, when confirmation is enabled
|
|
* and password is set
|
|
* self::NEW_ACCOUNT_EMAIL_CONFIRMATION email with confirmation link
|
|
*/
|
|
public const TEMPLATE_TYPES = [
|
|
self::NEW_ACCOUNT_EMAIL_REGISTERED => self::XML_PATH_REGISTER_EMAIL_TEMPLATE,
|
|
self::NEW_ACCOUNT_EMAIL_REGISTERED_NO_PASSWORD => self::XML_PATH_REGISTER_NO_PASSWORD_EMAIL_TEMPLATE,
|
|
self::NEW_ACCOUNT_EMAIL_CONFIRMED => self::XML_PATH_CONFIRMED_EMAIL_TEMPLATE,
|
|
self::NEW_ACCOUNT_EMAIL_CONFIRMATION => self::XML_PATH_CONFIRM_EMAIL_TEMPLATE,
|
|
];
|
|
|
|
/**#@-*/
|
|
|
|
/**
|
|
* @var CustomerRegistry
|
|
*/
|
|
private $customerRegistry;
|
|
|
|
/**
|
|
* @var StoreManagerInterface
|
|
*/
|
|
private $storeManager;
|
|
|
|
/**
|
|
* @var TransportBuilder
|
|
*/
|
|
private $transportBuilder;
|
|
|
|
/**
|
|
* @var CustomerViewHelper
|
|
*/
|
|
protected $customerViewHelper;
|
|
|
|
/**
|
|
* @var DataObjectProcessor
|
|
*/
|
|
protected $dataProcessor;
|
|
|
|
/**
|
|
* @var ScopeConfigInterface
|
|
*/
|
|
private $scopeConfig;
|
|
|
|
/**
|
|
* @var SenderResolverInterface
|
|
*/
|
|
private $senderResolver;
|
|
|
|
/**
|
|
* @var Emulation
|
|
*/
|
|
private $emulation;
|
|
|
|
/**
|
|
* @var AccountConfirmation
|
|
*/
|
|
private AccountConfirmation $accountConfirmation;
|
|
|
|
/**
|
|
* @param CustomerRegistry $customerRegistry
|
|
* @param StoreManagerInterface $storeManager
|
|
* @param TransportBuilder $transportBuilder
|
|
* @param CustomerViewHelper $customerViewHelper
|
|
* @param DataObjectProcessor $dataProcessor
|
|
* @param ScopeConfigInterface $scopeConfig
|
|
* @param SenderResolverInterface|null $senderResolver
|
|
* @param Emulation|null $emulation
|
|
* @param AccountConfirmation|null $accountConfirmation
|
|
*/
|
|
public function __construct(
|
|
CustomerRegistry $customerRegistry,
|
|
StoreManagerInterface $storeManager,
|
|
TransportBuilder $transportBuilder,
|
|
CustomerViewHelper $customerViewHelper,
|
|
DataObjectProcessor $dataProcessor,
|
|
ScopeConfigInterface $scopeConfig,
|
|
SenderResolverInterface $senderResolver = null,
|
|
Emulation $emulation = null,
|
|
?AccountConfirmation $accountConfirmation = null
|
|
) {
|
|
$this->customerRegistry = $customerRegistry;
|
|
$this->storeManager = $storeManager;
|
|
$this->transportBuilder = $transportBuilder;
|
|
$this->customerViewHelper = $customerViewHelper;
|
|
$this->dataProcessor = $dataProcessor;
|
|
$this->scopeConfig = $scopeConfig;
|
|
$this->senderResolver = $senderResolver ?? ObjectManager::getInstance()->get(SenderResolverInterface::class);
|
|
$this->emulation = $emulation ?? ObjectManager::getInstance()->get(Emulation::class);
|
|
$this->accountConfirmation = $accountConfirmation ?? ObjectManager::getInstance()
|
|
->get(AccountConfirmation::class);
|
|
}
|
|
|
|
/**
|
|
* Send notification to customer when email or/and password changed
|
|
*
|
|
* @param CustomerInterface $savedCustomer
|
|
* @param string $origCustomerEmail
|
|
* @param bool $isPasswordChanged
|
|
* @return void
|
|
* @throws LocalizedException
|
|
*/
|
|
public function credentialsChanged(
|
|
CustomerInterface $savedCustomer,
|
|
$origCustomerEmail,
|
|
$isPasswordChanged = false
|
|
): void {
|
|
if ($origCustomerEmail != $savedCustomer->getEmail()) {
|
|
$this->emailChangedConfirmation($savedCustomer);
|
|
if ($isPasswordChanged) {
|
|
$this->emailAndPasswordChanged($savedCustomer, $origCustomerEmail);
|
|
$this->emailAndPasswordChanged($savedCustomer, $savedCustomer->getEmail());
|
|
return;
|
|
}
|
|
|
|
$this->emailChanged($savedCustomer, $origCustomerEmail);
|
|
$this->emailChanged($savedCustomer, $savedCustomer->getEmail());
|
|
return;
|
|
}
|
|
|
|
if ($isPasswordChanged) {
|
|
$this->passwordReset($savedCustomer);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send email to customer when his email and password is changed
|
|
*
|
|
* @param CustomerInterface $customer
|
|
* @param string $email
|
|
* @return void
|
|
* @throws MailException
|
|
* @throws NoSuchEntityException|LocalizedException
|
|
*/
|
|
private function emailAndPasswordChanged(CustomerInterface $customer, $email): void
|
|
{
|
|
$storeId = $customer->getStoreId();
|
|
if ($storeId === null) {
|
|
$storeId = $this->getWebsiteStoreId($customer);
|
|
}
|
|
|
|
$customerEmailData = $this->getFullCustomerObject($customer);
|
|
|
|
$this->sendEmailTemplate(
|
|
$customer,
|
|
self::XML_PATH_CHANGE_EMAIL_AND_PASSWORD_TEMPLATE,
|
|
self::XML_PATH_FORGOT_EMAIL_IDENTITY,
|
|
['customer' => $customerEmailData, 'store' => $this->storeManager->getStore($storeId)],
|
|
$storeId,
|
|
$email
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Send email to customer when his email is changed
|
|
*
|
|
* @param CustomerInterface $customer
|
|
* @param string $email
|
|
* @return void
|
|
* @throws MailException
|
|
* @throws NoSuchEntityException|LocalizedException
|
|
*/
|
|
private function emailChanged(CustomerInterface $customer, $email): void
|
|
{
|
|
$storeId = $customer->getStoreId();
|
|
if ($storeId === null) {
|
|
$storeId = $this->getWebsiteStoreId($customer);
|
|
}
|
|
|
|
$customerEmailData = $this->getFullCustomerObject($customer);
|
|
|
|
$this->sendEmailTemplate(
|
|
$customer,
|
|
self::XML_PATH_CHANGE_EMAIL_TEMPLATE,
|
|
self::XML_PATH_FORGOT_EMAIL_IDENTITY,
|
|
['customer' => $customerEmailData, 'store' => $this->storeManager->getStore($storeId)],
|
|
$storeId,
|
|
$email
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Send email to customer when his password is reset
|
|
*
|
|
* @param CustomerInterface $customer
|
|
* @return void
|
|
* @throws MailException
|
|
* @throws NoSuchEntityException|LocalizedException
|
|
*/
|
|
private function passwordReset(CustomerInterface $customer): void
|
|
{
|
|
$storeId = $customer->getStoreId();
|
|
if ($storeId === null) {
|
|
$storeId = $this->getWebsiteStoreId($customer);
|
|
}
|
|
|
|
$customerEmailData = $this->getFullCustomerObject($customer);
|
|
|
|
$this->sendEmailTemplate(
|
|
$customer,
|
|
self::XML_PATH_RESET_PASSWORD_TEMPLATE,
|
|
self::XML_PATH_FORGOT_EMAIL_IDENTITY,
|
|
['customer' => $customerEmailData, 'store' => $this->storeManager->getStore($storeId)],
|
|
$storeId
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Send corresponding email template
|
|
*
|
|
* @param CustomerInterface $customer
|
|
* @param string $template configuration path of email template
|
|
* @param string $sender configuration path of email identity
|
|
* @param array $templateParams
|
|
* @param int|null $storeId
|
|
* @param string $email
|
|
* @return void
|
|
* @throws MailException|LocalizedException
|
|
*/
|
|
private function sendEmailTemplate(
|
|
$customer,
|
|
$template,
|
|
$sender,
|
|
$templateParams = [],
|
|
$storeId = null,
|
|
$email = null
|
|
): void {
|
|
$templateId = $this->scopeConfig->getValue($template, ScopeInterface::SCOPE_STORE, $storeId);
|
|
if ($email === null) {
|
|
$email = $customer->getEmail();
|
|
}
|
|
|
|
/** @var array $from */
|
|
$from = $this->senderResolver->resolve(
|
|
$this->scopeConfig->getValue($sender, ScopeInterface::SCOPE_STORE, $storeId),
|
|
$storeId
|
|
);
|
|
|
|
$transport = $this->transportBuilder->setTemplateIdentifier($templateId)
|
|
->setTemplateOptions(['area' => 'frontend', 'store' => $storeId])
|
|
->setTemplateVars($templateParams)
|
|
->setFrom($from)
|
|
->addTo($email, $this->customerViewHelper->getCustomerName($customer))
|
|
->getTransport();
|
|
|
|
$this->emulation->startEnvironmentEmulation($storeId, \Magento\Framework\App\Area::AREA_FRONTEND);
|
|
$transport->sendMessage();
|
|
$this->emulation->stopEnvironmentEmulation();
|
|
}
|
|
|
|
/**
|
|
* Create an object with data merged from Customer and CustomerSecure
|
|
*
|
|
* @param CustomerInterface $customer
|
|
* @return CustomerSecure
|
|
* @throws NoSuchEntityException
|
|
*/
|
|
private function getFullCustomerObject($customer): CustomerSecure
|
|
{
|
|
// No need to flatten the custom attributes or nested objects since the only usage is for email templates and
|
|
// object passed for events
|
|
$mergedCustomerData = $this->customerRegistry->retrieveSecureData($customer->getId());
|
|
$customerData = $this->dataProcessor
|
|
->buildOutputDataArray($customer, CustomerInterface::class);
|
|
$mergedCustomerData->addData($customerData);
|
|
$mergedCustomerData->setData('name', $this->customerViewHelper->getCustomerName($customer));
|
|
return $mergedCustomerData;
|
|
}
|
|
|
|
/**
|
|
* Get either first store ID from a set website or the provided as default
|
|
*
|
|
* @param CustomerInterface $customer
|
|
* @param int|string|null $defaultStoreId
|
|
* @return int
|
|
* @throws LocalizedException
|
|
*/
|
|
private function getWebsiteStoreId($customer, $defaultStoreId = null): int
|
|
{
|
|
if ($customer->getWebsiteId() != 0 && empty($defaultStoreId)) {
|
|
$storeIds = $this->storeManager->getWebsite($customer->getWebsiteId())->getStoreIds();
|
|
$defaultStoreId = reset($storeIds);
|
|
}
|
|
return $defaultStoreId;
|
|
}
|
|
|
|
/**
|
|
* Send email with new customer password
|
|
*
|
|
* @param CustomerInterface $customer
|
|
* @return void
|
|
* @throws LocalizedException
|
|
* @throws MailException
|
|
* @throws NoSuchEntityException
|
|
*/
|
|
public function passwordReminder(CustomerInterface $customer): void
|
|
{
|
|
$storeId = $customer->getStoreId();
|
|
if ($storeId === null) {
|
|
$storeId = $this->getWebsiteStoreId($customer);
|
|
}
|
|
|
|
$customerEmailData = $this->getFullCustomerObject($customer);
|
|
|
|
$this->sendEmailTemplate(
|
|
$customer,
|
|
self::XML_PATH_REMIND_EMAIL_TEMPLATE,
|
|
self::XML_PATH_FORGOT_EMAIL_IDENTITY,
|
|
['customer' => $customerEmailData, 'store' => $this->storeManager->getStore($storeId)],
|
|
$storeId
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Send email with reset password confirmation link
|
|
*
|
|
* @param CustomerInterface $customer
|
|
* @return void
|
|
* @throws LocalizedException
|
|
* @throws MailException
|
|
* @throws NoSuchEntityException
|
|
*/
|
|
public function passwordResetConfirmation(CustomerInterface $customer): void
|
|
{
|
|
$storeId = $customer->getStoreId();
|
|
if ($storeId === null) {
|
|
$storeId = $this->getWebsiteStoreId($customer);
|
|
}
|
|
|
|
$customerEmailData = $this->getFullCustomerObject($customer);
|
|
|
|
$this->sendEmailTemplate(
|
|
$customer,
|
|
self::XML_PATH_FORGOT_EMAIL_TEMPLATE,
|
|
self::XML_PATH_FORGOT_EMAIL_IDENTITY,
|
|
['customer' => $customerEmailData, 'store' => $this->storeManager->getStore($storeId)],
|
|
$storeId
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Send email with new account related information
|
|
*
|
|
* @param CustomerInterface $customer
|
|
* @param string $type
|
|
* @param string $backUrl
|
|
* @param int|null $storeId
|
|
* @param string $sendemailStoreId
|
|
* @return void
|
|
* @throws LocalizedException
|
|
*/
|
|
public function newAccount(
|
|
CustomerInterface $customer,
|
|
$type = self::NEW_ACCOUNT_EMAIL_REGISTERED,
|
|
$backUrl = '',
|
|
$storeId = null,
|
|
$sendemailStoreId = null
|
|
): void {
|
|
$types = self::TEMPLATE_TYPES;
|
|
|
|
if (!isset($types[$type])) {
|
|
throw new LocalizedException(
|
|
__('The transactional account email type is incorrect. Verify and try again.')
|
|
);
|
|
}
|
|
|
|
if ($storeId === null) {
|
|
$storeId = $this->getWebsiteStoreId($customer, $sendemailStoreId);
|
|
}
|
|
|
|
$store = $this->storeManager->getStore($customer->getStoreId());
|
|
|
|
$customerEmailData = $this->getFullCustomerObject($customer);
|
|
|
|
$this->sendEmailTemplate(
|
|
$customer,
|
|
$types[$type],
|
|
self::XML_PATH_REGISTER_EMAIL_IDENTITY,
|
|
['customer' => $customerEmailData, 'back_url' => $backUrl, 'store' => $store],
|
|
$storeId
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Sending an email to confirm the email address in case the email address has been changed
|
|
*
|
|
* @param CustomerInterface $customer
|
|
* @throws LocalizedException
|
|
*/
|
|
private function emailChangedConfirmation(CustomerInterface $customer): void
|
|
{
|
|
if (!$this->accountConfirmation->isCustomerEmailChangedConfirmRequired($customer)) {
|
|
return;
|
|
}
|
|
$this->newAccount($customer, self::NEW_ACCOUNT_EMAIL_CONFIRMATION, null, $customer->getStoreId());
|
|
}
|
|
}
|