CreatePost.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Customer\Controller\Account;
  7. use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
  8. use Magento\Customer\Model\Account\Redirect as AccountRedirect;
  9. use Magento\Customer\Api\Data\AddressInterface;
  10. use Magento\Framework\Api\DataObjectHelper;
  11. use Magento\Framework\App\Action\Context;
  12. use Magento\Customer\Model\Session;
  13. use Magento\Framework\App\Config\ScopeConfigInterface;
  14. use Magento\Framework\App\CsrfAwareActionInterface;
  15. use Magento\Framework\App\ObjectManager;
  16. use Magento\Framework\App\Request\InvalidRequestException;
  17. use Magento\Framework\App\RequestInterface;
  18. use Magento\Framework\Controller\Result\Redirect;
  19. use Magento\Framework\Exception\LocalizedException;
  20. use Magento\Framework\Phrase;
  21. use Magento\Store\Model\StoreManagerInterface;
  22. use Magento\Customer\Api\AccountManagementInterface;
  23. use Magento\Customer\Helper\Address;
  24. use Magento\Framework\UrlFactory;
  25. use Magento\Customer\Model\Metadata\FormFactory;
  26. use Magento\Newsletter\Model\SubscriberFactory;
  27. use Magento\Customer\Api\Data\RegionInterfaceFactory;
  28. use Magento\Customer\Api\Data\AddressInterfaceFactory;
  29. use Magento\Customer\Api\Data\CustomerInterfaceFactory;
  30. use Magento\Customer\Model\Url as CustomerUrl;
  31. use Magento\Customer\Model\Registration;
  32. use Magento\Framework\Escaper;
  33. use Magento\Customer\Model\CustomerExtractor;
  34. use Magento\Framework\Exception\StateException;
  35. use Magento\Framework\Exception\InputException;
  36. use Magento\Framework\Data\Form\FormKey\Validator;
  37. use Magento\Customer\Controller\AbstractAccount;
  38. /**
  39. * @SuppressWarnings(PHPMD.TooManyFields)
  40. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  41. */
  42. class CreatePost extends AbstractAccount implements CsrfAwareActionInterface, HttpPostActionInterface
  43. {
  44. /**
  45. * @var \Magento\Customer\Api\AccountManagementInterface
  46. */
  47. protected $accountManagement;
  48. /**
  49. * @var \Magento\Customer\Helper\Address
  50. */
  51. protected $addressHelper;
  52. /**
  53. * @var \Magento\Customer\Model\Metadata\FormFactory
  54. */
  55. protected $formFactory;
  56. /**
  57. * @var \Magento\Newsletter\Model\SubscriberFactory
  58. */
  59. protected $subscriberFactory;
  60. /**
  61. * @var \Magento\Customer\Api\Data\RegionInterfaceFactory
  62. */
  63. protected $regionDataFactory;
  64. /**
  65. * @var \Magento\Customer\Api\Data\AddressInterfaceFactory
  66. */
  67. protected $addressDataFactory;
  68. /**
  69. * @var \Magento\Customer\Model\Registration
  70. */
  71. protected $registration;
  72. /**
  73. * @var \Magento\Customer\Api\Data\CustomerInterfaceFactory
  74. */
  75. protected $customerDataFactory;
  76. /**
  77. * @var \Magento\Customer\Model\Url
  78. */
  79. protected $customerUrl;
  80. /**
  81. * @var \Magento\Framework\Escaper
  82. */
  83. protected $escaper;
  84. /**
  85. * @var \Magento\Customer\Model\CustomerExtractor
  86. */
  87. protected $customerExtractor;
  88. /**
  89. * @var \Magento\Framework\UrlInterface
  90. */
  91. protected $urlModel;
  92. /**
  93. * @var \Magento\Framework\Api\DataObjectHelper
  94. */
  95. protected $dataObjectHelper;
  96. /**
  97. * @var Session
  98. */
  99. protected $session;
  100. /**
  101. * @var AccountRedirect
  102. */
  103. private $accountRedirect;
  104. /**
  105. * @var \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory
  106. */
  107. private $cookieMetadataFactory;
  108. /**
  109. * @var \Magento\Framework\Stdlib\Cookie\PhpCookieManager
  110. */
  111. private $cookieMetadataManager;
  112. /**
  113. * @var Validator
  114. */
  115. private $formKeyValidator;
  116. /**
  117. * @param Context $context
  118. * @param Session $customerSession
  119. * @param ScopeConfigInterface $scopeConfig
  120. * @param StoreManagerInterface $storeManager
  121. * @param AccountManagementInterface $accountManagement
  122. * @param Address $addressHelper
  123. * @param UrlFactory $urlFactory
  124. * @param FormFactory $formFactory
  125. * @param SubscriberFactory $subscriberFactory
  126. * @param RegionInterfaceFactory $regionDataFactory
  127. * @param AddressInterfaceFactory $addressDataFactory
  128. * @param CustomerInterfaceFactory $customerDataFactory
  129. * @param CustomerUrl $customerUrl
  130. * @param Registration $registration
  131. * @param Escaper $escaper
  132. * @param CustomerExtractor $customerExtractor
  133. * @param DataObjectHelper $dataObjectHelper
  134. * @param AccountRedirect $accountRedirect
  135. * @param Validator $formKeyValidator
  136. *
  137. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  138. */
  139. public function __construct(
  140. Context $context,
  141. Session $customerSession,
  142. ScopeConfigInterface $scopeConfig,
  143. StoreManagerInterface $storeManager,
  144. AccountManagementInterface $accountManagement,
  145. Address $addressHelper,
  146. UrlFactory $urlFactory,
  147. FormFactory $formFactory,
  148. SubscriberFactory $subscriberFactory,
  149. RegionInterfaceFactory $regionDataFactory,
  150. AddressInterfaceFactory $addressDataFactory,
  151. CustomerInterfaceFactory $customerDataFactory,
  152. CustomerUrl $customerUrl,
  153. Registration $registration,
  154. Escaper $escaper,
  155. CustomerExtractor $customerExtractor,
  156. DataObjectHelper $dataObjectHelper,
  157. AccountRedirect $accountRedirect,
  158. Validator $formKeyValidator = null
  159. ) {
  160. $this->session = $customerSession;
  161. $this->scopeConfig = $scopeConfig;
  162. $this->storeManager = $storeManager;
  163. $this->accountManagement = $accountManagement;
  164. $this->addressHelper = $addressHelper;
  165. $this->formFactory = $formFactory;
  166. $this->subscriberFactory = $subscriberFactory;
  167. $this->regionDataFactory = $regionDataFactory;
  168. $this->addressDataFactory = $addressDataFactory;
  169. $this->customerDataFactory = $customerDataFactory;
  170. $this->customerUrl = $customerUrl;
  171. $this->registration = $registration;
  172. $this->escaper = $escaper;
  173. $this->customerExtractor = $customerExtractor;
  174. $this->urlModel = $urlFactory->create();
  175. $this->dataObjectHelper = $dataObjectHelper;
  176. $this->accountRedirect = $accountRedirect;
  177. $this->formKeyValidator = $formKeyValidator ?: ObjectManager::getInstance()->get(Validator::class);
  178. parent::__construct($context);
  179. }
  180. /**
  181. * Retrieve cookie manager
  182. *
  183. * @deprecated 100.1.0
  184. * @return \Magento\Framework\Stdlib\Cookie\PhpCookieManager
  185. */
  186. private function getCookieManager()
  187. {
  188. if (!$this->cookieMetadataManager) {
  189. $this->cookieMetadataManager = ObjectManager::getInstance()->get(
  190. \Magento\Framework\Stdlib\Cookie\PhpCookieManager::class
  191. );
  192. }
  193. return $this->cookieMetadataManager;
  194. }
  195. /**
  196. * Retrieve cookie metadata factory
  197. *
  198. * @deprecated 100.1.0
  199. * @return \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory
  200. */
  201. private function getCookieMetadataFactory()
  202. {
  203. if (!$this->cookieMetadataFactory) {
  204. $this->cookieMetadataFactory = ObjectManager::getInstance()->get(
  205. \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory::class
  206. );
  207. }
  208. return $this->cookieMetadataFactory;
  209. }
  210. /**
  211. * Add address to customer during create account
  212. *
  213. * @return AddressInterface|null
  214. */
  215. protected function extractAddress()
  216. {
  217. if (!$this->getRequest()->getPost('create_address')) {
  218. return null;
  219. }
  220. $addressForm = $this->formFactory->create('customer_address', 'customer_register_address');
  221. $allowedAttributes = $addressForm->getAllowedAttributes();
  222. $addressData = [];
  223. $regionDataObject = $this->regionDataFactory->create();
  224. foreach ($allowedAttributes as $attribute) {
  225. $attributeCode = $attribute->getAttributeCode();
  226. $value = $this->getRequest()->getParam($attributeCode);
  227. if ($value === null) {
  228. continue;
  229. }
  230. switch ($attributeCode) {
  231. case 'region_id':
  232. $regionDataObject->setRegionId($value);
  233. break;
  234. case 'region':
  235. $regionDataObject->setRegion($value);
  236. break;
  237. default:
  238. $addressData[$attributeCode] = $value;
  239. }
  240. }
  241. $addressDataObject = $this->addressDataFactory->create();
  242. $this->dataObjectHelper->populateWithArray(
  243. $addressDataObject,
  244. $addressData,
  245. \Magento\Customer\Api\Data\AddressInterface::class
  246. );
  247. $addressDataObject->setRegion($regionDataObject);
  248. $addressDataObject->setIsDefaultBilling(
  249. $this->getRequest()->getParam('default_billing', false)
  250. )->setIsDefaultShipping(
  251. $this->getRequest()->getParam('default_shipping', false)
  252. );
  253. return $addressDataObject;
  254. }
  255. /**
  256. * @inheritDoc
  257. */
  258. public function createCsrfValidationException(
  259. RequestInterface $request
  260. ): ?InvalidRequestException {
  261. /** @var Redirect $resultRedirect */
  262. $resultRedirect = $this->resultRedirectFactory->create();
  263. $url = $this->urlModel->getUrl('*/*/create', ['_secure' => true]);
  264. $resultRedirect->setUrl($this->_redirect->error($url));
  265. return new InvalidRequestException(
  266. $resultRedirect,
  267. [new Phrase('Invalid Form Key. Please refresh the page.')]
  268. );
  269. }
  270. /**
  271. * @inheritDoc
  272. */
  273. public function validateForCsrf(RequestInterface $request): ?bool
  274. {
  275. return null;
  276. }
  277. /**
  278. * Create customer account action
  279. *
  280. * @return void
  281. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  282. * @SuppressWarnings(PHPMD.NPathComplexity)
  283. */
  284. public function execute()
  285. {
  286. /** @var Redirect $resultRedirect */
  287. $resultRedirect = $this->resultRedirectFactory->create();
  288. if ($this->session->isLoggedIn() || !$this->registration->isAllowed()) {
  289. $resultRedirect->setPath('*/*/');
  290. return $resultRedirect;
  291. }
  292. if (!$this->getRequest()->isPost()
  293. || !$this->formKeyValidator->validate($this->getRequest())
  294. ) {
  295. $url = $this->urlModel->getUrl('*/*/create', ['_secure' => true]);
  296. return $this->resultRedirectFactory->create()
  297. ->setUrl($this->_redirect->error($url));
  298. }
  299. $this->session->regenerateId();
  300. try {
  301. $address = $this->extractAddress();
  302. $addresses = $address === null ? [] : [$address];
  303. $customer = $this->customerExtractor->extract('customer_account_create', $this->_request);
  304. $customer->setAddresses($addresses);
  305. $password = $this->getRequest()->getParam('password');
  306. $confirmation = $this->getRequest()->getParam('password_confirmation');
  307. $redirectUrl = $this->session->getBeforeAuthUrl();
  308. $this->checkPasswordConfirmation($password, $confirmation);
  309. $customer = $this->accountManagement
  310. ->createAccount($customer, $password, $redirectUrl);
  311. if ($this->getRequest()->getParam('is_subscribed', false)) {
  312. $this->subscriberFactory->create()->subscribeCustomerById($customer->getId());
  313. }
  314. $this->_eventManager->dispatch(
  315. 'customer_register_success',
  316. ['account_controller' => $this, 'customer' => $customer]
  317. );
  318. $confirmationStatus = $this->accountManagement->getConfirmationStatus($customer->getId());
  319. if ($confirmationStatus === AccountManagementInterface::ACCOUNT_CONFIRMATION_REQUIRED) {
  320. $email = $this->customerUrl->getEmailConfirmationUrl($customer->getEmail());
  321. // @codingStandardsIgnoreStart
  322. $this->messageManager->addSuccess(
  323. __(
  324. 'You must confirm your account. Please check your email for the confirmation link or <a href="%1">click here</a> for a new link.',
  325. $email
  326. )
  327. );
  328. // @codingStandardsIgnoreEnd
  329. $url = $this->urlModel->getUrl('*/*/index', ['_secure' => true]);
  330. $resultRedirect->setUrl($this->_redirect->success($url));
  331. } else {
  332. $this->session->setCustomerDataAsLoggedIn($customer);
  333. $this->messageManager->addSuccess($this->getSuccessMessage());
  334. $requestedRedirect = $this->accountRedirect->getRedirectCookie();
  335. if (!$this->scopeConfig->getValue('customer/startup/redirect_dashboard') && $requestedRedirect) {
  336. $resultRedirect->setUrl($this->_redirect->success($requestedRedirect));
  337. $this->accountRedirect->clearRedirectCookie();
  338. return $resultRedirect;
  339. }
  340. $resultRedirect = $this->accountRedirect->getRedirect();
  341. }
  342. if ($this->getCookieManager()->getCookie('mage-cache-sessid')) {
  343. $metadata = $this->getCookieMetadataFactory()->createCookieMetadata();
  344. $metadata->setPath('/');
  345. $this->getCookieManager()->deleteCookie('mage-cache-sessid', $metadata);
  346. }
  347. return $resultRedirect;
  348. } catch (StateException $e) {
  349. $url = $this->urlModel->getUrl('customer/account/forgotpassword');
  350. // @codingStandardsIgnoreStart
  351. $message = __(
  352. 'There is already an account with this email address. If you are sure that it is your email address, <a href="%1">click here</a> to get your password and access your account.',
  353. $url
  354. );
  355. // @codingStandardsIgnoreEnd
  356. $this->messageManager->addError($message);
  357. } catch (InputException $e) {
  358. $this->messageManager->addError($this->escaper->escapeHtml($e->getMessage()));
  359. foreach ($e->getErrors() as $error) {
  360. $this->messageManager->addError($this->escaper->escapeHtml($error->getMessage()));
  361. }
  362. } catch (LocalizedException $e) {
  363. $this->messageManager->addError($this->escaper->escapeHtml($e->getMessage()));
  364. } catch (\Exception $e) {
  365. $this->messageManager->addException($e, __('We can\'t save the customer.'));
  366. }
  367. $this->session->setCustomerFormData($this->getRequest()->getPostValue());
  368. $defaultUrl = $this->urlModel->getUrl('*/*/create', ['_secure' => true]);
  369. return $resultRedirect->setUrl($this->_redirect->error($defaultUrl));
  370. }
  371. /**
  372. * Make sure that password and password confirmation matched
  373. *
  374. * @param string $password
  375. * @param string $confirmation
  376. * @return void
  377. * @throws InputException
  378. */
  379. protected function checkPasswordConfirmation($password, $confirmation)
  380. {
  381. if ($password != $confirmation) {
  382. throw new InputException(__('Please make sure your passwords match.'));
  383. }
  384. }
  385. /**
  386. * Retrieve success message
  387. *
  388. * @return string
  389. */
  390. protected function getSuccessMessage()
  391. {
  392. if ($this->addressHelper->isVatValidationEnabled()) {
  393. if ($this->addressHelper->getTaxCalculationAddressType() == Address::TYPE_SHIPPING) {
  394. // @codingStandardsIgnoreStart
  395. $message = __(
  396. 'If you are a registered VAT customer, please <a href="%1">click here</a> to enter your shipping address for proper VAT calculation.',
  397. $this->urlModel->getUrl('customer/address/edit')
  398. );
  399. // @codingStandardsIgnoreEnd
  400. } else {
  401. // @codingStandardsIgnoreStart
  402. $message = __(
  403. 'If you are a registered VAT customer, please <a href="%1">click here</a> to enter your billing address for proper VAT calculation.',
  404. $this->urlModel->getUrl('customer/address/edit')
  405. );
  406. // @codingStandardsIgnoreEnd
  407. }
  408. } else {
  409. $message = __('Thank you for registering with %1.', $this->storeManager->getStore()->getFrontendName());
  410. }
  411. return $message;
  412. }
  413. }