Skip to content

Commit 8e31029

Browse files
author
Bohdan Korablov
committed
Merge remote-tracking branch 'mainline/2.2-develop' into MAGETWO-71922
2 parents b31765a + 7978fcf commit 8e31029

File tree

11 files changed

+398
-17
lines changed

11 files changed

+398
-17
lines changed

app/code/Magento/CatalogWidget/Block/Product/ProductsList.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,14 @@ protected function getConditions()
259259
$conditions = $this->conditionsHelper->decode($conditions);
260260
}
261261

262+
foreach ($conditions as $key => $condition) {
263+
if (!empty($condition['attribute'])
264+
&& in_array($condition['attribute'], ['special_from_date', 'special_to_date'])
265+
) {
266+
$conditions[$key]['value'] = date('Y-m-d H:i:s', strtotime($condition['value']));
267+
}
268+
}
269+
262270
$this->rule->loadPost(['conditions' => $conditions]);
263271
return $this->rule->getConditions();
264272
}

app/code/Magento/CatalogWidget/Test/Unit/Block/Product/ProductsListTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ public function testCreateCollection($pagerEnable, $productsCount, $productsPerP
288288
$this->collectionFactory->expects($this->once())->method('create')->willReturn($collection);
289289
$this->productsList->setData('conditions_encoded', 'some_serialized_conditions');
290290

291+
$this->widgetConditionsHelper->expects($this->once())
292+
->method('decode')
293+
->with('some_serialized_conditions')
294+
->willReturn([]);
295+
291296
$this->builder->expects($this->once())->method('attachConditionToCollection')
292297
->with($collection, $this->getConditionsForCollection($collection))
293298
->willReturnSelf();
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Deploy\Console;
7+
8+
use Magento\Framework\ObjectManagerInterface;
9+
10+
/**
11+
* Provides list of commands to be available for uninstalled application
12+
*/
13+
class CommandList implements \Magento\Framework\Console\CommandListInterface
14+
{
15+
/**
16+
* Object Manager
17+
*
18+
* @var ObjectManagerInterface
19+
*/
20+
private $objectManager;
21+
22+
/**
23+
* @param ObjectManagerInterface $objectManager Object Manager
24+
*/
25+
public function __construct(ObjectManagerInterface $objectManager)
26+
{
27+
$this->objectManager = $objectManager;
28+
}
29+
30+
/**
31+
* Gets list of command classes
32+
*
33+
* @return string[]
34+
*/
35+
private function getCommandsClasses()
36+
{
37+
return [
38+
\Magento\Deploy\Console\Command\App\ConfigImportCommand::class,
39+
];
40+
}
41+
42+
/**
43+
* @inheritdoc
44+
*/
45+
public function getCommands()
46+
{
47+
$commands = [];
48+
foreach ($this->getCommandsClasses() as $class) {
49+
if (class_exists($class)) {
50+
$commands[] = $this->objectManager->get($class);
51+
} else {
52+
throw new \Exception('Class ' . $class . ' does not exist');
53+
}
54+
}
55+
56+
return $commands;
57+
}
58+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Deploy\Test\Unit\Console;
7+
8+
use Magento\Deploy\Console\Command\App\ConfigImportCommand;
9+
use Magento\Deploy\Console\CommandList;
10+
use Magento\Framework\ObjectManagerInterface;
11+
use PHPUnit\Framework\TestCase;
12+
13+
/**
14+
* @inheritdoc
15+
*/
16+
class CommandListTest extends TestCase
17+
{
18+
/**
19+
* @var CommandList
20+
*/
21+
private $model;
22+
23+
/**
24+
* @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
25+
*/
26+
private $objectManagerMock;
27+
28+
/**
29+
* @inheritdoc
30+
*/
31+
protected function setUp()
32+
{
33+
$this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class)
34+
->getMockForAbstractClass();
35+
36+
$this->model = new CommandList(
37+
$this->objectManagerMock
38+
);
39+
}
40+
41+
public function testGetCommands()
42+
{
43+
$configImportCommand = $this->getMockBuilder(ConfigImportCommand::class)
44+
->disableOriginalConstructor()
45+
->getMock();
46+
47+
$this->objectManagerMock->expects($this->once())
48+
->method('get')
49+
->willReturnMap([
50+
[ConfigImportCommand::class, $configImportCommand],
51+
]);
52+
53+
$this->assertSame(
54+
[$configImportCommand],
55+
$this->model->getCommands()
56+
);
57+
}
58+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
if (PHP_SAPI == 'cli') {
7+
\Magento\Framework\Console\CommandLocator::register(\Magento\Deploy\Console\CommandList::class);
8+
}

app/code/Magento/Deploy/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
],
1818
"autoload": {
1919
"files": [
20+
"cli_commands.php",
2021
"registration.php"
2122
],
2223
"psr-4": {

app/code/Magento/Rule/Model/Condition/Sql/Builder.php

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ protected function _joinTablesToCollection(
108108
}
109109

110110
/**
111+
* Returns sql expression based on rule condition.
112+
*
111113
* @param AbstractCondition $condition
112114
* @param string $value
113115
* @return string
@@ -116,24 +118,27 @@ protected function _joinTablesToCollection(
116118
protected function _getMappedSqlCondition(AbstractCondition $condition, $value = '')
117119
{
118120
$argument = $condition->getMappedSqlField();
119-
if ($argument) {
120-
$conditionOperator = $condition->getOperatorForValidate();
121121

122-
if (!isset($this->_conditionOperatorMap[$conditionOperator])) {
123-
throw new \Magento\Framework\Exception\LocalizedException(__('Unknown condition operator'));
124-
}
122+
// If rule hasn't valid argument - create negative expression to prevent incorrect rule behavior.
123+
if (empty($argument)) {
124+
return $this->_expressionFactory->create(['expression' => '1 = -1']);
125+
}
125126

126-
$sql = str_replace(
127-
':field',
128-
$this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), 0),
129-
$this->_conditionOperatorMap[$conditionOperator]
130-
);
127+
$conditionOperator = $condition->getOperatorForValidate();
131128

132-
return $this->_expressionFactory->create(
133-
['expression' => $value . $this->_connection->quoteInto($sql, $condition->getBindArgumentValue())]
134-
);
129+
if (!isset($this->_conditionOperatorMap[$conditionOperator])) {
130+
throw new \Magento\Framework\Exception\LocalizedException(__('Unknown condition operator'));
135131
}
136-
return '';
132+
133+
$sql = str_replace(
134+
':field',
135+
$this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), 0),
136+
$this->_conditionOperatorMap[$conditionOperator]
137+
);
138+
139+
return $this->_expressionFactory->create(
140+
['expression' => $value . $this->_connection->quoteInto($sql, $condition->getBindArgumentValue())]
141+
);
137142
}
138143

139144
/**
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Rule\Model\Condition\Sql;
8+
9+
use Magento\TestFramework\Helper\Bootstrap;
10+
11+
class BuilderTest extends \PHPUnit\Framework\TestCase
12+
{
13+
/**
14+
* @var \Magento\Rule\Model\Condition\Sql\Builder
15+
*/
16+
private $model;
17+
18+
protected function setUp()
19+
{
20+
$this->model = Bootstrap::getObjectManager()->create(\Magento\Rule\Model\Condition\Sql\Builder::class);
21+
}
22+
23+
public function testAttachConditionToCollection()
24+
{
25+
/** @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory */
26+
$collectionFactory = Bootstrap::getObjectManager()->create(
27+
\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class
28+
);
29+
/** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */
30+
$collection = $collectionFactory->create();
31+
32+
/** @var \Magento\CatalogWidget\Model\RuleFactory $ruleFactory */
33+
$ruleFactory = Bootstrap::getObjectManager()->create(\Magento\CatalogWidget\Model\RuleFactory::class);
34+
/** @var \Magento\CatalogWidget\Model\Rule $rule */
35+
$rule = $ruleFactory->create();
36+
37+
$ruleConditionArray = [
38+
'conditions' => [
39+
'1' => [
40+
'type' => \Magento\CatalogWidget\Model\Rule\Condition\Combine::class,
41+
'aggregator' => 'all',
42+
'value' => '1',
43+
'new_child' => ''
44+
],
45+
'1--1' => [
46+
'type' => \Magento\CatalogWidget\Model\Rule\Condition\Product::class,
47+
'attribute' => 'category_ids',
48+
'operator' => '==',
49+
'value' => '3'
50+
],
51+
'1--2' => [
52+
'type' => \Magento\CatalogWidget\Model\Rule\Condition\Product::class,
53+
'attribute' => 'special_to_date',
54+
'operator' => '==',
55+
'value' => '2017-09-15'
56+
],
57+
]
58+
];
59+
60+
$rule->loadPost($ruleConditionArray);
61+
$this->model->attachConditionToCollection($collection, $rule->getConditions());
62+
63+
$whereString = 'WHERE (category_id IN (\'3\')))) AND(IFNULL(`e`.`entity_id`, 0) = \'2017-09-15\') ))';
64+
$this->assertNotFalse(strpos($collection->getSelectSql(true), $whereString));
65+
}
66+
}

lib/web/mage/menu.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ define([
5959
}
6060

6161
this._assignControls()._listen();
62+
this._setActiveMenu();
6263
},
6364

6465
/**
@@ -108,6 +109,111 @@ define([
108109
}
109110
},
110111

112+
/**
113+
* Tries to figure out the active category for current page and add appropriate classes:
114+
* - 'active' class for active category
115+
* - 'has-active' class for all parents of active category
116+
*
117+
* First, checks whether current URL is URL of category page,
118+
* otherwise tries to retrieve category URL in case of current URL is product view page URL
119+
* which has category tree path in it.
120+
*
121+
* @return void
122+
* @private
123+
*/
124+
_setActiveMenu: function () {
125+
var currentUrl = window.location.href.split('?')[0];
126+
127+
if (!this._setActiveMenuForCategory(currentUrl)) {
128+
this._setActiveMenuForProduct(currentUrl);
129+
}
130+
},
131+
132+
/**
133+
* Looks for category with provided URL and adds 'active' CSS class to it if it was not set before.
134+
* If menu item has parent categories, sets 'has-active' class to all af them.
135+
*
136+
* @param {String} url - possible category URL
137+
* @returns {Boolean} - true if active category was founded by provided URL, otherwise return false
138+
* @private
139+
*/
140+
_setActiveMenuForCategory: function (url) {
141+
var activeCategoryLink = this.element.find('a[href="' + url + '"]'),
142+
classes,
143+
classNav;
144+
145+
if (!activeCategoryLink || !activeCategoryLink.hasClass('ui-corner-all')) {
146+
147+
//category was not found by provided URL
148+
return false;
149+
} else if (!activeCategoryLink.parent().hasClass('active')) {
150+
activeCategoryLink.parent().addClass('active');
151+
classes = activeCategoryLink.parent().attr('class');
152+
classNav = classes.match(/(nav\-)[0-9]+(\-[0-9]+)+/gi);
153+
154+
if (classNav) {
155+
this._setActiveParent(classNav[0]);
156+
}
157+
}
158+
159+
return true;
160+
},
161+
162+
/**
163+
* Sets 'has-active' CSS class to all parent categories which have part of provided class in childClassName
164+
*
165+
* @example
166+
* childClassName - 'nav-1-2-3'
167+
* CSS class 'has-active' will be added to categories have 'nav-1-2' and 'nav-1' classes
168+
*
169+
* @param {String} childClassName - Class name of active category <li> element
170+
* @return void
171+
* @private
172+
*/
173+
_setActiveParent: function (childClassName) {
174+
var parentElement,
175+
parentClass = childClassName.substr(0, childClassName.lastIndexOf('-'));
176+
177+
if (parentClass.lastIndexOf('-') !== -1) {
178+
parentElement = this.element.find('.' + parentClass);
179+
180+
if (parentElement) {
181+
parentElement.addClass('has-active');
182+
}
183+
this._setActiveParent(parentClass);
184+
}
185+
},
186+
187+
/**
188+
* Tries to retrieve category URL from current URL and mark this category as active
189+
* @see _setActiveMenuForCategory(url)
190+
*
191+
* @example
192+
* currentUrl - http://magento.com/category1/category12/product.html,
193+
* category URLs has extensions .phtml - http://magento.com/category1.phtml
194+
* method sets active category which has URL http://magento.com/category1/category12.phtml
195+
*
196+
* @param {String} currentUrl - current page URL without parameters
197+
* @return void
198+
* @private
199+
*/
200+
_setActiveMenuForProduct: function (currentUrl) {
201+
var categoryUrlExtension,
202+
lastUrlSection,
203+
possibleCategoryUrl,
204+
//retrieve first category URL to know what extension is used for category URLs
205+
firstCategoryUrl = this.element.find('> li a').attr('href');
206+
207+
if (firstCategoryUrl) {
208+
lastUrlSection = firstCategoryUrl.substr(firstCategoryUrl.lastIndexOf('/'));
209+
categoryUrlExtension = lastUrlSection.lastIndexOf('.') !== -1 ?
210+
lastUrlSection.substr(lastUrlSection.lastIndexOf('.')) : '';
211+
212+
possibleCategoryUrl = currentUrl.substr(0, currentUrl.lastIndexOf('/')) + categoryUrlExtension;
213+
this._setActiveMenuForCategory(possibleCategoryUrl);
214+
}
215+
},
216+
111217
/**
112218
* Add class for expanded option.
113219
*/

0 commit comments

Comments
 (0)