Skip to content

Commit ce31d48

Browse files
author
mduuude
committed
Merge branch '2.3-develop' into MAGETWO-88600
2 parents 4a15cc3 + 120836e commit ce31d48

File tree

16 files changed

+454
-63
lines changed

16 files changed

+454
-63
lines changed

app/code/Magento/Backend/Block/Widget/Tabs.php

Lines changed: 94 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ public function addTab($tabId, $tab)
117117
if (empty($tabId)) {
118118
throw new \Exception(__('Please correct the tab configuration and try again. Tab Id should be not empty'));
119119
}
120+
120121
if (is_array($tab)) {
121122
$this->_tabs[$tabId] = new \Magento\Framework\DataObject($tab);
122123
} elseif ($tab instanceof \Magento\Framework\DataObject) {
@@ -126,13 +127,15 @@ public function addTab($tabId, $tab)
126127
}
127128
} elseif (is_string($tab)) {
128129
$this->_addTabByName($tab, $tabId);
130+
129131
if (!$this->_tabs[$tabId] instanceof TabInterface) {
130132
unset($this->_tabs[$tabId]);
131133
return $this;
132134
}
133135
} else {
134136
throw new \Exception(__('Please correct the tab configuration and try again.'));
135137
}
138+
136139
if ($this->_tabs[$tabId]->getUrl() === null) {
137140
$this->_tabs[$tabId]->setUrl('#');
138141
}
@@ -143,10 +146,7 @@ public function addTab($tabId, $tab)
143146

144147
$this->_tabs[$tabId]->setId($tabId);
145148
$this->_tabs[$tabId]->setTabId($tabId);
146-
147-
if ($this->_activeTab === null) {
148-
$this->_activeTab = $tabId;
149-
}
149+
150150
if (true === $this->_tabs[$tabId]->getActive()) {
151151
$this->setActiveTab($tabId);
152152
}
@@ -235,33 +235,108 @@ protected function _setActiveTab($tabId)
235235
*/
236236
protected function _beforeToHtml()
237237
{
238+
$this->_tabs = $this->reorderTabs();
239+
238240
if ($activeTab = $this->getRequest()->getParam('active_tab')) {
239241
$this->setActiveTab($activeTab);
240242
} elseif ($activeTabId = $this->_authSession->getActiveTabId()) {
241243
$this->_setActiveTab($activeTabId);
242244
}
243245

244-
$_new = [];
246+
if ($this->_activeTab === null && !empty($this->_tabs)) {
247+
/** @var TabInterface $tab */
248+
$this->_activeTab = (reset($this->_tabs))->getId();
249+
}
250+
251+
$this->assign('tabs', $this->_tabs);
252+
return parent::_beforeToHtml();
253+
}
254+
255+
/**
256+
* Reorder the tabs.
257+
*
258+
* @return array
259+
*/
260+
private function reorderTabs()
261+
{
262+
$orderByIdentity = [];
263+
$orderByPosition = [];
264+
$position = 100;
265+
266+
/**
267+
* Set the initial positions for each tab.
268+
*
269+
* @var string $key
270+
* @var TabInterface $tab
271+
*/
245272
foreach ($this->_tabs as $key => $tab) {
246-
foreach ($this->_tabs as $k => $t) {
247-
if ($t->getAfter() == $key) {
248-
$_new[$key] = $tab;
249-
$_new[$k] = $t;
250-
} else {
251-
if (!$tab->getAfter() || !in_array($tab->getAfter(), array_keys($this->_tabs))) {
252-
$_new[$key] = $tab;
253-
}
254-
}
255-
}
273+
$tab->setPosition($position);
274+
275+
$orderByIdentity[$key] = $tab;
276+
$orderByPosition[$position] = $tab;
277+
278+
$position += 100;
256279
}
257280

258-
$this->_tabs = $_new;
259-
unset($_new);
281+
return $this->applyTabsCorrectOrder($orderByPosition, $orderByIdentity);
282+
}
260283

261-
$this->assign('tabs', $this->_tabs);
262-
return parent::_beforeToHtml();
284+
/**
285+
* @param array $orderByPosition
286+
* @param array $orderByIdentity
287+
*
288+
* @return array
289+
*/
290+
private function applyTabsCorrectOrder(array $orderByPosition, array $orderByIdentity)
291+
{
292+
$positionFactor = 1;
293+
294+
/**
295+
* Rearrange the positions by using the after tag for each tab.
296+
*
297+
* @var integer $position
298+
* @var TabInterface $tab
299+
*/
300+
foreach ($orderByPosition as $position => $tab) {
301+
if (!$tab->getAfter() || !in_array($tab->getAfter(), array_keys($orderByIdentity))) {
302+
$positionFactor = 1;
303+
continue;
304+
}
305+
306+
$grandPosition = $orderByIdentity[$tab->getAfter()]->getPosition();
307+
$newPosition = $grandPosition + $positionFactor;
308+
309+
unset($orderByPosition[$position]);
310+
$orderByPosition[$newPosition] = $tab;
311+
$tab->setPosition($newPosition);
312+
313+
$positionFactor++;
314+
}
315+
316+
return $this->finalTabsSortOrder($orderByPosition);
263317
}
264318

319+
/**
320+
* Apply the last sort order to tabs.
321+
*
322+
* @param array $orderByPosition
323+
*
324+
* @return array
325+
*/
326+
private function finalTabsSortOrder(array $orderByPosition)
327+
{
328+
ksort($orderByPosition);
329+
330+
$ordered = [];
331+
332+
/** @var TabInterface $tab */
333+
foreach ($orderByPosition as $tab) {
334+
$ordered[$tab->getId()] = $tab;
335+
}
336+
337+
return $ordered;
338+
}
339+
265340
/**
266341
* @return string
267342
*/

app/code/Magento/Catalog/Controller/Adminhtml/Category/RefreshPath.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ public function execute()
3838

3939
/** @var \Magento\Framework\Controller\Result\Json $resultJson */
4040
$resultJson = $this->resultJsonFactory->create();
41-
return $resultJson->setData(['id' => $categoryId, 'path' => $category->getPath()]);
41+
return $resultJson->setData([
42+
'id' => $categoryId,
43+
'path' => $category->getPath(),
44+
'parentId' => $category->getParentId(),
45+
]);
4246
}
4347
}
4448
}

app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ public function execute()
139139
$parentId = isset($categoryPostData['parent']) ? $categoryPostData['parent'] : null;
140140
if ($categoryPostData) {
141141
$category->addData($categoryPostData);
142+
if ($parentId) {
143+
$category->setParentId($parentId);
144+
}
142145
if ($isNewCategory) {
143146
$parentCategory = $this->getParentCategory($parentId, $storeId);
144147
$category->setPath($parentCategory->getPath());
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Category;
10+
11+
use Magento\Framework\Controller\Result\JsonFactory;
12+
use Magento\Catalog\Controller\Adminhtml\Category\RefreshPath;
13+
use Magento\Backend\App\Action\Context;
14+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
15+
16+
/**
17+
* Test for class Magento\Catalog\Controller\Adminhtml\Category\RefreshPath.
18+
*/
19+
class RefreshPathTest extends \PHPUnit\Framework\TestCase
20+
{
21+
/**
22+
* @var JsonFactory|\PHPUnit_Framework_MockObject_MockObject
23+
*/
24+
private $resultJsonFactoryMock;
25+
26+
/**
27+
* @var Context|\PHPUnit_Framework_MockObject_MockObject
28+
*/
29+
private $contextMock;
30+
31+
/**
32+
* @inheritDoc
33+
*/
34+
protected function setUp()
35+
{
36+
$this->resultJsonFactoryMock = $this->getMockBuilder(JsonFactory::class)
37+
->disableOriginalConstructor()
38+
->setMethods(['create', 'setData'])
39+
->getMock();
40+
41+
$this->contextMock = $this->getMockBuilder(Context::class)
42+
->disableOriginalConstructor()
43+
->setMethods(['getRequest'])
44+
->getMock();
45+
}
46+
47+
/**
48+
* Sets object non-public property.
49+
*
50+
* @param mixed $object
51+
* @param string $propertyName
52+
* @param mixed $value
53+
*
54+
* @return void
55+
*/
56+
private function setObjectProperty($object, string $propertyName, $value) : void
57+
{
58+
$reflectionClass = new \ReflectionClass($object);
59+
$reflectionProperty = $reflectionClass->getProperty($propertyName);
60+
$reflectionProperty->setAccessible(true);
61+
$reflectionProperty->setValue($object, $value);
62+
}
63+
64+
/**
65+
* @return void
66+
*/
67+
public function testExecute() : void
68+
{
69+
$value = ['id' => 3, 'path' => '1/2/3', 'parentId' => 2];
70+
$result = '{"id":3,"path":"1/2/3","parentId":"2"}';
71+
72+
$requestMock = $this->getMockForAbstractClass(\Magento\Framework\App\RequestInterface::class);
73+
74+
$refreshPath = $this->getMockBuilder(RefreshPath::class)
75+
->setMethods(['getRequest', 'create'])
76+
->setConstructorArgs([
77+
$this->contextMock,
78+
$this->resultJsonFactoryMock,
79+
])->getMock();
80+
81+
$refreshPath->expects($this->any())->method('getRequest')->willReturn($requestMock);
82+
$requestMock->expects($this->any())->method('getParam')->with('id')->willReturn($value['id']);
83+
84+
$categoryMock = $this->getMockBuilder(\Magento\Catalog\Model\Category::class)
85+
->disableOriginalConstructor()
86+
->setMethods(['getPath', 'getParentId', 'getResource'])
87+
->getMock();
88+
89+
$categoryMock->expects($this->any())->method('getPath')->willReturn($value['path']);
90+
$categoryMock->expects($this->any())->method('getParentId')->willReturn($value['parentId']);
91+
92+
$categoryResource = $this->createMock(\Magento\Catalog\Model\ResourceModel\Category::class);
93+
94+
$objectManagerMock = $this->getMockBuilder(ObjectManager::class)
95+
->disableOriginalConstructor()
96+
->setMethods(['create'])
97+
->getMock();
98+
99+
$this->setObjectProperty($refreshPath, '_objectManager', $objectManagerMock);
100+
$this->setObjectProperty($categoryMock, '_resource', $categoryResource);
101+
102+
$objectManagerMock->expects($this->once())
103+
->method('create')
104+
->with(\Magento\Catalog\Model\Category::class)
105+
->willReturn($categoryMock);
106+
107+
$this->resultJsonFactoryMock->expects($this->any())->method('create')->willReturnSelf();
108+
$this->resultJsonFactoryMock->expects($this->any())
109+
->method('setData')
110+
->with($value)
111+
->willReturn($result);
112+
113+
$this->assertEquals($result, $refreshPath->execute());
114+
}
115+
116+
/**
117+
* @return void
118+
*/
119+
public function testExecuteWithoutCategoryId() : void
120+
{
121+
$requestMock = $this->getMockForAbstractClass(\Magento\Framework\App\RequestInterface::class);
122+
123+
$refreshPath = $this->getMockBuilder(RefreshPath::class)
124+
->setMethods(['getRequest', 'create'])
125+
->setConstructorArgs([
126+
$this->contextMock,
127+
$this->resultJsonFactoryMock,
128+
])->getMock();
129+
130+
$refreshPath->expects($this->any())->method('getRequest')->willReturn($requestMock);
131+
$requestMock->expects($this->any())->method('getParam')->with('id')->willReturn(null);
132+
133+
$objectManagerMock = $this->getMockBuilder(ObjectManager::class)
134+
->disableOriginalConstructor()
135+
->setMethods(['create'])
136+
->getMock();
137+
138+
$this->setObjectProperty($refreshPath, '_objectManager', $objectManagerMock);
139+
140+
$objectManagerMock->expects($this->never())
141+
->method('create')
142+
->with(\Magento\Catalog\Model\Category::class)
143+
->willReturnSelf();
144+
145+
$refreshPath->execute();
146+
}
147+
}

0 commit comments

Comments
 (0)