From 2ca15d02dbf1c57af28af936ae8cbaabb9f45c09 Mon Sep 17 00:00:00 2001 From: Pierre RAMBAUD Date: Tue, 28 May 2019 16:44:11 +0200 Subject: [PATCH 01/25] Fix Filters not working between attributes --- src/Adapter/MySQL.php | 41 ++++++--- src/Product/Search.php | 10 ++- tests/php/FacetedSearch/Adapter/MySQLTest.php | 87 ++++++++++++------- .../php/FacetedSearch/Product/SearchTest.php | 19 ++-- 4 files changed, 108 insertions(+), 49 deletions(-) diff --git a/src/Adapter/MySQL.php b/src/Adapter/MySQL.php index 97cd0e4ff..09e76880f 100644 --- a/src/Adapter/MySQL.php +++ b/src/Adapter/MySQL.php @@ -127,10 +127,10 @@ public function getQuery() $query .= implode(', ', $selectFields) . ' FROM ' . $referenceTable . ' p'; - foreach ($joinConditions as $tableName => $joinAliasConditionInfos) { - foreach ($joinAliasConditionInfos as $tableAlias => $joinConditionInfos) { - $query .= ' ' . $joinConditionInfos['joinType'] . ' ' . _DB_PREFIX_ . $tableName . ' ' . - $tableAlias . ' ON ' . $joinConditionInfos['joinCondition']; + foreach ($joinConditions as $joinAliasInfos) { + foreach ($joinAliasInfos as $tableAlias => $joinInfos) { + $query .= ' ' . $joinInfos['joinType'] . ' ' . _DB_PREFIX_ . $joinInfos['tableName'] . ' ' . + $tableAlias . ' ON ' . $joinInfos['joinCondition']; } } @@ -262,14 +262,14 @@ protected function getFieldMapping() 'out_of_stock' => [ 'tableName' => 'stock_available', 'tableAlias' => 'sa', - 'joinCondition' => '(p.id_product=sa.id_product AND 0 = sa.id_product_attribute ' . + 'joinCondition' => '(p.id_product = sa.id_product AND 0 = sa.id_product_attribute ' . $stockCondition . ')', 'joinType' => self::LEFT_JOIN, ], 'quantity' => [ 'tableName' => 'stock_available', 'tableAlias' => 'sa', - 'joinCondition' => '(p.id_product=sa.id_product AND 0 = sa.id_product_attribute ' . + 'joinCondition' => '(p.id_product = sa.id_product AND 0 = sa.id_product_attribute ' . $stockCondition . ')', 'joinType' => self::LEFT_JOIN, ], @@ -399,13 +399,13 @@ private function computeWhereConditions($filterToTableMapping) $operationsConditions = []; foreach ($filterOperations as $operations) { $conditions = []; - foreach ($operations as $operation) { + foreach ($operations as $idx => $operation) { $selectAlias = 'p'; $values = $operation[1]; $operator = '='; if (array_key_exists($operation[0], $filterToTableMapping)) { $joinMapping = $filterToTableMapping[$operation[0]]; - $selectAlias = $joinMapping['tableAlias']; + $selectAlias = $joinMapping['tableAlias'] . ($idx === 0 ? '' : $idx); $operation[0] = isset($joinMapping['fieldName']) ? $joinMapping['fieldName'] : $operation[0]; } @@ -511,7 +511,7 @@ private function computeJoinConditions($filterToTableMapping) { $joinList = new ArrayCollection(); - foreach ($this->getSelectFields() as $key => $selectField) { + foreach ($this->getSelectFields() as $selectField) { if (array_key_exists($selectField, $filterToTableMapping)) { $joinMapping = $filterToTableMapping[$selectField]; $this->addJoinConditions($joinList, $joinMapping, $filterToTableMapping); @@ -525,6 +525,26 @@ private function computeJoinConditions($filterToTableMapping) } } + foreach ($this->getOperationsFilters() as $filterOperations) { + foreach ($filterOperations as $operations) { + foreach ($operations as $idx => $operation) { + if (array_key_exists($operation[0], $filterToTableMapping)) { + $joinMapping = $filterToTableMapping[$operation[0]]; + if ($idx !== 0) { + $joinMapping['joinCondition'] = preg_replace( + '~([\(\s=]' . $joinMapping['tableAlias'] . ')\.~', + '${1}' . $idx . '.', + $joinMapping['joinCondition'] + ); + $joinMapping['tableAlias'] .= $idx; + } + + $this->addJoinConditions($joinList, $joinMapping, $filterToTableMapping); + } + } + } + } + foreach ($this->getGroupFields() as $groupFields => $filterContent) { if (array_key_exists($groupFields, $filterToTableMapping)) { $joinMapping = $filterToTableMapping[$groupFields]; @@ -554,11 +574,12 @@ private function addJoinConditions(ArrayCollection $joinList, $joinMapping, $fil $this->addJoinConditions($joinList, $dependencyJoinMapping, $filterToTableMapping); } $joinInfos[$joinMapping['tableAlias']] = [ + 'tableName' => $joinMapping['tableName'], 'joinCondition' => $joinMapping['joinCondition'], 'joinType' => $joinMapping['joinType'], ]; - $joinList->set($joinMapping['tableName'], $joinInfos); + $joinList->set($joinMapping['tableAlias'] . $joinMapping['tableName'], $joinInfos); } /** diff --git a/src/Product/Search.php b/src/Product/Search.php index 3a0afc438..f94d57123 100644 --- a/src/Product/Search.php +++ b/src/Product/Search.php @@ -138,7 +138,15 @@ private function addSearchFilters($selectedFilters, $parent, $idShop) break; case 'id_attribute_group': - $this->addFilter('id_attribute', $filterValues); + $operationsFilter = []; + foreach ($filterValues as $filterValue) { + $operationsFilter[] = ['id_attribute', $filterValue]; + } + + $this->getSearchAdapter()->addOperationsFilter( + 'with_attributes', + [$operationsFilter] + ); break; case 'category': diff --git a/tests/php/FacetedSearch/Adapter/MySQLTest.php b/tests/php/FacetedSearch/Adapter/MySQLTest.php index 7a63f706f..c4d351e2b 100644 --- a/tests/php/FacetedSearch/Adapter/MySQLTest.php +++ b/tests/php/FacetedSearch/Adapter/MySQLTest.php @@ -260,7 +260,7 @@ public function testGetQueryWithAllSelectField() ); $this->assertEquals( - 'SELECT p.id_product, pa.id_product_attribute, pac.id_attribute, a.id_attribute_group, fp.id_feature, ps.id_shop, p.id_feature_çvalue, cp.id_category, pl.name, c.nleft, c.nright, c.level_depth, sa.out_of_stock, sa.quantity, psi.price_min, psi.price_max, psi.range_start, psi.range_end, cg.id_group, m.name FROM ps_product p STRAIGHT_JOIN ps_product_attribute pa ON (p.id_product = pa.id_product) STRAIGHT_JOIN ps_product_attribute_combination pac ON (pa.id_product_attribute = pac.id_product_attribute) STRAIGHT_JOIN ps_attribute a ON (a.id_attribute = pac.id_attribute) INNER JOIN ps_feature_product fp ON (p.id_product = fp.id_product) INNER JOIN ps_product_shop ps ON (p.id_product = ps.id_product AND ps.id_shop = 1) INNER JOIN ps_category_product cp ON (p.id_product = cp.id_product) INNER JOIN ps_product_lang pl ON (p.id_product = pl.id_product AND pl.id_shop = 1 AND pl.id_lang = 2) INNER JOIN ps_category c ON (cp.id_category = c.id_category AND c.active=1) LEFT JOIN ps_stock_available sa ON (p.id_product=sa.id_product AND 0 = sa.id_product_attribute ) INNER JOIN ps_layered_price_index psi ON (psi.id_product = p.id_product AND psi.id_currency = 4 AND psi.id_country = 3) LEFT JOIN ps_category_group cg ON (cg.id_category = c.id_category) INNER JOIN ps_manufacturer m ON (p.id_manufacturer = m.id_manufacturer) WHERE p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20', + 'SELECT p.id_product, pa.id_product_attribute, pac.id_attribute, a.id_attribute_group, fp.id_feature, ps.id_shop, p.id_feature_çvalue, cp.id_category, pl.name, c.nleft, c.nright, c.level_depth, sa.out_of_stock, sa.quantity, psi.price_min, psi.price_max, psi.range_start, psi.range_end, cg.id_group, m.name FROM ps_product p STRAIGHT_JOIN ps_product_attribute pa ON (p.id_product = pa.id_product) STRAIGHT_JOIN ps_product_attribute_combination pac ON (pa.id_product_attribute = pac.id_product_attribute) STRAIGHT_JOIN ps_attribute a ON (a.id_attribute = pac.id_attribute) INNER JOIN ps_feature_product fp ON (p.id_product = fp.id_product) INNER JOIN ps_product_shop ps ON (p.id_product = ps.id_product AND ps.id_shop = 1) INNER JOIN ps_category_product cp ON (p.id_product = cp.id_product) INNER JOIN ps_product_lang pl ON (p.id_product = pl.id_product AND pl.id_shop = 1 AND pl.id_lang = 2) INNER JOIN ps_category c ON (cp.id_category = c.id_category AND c.active=1) LEFT JOIN ps_stock_available sa ON (p.id_product = sa.id_product AND 0 = sa.id_product_attribute ) INNER JOIN ps_layered_price_index psi ON (psi.id_product = p.id_product AND psi.id_currency = 4 AND psi.id_country = 3) LEFT JOIN ps_category_group cg ON (cg.id_category = c.id_category) INNER JOIN ps_manufacturer m ON (p.id_manufacturer = m.id_manufacturer) WHERE p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20', $this->adapter->getQuery() ); } @@ -286,35 +286,17 @@ public function testGetQueryWithManyFilters() $this->adapter->addFilter('id_product', [2, 20, 200], '='); $this->assertEquals( - 'SELECT p.id_product, sa.out_of_stock, sa.quantity, psi.price_min, psi.price_max, psi.range_start, psi.range_end FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product=sa.id_product AND 0 = sa.id_product_attribute ) INNER JOIN ps_layered_price_index psi ON (psi.id_product = p.id_product AND psi.id_currency = 4 AND psi.id_country = 3) WHERE p.condition IN (\'new\', \'used\') AND p.weight=\'10\' AND psi.price_min>=10 AND psi.price_min<=100 AND p.id_product IN (2, 20, 200) AND p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20', + 'SELECT p.id_product, sa.out_of_stock, sa.quantity, psi.price_min, psi.price_max, psi.range_start, psi.range_end FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product = sa.id_product AND 0 = sa.id_product_attribute ) INNER JOIN ps_layered_price_index psi ON (psi.id_product = p.id_product AND psi.id_currency = 4 AND psi.id_country = 3) WHERE p.condition IN (\'new\', \'used\') AND p.weight=\'10\' AND psi.price_min>=10 AND psi.price_min<=100 AND p.id_product IN (2, 20, 200) AND p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20', $this->adapter->getQuery() ); } - public function testGetQueryWithManyOperationsFilters() + /** + * @dataProvider getManyOperationsFilters + */ + public function testGetQueryWithManyOperationsFilters($fields, $operationsFilter, $expected) { - $this->adapter->setSelectFields( - [ - 'id_product', - 'out_of_stock', - 'quantity', - 'price_min', - 'price_max', - 'range_start', - 'range_end', - ] - ); - - $operationsFilter = [ - [ - ['quantity', [0], '>='], - ['out_of_stock', [1, 3, 4], '='], - ], - [ - ['quantity', [0], '>'], - ['out_of_stock', [1], '='], - ], - ]; + $this->adapter->setSelectFields($fields); $this->adapter->addOperationsFilter( 'out_of_stock_filter', @@ -322,7 +304,7 @@ public function testGetQueryWithManyOperationsFilters() ); $this->assertEquals( - 'SELECT p.id_product, sa.out_of_stock, sa.quantity, psi.price_min, psi.price_max, psi.range_start, psi.range_end FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product=sa.id_product AND 0 = sa.id_product_attribute ) INNER JOIN ps_layered_price_index psi ON (psi.id_product = p.id_product AND psi.id_currency = 4 AND psi.id_country = 3) WHERE ((sa.quantity>=0 AND sa.out_of_stock IN (1, 3, 4)) OR (sa.quantity>0 AND sa.out_of_stock=1)) AND p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20', + $expected, $this->adapter->getQuery() ); } @@ -371,7 +353,7 @@ public function testGetQueryWithPriceOrderFieldInAscWithInitialPopulation() $this->adapter->setOrderDirection('asc'); $this->assertEquals( - 'SELECT p.id_product FROM (SELECT p.id_product, p.id_manufacturer, sa.quantity, p.condition, p.weight, p.price, m.name FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product=sa.id_product AND 0 = sa.id_product_attribute ) INNER JOIN ps_manufacturer m ON (p.id_manufacturer = m.id_manufacturer) WHERE p.active = TRUE) p INNER JOIN ps_manufacturer m ON (p.id_manufacturer = m.id_manufacturer) ORDER BY m.name ASC', + 'SELECT p.id_product FROM (SELECT p.id_product, p.id_manufacturer, sa.quantity, p.condition, p.weight, p.price, m.name FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product = sa.id_product AND 0 = sa.id_product_attribute ) INNER JOIN ps_manufacturer m ON (p.id_manufacturer = m.id_manufacturer) WHERE p.active = TRUE) p INNER JOIN ps_manufacturer m ON (p.id_manufacturer = m.id_manufacturer) ORDER BY m.name ASC', $this->adapter->getQuery() ); } @@ -384,11 +366,56 @@ public function testGetQueryWithPositionOrderFieldInAscWithInitialPopulation() $this->adapter->setOrderDirection('desc'); $this->assertEquals( - 'SELECT p.id_product FROM (SELECT p.id_product, p.id_manufacturer, sa.quantity, p.condition, p.weight, p.price, cp.position FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product=sa.id_product AND 0 = sa.id_product_attribute ) INNER JOIN ps_category_product cp ON (p.id_product = cp.id_product) WHERE p.active = TRUE) p INNER JOIN ps_category_product cp ON (p.id_product = cp.id_product) ORDER BY p.position DESC', + 'SELECT p.id_product FROM (SELECT p.id_product, p.id_manufacturer, sa.quantity, p.condition, p.weight, p.price, cp.position FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product = sa.id_product AND 0 = sa.id_product_attribute ) INNER JOIN ps_category_product cp ON (p.id_product = cp.id_product) WHERE p.active = TRUE) p INNER JOIN ps_category_product cp ON (p.id_product = cp.id_product) ORDER BY p.position DESC', $this->adapter->getQuery() ); } + public function getManyOperationsFilters() + { + return [ + [ + 'fields' => [ + 'id_product', + 'out_of_stock', + 'quantity', + 'price_min', + 'price_max', + 'range_start', + 'range_end', + ], + 'operationsFilter' => [ + [ + ['quantity', [0], '>='], + ['out_of_stock', [1, 3, 4], '='], + ], + [ + ['quantity', [0], '>'], + ['out_of_stock', [1], '='], + ], + ], + 'expected' => 'SELECT p.id_product, sa.out_of_stock, sa.quantity, psi.price_min, psi.price_max, psi.range_start, psi.range_end FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product = sa.id_product AND 0 = sa.id_product_attribute ) INNER JOIN ps_layered_price_index psi ON (psi.id_product = p.id_product AND psi.id_currency = 4 AND psi.id_country = 3) LEFT JOIN ps_stock_available sa1 ON (p.id_product = sa1.id_product AND 0 = sa1.id_product_attribute ) WHERE ((sa.quantity>=0 AND sa1.out_of_stock IN (1, 3, 4)) OR (sa.quantity>0 AND sa1.out_of_stock=1)) AND p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20', + ], + [ + 'fields' => [ + 'id_product', + 'quantity', + ], + 'operationsFilter' => [ + [ + ['id_attribute', [2]], + ['id_attribute', [4]], + ], + [ + ['quantity', [0], '>'], + ['out_of_stock', [1], '='], + ], + ], + 'expected' => 'SELECT p.id_product, sa.quantity FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product = sa.id_product AND 0 = sa.id_product_attribute ) STRAIGHT_JOIN ps_product_attribute pa ON (p.id_product = pa.id_product) STRAIGHT_JOIN ps_product_attribute_combination pac ON (pa.id_product_attribute = pac.id_product_attribute) STRAIGHT_JOIN ps_product_attribute_combination pac1 ON (pa.id_product_attribute = pac1.id_product_attribute) LEFT JOIN ps_stock_available sa1 ON (p.id_product = sa1.id_product AND 0 = sa1.id_product_attribute ) WHERE ((pac.id_attribute=2 AND pac1.id_attribute=4) OR (sa.quantity>0 AND sa1.out_of_stock=1)) AND p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20', + ], + ]; + } + public function oneSelectFieldDataProvider() { return [ @@ -405,8 +432,8 @@ public function oneSelectFieldDataProvider() ['nleft', 'SELECT c.nleft FROM ps_product p INNER JOIN ps_category_product cp ON (p.id_product = cp.id_product) INNER JOIN ps_category c ON (cp.id_category = c.id_category AND c.active=1) WHERE p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20'], ['nright', 'SELECT c.nright FROM ps_product p INNER JOIN ps_category_product cp ON (p.id_product = cp.id_product) INNER JOIN ps_category c ON (cp.id_category = c.id_category AND c.active=1) WHERE p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20'], ['level_depth', 'SELECT c.level_depth FROM ps_product p INNER JOIN ps_category_product cp ON (p.id_product = cp.id_product) INNER JOIN ps_category c ON (cp.id_category = c.id_category AND c.active=1) WHERE p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20'], - ['out_of_stock', 'SELECT sa.out_of_stock FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product=sa.id_product AND 0 = sa.id_product_attribute ) WHERE p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20'], - ['quantity', 'SELECT sa.quantity FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product=sa.id_product AND 0 = sa.id_product_attribute ) WHERE p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20'], + ['out_of_stock', 'SELECT sa.out_of_stock FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product = sa.id_product AND 0 = sa.id_product_attribute ) WHERE p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20'], + ['quantity', 'SELECT sa.quantity FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product = sa.id_product AND 0 = sa.id_product_attribute ) WHERE p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20'], ['price_min', 'SELECT psi.price_min FROM ps_product p INNER JOIN ps_layered_price_index psi ON (psi.id_product = p.id_product AND psi.id_currency = 4 AND psi.id_country = 3) WHERE p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20'], ['price_max', 'SELECT psi.price_max FROM ps_product p INNER JOIN ps_layered_price_index psi ON (psi.id_product = p.id_product AND psi.id_currency = 4 AND psi.id_country = 3) WHERE p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20'], ['range_start', 'SELECT psi.range_start FROM ps_product p INNER JOIN ps_layered_price_index psi ON (psi.id_product = p.id_product AND psi.id_currency = 4 AND psi.id_country = 3) WHERE p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20'], diff --git a/tests/php/FacetedSearch/Product/SearchTest.php b/tests/php/FacetedSearch/Product/SearchTest.php index 3ebaf508a..756b81680 100644 --- a/tests/php/FacetedSearch/Product/SearchTest.php +++ b/tests/php/FacetedSearch/Product/SearchTest.php @@ -188,14 +188,6 @@ public function testInitSearchWithAllFilters() ], ], ], - 'id_attribute' => [ - '=' => [ - [ - 4, - 5, - ], - ], - ], 'weight' => [ '>=' => [ [ @@ -275,6 +267,17 @@ public function testInitSearchWithAllFilters() ], ], ], + 'with_attributes' => [ + [ + [ + 'id_attribute', + [ + 4, + 5, + ], + ], + ], + ], ], $this->search->getSearchAdapter()->getInitialPopulation()->getOperationsFilters()->toArray() ); From 6a59ea11d44acf7310545e345fe41ddaff6874a5 Mon Sep 17 00:00:00 2001 From: Pierre RAMBAUD Date: Tue, 28 May 2019 17:04:37 +0200 Subject: [PATCH 02/25] More tests --- tests/php/FacetedSearch/Adapter/MySQLTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/php/FacetedSearch/Adapter/MySQLTest.php b/tests/php/FacetedSearch/Adapter/MySQLTest.php index c4d351e2b..e97a4dbbd 100644 --- a/tests/php/FacetedSearch/Adapter/MySQLTest.php +++ b/tests/php/FacetedSearch/Adapter/MySQLTest.php @@ -413,6 +413,24 @@ public function getManyOperationsFilters() ], 'expected' => 'SELECT p.id_product, sa.quantity FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product = sa.id_product AND 0 = sa.id_product_attribute ) STRAIGHT_JOIN ps_product_attribute pa ON (p.id_product = pa.id_product) STRAIGHT_JOIN ps_product_attribute_combination pac ON (pa.id_product_attribute = pac.id_product_attribute) STRAIGHT_JOIN ps_product_attribute_combination pac1 ON (pa.id_product_attribute = pac1.id_product_attribute) LEFT JOIN ps_stock_available sa1 ON (p.id_product = sa1.id_product AND 0 = sa1.id_product_attribute ) WHERE ((pac.id_attribute=2 AND pac1.id_attribute=4) OR (sa.quantity>0 AND sa1.out_of_stock=1)) AND p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20', ], + [ + 'fields' => [ + 'id_product', + 'quantity', + ], + 'operationsFilter' => [ + [ + ['id_attribute', [2]], + ['id_attribute', [4, 5, 6]], + ['id_attribute', [7, 8, 9]], + ], + [ + ['quantity', [0], '>'], + ['out_of_stock', [0], '='], + ], + ], + 'expected' => 'SELECT p.id_product, sa.quantity FROM ps_product p LEFT JOIN ps_stock_available sa ON (p.id_product = sa.id_product AND 0 = sa.id_product_attribute ) STRAIGHT_JOIN ps_product_attribute pa ON (p.id_product = pa.id_product) STRAIGHT_JOIN ps_product_attribute_combination pac ON (pa.id_product_attribute = pac.id_product_attribute) STRAIGHT_JOIN ps_product_attribute_combination pac1 ON (pa.id_product_attribute = pac1.id_product_attribute) STRAIGHT_JOIN ps_product_attribute_combination pac2 ON (pa.id_product_attribute = pac2.id_product_attribute) LEFT JOIN ps_stock_available sa1 ON (p.id_product = sa1.id_product AND 0 = sa1.id_product_attribute ) WHERE ((pac.id_attribute=2 AND pac1.id_attribute IN (4, 5, 6) AND pac2.id_attribute IN (7, 8, 9)) OR (sa.quantity>0 AND sa1.out_of_stock=0)) AND p.active = TRUE ORDER BY p.id_product DESC LIMIT 0, 20', + ], ]; } From 6bd7614faae2882d385386befa6c9a41e365f779 Mon Sep 17 00:00:00 2001 From: Pierre RAMBAUD Date: Tue, 28 May 2019 17:50:53 +0200 Subject: [PATCH 03/25] Render as a widget if hook is not found during the callable stack --- src/HookDispatcher.php | 14 +++++++++++++- tests/php/FacetedSearch/HookDispatcherTest.php | 15 ++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/HookDispatcher.php b/src/HookDispatcher.php index 91494a844..568ea337d 100644 --- a/src/HookDispatcher.php +++ b/src/HookDispatcher.php @@ -60,6 +60,13 @@ class HookDispatcher */ private $hooks = []; + /** + * Module + * + * @var Ps_Facetedsearch + */ + private $module; + /** * Init hooks * @@ -67,8 +74,10 @@ class HookDispatcher */ public function __construct(Ps_Facetedsearch $module) { + $this->module = $module; + foreach (self::CLASSES as $hookClass) { - $hook = new $hookClass($module); + $hook = new $hookClass($this->module); $this->availableHooks = array_merge($this->availableHooks, $hook->getAvailableHooks()); $this->hooks[] = $hook; } @@ -101,5 +110,8 @@ public function dispatch($hookName, array $params = []) return call_user_func([$hook, $hookName], $params); } } + + // No hook found, render it as a widget + return $this->module->renderWidget($hookName, $params); } } diff --git a/tests/php/FacetedSearch/HookDispatcherTest.php b/tests/php/FacetedSearch/HookDispatcherTest.php index b5a37fe28..33bd796c7 100644 --- a/tests/php/FacetedSearch/HookDispatcherTest.php +++ b/tests/php/FacetedSearch/HookDispatcherTest.php @@ -33,6 +33,7 @@ class HookDispatcherTest extends TestCase { + private $module; private $dispatcher; protected function setUp() @@ -42,14 +43,14 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $module = $this->getMockBuilder(Ps_FacetedSearch::class) - ->setMethods(['getContext', 'getDatabase']) + $this->module = $this->getMockBuilder(Ps_FacetedSearch::class) + ->setMethods(['getContext', 'getDatabase', 'renderWidget']) ->disableOriginalConstructor() ->getMock(); - $module->method('getContext') + $this->module->method('getContext') ->willReturn($contextMock); - $this->dispatcher = new HookDispatcher($module); + $this->dispatcher = new HookDispatcher($this->module); } public function testGetAvailableHooks() @@ -86,6 +87,10 @@ public function testGetAvailableHooks() public function testDispatchUnfoundHook() { - $this->assertNull($this->dispatcher->dispatch('ThisHookDoesNotExists')); + $this->module->expects($this->once()) + ->method('renderWidget') + ->with('ThisHookDoesNotExists', []) + ->willReturn(''); + $this->assertEquals('', $this->dispatcher->dispatch('ThisHookDoesNotExists')); } } From 5982b1784333f5c2ba10f103f574e750b9353b2c Mon Sep 17 00:00:00 2001 From: Pierre RAMBAUD Date: Wed, 29 May 2019 10:12:09 +0200 Subject: [PATCH 04/25] Cleanup code --- src/Adapter/MySQL.php | 62 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/Adapter/MySQL.php b/src/Adapter/MySQL.php index 09e76880f..e4b39ecab 100644 --- a/src/Adapter/MySQL.php +++ b/src/Adapter/MySQL.php @@ -320,7 +320,7 @@ protected function getFieldMapping() * * @return string */ - private function computeOrderByField($filterToTableMapping) + private function computeOrderByField(array $filterToTableMapping) { $orderField = $this->getOrderField(); if ($this->getInitialPopulation() !== null && !empty($orderField)) { @@ -362,7 +362,7 @@ private function computeOrderByField($filterToTableMapping) * * @return array */ - private function computeSelectFields($filterToTableMapping) + private function computeSelectFields(array $filterToTableMapping) { $selectFields = []; foreach ($this->getSelectFields() as $key => $selectField) { @@ -392,7 +392,7 @@ private function computeSelectFields($filterToTableMapping) * * @return array */ - private function computeWhereConditions($filterToTableMapping) + private function computeWhereConditions(array $filterToTableMapping) { $whereConditions = []; foreach ($this->getOperationsFilters() as $filterName => $filterOperations) { @@ -402,18 +402,16 @@ private function computeWhereConditions($filterToTableMapping) foreach ($operations as $idx => $operation) { $selectAlias = 'p'; $values = $operation[1]; - $operator = '='; if (array_key_exists($operation[0], $filterToTableMapping)) { $joinMapping = $filterToTableMapping[$operation[0]]; + // If index is not the first, append to the table alias for + // multi join $selectAlias = $joinMapping['tableAlias'] . ($idx === 0 ? '' : $idx); $operation[0] = isset($joinMapping['fieldName']) ? $joinMapping['fieldName'] : $operation[0]; } - if (count($values) == 1) { - if (!empty($operation[2])) { - $operator = $operation[2]; - } - + if (count($values) === 1) { + $operator = !empty($operation[2]) ? $operation[2] : '='; $conditions[] = $selectAlias . '.' . $operation[0] . $operator . current($values); } else { $conditions[] = $selectAlias . '.' . $operation[0] . ' IN (' . implode(', ', array_map(function ($value) { @@ -507,23 +505,12 @@ private function computeWhereConditions($filterToTableMapping) * * @return ArrayCollection */ - private function computeJoinConditions($filterToTableMapping) + private function computeJoinConditions(array $filterToTableMapping) { $joinList = new ArrayCollection(); - foreach ($this->getSelectFields() as $selectField) { - if (array_key_exists($selectField, $filterToTableMapping)) { - $joinMapping = $filterToTableMapping[$selectField]; - $this->addJoinConditions($joinList, $joinMapping, $filterToTableMapping); - } - } - - foreach ($this->getFilters() as $filterName => $filterContent) { - if (array_key_exists($filterName, $filterToTableMapping)) { - $joinMapping = $filterToTableMapping[$filterName]; - $this->addJoinConditions($joinList, $joinMapping, $filterToTableMapping); - } - } + $this->addJoinList($joinList, $this->getSelectFields(), $filterToTableMapping); + $this->addJoinList($joinList, $this->getFilters()->getKeys(), $filterToTableMapping); foreach ($this->getOperationsFilters() as $filterOperations) { foreach ($filterOperations as $operations) { @@ -531,6 +518,7 @@ private function computeJoinConditions($filterToTableMapping) if (array_key_exists($operation[0], $filterToTableMapping)) { $joinMapping = $filterToTableMapping[$operation[0]]; if ($idx !== 0) { + // Index is not the first, append index to tableAlias on joinCondition $joinMapping['joinCondition'] = preg_replace( '~([\(\s=]' . $joinMapping['tableAlias'] . ')\.~', '${1}' . $idx . '.', @@ -545,12 +533,7 @@ private function computeJoinConditions($filterToTableMapping) } } - foreach ($this->getGroupFields() as $groupFields => $filterContent) { - if (array_key_exists($groupFields, $filterToTableMapping)) { - $joinMapping = $filterToTableMapping[$groupFields]; - $this->addJoinConditions($joinList, $joinMapping, $filterToTableMapping); - } - } + $this->addJoinList($joinList, $this->getGroupFields()->getKeys(), $filterToTableMapping); if (array_key_exists($this->getOrderField(), $filterToTableMapping)) { $joinMapping = $filterToTableMapping[$this->getOrderField()]; @@ -560,6 +543,23 @@ private function computeJoinConditions($filterToTableMapping) return $joinList; } + /** + * Helper to add tables infos to the join list. + * + * @param ArrayCollection $joinList + * @param array|ArrayCollection $list + * @param array $filterToTableMapping + */ + private function addJoinList(ArrayCollection $joinList, $list, array $filterToTableMapping) + { + foreach ($list as $field) { + if (array_key_exists($field, $filterToTableMapping)) { + $joinMapping = $filterToTableMapping[$field]; + $this->addJoinConditions($joinList, $joinMapping, $filterToTableMapping); + } + } + } + /** * Add the required table infos to the join list, taking care of the dependent tables * @@ -567,7 +567,7 @@ private function computeJoinConditions($filterToTableMapping) * @param array $joinMapping * @param array $filterToTableMapping */ - private function addJoinConditions(ArrayCollection $joinList, $joinMapping, $filterToTableMapping) + private function addJoinConditions(ArrayCollection $joinList, array $joinMapping, array $filterToTableMapping) { if (array_key_exists('dependencyField', $joinMapping)) { $dependencyJoinMapping = $filterToTableMapping[$joinMapping['dependencyField']]; @@ -589,7 +589,7 @@ private function addJoinConditions(ArrayCollection $joinList, $joinMapping, $fil * * @return array */ - private function computeGroupByFields($filterToTableMapping) + private function computeGroupByFields(array $filterToTableMapping) { $groupFields = []; if (empty($this->getGroupFields())) { From afaf7d61f2eb84f175918e7eea5b8d747f6f11fd Mon Sep 17 00:00:00 2001 From: Pierre RAMBAUD Date: Wed, 29 May 2019 11:45:43 +0200 Subject: [PATCH 05/25] Make sure id are different between widgets --- _dev/front/slider.js | 2 +- ps_facetedsearch.php | 7 +++++-- views/dist/front.js | 2 +- views/dist/front.js.map | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/_dev/front/slider.js b/_dev/front/slider.js index 307c93bb3..52e3cdc21 100644 --- a/_dev/front/slider.js +++ b/_dev/front/slider.js @@ -69,7 +69,7 @@ const refreshSliders = () => { values === null ? $el.data('slider-min') : values[0], values === null ? $el.data('slider-max') : values[1], ], - change(event, ui) { + stop(event, ui) { const nextEncodedFacetsURL = $el.data('slider-encoded-url'); const urlsSplitted = nextEncodedFacetsURL.split('?'); let queryParams = []; diff --git a/ps_facetedsearch.php b/ps_facetedsearch.php index dc2320df5..7a806381a 100755 --- a/ps_facetedsearch.php +++ b/ps_facetedsearch.php @@ -1424,8 +1424,11 @@ private function indexPricesUnbreakable($cursor, $full = false, $smart = false, public function renderWidget($hookName, array $configuration) { $this->smarty->assign($this->getWidgetVariables($hookName, $configuration)); - - return $this->fetch('module:ps_facetedsearch/ps_facetedsearch.tpl'); + return $this->fetch( + 'module:ps_facetedsearch/ps_facetedsearch.tpl', + false, + false + ); } /** diff --git a/views/dist/front.js b/views/dist/front.js index 38047b69b..23033b6aa 100644 --- a/views/dist/front.js +++ b/views/dist/front.js @@ -142,7 +142,7 @@ * @copyright 2007-2019 PrestaShop SA * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) * International Registered Trademark & Property of PrestaShop SA - */let v;const y=(t,e,i)=>{void 0===v?t.text(t.text().replace(/([^\d]*)(?:[\d .,]+)([^\d]+)(?:[\d .,]+)(.*)/,`$1${e}$2${i}$3`)):t.text(`${v.format(e)} - ${v.format(i)}`)};var b=()=>{$(".faceted-slider").each(function(){const t=$(this),e=t.data("slider-values"),i=t.data("slider-specifications");null!=i&&(v=m.build(i)),y($(`#facet_label_${t.data("slider-id")}`),null===e?t.data("slider-min"):e[0],null===e?t.data("slider-max"):e[1]),$(`#slider-range_${t.data("slider-id")}`).slider({range:!0,min:t.data("slider-min"),max:t.data("slider-max"),values:[null===e?t.data("slider-min"):e[0],null===e?t.data("slider-max"):e[1]],change(e,i){const r=t.data("slider-encoded-url").split("?");let s=[];r.length>1&&(s=n(r[1]));let o=!1;s.forEach(t=>{"q"===t.name&&(o=!0)}),o||s.push({name:"q",value:""}),s.forEach(e=>{"q"===e.name&&(e.value+=[e.value.length>0?"/":"",t.data("slider-label"),"-",t.data("slider-unit"),"-",i.values[0],"-",i.values[1]].join(""))});const a=[r[0],"?",$.param(s)].join("");prestashop.emit("updateFacets",a)},slide(e,i){y($(`#facet_label_${t.data("slider-id")}`),i.values[0],i.values[1])}})})};i(2); + */let v;const y=(t,e,i)=>{void 0===v?t.text(t.text().replace(/([^\d]*)(?:[\d .,]+)([^\d]+)(?:[\d .,]+)(.*)/,`$1${e}$2${i}$3`)):t.text(`${v.format(e)} - ${v.format(i)}`)};var b=()=>{$(".faceted-slider").each(function(){const t=$(this),e=t.data("slider-values"),i=t.data("slider-specifications");null!=i&&(v=m.build(i)),y($(`#facet_label_${t.data("slider-id")}`),null===e?t.data("slider-min"):e[0],null===e?t.data("slider-max"):e[1]),$(`#slider-range_${t.data("slider-id")}`).slider({range:!0,min:t.data("slider-min"),max:t.data("slider-max"),values:[null===e?t.data("slider-min"):e[0],null===e?t.data("slider-max"):e[1]],stop(e,i){const r=t.data("slider-encoded-url").split("?");let s=[];r.length>1&&(s=n(r[1]));let o=!1;s.forEach(t=>{"q"===t.name&&(o=!0)}),o||s.push({name:"q",value:""}),s.forEach(e=>{"q"===e.name&&(e.value+=[e.value.length>0?"/":"",t.data("slider-label"),"-",t.data("slider-unit"),"-",i.values[0],"-",i.values[1]].join(""))});const a=[r[0],"?",$.param(s)].join("");prestashop.emit("updateFacets",a)},slide(e,i){y($(`#facet_label_${t.data("slider-id")}`),i.values[0],i.values[1])}})})};i(2); /** * 2007-2019 PrestaShop. * diff --git a/views/dist/front.js.map b/views/dist/front.js.map index 7f551daf3..bcd0ac8d1 100644 --- a/views/dist/front.js.map +++ b/views/dist/front.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./node_modules/style-loader/lib/addStyles.js","webpack:///./node_modules/style-loader/lib/urls.js","webpack:///./_dev/front/overlay.scss?8707","webpack:///./_dev/front/slider.scss?98f8","webpack:///./_dev/front/facet.scss?49f4","webpack:///./_dev/front/urlparser.js","webpack:///./_dev/cldr/exception/localization.js","webpack:///./_dev/cldr/number-symbol.js","webpack:///./_dev/cldr/specifications/number.js","webpack:///./_dev/cldr/specifications/price.js","webpack:///./_dev/cldr/number-formatter.js","webpack:///./_dev/front/slider.js","webpack:///./_dev/front/overlay.js","webpack:///./_dev/front/events.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","fn","memo","stylesInDom","isOldIE","window","document","all","atob","apply","this","arguments","getElement","target","parent","styleTarget","querySelector","HTMLIFrameElement","contentDocument","head","e","singleton","singletonCounter","stylesInsertedAtTop","fixUrls","addStylesToDom","styles","options","length","item","domStyle","id","refs","j","parts","push","addStyle","listToStyles","list","newStyles","base","part","css","media","sourceMap","insertStyleElement","style","insertInto","Error","lastStyleElementInsertedAtTop","insertAt","nextSibling","insertBefore","appendChild","firstChild","before","removeStyleElement","parentNode","removeChild","idx","indexOf","splice","createStyleElement","createElement","undefined","attrs","type","nonce","nc","getNonce","addAttrs","el","keys","forEach","setAttribute","obj","update","remove","result","transform","default","styleIndex","applyToSingletonTag","URL","createObjectURL","revokeObjectURL","Blob","btoa","link","rel","createLinkElement","autoFixUrls","convertToAbsoluteUrls","unescape","encodeURIComponent","JSON","stringify","blob","oldSrc","href","styleSheet","cssText","createTextNode","newObj","DEBUG","newList","mayRemove","textStore","replaceText","index","replacement","filter","Boolean","join","cssNode","childNodes","location","baseUrl","protocol","host","currentDir","pathname","replace","fullMatch","origUrl","newUrl","unquotedOrigUrl","trim","$1","test","content","hmr","locals","urlparser","params","split","map","str","val","decodeURIComponent","localization","[object Object]","message","number_symbol","decimal","group","percentSign","minusSign","plusSign","exponential","superscriptingExponent","perMille","infinity","nan","validateData","number","positivePattern","negativePattern","symbol","maxFractionDigits","minFractionDigits","groupingUsed","primaryGroupSize","secondaryGroupSize","CURRENCY_DISPLAY_SYMBOL","price","currencySymbol","currencyCode","super","CURRENCY_SYMBOL_PLACEHOLDER","DECIMAL_SEPARATOR_PLACEHOLDER","GROUP_SEPARATOR_PLACEHOLDER","MINUS_SIGN_PLACEHOLDER","PERCENT_SYMBOL_PLACEHOLDER","PLUS_SIGN_PLACEHOLDER","number_formatter_NumberFormatter","specification","numberSpecification","num","Math","abs","toFixed","getMaxFractionDigits","majorDigits","minorDigits","extractMajorMinorDigits","formattedNumber","splitMajorGroups","adjustMinorDigitsZeroes","pattern","getCldrPattern","addPlaceholders","replaceSymbols","performSpecificReplacements","toString","digit","isGroupingUsed","reverse","groups","getPrimaryGroupSize","getSecondaryGroupSize","newGroups","getMinFractionDigits","padEnd","isNegative","getNegativePattern","getPositivePattern","symbols","getSymbol","getDecimal","getGroup","getMinusSign","getPercentSign","getPlusSign","getCurrencySymbol","specifications","parseInt","number_formatter","formatter","displayLabelBlock","displayBlock","min","max","text","format","slider","$","each","$el","values","data","build","range","event","ui","urlsSplitted","queryParams","found","query","requestUrl","param","prestashop","emit","template","ready","on","append"],"mappings":"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","file":"front.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 11);\n","/*\n\tMIT License http://www.opensource.org/licenses/mit-license.php\n\tAuthor Tobias Koppers @sokra\n*/\n\nvar stylesInDom = {};\n\nvar\tmemoize = function (fn) {\n\tvar memo;\n\n\treturn function () {\n\t\tif (typeof memo === \"undefined\") memo = fn.apply(this, arguments);\n\t\treturn memo;\n\t};\n};\n\nvar isOldIE = memoize(function () {\n\t// Test for IE <= 9 as proposed by Browserhacks\n\t// @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805\n\t// Tests for existence of standard globals is to allow style-loader\n\t// to operate correctly into non-standard environments\n\t// @see https://github.com/webpack-contrib/style-loader/issues/177\n\treturn window && document && document.all && !window.atob;\n});\n\nvar getTarget = function (target, parent) {\n if (parent){\n return parent.querySelector(target);\n }\n return document.querySelector(target);\n};\n\nvar getElement = (function (fn) {\n\tvar memo = {};\n\n\treturn function(target, parent) {\n // If passing function in options, then use it for resolve \"head\" element.\n // Useful for Shadow Root style i.e\n // {\n // insertInto: function () { return document.querySelector(\"#foo\").shadowRoot }\n // }\n if (typeof target === 'function') {\n return target();\n }\n if (typeof memo[target] === \"undefined\") {\n\t\t\tvar styleTarget = getTarget.call(this, target, parent);\n\t\t\t// Special case to return head of iframe instead of iframe itself\n\t\t\tif (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n\t\t\t\ttry {\n\t\t\t\t\t// This will throw an exception if access to iframe is blocked\n\t\t\t\t\t// due to cross-origin restrictions\n\t\t\t\t\tstyleTarget = styleTarget.contentDocument.head;\n\t\t\t\t} catch(e) {\n\t\t\t\t\tstyleTarget = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tmemo[target] = styleTarget;\n\t\t}\n\t\treturn memo[target]\n\t};\n})();\n\nvar singleton = null;\nvar\tsingletonCounter = 0;\nvar\tstylesInsertedAtTop = [];\n\nvar\tfixUrls = require(\"./urls\");\n\nmodule.exports = function(list, options) {\n\tif (typeof DEBUG !== \"undefined\" && DEBUG) {\n\t\tif (typeof document !== \"object\") throw new Error(\"The style-loader cannot be used in a non-browser environment\");\n\t}\n\n\toptions = options || {};\n\n\toptions.attrs = typeof options.attrs === \"object\" ? options.attrs : {};\n\n\t// Force single-tag solution on IE6-9, which has a hard limit on the # of