Skip to content

Commit eb0fb33

Browse files
authored
Merge branch '2.4-develop' into patch-3
2 parents 49ef010 + 2a252ae commit eb0fb33

File tree

122 files changed

+4101
-729
lines changed

Some content is hidden

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

122 files changed

+4101
-729
lines changed

app/bootstrap.php

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@
1313
}
1414
#ini_set('display_errors', 1);
1515

16-
/* PHP version validation */
17-
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 80100) {
18-
if (PHP_SAPI == 'cli') {
16+
if (PHP_VERSION_ID < 80100) {
17+
if (PHP_SAPI === 'cli') {
1918
echo 'Magento supports PHP 8.1.0 or later. ' .
2019
'Please read https://experienceleague.adobe.com/docs/commerce-operations/installation-guide/system-requirements.html';
2120
} else {
@@ -31,16 +30,6 @@
3130
exit(1);
3231
}
3332

34-
// PHP 8 compatibility. Define constants that are not present in PHP < 8.0
35-
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 80000) {
36-
if (!defined('T_NAME_QUALIFIED')) {
37-
define('T_NAME_QUALIFIED', 24001);
38-
}
39-
if (!defined('T_NAME_FULLY_QUALIFIED')) {
40-
define('T_NAME_FULLY_QUALIFIED', 24002);
41-
}
42-
}
43-
4433
require_once __DIR__ . '/autoload.php';
4534
// Sets default autoload mappings, may be overridden in Bootstrap::create
4635
\Magento\Framework\App\Bootstrap::populateAutoloader(BP, []);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\AdvancedSearch\Model\Client;
9+
10+
class ClientException extends \Exception
11+
{
12+
13+
}

app/code/Magento/Backend/Block/Template.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ public function __construct(
8080
$this->formKey = $context->getFormKey();
8181
$this->nameBuilder = $context->getNameBuilder();
8282
$data['jsonHelper'] = $jsonHelper ?? ObjectManager::getInstance()->get(JsonHelper::class);
83-
$data['directoryHelper']= $directoryHelper ?? ObjectManager::getInstance()->get(DirectoryHelper::class);
83+
if (empty($data['directoryHelper'])) {
84+
$data['directoryHelper'] = $directoryHelper ?? ObjectManager::getInstance()->get(DirectoryHelper::class);
85+
}
8486
parent::__construct($context, $data);
8587
}
8688

@@ -107,6 +109,7 @@ public function getFormKey()
107109
* not be used in future development. Module design should explicitly state dependencies to avoid requiring output
108110
* disabling. This functionality will temporarily be kept in Magento core, as there are unresolved modularity
109111
* issues that will be addressed in future releases.
112+
* @see no alternatives
110113
*/
111114
public function isOutputEnabled($moduleName = null)
112115
{

app/code/Magento/Backend/Controller/Adminhtml/System/Store/Save.php

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
*/
66
namespace Magento\Backend\Controller\Adminhtml\System\Store;
77

8+
use Magento\Backend\App\Action\Context;
9+
use Magento\Backend\Model\View\Result\ForwardFactory;
10+
use Magento\Framework\App\Cache\TypeListInterface;
11+
use Magento\Framework\Filter\FilterManager;
12+
use Magento\Framework\Registry;
13+
use Magento\Framework\View\Result\PageFactory;
814
use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
915
use Magento\Store\Model\Group as StoreGroup;
1016
use Magento\Store\Model\Store;
@@ -17,6 +23,32 @@
1723
*/
1824
class Save extends \Magento\Backend\Controller\Adminhtml\System\Store implements HttpPostActionInterface
1925
{
26+
/**
27+
* @var TypeListInterface
28+
*/
29+
private $cacheTypeList;
30+
31+
/**
32+
* Constructor
33+
*
34+
* @param Context $context
35+
* @param Registry $coreRegistry
36+
* @param FilterManager $filterManager
37+
* @param ForwardFactory $resultForwardFactory
38+
* @param PageFactory $resultPageFactory
39+
* @param TypeListInterface $cacheTypeList
40+
*/
41+
public function __construct(
42+
Context $context,
43+
Registry $coreRegistry,
44+
FilterManager $filterManager,
45+
ForwardFactory $resultForwardFactory,
46+
PageFactory $resultPageFactory,
47+
TypeListInterface $cacheTypeList,
48+
) {
49+
parent::__construct($context, $coreRegistry, $filterManager, $resultForwardFactory, $resultPageFactory);
50+
$this->cacheTypeList = $cacheTypeList;
51+
}
2052
/**
2153
* Process Website model save
2254
*
@@ -67,6 +99,8 @@ private function processStoreSave($postData)
6799
if ($postData['store']['store_id']) {
68100
$storeModel->load($postData['store']['store_id']);
69101
}
102+
$originalCode = $storeModel->getCode();
103+
$newCode = $postData['store']['code'] ?? null;
70104
$storeModel->setData($postData['store']);
71105
if ($postData['store']['store_id'] == '') {
72106
$storeModel->setId(null);
@@ -84,7 +118,9 @@ private function processStoreSave($postData)
84118
}
85119
$storeModel->save();
86120
$this->messageManager->addSuccessMessage(__('You saved the store view.'));
87-
121+
if ($originalCode !== $newCode) {
122+
$this->cacheTypeList->cleanType('config');
123+
}
88124
return $postData;
89125
}
90126

@@ -120,7 +156,10 @@ private function processGroupSave($postData)
120156
}
121157

122158
/**
159+
* Saving edited store information
160+
*
123161
* @return \Magento\Backend\Model\View\Result\Redirect
162+
*
124163
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
125164
*/
126165
public function execute()
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Backend\Test\Unit\Controller\Adminhtml\System\Store;
9+
10+
use Magento\Backend\App\Action\Context;
11+
use Magento\Backend\Controller\Adminhtml\System\Store\Save;
12+
use Magento\Backend\Helper\Data;
13+
use Magento\Backend\Model\Session;
14+
use Magento\Backend\Model\View\Result\ForwardFactory;
15+
use Magento\Backend\Model\View\Result\Redirect;
16+
use Magento\Framework\App\Cache\TypeListInterface;
17+
use Magento\Framework\App\Request\Http;
18+
use Magento\Framework\App\RequestInterface;
19+
use Magento\Framework\App\ResponseInterface;
20+
use Magento\Framework\Controller\Result\RedirectFactory;
21+
use Magento\Framework\Filter\FilterManager;
22+
use Magento\Framework\Message\ManagerInterface;
23+
use Magento\Framework\ObjectManager\ObjectManager;
24+
use Magento\Framework\Registry;
25+
use Magento\Framework\View\Result\PageFactory;
26+
use Magento\Store\Model\Group;
27+
use Magento\Store\Model\Store;
28+
use PHPUnit\Framework\MockObject\MockObject;
29+
use PHPUnit\Framework\TestCase;
30+
31+
/**
32+
* Unit test for \Magento\Backend\Controller\Adminhtml\System\Store\Save controller.
33+
*
34+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
35+
*/
36+
class SaveTest extends TestCase
37+
{
38+
/**
39+
* @var Save
40+
*/
41+
private $controller;
42+
43+
/**
44+
* @var RequestInterface|MockObject
45+
*/
46+
private $requestMock;
47+
48+
/**
49+
* @var ResponseInterface|MockObject
50+
*/
51+
private $responseMock;
52+
53+
/**
54+
* @var ObjectManager|MockObject
55+
*/
56+
private $objectManagerMock;
57+
58+
/**
59+
* @var ManagerInterface|MockObject
60+
*/
61+
private $messagesMock;
62+
63+
/**
64+
* @var Data|MockObject
65+
*/
66+
private $helperMock;
67+
68+
/**
69+
* @var Session|MockObject
70+
*/
71+
private $sessionMock;
72+
73+
/**
74+
* @var Store|MockObject
75+
*/
76+
private $storeModelMock;
77+
78+
/**
79+
* @var Group|MockObject
80+
*/
81+
private $groupModelMock;
82+
83+
/**
84+
* @var FilterManager|MockObject
85+
*/
86+
private $filterManagerMock;
87+
88+
/**
89+
* @var TypeListInterface|MockObject
90+
*/
91+
private $cacheTypeListMock;
92+
93+
/**
94+
* @var Registry|MockObject
95+
*/
96+
private $registryMock;
97+
98+
/**
99+
* @var ForwardFactory|MockObject
100+
*/
101+
private $resultForwardFactoryMock;
102+
103+
/**
104+
* @var PageFactory|MockObject
105+
*/
106+
private $resultPageFactoryMock;
107+
108+
/**
109+
* @inheritDoc
110+
*/
111+
public function setUp(): void
112+
{
113+
$this->requestMock = $this->getMockBuilder(Http::class)
114+
->disableOriginalConstructor()
115+
->onlyMethods(['isPost', 'getPostValue'])
116+
->getMock();
117+
$this->responseMock = $this->getMockBuilder(\Magento\Framework\App\Response\Http::class)
118+
->disableOriginalConstructor()
119+
->getMock();
120+
$this->objectManagerMock = $this->getMockBuilder(ObjectManager::class)
121+
->disableOriginalConstructor()
122+
->onlyMethods(['get', 'create'])
123+
->getMock();
124+
$this->messagesMock = $this->getMockBuilder(ManagerInterface::class)
125+
->disableOriginalConstructor()
126+
->onlyMethods(['addSuccessMessage', 'addErrorMessage'])
127+
->getMockForAbstractClass();
128+
$this->helperMock = $this->getMockBuilder(Data::class)
129+
->disableOriginalConstructor()
130+
->onlyMethods(['getUrl'])
131+
->getMock();
132+
$this->sessionMock = $this->getMockBuilder(Session::class)
133+
->disableOriginalConstructor()
134+
->addMethods(['setPostData'])
135+
->getMock();
136+
$this->storeModelMock = $this->getMockBuilder(Store::class)
137+
->disableOriginalConstructor()
138+
->onlyMethods(['load', 'setData', 'setId', 'getGroupId', 'setWebsiteId', 'isActive', 'isDefault', 'save'])
139+
->getMock();
140+
$this->groupModelMock = $this->getMockBuilder(Group::class)
141+
->disableOriginalConstructor()
142+
->onlyMethods(['load', 'getWebsiteId'])
143+
->getMock();
144+
$this->filterManagerMock = $this->getMockBuilder(FilterManager::class)
145+
->disableOriginalConstructor()
146+
->addMethods(['removeTags'])
147+
->getMock();
148+
$this->cacheTypeListMock = $this->getMockBuilder(TypeListInterface::class)
149+
->disableOriginalConstructor()
150+
->onlyMethods(['cleanType'])
151+
->getMockForAbstractClass();
152+
$this->registryMock = $this->getMockBuilder(Registry::class)
153+
->disableOriginalConstructor()
154+
->getMock();
155+
$this->resultForwardFactoryMock = $this->getMockBuilder(ForwardFactory::class)
156+
->disableOriginalConstructor()
157+
->getMock();
158+
$this->resultPageFactoryMock = $this->getMockBuilder(PageFactory::class)
159+
->disableOriginalConstructor()
160+
->getMock();
161+
$redirectFactory = $this->getMockBuilder(RedirectFactory::class)
162+
->disableOriginalConstructor()
163+
->onlyMethods(['create'])
164+
->getMock();
165+
$resultRedirect = $this->getMockBuilder(Redirect::class)
166+
->disableOriginalConstructor()
167+
->onlyMethods(['setPath', 'setUrl'])
168+
->getMock();
169+
$resultRedirect->expects($this->once())->method('setPath')->willReturnSelf();
170+
$redirectFactory->expects($this->atLeastOnce())->method('create')->willReturn($resultRedirect);
171+
$contextMock = $this->getMockBuilder(Context::class)
172+
->onlyMethods([
173+
'getRequest',
174+
'getResponse',
175+
'getObjectManager',
176+
'getHelper',
177+
'getMessageManager',
178+
'getResultRedirectFactory'
179+
])
180+
->disableOriginalConstructor()
181+
->getMock();
182+
$contextMock->expects($this->once())->method('getRequest')->willReturn($this->requestMock);
183+
$contextMock->expects($this->once())->method('getResponse')->willReturn($this->responseMock);
184+
$contextMock->expects($this->once())->method('getObjectManager')->willReturn($this->objectManagerMock);
185+
$contextMock->expects($this->once())->method('getHelper')->willReturn($this->helperMock);
186+
$contextMock->expects($this->once())->method('getMessageManager')->willReturn($this->messagesMock);
187+
$contextMock->expects($this->once())->method('getResultRedirectFactory')->willReturn($redirectFactory);
188+
$this->controller = new Save(
189+
$contextMock,
190+
$this->registryMock,
191+
$this->filterManagerMock,
192+
$this->resultForwardFactoryMock,
193+
$this->resultPageFactoryMock,
194+
$this->cacheTypeListMock
195+
);
196+
}
197+
198+
/**
199+
* Test saving a store view
200+
*/
201+
public function testSaveAction(): void
202+
{
203+
$storeId = 2;
204+
$requestParams = [
205+
'store_type' => 'store',
206+
'store_action' => 'edit',
207+
'store' => [
208+
'store_id' => $storeId,
209+
'name' => 'Test Store View',
210+
'code' => 'test_store',
211+
'is_active' => 1,
212+
'group_id' => 1
213+
]
214+
];
215+
$this->requestMock->expects($this->once())->method('isPost')->willReturn(true);
216+
$this->requestMock->expects($this->once())->method('getPostValue')->willReturn($requestParams);
217+
$this->filterManagerMock->expects($this->once())
218+
->method('removeTags')
219+
->with($requestParams['store']['name'])
220+
->willReturn($requestParams['store']['name']);
221+
$this->objectManagerMock->expects($this->exactly(2))
222+
->method('create')
223+
->willReturnMap([
224+
[Store::class, $this->storeModelMock],
225+
[Group::class, $this->groupModelMock]
226+
]);
227+
$this->storeModelMock->expects($this->once())->method('load')->with($storeId)->willReturnSelf();
228+
$this->storeModelMock->expects($this->once())->method('setData')->willReturnSelf();
229+
$this->storeModelMock->expects($this->never())->method('setId');
230+
$this->storeModelMock->expects($this->once())->method('getGroupId')->willReturn(1);
231+
$this->storeModelMock->expects($this->once())->method('isActive')->willReturn(true);
232+
$this->storeModelMock->expects($this->once())->method('save')->willReturnSelf();
233+
$this->groupModelMock->expects($this->once())->method('load')->willReturnSelf();
234+
$this->groupModelMock->expects($this->once())->method('getWebsiteId')->willReturn(1);
235+
$this->storeModelMock->expects($this->once())->method('setWebsiteId')->willReturnSelf();
236+
$this->cacheTypeListMock->expects($this->once())->method('cleanType')->with('config');
237+
$this->messagesMock->expects($this->once())
238+
->method('addSuccessMessage')
239+
->with(__('You saved the store view.'));
240+
$this->controller->execute();
241+
}
242+
}

0 commit comments

Comments
 (0)