diff --git a/app/code/Magento/Catalog/Api/CategoryListInterface.php b/app/code/Magento/Catalog/Api/CategoryListInterface.php
new file mode 100644
index 0000000000000..67a4ba5db000e
--- /dev/null
+++ b/app/code/Magento/Catalog/Api/CategoryListInterface.php
@@ -0,0 +1,20 @@
+categoryCollectionFactory = $categoryCollectionFactory;
+ $this->extensionAttributesJoinProcessor = $extensionAttributesJoinProcessor;
+ $this->categorySearchResultsFactory = $categorySearchResultsFactory;
+ $this->categoryRepository = $categoryRepository;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getList(SearchCriteriaInterface $searchCriteria)
+ {
+ /** @var Collection $collection */
+ $collection = $this->categoryCollectionFactory->create();
+ $this->extensionAttributesJoinProcessor->process($collection);
+
+ foreach ($searchCriteria->getFilterGroups() as $group) {
+ $this->addFilterGroupToCollection($group, $collection);
+ }
+
+ /** @var SortOrder $sortOrder */
+ $sortOrders = $searchCriteria->getSortOrders();
+ if ($sortOrders) {
+ foreach ($sortOrders as $sortOrder) {
+ $collection->addOrder(
+ $sortOrder->getField(),
+ ($sortOrder->getDirection() === SortOrder::SORT_ASC) ? SortOrder::SORT_ASC : SortOrder::SORT_DESC
+ );
+ }
+ }
+
+ $collection->setCurPage($searchCriteria->getCurrentPage());
+ $collection->setPageSize($searchCriteria->getPageSize());
+
+ $items = [];
+ foreach ($collection->getAllIds() as $id) {
+ $items[] = $this->categoryRepository->get($id);
+ }
+
+ /** @var CategorySearchResultsInterface $searchResult */
+ $searchResult = $this->categorySearchResultsFactory->create();
+ $searchResult->setSearchCriteria($searchCriteria);
+ $searchResult->setItems($items);
+ $searchResult->setTotalCount($collection->getSize());
+ return $searchResult;
+ }
+
+ /**
+ * Add filter group to collection
+ *
+ * @param FilterGroup $filterGroup
+ * @param Collection $collection
+ * @return void
+ */
+ private function addFilterGroupToCollection(FilterGroup $filterGroup, Collection $collection)
+ {
+ $filters = $filterGroup->getFilters();
+ if ($filters) {
+ $fields = [];
+ foreach ($filters as $filter) {
+ $conditionType = $filter->getConditionType() ? $filter->getConditionType() : 'eq';
+ $fields[] = ['attribute' => $filter->getField(), $conditionType => $filter->getValue()];
+ }
+ $collection->addFieldToFilter($fields);
+ }
+ }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryListTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryListTest.php
new file mode 100644
index 0000000000000..4f72f43485bc7
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryListTest.php
@@ -0,0 +1,138 @@
+categoryCollectionFactory = $this->getMockBuilder(CollectionFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+ $this->extensionAttributesJoinProcessor = $this->getMock(JoinProcessorInterface::class);
+ $this->categorySearchResultsFactory = $this->getMockBuilder(CategorySearchResultsInterfaceFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+ $this->categoryRepository = $this->getMock(CategoryRepositoryInterface::class);
+
+ $this->model = (new ObjectManager($this))->getObject(
+ CategoryList::class,
+ [
+ 'categoryCollectionFactory' => $this->categoryCollectionFactory,
+ 'extensionAttributesJoinProcessor' => $this->extensionAttributesJoinProcessor,
+ 'categorySearchResultsFactory' => $this->categorySearchResultsFactory,
+ 'categoryRepository' => $this->categoryRepository,
+ ]
+ );
+ }
+
+ public function testGetList()
+ {
+ $fieldName = 'field_1';
+ $value = 'value_1';
+ $conditionType = 'eq';
+ $currentPage = 2;
+ $pageSize = 1;
+ $totalCount = 2;
+ $categoryIdFirst = 1;
+ $categoryIdSecond = 2;
+
+ $categoryFirst = $this->getMockBuilder(Category::class)->disableOriginalConstructor()->getMock();
+ $categorySecond = $this->getMockBuilder(Category::class)->disableOriginalConstructor()->getMock();
+
+ $filter = $this->getMockBuilder(Filter::class)->disableOriginalConstructor()->getMock();
+ $filter->expects($this->atLeastOnce())->method('getConditionType')->willReturn($conditionType);
+ $filter->expects($this->atLeastOnce())->method('getField')->willReturn($fieldName);
+ $filter->expects($this->once())->method('getValue')->willReturn($value);
+
+ $filterGroup = $this->getMockBuilder(FilterGroup::class)->disableOriginalConstructor()->getMock();
+ $filterGroup->expects($this->once())->method('getFilters')->willReturn([$filter]);
+
+ $sortOrder = $this->getMockBuilder(SortOrder::class)->disableOriginalConstructor()->getMock();
+ $sortOrder->expects($this->once())->method('getField')->willReturn($fieldName);
+ $sortOrder->expects($this->once())->method('getDirection')->willReturn(SortOrder::SORT_ASC);
+
+ /** @var SearchCriteriaInterface|\PHPUnit_Framework_MockObject_MockObject $searchCriteria */
+ $searchCriteria = $this->getMock(SearchCriteriaInterface::class);
+ $searchCriteria->expects($this->once())->method('getFilterGroups')->willReturn([$filterGroup]);
+ $searchCriteria->expects($this->once())->method('getCurrentPage')->willReturn($currentPage);
+ $searchCriteria->expects($this->once())->method('getPageSize')->willReturn($pageSize);
+ $searchCriteria->expects($this->once())->method('getSortOrders')->willReturn([$sortOrder]);
+
+ $collection = $this->getMockBuilder(Collection::class)->disableOriginalConstructor()->getMock();
+ $collection->expects($this->once())
+ ->method('addFieldToFilter')
+ ->with([['attribute' => $fieldName, $conditionType => $value]]);
+ $collection->expects($this->once())->method('addOrder')->with($fieldName, SortOrder::SORT_ASC);
+ $collection->expects($this->once())->method('setCurPage')->with($currentPage);
+ $collection->expects($this->once())->method('setPageSize')->with($pageSize);
+ $collection->expects($this->once())->method('getSize')->willReturn($totalCount);
+ $collection->expects($this->once())->method('getAllIds')->willReturn([$categoryIdFirst, $categoryIdSecond]);
+
+ $searchResult = $this->getMock(CategorySearchResultsInterface::class);
+ $searchResult->expects($this->once())->method('setSearchCriteria')->with($searchCriteria);
+ $searchResult->expects($this->once())->method('setItems')->with([$categoryFirst, $categorySecond]);
+ $searchResult->expects($this->once())->method('setTotalCount')->with($totalCount);
+
+ $this->categoryRepository->expects($this->exactly(2))
+ ->method('get')
+ ->willReturnMap([
+ [$categoryIdFirst, $categoryFirst],
+ [$categoryIdSecond, $categorySecond],
+ ])
+ ->willReturn($categoryFirst);
+
+ $this->categorySearchResultsFactory->expects($this->once())->method('create')->willReturn($searchResult);
+ $this->categoryCollectionFactory->expects($this->once())->method('create')->willReturn($collection);
+ $this->extensionAttributesJoinProcessor->expects($this->once())->method('process')->with($collection);
+
+ $this->assertEquals($searchResult, $this->model->getList($searchCriteria));
+ }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryRepositoryTest.php
index 705f904ac9b73..ad50dc5407f7a 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/CategoryRepositoryTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryRepositoryTest.php
@@ -5,10 +5,15 @@
*/
namespace Magento\Catalog\Test\Unit\Model;
+use Magento\Catalog\Model\Category;
+use Magento\Catalog\Model\CategoryRepository;
+use Magento\Catalog\Model\ResourceModel\Category\Collection;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
class CategoryRepositoryTest extends \PHPUnit_Framework_TestCase
{
/**
- * @var \Magento\Catalog\Model\CategoryRepository
+ * @var CategoryRepository
*/
protected $model;
@@ -88,21 +93,16 @@ protected function setUp()
->with(\Magento\Catalog\Api\Data\CategoryInterface::class)
->willReturn($metadataMock);
- $this->model = new \Magento\Catalog\Model\CategoryRepository(
- $this->categoryFactoryMock,
- $this->categoryResourceMock,
- $this->storeManagerMock
+ $this->model = (new ObjectManager($this))->getObject(
+ CategoryRepository::class,
+ [
+ 'categoryFactory' => $this->categoryFactoryMock,
+ 'categoryResource' => $this->categoryResourceMock,
+ 'storeManager' => $this->storeManagerMock,
+ 'metadataPool' => $this->metadataPoolMock,
+ 'extensibleDataObjectConverter' => $this->extensibleDataObjectConverterMock,
+ ]
);
-
- $this->setProperties($this->model, [
- 'metadataPool' => $this->metadataPoolMock
- ]);
-
- // Todo: \Magento\Framework\TestFramework\Unit\Helper\ObjectManager to do this automatically (MAGETWO-49793)
- $reflection = new \ReflectionClass(get_class($this->model));
- $reflectionProperty = $reflection->getProperty('extensibleDataObjectConverter');
- $reflectionProperty->setAccessible(true);
- $reflectionProperty->setValue($this->model, $this->extensibleDataObjectConverterMock);
}
public function testGet()
@@ -370,20 +370,4 @@ public function testDeleteByIdentifierWithException()
);
$this->model->deleteByIdentifier($categoryId);
}
-
- /**
- * @param $object
- * @param array $properties
- */
- private function setProperties($object, $properties = [])
- {
- $reflectionClass = new \ReflectionClass(get_class($object));
- foreach ($properties as $key => $value) {
- if ($reflectionClass->hasProperty($key)) {
- $reflectionProperty = $reflectionClass->getProperty($key);
- $reflectionProperty->setAccessible(true);
- $reflectionProperty->setValue($object, $value);
- }
- }
- }
}
diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml
index 258602d8457aa..68d2e7f5fb927 100644
--- a/app/code/Magento/Catalog/etc/di.xml
+++ b/app/code/Magento/Catalog/etc/di.xml
@@ -44,6 +44,8 @@
+
+
diff --git a/app/code/Magento/Catalog/etc/webapi.xml b/app/code/Magento/Catalog/etc/webapi.xml
index a8dc6ead7975f..99670c347a89b 100644
--- a/app/code/Magento/Catalog/etc/webapi.xml
+++ b/app/code/Magento/Catalog/etc/webapi.xml
@@ -283,6 +283,12 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogSearch/Controller/Result/Index.php b/app/code/Magento/CatalogSearch/Controller/Result/Index.php
index f9866aaeff36b..394c3d0bf3687 100644
--- a/app/code/Magento/CatalogSearch/Controller/Result/Index.php
+++ b/app/code/Magento/CatalogSearch/Controller/Result/Index.php
@@ -79,8 +79,9 @@ public function execute()
} else {
$query->saveIncrementalPopularity();
- if ($query->getRedirect()) {
- $this->getResponse()->setRedirect($query->getRedirect());
+ $redirect = $query->getRedirect();
+ if ($redirect && $this->_url->getCurrentUrl() !== $redirect) {
+ $this->getResponse()->setRedirect($redirect);
return;
}
}
diff --git a/app/code/Magento/CatalogWidget/Model/Rule/Condition/Combine.php b/app/code/Magento/CatalogWidget/Model/Rule/Condition/Combine.php
index 386e77580fa4a..0672ff9a47840 100644
--- a/app/code/Magento/CatalogWidget/Model/Rule/Condition/Combine.php
+++ b/app/code/Magento/CatalogWidget/Model/Rule/Condition/Combine.php
@@ -21,19 +21,27 @@ class Combine extends \Magento\Rule\Model\Condition\Combine
*/
protected $elementName = 'parameters';
+ /**
+ * @var array
+ */
+ private $excludedAttributes;
+
/**
* @param \Magento\Rule\Model\Condition\Context $context
* @param \Magento\CatalogWidget\Model\Rule\Condition\ProductFactory $conditionFactory
* @param array $data
+ * @param array $excludedAttributes
*/
public function __construct(
\Magento\Rule\Model\Condition\Context $context,
\Magento\CatalogWidget\Model\Rule\Condition\ProductFactory $conditionFactory,
- array $data = []
+ array $data = [],
+ array $excludedAttributes = []
) {
$this->productFactory = $conditionFactory;
parent::__construct($context, $data);
$this->setType('Magento\CatalogWidget\Model\Rule\Condition\Combine');
+ $this->excludedAttributes = $excludedAttributes;
}
/**
@@ -44,10 +52,12 @@ public function getNewChildSelectOptions()
$productAttributes = $this->productFactory->create()->loadAttributeOptions()->getAttributeOption();
$attributes = [];
foreach ($productAttributes as $code => $label) {
- $attributes[] = [
- 'value' => 'Magento\CatalogWidget\Model\Rule\Condition\Product|' . $code,
- 'label' => $label,
- ];
+ if (!in_array($code, $this->excludedAttributes)) {
+ $attributes[] = [
+ 'value' => 'Magento\CatalogWidget\Model\Rule\Condition\Product|' . $code,
+ 'label' => $label,
+ ];
+ }
}
$conditions = parent::getNewChildSelectOptions();
$conditions = array_merge_recursive(
diff --git a/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/CombineTest.php b/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/CombineTest.php
index a0a78d1d64950..8a45a80e748a3 100644
--- a/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/CombineTest.php
+++ b/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/CombineTest.php
@@ -35,6 +35,7 @@ protected function setUp()
->disableOriginalConstructor()
->getMock();
$arguments['conditionFactory'] = $this->conditionFactory;
+ $arguments['excludedAttributes'] = ['excluded_attribute'];
$this->condition = $objectManagerHelper->getObject(
'Magento\CatalogWidget\Model\Rule\Condition\Combine',
@@ -56,6 +57,7 @@ public function testGetNewChildSelectOptions()
$attributeOptions = [
'sku' => 'SKU',
'category' => 'Category',
+ 'excluded_attribute' => 'Excluded attribute',
];
$productCondition = $this->getMockBuilder('\Magento\CatalogWidget\Model\Rule\Condition\Product')
->setMethods(['loadAttributeOptions', 'getAttributeOption'])
diff --git a/app/code/Magento/CatalogWidget/etc/di.xml b/app/code/Magento/CatalogWidget/etc/di.xml
new file mode 100644
index 0000000000000..625bcf58c5ca7
--- /dev/null
+++ b/app/code/Magento/CatalogWidget/etc/di.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+ - quantity_and_stock_status
+
+
+
+
diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryListTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryListTest.php
new file mode 100644
index 0000000000000..e7d53148d8454
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryListTest.php
@@ -0,0 +1,63 @@
+ [
+ 'filter_groups' => [
+ [
+ 'filters' => [
+ [
+ 'field' => 'name',
+ 'value' => 'Category 1',
+ 'condition_type' => 'eq',
+ ],
+ ],
+ ],
+ ],
+ 'current_page' => 1,
+ 'page_size' => 2,
+ ],
+ ];
+
+ $serviceInfo = [
+ 'rest' => [
+ 'resourcePath' => self::RESOURCE_PATH . '?' . http_build_query($searchCriteria),
+ 'httpMethod' => Request::HTTP_METHOD_GET,
+ ],
+ 'soap' => [
+ 'service' => self::SERVICE_NAME,
+ 'operation' => self::SERVICE_NAME . 'GetList',
+ ],
+ ];
+
+ $response = $this->_webApiCall($serviceInfo, $searchCriteria);
+
+ $this->assertArrayHasKey('search_criteria', $response);
+ $this->assertArrayHasKey('total_count', $response);
+ $this->assertArrayHasKey('items', $response);
+
+ $this->assertEquals($searchCriteria['searchCriteria'], $response['search_criteria']);
+ $this->assertTrue($response['total_count'] > 0);
+ $this->assertTrue(count($response['items']) > 0);
+
+ $this->assertNotNull($response['items'][0]['name']);
+ $this->assertEquals('Category 1', $response['items'][0]['name']);
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Controller/ResultTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Controller/ResultTest.php
index 0bf8a0ff2ca51..97026b5e229ea 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Controller/ResultTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/Controller/ResultTest.php
@@ -37,4 +37,26 @@ public function testIndexActionXSSQueryVerification()
$this->assertNotContains($data, $responseBody);
$this->assertContains(htmlspecialchars($data, ENT_COMPAT, 'UTF-8', false), $responseBody);
}
+
+ /**
+ * @magentoDataFixture Magento/CatalogSearch/_files/query_redirect.php
+ */
+ public function testRedirect()
+ {
+ $this->dispatch('/catalogsearch/result/?q=query_text');
+ $responseBody = $this->getResponse();
+
+ $this->assertTrue($responseBody->isRedirect());
+ }
+
+ /**
+ * @magentoDataFixture Magento/CatalogSearch/_files/query_redirect.php
+ */
+ public function testNoRedirectIfCurrentUrlAndRedirectTermAreSame()
+ {
+ $this->dispatch('/catalogsearch/result/?q=query_text&cat=41');
+ $responseBody = $this->getResponse();
+
+ $this->assertFalse($responseBody->isRedirect());
+ }
}
diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/_files/query_redirect.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/_files/query_redirect.php
new file mode 100644
index 0000000000000..0dcada80c2959
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/_files/query_redirect.php
@@ -0,0 +1,17 @@
+get(UrlInterface::class);
+
+$query->setRedirect($url->getCurrentUrl() . 'catalogsearch/result/?q=query_text&cat=41')
+ ->save();