diff --git a/src/Product/Search.php b/src/Product/Search.php index 23e13185c..2fafe50ed 100644 --- a/src/Product/Search.php +++ b/src/Product/Search.php @@ -493,7 +493,12 @@ public function addFilter($filterName, array $filterValues) */ private function addPriceFilter($minPrice, $maxPrice) { - $this->getSearchAdapter()->addFilter('price_min', [$maxPrice], '<='); - $this->getSearchAdapter()->addFilter('price_max', [$minPrice], '>='); + // The slider is built from floor() of the lowest indexed price and ceil() of the highest, + // so a product indexed at 5995.000001 is offered as spanning 5995 to 5996. Comparing the + // raw column against those bounds then rejects it at both ends of its own range. + // `price_min < floor(max) + 1` is the same condition as `floor(price_min) <= max`, and + // keeps the column alone on its side of the comparison so the index is still usable. + $this->getSearchAdapter()->addFilter('price_min', [floor($maxPrice) + 1], '<'); + $this->getSearchAdapter()->addFilter('price_max', [ceil($minPrice) - 1], '>'); } } diff --git a/tests/php/FacetedSearch/Product/SearchTest.php b/tests/php/FacetedSearch/Product/SearchTest.php index 5aa33fd28..f15728c1a 100644 --- a/tests/php/FacetedSearch/Product/SearchTest.php +++ b/tests/php/FacetedSearch/Product/SearchTest.php @@ -334,16 +334,18 @@ public function testInitSearchWithAllFilters() ], ], 'price_min' => [ - '<=' => [ + // The bounds are widened by one unit so a product matches the range the slider + // displayed for it, which is floor(price_min) to ceil(price_max). + '<' => [ [ - 200.0, + 201.0, ], ], ], 'price_max' => [ - '>=' => [ + '>' => [ [ - 50.0, + 49.0, ], ], ], @@ -441,6 +443,25 @@ public function testInitSearchWithAllFilters() ); } + /** + * The slider is built from floor() of the lowest indexed price and ceil() of the highest, so a + * product indexed at 5995.000001 is offered to the shopper as spanning 5995 to 5996. Comparing + * the raw column against those bounds rejected it at both ends of its own range, which emptied + * the listing as soon as either handle was dragged. + * + * @see https://github.com/PrestaShop/PrestaShop/issues/37604 + */ + public function testInitSearchWidensPriceBoundsToTheDisplayedRange() + { + $this->search->initSearch(['price' => [5995, 5995]]); + + $filters = $this->search->getSearchAdapter()->getInitialPopulation()->getFilters()->toArray(); + + // 5995.000001 satisfies both: it is below 5996 and above 5994. + $this->assertEquals(['<' => [[5996.0]]], $filters['price_min']); + $this->assertEquals(['>' => [[5994.0]]], $filters['price_max']); + } + public function testInitSearchWithManyFeatures() { $this->search->initSearch(