Skip to content

Commit ca6ac76

Browse files
Merge pull request #786 from magento-south/BUGS
Bugs - MAGETWO-63022 [2.2] SCD does not work when multiple languages are specified. - MAGETWO-62276 'State/Province' isn't changed to input after selecting 'United Kingdom' while filling address on checkout - MAGETWO-63009 Jasmine test randomly fails on bamboo - MAGETWO-54733 Unable to save product with all unchecked values for multiple select attribute #7687 - MAGETWO-59966 [SWAT][Magento Cloud] - Cache-miss when Fastly is enabled - MAGETWO-60258 [Magento Cloud] - Product position set in the admin is not honored in the category when seen in the Frontend
2 parents 0aff845 + c5c0686 commit ca6ac76

File tree

19 files changed

+456
-44
lines changed

19 files changed

+456
-44
lines changed

app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,6 @@
77

88
class Full extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractAction
99
{
10-
/**
11-
* Whether to use main or temporary index table
12-
*
13-
* @var bool
14-
*/
15-
protected $useTempTable = false;
16-
1710
/**
1811
* Refresh entities index
1912
*

app/code/Magento/Catalog/Setup/UpgradeSchema.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $con
6565
$this->addSourceEntityIdToProductEavIndex($setup);
6666
}
6767

68+
if (version_compare($context->getVersion(), '2.1.4', '<')) {
69+
$this->recreateCatalogCategoryProductIndexTmpTable($setup);
70+
}
71+
6872
$setup->endSetup();
6973
}
7074

@@ -375,4 +379,74 @@ private function addPercentageValueColumn(SchemaSetupInterface $setup)
375379
]
376380
);
377381
}
382+
383+
/**
384+
* Drop and recreate catalog_category_product_index_tmp table
385+
*
386+
* Before this update the catalog_category_product_index_tmp table was created without usage of PK
387+
* and with engine=MEMORY. Such structure of catalog_category_product_index_tmp table causes
388+
* issues with MySQL DB replication.
389+
*
390+
* To avoid replication issues this method drops catalog_category_product_index_tmp table
391+
* and creates new one with PK and engine=InnoDB
392+
*
393+
* @param SchemaSetupInterface $setup
394+
* @return void
395+
*/
396+
private function recreateCatalogCategoryProductIndexTmpTable(SchemaSetupInterface $setup)
397+
{
398+
$tableName = $setup->getTable('catalog_category_product_index_tmp');
399+
400+
// Drop catalog_category_product_index_tmp table
401+
$setup->getConnection()->dropTable($tableName);
402+
403+
// Create catalog_category_product_index_tmp table with PK and engine=InnoDB
404+
$table = $setup->getConnection()
405+
->newTable($tableName)
406+
->addColumn(
407+
'category_id',
408+
\Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
409+
null,
410+
['unsigned' => true, 'nullable' => false, 'primary' => true, 'default' => '0'],
411+
'Category ID'
412+
)
413+
->addColumn(
414+
'product_id',
415+
\Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
416+
null,
417+
['unsigned' => true, 'nullable' => false, 'primary' => true, 'default' => '0'],
418+
'Product ID'
419+
)
420+
->addColumn(
421+
'position',
422+
\Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
423+
null,
424+
['nullable' => false, 'default' => '0'],
425+
'Position'
426+
)
427+
->addColumn(
428+
'is_parent',
429+
\Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
430+
null,
431+
['unsigned' => true, 'nullable' => false, 'default' => '0'],
432+
'Is Parent'
433+
)
434+
->addColumn(
435+
'store_id',
436+
\Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
437+
null,
438+
['unsigned' => true, 'nullable' => false, 'primary' => true, 'default' => '0'],
439+
'Store ID'
440+
)
441+
->addColumn(
442+
'visibility',
443+
\Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
444+
null,
445+
['unsigned' => true, 'nullable' => false],
446+
'Visibility'
447+
)
448+
->setComment('Catalog Category Product Indexer temporary table');
449+
450+
$setup->getConnection()->createTable($table);
451+
}
378452
}

app/code/Magento/Catalog/etc/module.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77
-->
88
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
9-
<module name="Magento_Catalog" setup_version="2.1.3">
9+
<module name="Magento_Catalog" setup_version="2.1.4">
1010
<sequence>
1111
<module name="Magento_Eav"/>
1212
<module name="Magento_Cms"/>

app/code/Magento/Eav/Model/Entity/Attribute/Backend/ArrayBackend.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public function validate($object)
4242
$data = $object->getData($attributeCode);
4343
if (is_array($data)) {
4444
$object->setData($attributeCode, implode(',', array_filter($data)));
45+
} elseif (empty($data)) {
46+
$object->setData($attributeCode, null);
4547
}
4648
return parent::validate($object);
4749
}

app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Backend/ArrayTest.php renamed to app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Backend/ArrayBackendTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
namespace Magento\Eav\Test\Unit\Model\Entity\Attribute\Backend;
77

8-
class ArrayTest extends \PHPUnit_Framework_TestCase
8+
class ArrayBackendTest extends \PHPUnit_Framework_TestCase
99
{
1010
/**
1111
* @var \Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend
@@ -37,9 +37,10 @@ protected function setUp()
3737
public function testValidate($data)
3838
{
3939
$this->_attribute->expects($this->atLeastOnce())->method('getAttributeCode')->will($this->returnValue('code'));
40-
$product = new \Magento\Framework\DataObject(['code' => $data]);
40+
$product = new \Magento\Framework\DataObject(['code' => $data, 'empty' => '']);
4141
$this->_model->validate($product);
4242
$this->assertEquals('1,2,3', $product->getCode());
43+
$this->assertEquals(null, $product->getEmpty());
4344
}
4445

4546
public static function attributeValueDataProvider()

app/code/Magento/Theme/Controller/Result/MessagePlugin.php

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ public function __construct(
6666
}
6767

6868
/**
69+
* Set 'mage-messages' cookie
70+
*
71+
* Checks the result that controller actions must return. If result is not JSON type, then
72+
* sets 'mage-messages' cookie.
73+
*
6974
* @param ResultInterface $subject
7075
* @param ResultInterface $result
7176
* @return ResultInterface
@@ -75,18 +80,48 @@ public function afterRenderResult(
7580
ResultInterface $result
7681
) {
7782
if (!($subject instanceof Json)) {
83+
$this->setCookie($this->getMessages());
84+
}
85+
return $result;
86+
}
87+
88+
/**
89+
* Set 'mage-messages' cookie with 'messages' array
90+
*
91+
* Checks the $messages argument. If $messages is not an empty array, then
92+
* sets 'mage-messages' public cookie:
93+
*
94+
* Cookie Name: 'mage-messages';
95+
* Cookie Duration: 1 year;
96+
* Cookie Path: /;
97+
* Cookie HTTP Only flag: FALSE. Cookie can be accessed by client-side APIs.
98+
*
99+
* The 'messages' list has format:
100+
* [
101+
* [
102+
* 'type' => 'type_value',
103+
* 'text' => 'cookie_value',
104+
* ],
105+
* ]
106+
*
107+
*
108+
* @param array $messages List of Magento messages that must be set as 'mage-messages' cookie.
109+
* @return void
110+
*/
111+
private function setCookie(array $messages)
112+
{
113+
if (!empty($messages)) {
78114
$publicCookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata();
79115
$publicCookieMetadata->setDurationOneYear();
80116
$publicCookieMetadata->setPath('/');
81117
$publicCookieMetadata->setHttpOnly(false);
118+
82119
$this->cookieManager->setPublicCookie(
83120
self::MESSAGES_COOKIES_NAME,
84-
$this->jsonHelper->jsonEncode($this->getMessages()),
121+
$this->jsonHelper->jsonEncode($messages),
85122
$publicCookieMetadata
86123
);
87124
}
88-
89-
return $result;
90125
}
91126

92127
/**

app/code/Magento/Theme/Test/Unit/Controller/Result/MessagePluginTest.php

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ public function testAfterRenderResultJson()
7979

8080
public function testAfterRenderResult()
8181
{
82-
8382
$existingMessages = [
8483
[
8584
'type' => 'message0type',
@@ -125,14 +124,14 @@ public function testAfterRenderResult()
125124
)
126125
->willReturn(\Zend_Json::encode($existingMessages));
127126

128-
$this->dataMock->expects($this->any())
127+
$this->dataMock->expects($this->once())
129128
->method('jsonDecode')
130129
->willReturnCallback(
131130
function ($data) {
132131
return \Zend_Json::decode($data);
133132
}
134133
);
135-
$this->dataMock->expects($this->any())
134+
$this->dataMock->expects($this->exactly(2))
136135
->method('jsonEncode')
137136
->willReturnCallback(
138137
function ($data) {
@@ -168,6 +167,56 @@ function ($data) {
168167
$this->assertEquals($resultMock, $this->model->afterRenderResult($resultMock, $resultMock));
169168
}
170169

170+
public function testAfterRenderResultWithNoMessages()
171+
{
172+
/** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $resultMock */
173+
$resultMock = $this->getMockBuilder(Redirect::class)
174+
->disableOriginalConstructor()
175+
->getMock();
176+
177+
$this->cookieManagerMock->expects($this->once())
178+
->method('getCookie')
179+
->with(
180+
MessagePlugin::MESSAGES_COOKIES_NAME,
181+
\Zend_Json::encode([])
182+
)
183+
->willReturn(\Zend_Json::encode([]));
184+
185+
$this->dataMock->expects($this->once())
186+
->method('jsonDecode')
187+
->willReturnCallback(
188+
function ($data) {
189+
return \Zend_Json::decode($data);
190+
}
191+
);
192+
$this->dataMock->expects($this->once())
193+
->method('jsonEncode')
194+
->willReturnCallback(
195+
function ($data) {
196+
return \Zend_Json::encode($data);
197+
}
198+
);
199+
200+
/** @var Collection|\PHPUnit_Framework_MockObject_MockObject $collectionMock */
201+
$collectionMock = $this->getMockBuilder(Collection::class)
202+
->disableOriginalConstructor()
203+
->getMock();
204+
$collectionMock->expects($this->once())
205+
->method('getItems')
206+
->willReturn([]);
207+
208+
$this->managerMock->expects($this->once())
209+
->method('getMessages')
210+
->with(true, null)
211+
->willReturn($collectionMock);
212+
213+
$this->cookieMetadataFactoryMock->expects($this->never())
214+
->method('createPublicCookieMetadata')
215+
->willReturn(null);
216+
217+
$this->assertEquals($resultMock, $this->model->afterRenderResult($resultMock, $resultMock));
218+
}
219+
171220
public function testAfterRenderResultWithoutExisting()
172221
{
173222
$messageType = 'message1type';

app/code/Magento/Ui/view/base/web/js/form/client.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ define([
2222
function beforeSave(data, url, selectorPrefix, messagesClass) {
2323
var save = $.Deferred();
2424

25-
data = utils.serialize(data);
26-
25+
data = utils.serialize(utils.filterFormData(data));
2726
data['form_key'] = window.FORM_KEY;
2827

2928
if (!url || url === 'undefined') {

app/code/Magento/Ui/view/base/web/js/form/element/multiselect.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ define([
1313
return Select.extend({
1414
defaults: {
1515
size: 5,
16-
elementTmpl: 'ui/form/element/multiselect'
16+
elementTmpl: 'ui/form/element/multiselect',
17+
listens: {
18+
value: 'setDifferedFromDefault setPrepareToSendData'
19+
}
1720
},
1821

1922
/**
@@ -38,6 +41,21 @@ define([
3841
return _.isString(value) ? value.split(',') : value;
3942
},
4043

44+
/**
45+
* Sets the prepared data to dataSource
46+
* by path, where key is component link to dataSource with
47+
* suffix "-prepared-for-send"
48+
*
49+
* @param {Array} data - current component value
50+
*/
51+
setPrepareToSendData: function (data) {
52+
if (!data.length) {
53+
data = '';
54+
}
55+
56+
this.source.set(this.dataScope + '-prepared-for-send', data);
57+
},
58+
4159
/**
4260
* @inheritdoc
4361
*/

app/code/Magento/Ui/view/base/web/js/form/element/select.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ define([
4444
if (_.isUndefined(caption)) {
4545
caption = node.label;
4646
}
47+
} else {
48+
return node;
4749
}
48-
49-
return node;
5050
});
5151

5252
return {

dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Domain/VirtualTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,23 @@ class VirtualTest extends \PHPUnit_Framework_TestCase
1919
'theme_title' => 'Test physical theme',
2020
'area' => \Magento\Framework\App\Area::AREA_FRONTEND,
2121
'type' => ThemeInterface::TYPE_PHYSICAL,
22+
'code' => 'physical',
2223
],
2324
'virtual' => [
2425
'parent_id' => null,
2526
'theme_path' => '',
2627
'theme_title' => 'Test virtual theme',
2728
'area' => \Magento\Framework\App\Area::AREA_FRONTEND,
2829
'type' => ThemeInterface::TYPE_VIRTUAL,
30+
'code' => 'virtual',
2931
],
3032
'staging' => [
3133
'parent_id' => null,
3234
'theme_path' => '',
3335
'theme_title' => 'Test staging theme',
3436
'area' => \Magento\Framework\App\Area::AREA_FRONTEND,
3537
'type' => ThemeInterface::TYPE_STAGING,
38+
'code' => 'staging',
3639
],
3740
];
3841

0 commit comments

Comments
 (0)