Skip to content

Commit ced998f

Browse files
authored
Merge pull request #1598 from magento-panda/PANDA-FIXES-2.1
Fixed issues: MAGETWO-70062 Product price filter in admin shows incorrect product amount MAGETWO-72106 [Magento Cloud] Using search synonyms from the same group gives different results
2 parents 8d7b39d + 85e2941 commit ced998f

File tree

6 files changed

+232
-29
lines changed

6 files changed

+232
-29
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
/**
3+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Catalog\Ui\DataProvider\Product;
7+
8+
/**
9+
* Collection which is used for rendering product list in the backend.
10+
*
11+
* Used for product grid and customizes behavior of the default Product collection for grid needs.
12+
*/
13+
class ProductCollection extends \Magento\Catalog\Model\ResourceModel\Product\Collection
14+
{
15+
/**
16+
* Disables using of price index for grid rendering
17+
*
18+
* Admin area shouldn't use price index and should rely on actual product data instead.
19+
*
20+
* @codeCoverageIgnore
21+
* @return \Magento\Catalog\Model\ResourceModel\Product\Collection
22+
*/
23+
protected function _productLimitationJoinPrice()
24+
{
25+
$this->_productLimitationFilters->setUsePriceIndex(false);
26+
return $this->_productLimitationPrice(true);
27+
}
28+
}

app/code/Magento/Catalog/etc/adminhtml/di.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@
7777
<type name="Magento\Catalog\Model\ResourceModel\Attribute">
7878
<plugin name="invalidate_pagecache_after_attribute_save" type="Magento\Catalog\Plugin\Model\ResourceModel\Attribute\Save" />
7979
</type>
80+
<virtualType name="\Magento\Catalog\Ui\DataProvider\Product\ProductCollectionFactory" type="\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory">
81+
<arguments>
82+
<argument name="instanceName" xsi:type="string">\Magento\Catalog\Ui\DataProvider\Product\ProductCollection</argument>
83+
</arguments>
84+
</virtualType>
8085
<type name="Magento\Catalog\Ui\DataProvider\Product\ProductDataProvider">
8186
<arguments>
8287
<argument name="addFieldStrategies" xsi:type="array">
@@ -85,6 +90,7 @@
8590
<argument name="addFilterStrategies" xsi:type="array">
8691
<item name="store_id" xsi:type="object">Magento\Catalog\Ui\DataProvider\Product\AddStoreFieldToCollection</item>
8792
</argument>
93+
<argument name="collectionFactory" xsi:type="object">\Magento\Catalog\Ui\DataProvider\Product\ProductCollectionFactory</argument>
8894
</arguments>
8995
</type>
9096
<type name="Magento\Catalog\Model\Product\Action">

app/code/Magento/Search/Model/SynonymAnalyzer.php

Lines changed: 97 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@
33
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
67
namespace Magento\Search\Model;
78

89
use Magento\Search\Api\SynonymAnalyzerInterface;
910

11+
/**
12+
* SynonymAnalyzer responsible for search of synonyms matching a word or a phrase.
13+
*/
1014
class SynonymAnalyzer implements SynonymAnalyzerInterface
1115
{
1216
/**
@@ -42,55 +46,119 @@ public function __construct(SynonymReader $synReader)
4246
*/
4347
public function getSynonymsForPhrase($phrase)
4448
{
45-
$synGroups = [];
49+
$result = [];
4650

47-
if (empty($phrase)) {
48-
return $synGroups;
51+
if (empty(trim($phrase))) {
52+
return $result;
4953
}
5054

51-
$rows = $this->synReaderModel->loadByPhrase($phrase)->getData();
52-
$synonyms = [];
53-
foreach ($rows as $row) {
54-
$synonyms [] = $row['synonyms'];
55-
}
55+
$synonymGroups = $this->getSynonymGroupsByPhrase($phrase);
56+
57+
// Replace multiple spaces in a row with the only one space
58+
$phrase = preg_replace("/ {2,}/", " ", $phrase);
5659

5760
// Go through every returned record looking for presence of the actual phrase. If there were no matching
5861
// records found in DB then create a new entry for it in the returned array
5962
$words = explode(' ', $phrase);
60-
foreach ($words as $w) {
61-
$position = $this->findInArray($w, $synonyms);
62-
if ($position !== false) {
63-
$synGroups[] = explode(',', $synonyms[$position]);
64-
} else {
65-
// No synonyms were found. Return the original word in this position
66-
$synGroups[] = [$w];
63+
64+
foreach ($words as $offset => $word) {
65+
$synonyms = [$word];
66+
67+
if ($synonymGroups) {
68+
$pattern = $this->getSearchPattern(array_slice($words, $offset));
69+
$position = $this->findInArray($pattern, $synonymGroups);
70+
if ($position !== null) {
71+
$synonyms = explode(',', $synonymGroups[$position]);
72+
}
6773
}
74+
75+
$result[] = $synonyms;
6876
}
69-
return $synGroups;
77+
78+
return $result;
7079
}
7180

7281
/**
73-
* Helper method to find the presence of $word in $wordsArray. If found, the particular array index is returned.
82+
* Helper method to find the matching of $pattern to $synonymGroupsToExamine.
83+
* If matches, the particular array index is returned.
7484
* Otherwise false will be returned.
7585
*
76-
* @param string $word
77-
* @param $array $wordsArray
78-
* @return boolean | int
86+
* @param string $pattern
87+
* @param array $synonymGroupsToExamine
88+
* @return int|null
7989
*/
80-
private function findInArray($word, $wordsArray)
90+
private function findInArray($pattern, array $synonymGroupsToExamine)
8191
{
82-
if (empty($wordsArray)) {
83-
return false;
84-
}
8592
$position = 0;
86-
foreach ($wordsArray as $wordsLine) {
87-
$pattern = '/^' . $word . ',|,' . $word . ',|,' . $word . '$/';
88-
$rv = preg_match($pattern, $wordsLine);
89-
if ($rv != 0) {
93+
foreach ($synonymGroupsToExamine as $synonymGroup) {
94+
$matchingResultCode = preg_match($pattern, $synonymGroup);
95+
if ($matchingResultCode === 1) {
9096
return $position;
9197
}
9298
$position++;
9399
}
94-
return false;
100+
return null;
101+
}
102+
103+
/**
104+
* Returns a regular expression to search for synonyms of the phrase represented as the list of words.
105+
*
106+
* Returned pattern contains expression to search for a part of the phrase from the beginning.
107+
*
108+
* For example, in the phrase "Elizabeth is the English queen" with subset from the very first word,
109+
* the method will build an expression which looking for synonyms for all these patterns:
110+
* - Elizabeth is the English queen
111+
* - Elizabeth is the English
112+
* - Elizabeth is the
113+
* - Elizabeth is
114+
* - Elizabeth
115+
*
116+
* For the same phrase on the second iteration with the first word "is" it will match for these synonyms:
117+
* - is the English queen
118+
* - is the English
119+
* - is the
120+
* - is
121+
*
122+
* The pattern looking for exact match and will not find these phrases as synonyms:
123+
* - Is there anybody in the room?
124+
* - Is the English is most popular language?
125+
* - Is the English queen Elizabeth?
126+
*
127+
* Take into account that returned pattern expects that data will be represented as comma-separated value.
128+
*
129+
* @param array $words
130+
* @return string
131+
*/
132+
private function getSearchPattern(array $words)
133+
{
134+
$patterns = [];
135+
for ($lastItem = count($words); $lastItem > 0; $lastItem--) {
136+
$phrase = implode("\s+", array_slice($words, 0, $lastItem));
137+
$patterns[] = '^' . $phrase . ',';
138+
$patterns[] = ',' . $phrase . ',';
139+
$patterns[] = ',' . $phrase . '$';
140+
}
141+
142+
$pattern = '/' . implode('|', $patterns) . '/i';
143+
return $pattern;
144+
}
145+
146+
/**
147+
* Get all synonym groups for the phrase
148+
*
149+
* Returns an array of synonyms which are represented as comma-separated value for each item in the list
150+
*
151+
* @param string $phrase
152+
* @return string[]
153+
*/
154+
private function getSynonymGroupsByPhrase($phrase)
155+
{
156+
$result = [];
157+
158+
$synonymGroups = $this->synReaderModel->loadByPhrase($phrase)->getData();
159+
foreach ($synonymGroups as $row) {
160+
$result[] = $row['synonyms'];
161+
}
162+
return $result;
95163
}
96164
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
/**
3+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Catalog\Ui\DataProvider;
7+
8+
use Magento\Framework\Data\Collection;
9+
10+
/**
11+
* @magentoAppArea adminhtml
12+
*/
13+
class ProductTest extends \PHPUnit_Framework_TestCase
14+
{
15+
/**
16+
* @var \Magento\Catalog\Ui\DataProvider\Product\ProductDataProvider
17+
*/
18+
private $dataProvider;
19+
20+
protected function setUp()
21+
{
22+
$this->dataProvider = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
23+
\Magento\Catalog\Ui\DataProvider\Product\ProductDataProvider::class,
24+
[
25+
'name'=> 'products',
26+
'primaryFieldName' => 'entity_id',
27+
'requestFieldName' => 'id',
28+
]
29+
);
30+
}
31+
32+
/**
33+
* @dataProvider sortingFieldsDataProvider
34+
* @magentoDataFixture Magento/Catalog/_files/multiple_products.php
35+
*
36+
* @param string $orderByField
37+
* @param string $direction
38+
*/
39+
public function testSortingNotAffectsCount($orderByField, $direction)
40+
{
41+
$this->dataProvider->addOrder($orderByField, $direction);
42+
$result = $this->dataProvider->getData();
43+
$this->assertEquals(3, $result['totalRecords']);
44+
}
45+
46+
/**
47+
* @return array
48+
*/
49+
public function sortingFieldsDataProvider()
50+
{
51+
return [
52+
'name ASC' => ['name', Collection::SORT_ORDER_ASC],
53+
'name DESC' => ['name', Collection::SORT_ORDER_DESC],
54+
'sku ASC' => ['sku', Collection::SORT_ORDER_ASC],
55+
'sku DESC' => ['sku', Collection::SORT_ORDER_DESC],
56+
'price ASC' => ['price', Collection::SORT_ORDER_ASC],
57+
'price DESC' => ['price', Collection::SORT_ORDER_DESC],
58+
];
59+
}
60+
}

dev/tests/integration/testsuite/Magento/Search/Model/SynonymAnalyzerTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,38 @@ public static function loadGetSynonymsForPhraseDataProvider()
4242
'phrase' => 'universe is enormous',
4343
'expectedResult' => [['universe', 'cosmos'], ['is'], ['big', 'huge', 'large', 'enormous']]
4444
],
45+
'WithCaseMismatch' => [
46+
'phrase' => 'GNU\'s Not Unix',
47+
'expectedResult' => [['GNU\'s'], ['Not'], ['unix', 'linux'],]
48+
],
49+
'WithMultiWordPhrase' => [
50+
'phrase' => 'Coastline of Great Britain stretches for 11,073 miles',
51+
'expectedResult' => [
52+
['Coastline'],
53+
['of'],
54+
['Great Britain', 'United Kingdom'],
55+
['Britain'],
56+
['stretches'],
57+
['for'],
58+
['11,073'],
59+
['miles']
60+
]
61+
],
62+
'PartialSynonymMatching' => [
63+
'phrase' => 'Magento Engineering',
64+
'expectedResult' => [
65+
['orange', 'magento'],
66+
['Engineering', 'Technical Staff']
67+
]
68+
],
4569
'noSynonyms' => [
4670
'phrase' => 'this sentence has no synonyms',
4771
'expectedResult' => [['this'], ['sentence'], ['has'], ['no'], ['synonyms']]
4872
],
73+
'multipleSpaces' => [
74+
'phrase' => 'GNU\'s Not Unix',
75+
'expectedResult' => [['GNU\'s'], ['Not'], ['unix', 'linux'],]
76+
],
4977
'oneMoreTest' => [
5078
'phrase' => 'schlicht',
5179
'expectedResult' => [['schlicht', 'natürlich']]

dev/tests/integration/testsuite/Magento/Search/_files/synonym_reader.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,22 @@
2424
$synonymsModel = $objectManager->create('Magento\Search\Model\SynonymReader');
2525
$synonymsModel->setSynonyms('hill,mountain,peak')->setWebsiteId(1)->save();
2626

27+
$synonymsModel = $objectManager->create('Magento\Search\Model\SynonymReader');
28+
$synonymsModel->setSynonyms('Community Engineering,Contributors,Magento Community Engineering')->setWebsiteId(1)
29+
->save();
30+
31+
$synonymsModel = $objectManager->create('Magento\Search\Model\SynonymReader');
32+
$synonymsModel->setSynonyms('Engineering,Technical Staff')->setWebsiteId(1)->save();
33+
2734
// Synonym groups for "All Store Views"
2835
$synonymsModel = $objectManager->create('Magento\Search\Model\SynonymReader');
2936
$synonymsModel->setSynonyms('universe,cosmos')->setWebsiteId(0)->save();
3037

38+
$synonymsModel = $objectManager->create('Magento\Search\Model\SynonymReader');
39+
$synonymsModel->setSynonyms('unix,linux')->setWebsiteId(0)->save();
40+
41+
$synonymsModel = $objectManager->create('Magento\Search\Model\SynonymReader');
42+
$synonymsModel->setSynonyms('Great Britain,United Kingdom')->setWebsiteId(0)->save();
43+
3144
$synonymsModel = $objectManager->create('Magento\Search\Model\SynonymReader');
3245
$synonymsModel->setSynonyms('big,huge,large,enormous')->setWebsiteId(0)->save();

0 commit comments

Comments
 (0)