Skip to content

Commit 903e7a4

Browse files
committed
Merge remote-tracking branch 'origin/MAGETWO-90940' into 2.2-develop-pr33
2 parents 6fc3812 + 3416f46 commit 903e7a4

File tree

7 files changed

+164
-27
lines changed

7 files changed

+164
-27
lines changed

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

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,27 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
7+
68
namespace Magento\Catalog\Controller\Adminhtml;
79

10+
use Magento\Store\Model\Store;
11+
use Magento\Backend\App\Action\Context;
12+
use Magento\Framework\Stdlib\DateTime\Filter\Date;
13+
use Magento\Catalog\Model\Category as CategoryModel;
14+
use Magento\Backend\App\Action;
15+
use Magento\Store\Model\StoreManagerInterface;
16+
use Magento\Framework\Registry;
17+
use Magento\Cms\Model\Wysiwyg\Config;
18+
use Magento\Backend\Model\View\Result\Page;
19+
use Magento\Framework\Controller\Result\Json;
20+
use Magento\Backend\Model\Auth\Session;
21+
use Magento\Framework\DataObject;
22+
823
/**
924
* Catalog category controller
1025
*/
11-
abstract class Category extends \Magento\Backend\App\Action
26+
abstract class Category extends Action
1227
{
1328
/**
1429
* Authorization level of a basic admin session
@@ -18,18 +33,16 @@ abstract class Category extends \Magento\Backend\App\Action
1833
const ADMIN_RESOURCE = 'Magento_Catalog::categories';
1934

2035
/**
21-
* @var \Magento\Framework\Stdlib\DateTime\Filter\Date
36+
* @var Date
2237
*/
2338
protected $dateFilter;
2439

2540
/**
26-
* @param \Magento\Backend\App\Action\Context $context
27-
* @param \Magento\Framework\Stdlib\DateTime\Filter\Date|null $dateFilter
41+
* @param Context $context
42+
* @param Date|null $dateFilter
2843
*/
29-
public function __construct(
30-
\Magento\Backend\App\Action\Context $context,
31-
\Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter = null
32-
) {
44+
public function __construct(Context $context, Date $dateFilter = null)
45+
{
3346
$this->dateFilter = $dateFilter;
3447
parent::__construct($context);
3548
}
@@ -39,20 +52,20 @@ public function __construct(
3952
* Root category can be returned, if inappropriate store/category is specified
4053
*
4154
* @param bool $getRootInstead
42-
* @return \Magento\Catalog\Model\Category|false
55+
* @return CategoryModel|false
4356
*/
44-
protected function _initCategory($getRootInstead = false)
57+
protected function _initCategory(bool $getRootInstead = false)
4558
{
4659
$categoryId = $this->resolveCategoryId();
47-
$storeId = (int)$this->getRequest()->getParam('store');
48-
$category = $this->_objectManager->create(\Magento\Catalog\Model\Category::class);
60+
$storeId = $this->resolveStoreId();
61+
$category = $this->_objectManager->create(CategoryModel::class);
4962
$category->setStoreId($storeId);
5063

5164
if ($categoryId) {
5265
$category->load($categoryId);
5366
if ($storeId) {
5467
$rootId = $this->_objectManager->get(
55-
\Magento\Store\Model\StoreManagerInterface::class
68+
StoreManagerInterface::class
5669
)->getStore(
5770
$storeId
5871
)->getRootCategoryId();
@@ -67,9 +80,9 @@ protected function _initCategory($getRootInstead = false)
6780
}
6881
}
6982

70-
$this->_objectManager->get(\Magento\Framework\Registry::class)->register('category', $category);
71-
$this->_objectManager->get(\Magento\Framework\Registry::class)->register('current_category', $category);
72-
$this->_objectManager->get(\Magento\Cms\Model\Wysiwyg\Config::class)
83+
$this->_objectManager->get(Registry::class)->register('category', $category);
84+
$this->_objectManager->get(Registry::class)->register('current_category', $category);
85+
$this->_objectManager->get(Config::class)
7386
->setStoreId($this->getRequest()->getParam('store'));
7487
return $category;
7588
}
@@ -79,31 +92,46 @@ protected function _initCategory($getRootInstead = false)
7992
*
8093
* @return int
8194
*/
82-
private function resolveCategoryId()
95+
private function resolveCategoryId(): int
8396
{
8497
$categoryId = (int)$this->getRequest()->getParam('id', false);
8598

8699
return $categoryId ?: (int)$this->getRequest()->getParam('entity_id', false);
87100
}
88101

102+
/**
103+
* Resolve store id
104+
*
105+
* Tries to take store id from store HTTP parameter
106+
* @see Store
107+
*
108+
* @return int
109+
*/
110+
private function resolveStoreId(): int
111+
{
112+
$storeId = (int)$this->getRequest()->getParam('store', false);
113+
114+
return $storeId ?: (int)$this->getRequest()->getParam('store_id', Store::DEFAULT_STORE_ID);
115+
}
116+
89117
/**
90118
* Build response for ajax request
91119
*
92-
* @param \Magento\Catalog\Model\Category $category
93-
* @param \Magento\Backend\Model\View\Result\Page $resultPage
120+
* @param CategoryModel $category
121+
* @param Page $resultPage
94122
*
95-
* @return \Magento\Framework\Controller\Result\Json
123+
* @return Json
96124
*
97125
* @deprecated 101.0.0
98126
*/
99-
protected function ajaxRequestResponse($category, $resultPage)
127+
protected function ajaxRequestResponse(CategoryModel $category, Page $resultPage): Json
100128
{
101129
// prepare breadcrumbs of selected category, if any
102130
$breadcrumbsPath = $category->getPath();
103131
if (empty($breadcrumbsPath)) {
104132
// but if no category, and it is deleted - prepare breadcrumbs from path, saved in session
105133
$breadcrumbsPath = $this->_objectManager->get(
106-
\Magento\Backend\Model\Auth\Session::class
134+
Session::class
107135
)->getDeletedPath(
108136
true
109137
);
@@ -119,7 +147,7 @@ protected function ajaxRequestResponse($category, $resultPage)
119147
}
120148
}
121149

122-
$eventResponse = new \Magento\Framework\DataObject([
150+
$eventResponse = new DataObject([
123151
'content' => $resultPage->getLayout()->getUiComponent('category_form')->getFormHtml()
124152
. $resultPage->getLayout()->getBlock('category.tree')
125153
->getBreadcrumbsJavascript($breadcrumbsPath, 'editingCategoryBreadcrumbs'),
@@ -130,22 +158,23 @@ protected function ajaxRequestResponse($category, $resultPage)
130158
'category_prepare_ajax_response',
131159
['response' => $eventResponse, 'controller' => $this]
132160
);
133-
/** @var \Magento\Framework\Controller\Result\Json $resultJson */
134-
$resultJson = $this->_objectManager->get(\Magento\Framework\Controller\Result\Json::class);
161+
/** @var Json $resultJson */
162+
$resultJson = $this->_objectManager->get(Json::class);
135163
$resultJson->setHeader('Content-type', 'application/json', true);
136164
$resultJson->setData($eventResponse->getData());
165+
137166
return $resultJson;
138167
}
139168

140169
/**
141170
* Datetime data preprocessing
142171
*
143-
* @param \Magento\Catalog\Model\Category $category
172+
* @param CategoryModel $category
144173
* @param array $postData
145174
*
146175
* @return array
147176
*/
148-
protected function dateTimePreprocessing($category, $postData)
177+
protected function dateTimePreprocessing(CategoryModel $category, array $postData): array
149178
{
150179
$dateFieldFilters = [];
151180
$attributes = $category->getAttributes();

dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminCategoryActionGroup.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,21 @@
4141
<click selector="{{AdminCategorySidebarTreeSection.expandAll}}" stepKey="expandToSeeAllCategories"/>
4242
<dontSee selector="{{AdminCategorySidebarTreeSection.categoryInTree(categoryEntity.name)}}" stepKey="dontSeeCategoryInTree"/>
4343
</actionGroup>
44+
<!--Actions to switch store view in category edit page-->
45+
<actionGroup name="switchCategoryStoreView">
46+
<arguments>
47+
<argument name="store"/>
48+
<argument name="catName"/>
49+
</arguments>
50+
<amOnPage url="{{AdminCategoryPage.url}}" stepKey="amOnCategoryPage"/>
51+
<waitForPageLoad stepKey="waitForPageLoad1"/>
52+
<click selector="{{AdminCategorySidebarTreeSection.categoryInTree(catName)}}" stepKey="navigateToCreatedCategory"/>
53+
<waitForPageLoad stepKey="waitForPageLoad2"/>
54+
<scrollToTopOfPage stepKey="scrollToToggle"/>
55+
<click selector="{{AdminCategoryMainActionsSection.categoryStoreViewDropdownToggle}}" stepKey="openStoreViewDropDown"/>
56+
<click selector="{{AdminCategoryMainActionsSection.categoryStoreViewOption(store)}}" stepKey="selectStoreView"/>
57+
<waitForPageLoad stepKey="waitForPageLoad3"/>
58+
<click selector="{{AdminCategoryMainActionsSection.categoryStoreViewModalAccept}}" stepKey="selectStoreViewAccept"/>
59+
<waitForPageLoad stepKey="waitForStoreViewChangeLoad"/>
60+
</actionGroup>
4461
</actionGroups>

dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCategoryBasicFieldSection.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111
<section name="AdminCategoryBasicFieldSection">
1212
<element name="IncludeInMenu" type="checkbox" selector="input[name='include_in_menu']"/>
1313
<element name="includeInMenuLabel" type="text" selector="input[name='include_in_menu']+label"/>
14+
<element name="includeInMenuUseDefault" type="checkbox" selector="input[name='use_default[include_in_menu]']"/>
1415
<element name="EnableCategory" type="checkbox" selector="input[name='is_active']"/>
1516
<element name="enableCategoryLabel" type="text" selector="input[name='is_active']+label"/>
17+
<element name="enableUseDefault" type="checkbox" selector="input[name='use_default[is_active]']"/>
1618
<element name="CategoryNameInput" type="input" selector="input[name='name']"/>
19+
<element name="categoryNameUseDefault" type="checkbox" selector="input[name='use_default[name]']"/>
1720
</section>
1821
<section name="CatalogWYSIWYGSection">
1922
<element name="ShowHideBtn" type="button" selector="#togglecategory_form_description"/>

dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCategoryMainActionsSection.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,8 @@
1111
<section name="AdminCategoryMainActionsSection">
1212
<element name="SaveButton" type="button" selector=".page-actions-inner #save" timeout="30"/>
1313
<element name="DeleteButton" type="button" selector=".page-actions-inner #delete" timeout="30"/>
14+
<element name="categoryStoreViewDropdownToggle" type="button" selector="#store-change-button"/>
15+
<element name="categoryStoreViewOption" type="button" selector="//div[contains(@class, 'store-switcher')]//a[normalize-space()='{{store}}']" parameterized="true"/>
16+
<element name="categoryStoreViewModalAccept" type="button" selector=".modal-popup.confirm._show .action-accept"/>
1417
</section>
1518
</sections>

dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCategorySEOSection.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
<section name="AdminCategorySEOSection">
1212
<element name="SectionHeader" type="button" selector="div[data-index='search_engine_optimization']" timeout="30"/>
1313
<element name="UrlKeyInput" type="input" selector="input[name='url_key']"/>
14+
<element name="urlKeyDefaultValueCheckbox" type="button" selector="input[name='use_default[url_key]']"/>
15+
<element name="urlKeyRedirectCheckbox" type="button" selector="[data-index='url_key_create_redirect'] input[type='checkbox']"/>
1416
<element name="MetaTitleInput" type="input" selector="input[name='meta_title']"/>
1517
<element name="MetaKeywordsInput" type="textarea" selector="textarea[name='meta_keywords']"/>
1618
<element name="MetaDescriptionInput" type="textarea" selector="textarea[name='meta_description']"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd">
11+
<test name="AdminUpdateCategoryStoreUrlKeyTest">
12+
<annotations>
13+
<features value="SEO-friendly URL Key Update"/>
14+
<stories value="Update SEO-friendly URL via the Admin"/>
15+
<title value="SEO-friendly URL should update regardless of scope or redirect change."/>
16+
<description value="SEO-friendly URL should update regardless of scope or redirect change."/>
17+
<severity value="CRITICAL"/>
18+
<testCaseId value="MAGETWO-92916"/>
19+
<group value="category"/>
20+
</annotations>
21+
<before>
22+
<!-- Create category -->
23+
<actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>
24+
<amOnPage url="{{AdminCategoryPage.url}}" stepKey="navigateToCategoryPage"/>
25+
<waitForPageLoad stepKey="waitForPageLoad1"/>
26+
<actionGroup ref="CreateCategory" stepKey="createCategory">
27+
<argument name="categoryEntity" value="_defaultCategory"/>
28+
</actionGroup>
29+
</before>
30+
<after>
31+
<!-- Delete category and logout from admin account -->
32+
<actionGroup ref="DeleteCategory" stepKey="deleteCategory">
33+
<argument name="categoryEntity" value="_defaultCategory"/>
34+
</actionGroup>
35+
<amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/>
36+
</after>
37+
38+
<!--Switch to "Default Store View" scope-->
39+
<actionGroup ref="switchCategoryStoreView" stepKey="SwitchStoreView">
40+
<argument name="store" value="_defaultStore.name"/>
41+
<argument name="catName" value="_defaultCategory.name"/>
42+
</actionGroup>
43+
<!--See "Use Default Value" checkboxes-->
44+
<seeElement selector="{{AdminCategoryBasicFieldSection.enableUseDefault}}" stepKey="seeUseDefaultEnable"/>
45+
<seeElement selector="{{AdminCategoryBasicFieldSection.includeInMenuUseDefault}}" stepKey="seeUseDefaultMenu"/>
46+
<seeElement selector="{{AdminCategoryBasicFieldSection.categoryNameUseDefault}}" stepKey="seeUseDefaultName"/>
47+
<!-- Update SEO key, uncheck "Create Redirect", confirm in frontend -->
48+
<click selector="{{AdminCategorySEOSection.SectionHeader}}" stepKey="openSeoSection"/>
49+
<uncheckOption selector="{{AdminCategorySEOSection.urlKeyDefaultValueCheckbox}}" stepKey="uncheckUseDefaultUrlKey"/>
50+
<fillField selector="{{AdminCategorySEOSection.UrlKeyInput}}" userInput="{{_defaultCategory.name_lwr}}-hattest" stepKey="enterURLKey"/>
51+
<uncheckOption selector="{{AdminCategorySEOSection.urlKeyRedirectCheckbox}}" stepKey="uncheckRedirect1"/>
52+
<click selector="{{AdminCategoryMainActionsSection.SaveButton}}" stepKey="saveCategoryAfterFirstSeoUpdate"/>
53+
<seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="assertSuccessMessage"/>
54+
<amOnPage url="" stepKey="goToStorefront"/>
55+
<waitForPageLoad stepKey="waitForFrontendLoad"/>
56+
<click selector="{{StorefrontHeaderSection.NavigationCategoryByName(_defaultCategory.name)}}" stepKey="clickCategory"/>
57+
<see selector="{{StorefrontCategoryMainSection.CategoryTitle}}" userInput="{{_defaultCategory.name}}" stepKey="assertCategoryOnStorefront"/>
58+
<seeInTitle userInput="{{_defaultCategory.name}}" stepKey="seeCategoryNameInTitle"/>
59+
<seeInCurrentUrl stepKey="verifyUrlKey" url="{{_defaultCategory.name_lwr}}-hattest.html"/>
60+
<!-- Update SEO key to original, uncheck "Create Redirect", confirm in frontend -->
61+
<!--Switch to "Default Store View" scope-->
62+
<actionGroup ref="switchCategoryStoreView" stepKey="SwitchStoreView2">
63+
<argument name="store" value="_defaultStore.name"/>
64+
<argument name="catName" value="_defaultCategory.name"/>
65+
</actionGroup>
66+
<click selector="{{AdminCategorySEOSection.SectionHeader}}" stepKey="openSeoSection2"/>
67+
<fillField selector="{{AdminCategorySEOSection.UrlKeyInput}}" userInput="{{_defaultCategory.name_lwr}}" stepKey="enterOriginalURLKey"/>
68+
<uncheckOption selector="{{AdminCategorySEOSection.urlKeyRedirectCheckbox}}" stepKey="uncheckRedirect2"/>
69+
<click selector="{{AdminCategoryMainActionsSection.SaveButton}}" stepKey="saveCategoryAfterOriginalSeoKey"/>
70+
<seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="assertSuccessMessageAfterOriginalSeoKey"/>
71+
<amOnPage url="" stepKey="goToStorefrontAfterOriginalSeoKey"/>
72+
<waitForPageLoad stepKey="waitForFrontendLoadAfterOriginalSeoKey"/>
73+
<click selector="{{StorefrontHeaderSection.NavigationCategoryByName(_defaultCategory.name)}}" stepKey="clickCategoryAfterOriginalSeoKey"/>
74+
<see selector="{{StorefrontCategoryMainSection.CategoryTitle}}" userInput="{{_defaultCategory.name}}" stepKey="assertCategoryOnStorefront2"/>
75+
<seeInTitle userInput="{{_defaultCategory.name}}" stepKey="seeCategoryNameInTitle2"/>
76+
<seeInCurrentUrl url="{{_defaultCategory.name_lwr}}.html" stepKey="verifyUrlKeyAfterOriginalSeoKey"/>
77+
</test>
78+
</tests>

dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Data/StoreData.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
*/
77
-->
88
<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd">
9+
<entity name="_defaultStore" type="store">
10+
<data key="name">Default Store View</data>
11+
<data key="code">default</data>
12+
<data key="is_active">1</data>
13+
</entity>
914
<entity name="customStore" type="store">
1015
<!--data key="group_id">customStoreGroup.id</data-->
1116
<data key="name" unique="suffix">store</data>

0 commit comments

Comments
 (0)