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();