diff --git a/app/code/Magento/Catalog/Controller/Category/View.php b/app/code/Magento/Catalog/Controller/Category/View.php index da7c5326587e3..66f7b8801835e 100644 --- a/app/code/Magento/Catalog/Controller/Category/View.php +++ b/app/code/Magento/Catalog/Controller/Category/View.php @@ -212,6 +212,13 @@ public function execute() $category = $this->_initCategory(); if ($category) { + // Negative ?p= value is not supported, redirect to a base version of category page. + if ($this->_request->getParam(Toolbar::PAGE_PARM_NAME) < 0) { + return $this->resultRedirectFactory->create() + ->setHttpResponseCode(301) + ->setUrl($category->getUrl()); + } + $this->layerResolver->create(Resolver::CATALOG_LAYER_CATEGORY); $settings = $this->_catalogDesign->getDesignSettings($category); diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPaginationResetOnNegativePageNumberTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPaginationResetOnNegativePageNumberTest.xml new file mode 100644 index 0000000000000..ff1e3d22a2479 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPaginationResetOnNegativePageNumberTest.xml @@ -0,0 +1,47 @@ + + + + + + + + + <description value="Pagination should reset on storefront when negative page number requested"/> + <severity value="AVERAGE"/> + <testCaseId value=""/> + <useCaseId value=""/> + <group value="catalog"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createSimpleProductOne"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="SimpleProduct" stepKey="createSimpleProductTwo"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createSimpleProductOne" stepKey="deleteProductOne"/> + <deleteData createDataKey="createSimpleProductTwo" stepKey="deleteProductTwo"/> + </after> + <!-- Go to category page with `-1` as a Page Number --> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.custom_attributes[url_key]$$)}}?p=-1" stepKey="goToStorefrontCreatedCategoryPage"/> + <!-- Validate that "no products found" error message is not present --> + <actionGroup ref="StorefrontDontSeeNoProductsFoundActionGroup" stepKey="dontSeeNoProdsFoundMessage"/> + <!-- Verify the products are visible on the Category Page --> + <actionGroup ref="AssertStorefrontProductIsPresentOnCategoryPageActionGroup" stepKey="seeProductOneOnGrid"> + <argument name="productName" value="$$createSimpleProductOne.name$$"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductIsPresentOnCategoryPageActionGroup" stepKey="seeProductTwoOnGrid"> + <argument name="productName" value="$$createSimpleProductTwo.name$$"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/CatalogSearch/Controller/Result/Index.php b/app/code/Magento/CatalogSearch/Controller/Result/Index.php index 61d55d10dd45b..da588c5940f82 100644 --- a/app/code/Magento/CatalogSearch/Controller/Result/Index.php +++ b/app/code/Magento/CatalogSearch/Controller/Result/Index.php @@ -3,8 +3,10 @@ * Copyright 2014 Adobe * All Rights Reserved. */ + namespace Magento\CatalogSearch\Controller\Result; +use Magento\Catalog\Model\Product\ProductList\Toolbar; use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Catalog\Model\Layer\Resolver; use Magento\Catalog\Model\Session; @@ -88,28 +90,37 @@ public function execute() $queryText = $query->getQueryText(); - if ($queryText != '') { - $catalogSearchHelper = $this->_objectManager->get(\Magento\CatalogSearch\Helper\Data::class); + if (empty($queryText)) { + $this->getResponse()->setRedirect($this->_redirect->getRedirectUrl()); + return; + } - $getAdditionalRequestParameters = $this->getRequest()->getParams(); - unset($getAdditionalRequestParameters[QueryFactory::QUERY_VAR_NAME]); + // Negative ?p= value is not supported, redirect to a base version of category page. + if ($this->_request->getParam(Toolbar::PAGE_PARM_NAME) < 0) { + $this->getResponse()->setRedirect( + $this->_url->getUrl('*/*', ['_current' => true, '_query' => [Toolbar::PAGE_PARM_NAME => null]]) + ); + return; + } - $handles = null; - if ($query->getNumResults() == 0) { - $this->_view->getPage()->initLayout(); - $handles = $this->_view->getLayout()->getUpdate()->getHandles(); - $handles[] = static::DEFAULT_NO_RESULT_HANDLE; - } + $catalogSearchHelper = $this->_objectManager->get(\Magento\CatalogSearch\Helper\Data::class); - if (empty($getAdditionalRequestParameters) && - $this->_objectManager->get(PopularSearchTerms::class)->isCacheable($queryText, $storeId) - ) { - $this->getCacheableResult($catalogSearchHelper, $query, $handles); - } else { - $this->getNotCacheableResult($catalogSearchHelper, $query, $handles); - } + $getAdditionalRequestParameters = $this->getRequest()->getParams(); + unset($getAdditionalRequestParameters[QueryFactory::QUERY_VAR_NAME]); + + $handles = null; + if ($query->getNumResults() == 0) { + $this->_view->getPage()->initLayout(); + $handles = $this->_view->getLayout()->getUpdate()->getHandles(); + $handles[] = static::DEFAULT_NO_RESULT_HANDLE; + } + + if (empty($getAdditionalRequestParameters) && + $this->_objectManager->get(PopularSearchTerms::class)->isCacheable($queryText, $storeId) + ) { + $this->getCacheableResult($catalogSearchHelper, $query, $handles); } else { - $this->getResponse()->setRedirect($this->_redirect->getRedirectUrl()); + $this->getNotCacheableResult($catalogSearchHelper, $query, $handles); } } diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/Test/CatalogSearchWithNegativePageNumberTest.xml b/app/code/Magento/CatalogSearch/Test/Mftf/Test/CatalogSearchWithNegativePageNumberTest.xml new file mode 100644 index 0000000000000..a4b9a90ab9bd7 --- /dev/null +++ b/app/code/Magento/CatalogSearch/Test/Mftf/Test/CatalogSearchWithNegativePageNumberTest.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright 2019 Adobe + * All Rights Reserved. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="CatalogSearchWithNegativePageNumberTest"> + <annotations> + <features value="CatalogSearch"/> + <stories value="Catalog Search Results"/> + <title value="Pagination should reset on Storefront when negative page number requested"/> + <description value="Pagination should reset on Storefront when negative page number requested"/> + <severity value="AVERAGE"/> + <testCaseId value=""/> + <useCaseId value=""/> + <group value="CatalogSearch"/> + <group value="SearchEngine"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createSimpleProductOne"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="SimpleProduct" stepKey="createSimpleProductTwo"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createSimpleProductOne" stepKey="deleteProductOne"/> + <deleteData createDataKey="createSimpleProductTwo" stepKey="deleteProductTwo"/> + </after> + + <actionGroup ref="StorefrontQuickSearchWithPaginationActionGroup" stepKey="visitSearchResults"> + <argument name="phrase" value="simple"/> + <argument name="pageNumber" value="-1"/> + </actionGroup> + + <!-- Validate that "no products found" error message is not present --> + <actionGroup ref="StorefrontDontSeeNoProductsFoundActionGroup" stepKey="dontSeeNoProdsFoundMessage"/> + <!-- Verify the products are visible on the Category Page --> + <actionGroup ref="AssertStorefrontProductIsPresentOnCategoryPageActionGroup" stepKey="seeProductOneOnGrid"> + <argument name="productName" value="$$createSimpleProductOne.name$$"/> + </actionGroup> + <actionGroup ref="AssertStorefrontProductIsPresentOnCategoryPageActionGroup" stepKey="seeProductTwoOnGrid"> + <argument name="productName" value="$$createSimpleProductTwo.name$$"/> + </actionGroup> + </test> +</tests>