Skip to content

Commit 4439514

Browse files
committed
Merge branch 'ACP2E-1854' of https://github.com/magento-l3/magento2ce into PR-VK-2023-09-29
2 parents c0a8275 + eee9fb8 commit 4439514

File tree

13 files changed

+335
-22
lines changed

13 files changed

+335
-22
lines changed

app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Front.php

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Magento\Catalog\Model\Entity\Attribute;
1414
use Magento\Eav\Block\Adminhtml\Attribute\PropertyLocker;
1515
use Magento\Framework\Data\FormFactory;
16+
use Magento\Framework\Exception\LocalizedException;
1617
use Magento\Framework\Registry;
1718

1819
/**
@@ -58,6 +59,7 @@ public function __construct(
5859
* @inheritDoc
5960
* @return $this
6061
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
62+
* @throws LocalizedException
6163
*/
6264
protected function _prepareForm()
6365
{
@@ -176,28 +178,34 @@ protected function _prepareForm()
176178
['form' => $form, 'attribute' => $attributeObject]
177179
);
178180

181+
$dependencies = $this->getLayout()->createBlock(
182+
\Magento\Backend\Block\Widget\Form\Element\Dependence::class
183+
)->addFieldMap(
184+
"is_html_allowed_on_front",
185+
'html_allowed_on_front'
186+
)->addFieldMap(
187+
"frontend_input",
188+
'frontend_input_type'
189+
)->addFieldMap(
190+
"is_searchable",
191+
'searchable'
192+
)->addFieldMap(
193+
"is_visible_in_advanced_search",
194+
'advanced_search'
195+
)->addFieldDependence(
196+
'advanced_search',
197+
'searchable',
198+
'1'
199+
);
200+
$this->_eventManager->dispatch(
201+
'adminhtml_catalog_product_attribute_edit_frontend_prepare_field_dependencies',
202+
['dependencies' => $dependencies]
203+
);
204+
179205
// define field dependencies
180206
$this->setChild(
181207
'form_after',
182-
$this->getLayout()->createBlock(
183-
\Magento\Backend\Block\Widget\Form\Element\Dependence::class
184-
)->addFieldMap(
185-
"is_html_allowed_on_front",
186-
'html_allowed_on_front'
187-
)->addFieldMap(
188-
"frontend_input",
189-
'frontend_input_type'
190-
)->addFieldMap(
191-
"is_searchable",
192-
'searchable'
193-
)->addFieldMap(
194-
"is_visible_in_advanced_search",
195-
'advanced_search'
196-
)->addFieldDependence(
197-
'advanced_search',
198-
'searchable',
199-
'1'
200-
)
208+
$dependencies
201209
);
202210

203211
$this->setForm($form);

app/code/Magento/Catalog/Test/Mftf/Test/SavingCustomAttributeValuesUsingUITest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
<actionGroup ref="AdminSetProductAttributeUseInLayeredNavigationOptionActionGroup" stepKey="setDropdownUseInLayeredNavigationNoResults">
5656
<argument name="useInLayeredNavigationValue" value="Filterable (with results)"/>
5757
</actionGroup>
58+
<selectOption selector="{{AdvancedAttributePropertiesSection.UseInSearch}}" userInput="Yes" stepKey="selectIsSearchAble"/>
5859
<selectOption selector="{{AttributePropertiesSection.useInSearchResultsLayeredNavigation}}" userInput="Yes" stepKey="selectUseInLayeredNavigationOption"/>
5960
<click stepKey="saveAttribute" selector="{{AttributePropertiesSection.Save}}"/>
6061

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
10+
<test name="QuickSearchProductByAttributeNotSearchableUsedInLayeredNavigationTest">
11+
<annotations>
12+
<stories value="Search Product on Storefront"/>
13+
<title value="Products should not appear in search results when search by attribute value if attribute has the Use in search set to No"/>
14+
<description value="A product should not be searchable by attribute value if attribute has 'Use in search' to 'No' even if 'Use in Layered Navigation is set"/>
15+
<severity value="MAJOR"/>
16+
<testCaseId value="AC-9146"/>
17+
<group value="CatalogSearch"/>
18+
</annotations>
19+
<before>
20+
<!--Create category, attribute set with multiselect product attribute with two options-->
21+
<createData entity="SimpleSubCategory" stepKey="createCategory"/>
22+
<createData entity="CatalogAttributeSet" stepKey="createAttributeSet"/>
23+
<createData entity="multipleSelectProductAttribute" stepKey="createMultiselectAttribute"/>
24+
<createData entity="ProductAttributeOption10" stepKey="firstMultiselectOption">
25+
<requiredEntity createDataKey="createMultiselectAttribute"/>
26+
</createData>
27+
<createData entity="ProductAttributeOption11" stepKey="secondMultiselectOption">
28+
<requiredEntity createDataKey="createMultiselectAttribute"/>
29+
</createData>
30+
<getData entity="ProductAttributeOptionGetter" index="1" stepKey="getFirstMultiselectOption">
31+
<requiredEntity createDataKey="createMultiselectAttribute"/>
32+
</getData>
33+
<getData entity="ProductAttributeOptionGetter" index="2" stepKey="getSecondMultiselectOption">
34+
<requiredEntity createDataKey="createMultiselectAttribute"/>
35+
</getData>
36+
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
37+
<amOnPage url="{{AdminProductAttributeSetEditPage.url}}/$createAttributeSet.attribute_set_id$/" stepKey="onAttributeSetEdit"/>
38+
<waitForPageLoad stepKey="waitForAttributeSetPageLoad"/>
39+
<actionGroup ref="AssignAttributeToGroupActionGroup" stepKey="assignMultiselectAttributeToGroup">
40+
<argument name="group" value="Product Details"/>
41+
<argument name="attribute" value="$createMultiselectAttribute.attribute_code$"/>
42+
</actionGroup>
43+
<actionGroup ref="SaveAttributeSetActionGroup" stepKey="saveAttributeSet"/>
44+
45+
<!-- Create simple product with multiselect attribute -->
46+
<createData entity="SimpleOne" storeCode="all" stepKey="createFirstSimpleProduct">
47+
<field key="attribute_set_id">$createAttributeSet.attribute_set_id$</field>
48+
<requiredEntity createDataKey="createMultiselectAttribute"/>
49+
<requiredEntity createDataKey="getFirstMultiselectOption"/>
50+
<requiredEntity createDataKey="createCategory"/>
51+
</createData>
52+
</before>
53+
<after>
54+
<deleteData createDataKey="createFirstSimpleProduct" stepKey="deleteFirstSimpleProduct"/>
55+
<deleteData createDataKey="createMultiselectAttribute" stepKey="deleteMultiselectAttribute"/>
56+
<deleteData createDataKey="createAttributeSet" stepKey="deleteAttributeSet"/>
57+
<deleteData createDataKey="createCategory" stepKey="deleteCategory"/>
58+
<magentoCron groups="index" stepKey="reindexInvalidatedIndices"/>
59+
<actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/>
60+
</after>
61+
62+
<!-- Set Use in layered navigation for attribute to Filterable -->
63+
<actionGroup ref="OpenProductAttributeFromSearchResultInGridActionGroup" stepKey="goToDropdownAttributePage">
64+
<argument name="productAttributeCode" value="$createMultiselectAttribute.attribute_code$"/>
65+
</actionGroup>
66+
<actionGroup ref="AdminSetUseInSearchValueForProductAttributeActionGroup" stepKey="makeAttributeUnsearchableInAQuickSearch">
67+
<argument name="useInSearchValue" value="No"/>
68+
</actionGroup>
69+
<actionGroup ref="AdminSetProductAttributeUseInLayeredNavigationOptionActionGroup" stepKey="setDropdownUseInLayeredNavigationNoResults">
70+
<argument name="useInLayeredNavigationValue" value="Filterable (no results)"/>
71+
</actionGroup>
72+
<actionGroup ref="AdminProductAttributeSaveActionGroup" stepKey="saveMultiSelectAttribute"/>
73+
74+
<!-- Perform search with attribute value -->
75+
<actionGroup ref="StorefrontOpenHomePageActionGroup" stepKey="goToFrontPage"/>
76+
<actionGroup ref="StorefrontCheckQuickSearchStringActionGroup" stepKey="searchStorefront">
77+
<argument name="phrase" value="$getFirstMultiselectOption.label$"/>
78+
</actionGroup>
79+
80+
<!-- Should not see any search results -->
81+
<dontSee userInput="$$createFirstSimpleProduct.sku$$" selector="{{StorefrontCatalogSearchMainSection.searchResults}}" stepKey="dontSeeProduct"/>
82+
<see selector="{{StorefrontCatalogSearchMainSection.message}}" userInput="Your search returned no results." stepKey="seeCantFindProductOneMessage"/>
83+
</test>
84+
</tests>

app/code/Magento/CatalogSearch/etc/search_request.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@
2020
<queryReference clause="must" ref="visibility"/>
2121
</query>
2222
<query xsi:type="matchQuery" value="$search_term$" name="search">
23-
<match field="*"/>
23+
<match field="name" matchCondition="match_phrase_prefix"/>
2424
</query>
2525
<query xsi:type="matchQuery" value="$search_term$" name="partial_search">
26-
<match field="*"/>
2726
<match field="name" matchCondition="match_phrase_prefix"/>
2827
<match field="sku" matchCondition="match_phrase_prefix"/>
2928
</query>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\LayeredNavigation\Observer\Edit\Tab\Front;
9+
10+
use Magento\Framework\Module\Manager;
11+
use Magento\Framework\Event\ObserverInterface;
12+
use Magento\Framework\Event\Observer;
13+
use Magento\Framework\View\Element\BlockInterface;
14+
15+
class ProductAttributeFormBuildFormFieldDependenciesObserver implements ObserverInterface
16+
{
17+
/**
18+
* @var Manager
19+
*/
20+
protected Manager $moduleManager;
21+
22+
/**
23+
* @param Manager $moduleManager
24+
*/
25+
public function __construct(Manager $moduleManager)
26+
{
27+
$this->moduleManager = $moduleManager;
28+
}
29+
30+
/**
31+
* Adds field related dependencies in the administrator attribute edit form
32+
*
33+
* @param Observer $observer
34+
* @return void
35+
*/
36+
public function execute(Observer $observer)
37+
{
38+
if (!$this->moduleManager->isOutputEnabled('Magento_LayeredNavigation')) {
39+
return;
40+
}
41+
/** @var BlockInterface $dependencies */
42+
$dependencies = $observer->getDependencies();
43+
$dependencies->addFieldMap('is_filterable_in_search', 'filterable_in_search');
44+
$dependencies->addFieldDependence(
45+
'filterable_in_search',
46+
'searchable',
47+
'1'
48+
);
49+
}
50+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\LayeredNavigation\Plugin\Save;
9+
10+
use Magento\Catalog\Model\Product\Attribute\Frontend\Inputtype\Presentation;
11+
12+
class AdjustAttributeSearchable
13+
{
14+
/**
15+
* Change attribute value if the filterable option is not enabled
16+
*
17+
* @param Presentation $subject
18+
* @param array $result
19+
* @return array
20+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
21+
*/
22+
public function afterConvertPresentationDataToInputType(Presentation $subject, array $result): array
23+
{
24+
if (isset($result['is_filterable_in_search']) &&
25+
$result['is_filterable_in_search'] == '1' &&
26+
$result['is_searchable'] == '0'
27+
) {
28+
$result['is_filterable_in_search'] = '0';
29+
}
30+
31+
return $result;
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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\LayeredNavigation\Test\Unit\Observer\Edit\Tab\Front;
10+
11+
use Magento\Backend\Block\Widget\Form\Element\Dependence;
12+
use Magento\Framework\Event\Observer;
13+
use Magento\Framework\Module\Manager;
14+
use Magento\LayeredNavigation\Observer\Edit\Tab\Front\ProductAttributeFormBuildFormFieldDependenciesObserver;
15+
use PHPUnit\Framework\MockObject\MockObject;
16+
use PHPUnit\Framework\TestCase;
17+
18+
class ProductAttributeFormBuildFormFieldDependenciesObserverTest extends TestCase
19+
{
20+
/**
21+
* @var MockObject|Manager
22+
*/
23+
private Manager $moduleManager;
24+
/**
25+
* @var MockObject|Observer
26+
*/
27+
private Observer $event;
28+
29+
/**
30+
* @var MockObject|ProductAttributeFormBuildFormFieldDependenciesObserver
31+
*/
32+
private ProductAttributeFormBuildFormFieldDependenciesObserver $observer;
33+
34+
/**
35+
* @inheritDoc
36+
*/
37+
protected function setUp(): void
38+
{
39+
$this->moduleManager = $this->createMock(Manager::class);
40+
$this->event = $this->getMockBuilder(Observer::class)
41+
->disableOriginalConstructor()
42+
->addMethods(['getDependencies'])
43+
->getMock();
44+
$this->observer = new ProductAttributeFormBuildFormFieldDependenciesObserver($this->moduleManager);
45+
46+
parent::setUp();
47+
}
48+
49+
/**
50+
* Test case when module output is disabled
51+
*/
52+
public function testExecuteDisabled(): void
53+
{
54+
$this->moduleManager->expects($this->once())
55+
->method('isOutputEnabled')
56+
->with('Magento_LayeredNavigation')
57+
->willReturn(false);
58+
59+
$this->event->expects($this->never())->method('getDependencies');
60+
61+
$this->observer->execute($this->event);
62+
}
63+
64+
/**
65+
* Test case when module output is enabled
66+
*/
67+
public function testExecuteEnabled(): void
68+
{
69+
$this->moduleManager->expects($this->once())
70+
->method('isOutputEnabled')
71+
->with('Magento_LayeredNavigation')
72+
->willReturn(true);
73+
74+
$dependencies = $this->createMock(Dependence::class);
75+
$dependencies->expects($this->once())
76+
->method('addFieldMap')
77+
->with('is_filterable_in_search', 'filterable_in_search');
78+
$dependencies->expects($this->once())
79+
->method('addFieldDependence')
80+
->with('filterable_in_search', 'searchable', '1');
81+
$this->event->expects($this->once())
82+
->method('getDependencies')
83+
->willReturn($dependencies);
84+
85+
$this->observer->execute($this->event);
86+
}
87+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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\LayeredNavigation\Test\Unit\Plugin\Save;
10+
11+
use Magento\Catalog\Model\Product\Attribute\Frontend\Inputtype\Presentation;
12+
use Magento\LayeredNavigation\Plugin\Save\AdjustAttributeSearchable;
13+
use PHPUnit\Framework\TestCase;
14+
15+
class AdjustAttributeSearchableTest extends TestCase
16+
{
17+
/**
18+
* @return void
19+
*/
20+
public function testAfterConvertPresentationDataToInputType(): void
21+
{
22+
$presentation = $this->createMock(Presentation::class);
23+
$result = [
24+
'is_filterable_in_search' => '1',
25+
'is_searchable' => '0'
26+
];
27+
$interceptor = new AdjustAttributeSearchable();
28+
$this->assertSame(
29+
['is_filterable_in_search' => '0', 'is_searchable' => '0'],
30+
$interceptor->afterConvertPresentationDataToInputType($presentation, $result)
31+
);
32+
}
33+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
9+
<type name="Magento\Catalog\Model\Product\Attribute\Frontend\Inputtype\Presentation">
10+
<plugin name="adjust_searchable_attribute_values" type="Magento\LayeredNavigation\Plugin\Save\AdjustAttributeSearchable" sortOrder="1" disabled="false" />
11+
</type>
12+
</config>
13+

0 commit comments

Comments
 (0)