Skip to content

Commit 7a26572

Browse files
authored
Merge branch '2.4-develop' into bug/issue-39568-reorder-bug
2 parents 1479cd3 + 0057e06 commit 7a26572

File tree

66 files changed

+1410
-1044
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1410
-1044
lines changed

app/code/Magento/Checkout/Test/Mftf/ActionGroup/GuestCheckoutFillingShippingSectionActionGroup.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88

app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAppliedTest.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -82,6 +82,7 @@
8282
<argument name="discountCode" value="{{CatPriceRule.coupon_code}}"/>
8383
</actionGroup>
8484
<!-- Assert order cannot be placed and error message will shown. -->
85+
<actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectDefaultPaymentMethod"/>
8586
<actionGroup ref="AssertStorefrontOrderIsNotPlacedActionGroup" stepKey="seeShippingMethodError">
8687
<argument name="error" value="The shipping method is missing. Select the shipping method and try again."/>
8788
</actionGroup>

app/code/Magento/Checkout/Test/Mftf/Test/VerifyStateOptionApplicableForCheckoutFlowTest.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88

@@ -65,6 +65,7 @@
6565
<actionGroup ref="StorefrontCheckoutClickNextOnShippingStepActionGroup" stepKey="clickNext"/>
6666
<waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/>
6767
<seeCurrentUrlMatches regex="~/checkout/?#payment~" stepKey="assertCheckoutPaymentUrl"/>
68+
<actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectDefaultPaymentMethod"/>
6869
<waitForElementVisible selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/>
6970
<click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/>
7071
<seeElement selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="seeOrderNumber"/>
Lines changed: 108 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2015 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

88
namespace Magento\Email\Model;
99

10-
use Laminas\Mail\Transport\Smtp;
11-
use Laminas\Mail\Transport\SmtpOptions;
10+
use Magento\Framework\Mail\EmailMessageInterface;
11+
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
12+
use Symfony\Component\Mailer\Mailer;
13+
use Symfony\Component\Mailer\Transport\NativeTransportFactory;
14+
use Symfony\Component\Mailer\Transport\Dsn;
15+
use Symfony\Component\Mailer\Transport\TransportInterface as SymfonyTransportInterface;
16+
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
17+
use Symfony\Component\Mailer\Transport\Smtp\Auth\LoginAuthenticator;
18+
use Symfony\Component\Mailer\Transport\Smtp\Auth\PlainAuthenticator;
1219
use Magento\Framework\App\Config\ScopeConfigInterface;
1320
use Magento\Framework\App\ObjectManager;
1421
use Magento\Framework\Exception\MailException;
15-
use Magento\Framework\Mail\MessageInterface;
1622
use Magento\Framework\Mail\TransportInterface;
1723
use Magento\Framework\Phrase;
24+
use Symfony\Component\Mime\Message as SymfonyMessage;
1825
use Magento\Store\Model\ScopeInterface;
19-
use Laminas\Mail\Message;
20-
use Laminas\Mail\Transport\Sendmail;
21-
use Laminas\Mail\Transport\TransportInterface as LaminasTransportInterface;
2226
use Psr\Log\LoggerInterface;
2327

2428
/**
2529
* Class that responsible for filling some message data before transporting it.
26-
* @see \Laminas\Mail\Transport\Sendmail is used for transport
30+
* @see \Symfony\Component\Mailer\Transport is used for transport
2731
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2832
*/
2933
class Transport implements TransportInterface
@@ -84,48 +88,41 @@ class Transport implements TransportInterface
8488
*
8589
* @var int
8690
*/
87-
private $isSetReturnPath;
91+
private int $isSetReturnPath;
8892

8993
/**
9094
* @var string|null
9195
*/
92-
private $returnPathValue;
96+
private ?string $returnPathValue;
9397

9498
/**
9599
* @var ScopeConfigInterface
96100
*/
97-
private $scopeConfig;
101+
private ScopeConfigInterface $scopeConfig;
98102

99103
/**
100-
* @var LaminasTransportInterface|null
104+
* @var SymfonyTransportInterface
101105
*/
102-
private $laminasTransport;
106+
private SymfonyTransportInterface $symfonyTransport;
103107

104108
/**
105-
* @var null|string|array|\Traversable
109+
* @var EmailMessageInterface
106110
*/
107-
private $parameters;
108-
109-
/**
110-
* @var MessageInterface
111-
*/
112-
private $message;
111+
private EmailMessageInterface $message;
113112

114113
/**
115114
* @var LoggerInterface|null
116115
*/
117-
private $logger;
116+
private ?LoggerInterface $logger;
118117

119118
/**
120-
* @param MessageInterface $message Email message object
119+
* @param EmailMessageInterface $message Email message object
121120
* @param ScopeConfigInterface $scopeConfig Core store config
122-
* @param null|string|array|\Traversable $parameters Config options for sendmail parameters
123121
* @param LoggerInterface|null $logger
124122
*/
125123
public function __construct(
126-
MessageInterface $message,
124+
EmailMessageInterface $message,
127125
ScopeConfigInterface $scopeConfig,
128-
$parameters = null,
129126
?LoggerInterface $logger = null
130127
) {
131128
$this->isSetReturnPath = (int) $scopeConfig->getValue(
@@ -138,131 +135,126 @@ public function __construct(
138135
);
139136
$this->message = $message;
140137
$this->scopeConfig = $scopeConfig;
141-
$this->parameters = $parameters;
142138
$this->logger = $logger ?: ObjectManager::getInstance()->get(LoggerInterface::class);
143139
}
144140

145141
/**
146-
* Get the LaminasTransport based on the configuration.
142+
* Get the SymfonyTransport based on the configuration.
147143
*
148-
* @return LaminasTransportInterface
144+
* @return SymfonyTransportInterface
149145
*/
150-
public function getTransport(): LaminasTransportInterface
146+
public function getTransport(): SymfonyTransportInterface
151147
{
152-
if ($this->laminasTransport === null) {
153-
$transport = $this->scopeConfig->getValue(
154-
self::XML_PATH_TRANSPORT,
155-
ScopeInterface::SCOPE_STORE
156-
);
157-
158-
if ($transport === 'smtp') {
159-
$this->laminasTransport = $this->createSmtpTransport();
148+
if (!isset($this->symfonyTransport)) {
149+
$transportType = $this->scopeConfig->getValue(self::XML_PATH_TRANSPORT);
150+
if ($transportType === 'smtp') {
151+
$this->symfonyTransport = $this->createSmtpTransport();
160152
} else {
161-
$this->laminasTransport = $this->createSendmailTransport();
153+
$this->symfonyTransport = $this->createSendmailTransport();
162154
}
163155
}
164156

165-
return $this->laminasTransport;
157+
return $this->symfonyTransport;
166158
}
167159

168160
/**
169-
* @inheritdoc
161+
* Build the DSN string for Symfony transport based on configuration.
162+
*
163+
* @return SymfonyTransportInterface
170164
*/
171-
public function sendMessage()
165+
private function createSmtpTransport(): SymfonyTransportInterface
172166
{
173-
try {
174-
$laminasMessage = Message::fromString($this->message->getRawMessage())->setEncoding('utf-8');
175-
if (2 === $this->isSetReturnPath && $this->returnPathValue) {
176-
$laminasMessage->setSender($this->returnPathValue);
177-
} elseif (1 === $this->isSetReturnPath && $laminasMessage->getFrom()->count()) {
178-
$fromAddressList = $laminasMessage->getFrom();
179-
$fromAddressList->rewind();
180-
$laminasMessage->setSender($fromAddressList->current()->getEmail());
181-
}
167+
$host = $this->scopeConfig->getValue(self::XML_PATH_HOST, ScopeInterface::SCOPE_STORE);
168+
$port = (int) $this->scopeConfig->getValue(self::XML_PATH_PORT, ScopeInterface::SCOPE_STORE);
169+
$username = $this->scopeConfig->getValue(self::XML_PATH_USERNAME, ScopeInterface::SCOPE_STORE);
170+
$password = $this->scopeConfig->getValue(self::XML_PATH_PASSWORD, ScopeInterface::SCOPE_STORE);
171+
$auth = $this->scopeConfig->getValue(self::XML_PATH_AUTH, ScopeInterface::SCOPE_STORE);
172+
$ssl = $this->scopeConfig->getValue(self::XML_PATH_SSL, ScopeInterface::SCOPE_STORE);
173+
$tls = false;
174+
175+
if ($ssl === 'tls') {
176+
$tls = true;
177+
}
182178

183-
$this->getTransport()->send($laminasMessage);
184-
} catch (\Exception $e) {
185-
$this->logger->error($e);
186-
throw new MailException(new Phrase('Unable to send mail. Please try again later.'), $e);
179+
$transport = new EsmtpTransport($host, $port, $tls);
180+
if ($username) {
181+
$transport->setUsername($username);
182+
}
183+
if ($password) {
184+
$transport->setPassword($password);
187185
}
186+
187+
switch ($auth) {
188+
case 'plain':
189+
$transport->setAuthenticators([new PlainAuthenticator()]);
190+
break;
191+
case 'login':
192+
$transport->setAuthenticators([new LoginAuthenticator()]);
193+
break;
194+
case 'none':
195+
break;
196+
default:
197+
throw new \InvalidArgumentException('Invalid authentication type: ' . $auth);
198+
}
199+
200+
return $transport;
188201
}
189202

190203
/**
191-
* @inheritdoc
204+
* Create a Sendmail transport for Symfony Mailer.
205+
*
206+
* @return SymfonyTransportInterface
192207
*/
193-
public function getMessage()
208+
private function createSendmailTransport(): SymfonyTransportInterface
194209
{
195-
return $this->message;
210+
$dsn = new Dsn('native', 'default');
211+
$nativeTransportFactory = new NativeTransportFactory();
212+
return $nativeTransportFactory->create($dsn);
196213
}
197214

198215
/**
199-
* Create a Smtp LaminasTransport.
200-
*
201-
* @return Smtp
216+
* @inheritdoc
202217
*/
203-
private function createSmtpTransport(): Smtp
218+
public function sendMessage(): void
204219
{
205-
$host = $this->scopeConfig->getValue(
206-
self::XML_PATH_HOST,
207-
ScopeInterface::SCOPE_STORE
208-
);
209-
210-
$port = $this->scopeConfig->getValue(
211-
self::XML_PATH_PORT,
212-
ScopeInterface::SCOPE_STORE
213-
);
214-
215-
$username = $this->scopeConfig->getValue(
216-
self::XML_PATH_USERNAME,
217-
ScopeInterface::SCOPE_STORE
218-
);
219-
220-
$password = $this->scopeConfig->getValue(
221-
self::XML_PATH_PASSWORD,
222-
ScopeInterface::SCOPE_STORE
223-
);
224-
225-
$auth = $this->scopeConfig->getValue(
226-
self::XML_PATH_AUTH,
227-
ScopeInterface::SCOPE_STORE
228-
);
229-
230-
$ssl = $this->scopeConfig->getValue(
231-
self::XML_PATH_SSL,
232-
ScopeInterface::SCOPE_STORE
233-
);
234-
235-
$options = [
236-
'name' => 'localhost',
237-
'host' => $host,
238-
'port' => $port,
239-
'connection_config' => [
240-
'username' => $username,
241-
'password' => $password,
242-
]
243-
];
244-
245-
if ($auth && $auth !== 'none') {
246-
$options['connection_class'] = $auth;
220+
try {
221+
$email = $this->message->getSymfonyMessage();
222+
$this->setReturnPath($email);
223+
$mailer = new Mailer($this->getTransport());
224+
$mailer->send($email);
225+
} catch (TransportExceptionInterface $transportException) {
226+
$this->logger->error('Transport error while sending email: ' . $transportException->getMessage());
227+
throw new MailException(
228+
new Phrase('Transport error: Unable to send mail at this time.'),
229+
$transportException
230+
);
231+
} catch (\Exception $e) {
232+
$this->logger->error($e);
233+
throw new MailException(new Phrase('Unable to send mail. Please try again later.'), $e);
247234
}
235+
}
248236

249-
if ($ssl && $ssl !== 'none') {
250-
$options['connection_config']['ssl'] = $ssl;
237+
/**
238+
* Set the return path if configured.
239+
*
240+
* @param SymfonyMessage $email
241+
*/
242+
private function setReturnPath(SymfonyMessage $email): void
243+
{
244+
if ($this->isSetReturnPath === 2 && $this->returnPathValue) {
245+
$email->getHeaders()->addMailboxListHeader('Sender', [$this->returnPathValue]);
246+
} elseif ($this->isSetReturnPath === 1 &&
247+
!empty($fromAddresses = $email->getHeaders()->get('From')?->getAddresses())) {
248+
reset($fromAddresses);
249+
$email->getHeaders()->addMailboxListHeader('Sender', [current($fromAddresses)->getAddress()]);
251250
}
252-
253-
$transport = new Smtp();
254-
$transport->setOptions(new SmtpOptions($options));
255-
256-
return $transport;
257251
}
258252

259253
/**
260-
* Create a Sendmail Laminas Transport
261-
*
262-
* @return Sendmail
254+
* @inheritdoc
263255
*/
264-
private function createSendmailTransport(): Sendmail
256+
public function getMessage(): EmailMessageInterface
265257
{
266-
return new Sendmail($this->parameters);
258+
return $this->message;
267259
}
268260
}

app/code/Magento/Email/Test/Fixture/FileTransport.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2015 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

@@ -18,8 +18,9 @@
1818
class FileTransport implements RevertibleDataFixtureInterface
1919
{
2020
private const DEFAULT_DATA = [
21-
'directory' => DirectoryList::TMP,
21+
'directory' => DirectoryList::VAR_DIR,
2222
'path' => 'mail/%uniqid%',
23+
'data' => 'Bienvenue sur Le Site de Paris.'
2324
];
2425

2526
private const CONFIG_FILE = 'mail-transport-config.json';

0 commit comments

Comments
 (0)