diff --git a/src/Storm/Model/Loader.php b/src/Storm/Model/Loader.php index ac40c5ae3d81be540e1a3fc628f4feb98f818199..afda9e42e1dc8512a08045849f4e01deb8c3f882 100644 --- a/src/Storm/Model/Loader.php +++ b/src/Storm/Model/Loader.php @@ -498,9 +498,4 @@ class Storm_Model_Loader { public function fetchFirstForQuery(Storm_Query $query) : ?Storm_Model_Abstract { return $this->_findFirstFrom($this->fetchForQuery($query->limit(1))); } - - - public function greater(string $key, string $value) : Storm_Query_Clause { - return Storm_Query_Clause::greater($key, $value); - } } diff --git a/src/Storm/Query/Clause/Match.php b/src/Storm/Query/Clause/Match.php index f7ce65cbe45a59bc62cff3492aec8a26d64f12a8..e7f48b9810fc03c3cd622844b71b207333d4bceb 100644 --- a/src/Storm/Query/Clause/Match.php +++ b/src/Storm/Query/Clause/Match.php @@ -33,9 +33,7 @@ class Storm_Query_Clause_Match extends Storm_Query_Clause { $content = ''; foreach ($value->getTerms() as $key => $term) - $content = implode(' ', - array_filter([$content, - $term->getFormatDb($value->isStrict())])); + $content = implode(' ', array_filter([$content, $term->getFormatDb()])); $against = sprintf('AGAINST(%s%s)', Zend_Db_Table_Abstract::getDefaultAdapter() @@ -60,7 +58,7 @@ class Storm_Query_Clause_Match extends Storm_Query_Clause { foreach ($value->getTerms() as $term) { $new_compare = $term->getCompareValue($contents); - if ($value->isStrict() && 0 === $new_compare) + if ($term->isStrict() && 0 === $new_compare) return 0; $compare += $term->getCompareValue($contents); @@ -77,15 +75,16 @@ class Storm_Query_Clause_Match extends Storm_Query_Clause { || !($contents = $this->_getContents($model))) return false; + $contains_all = false; foreach ($value->getTerms() as $term) { - if ($value->isStrict() && !$term->containVolatile($contents)) + $contain = $term->containVolatile($contents); + if ($term->isStrict() && !$contain) return false; - if (!$value->isStrict() && $term->containVolatile($contents)) - return true; + $contains_all |= $contain; } - return $value->isStrict(); + return $contains_all; } diff --git a/src/Storm/Query/Clause/MatchTerms.php b/src/Storm/Query/Clause/MatchTerms.php index d255ac6bd1e29699615d45d0f73610c780eaff58..8bccf0d9772a6fc221578ed5d15d3200cd73a103 100644 --- a/src/Storm/Query/Clause/MatchTerms.php +++ b/src/Storm/Query/Clause/MatchTerms.php @@ -29,24 +29,26 @@ class Storm_Query_Clause_MatchTerms { protected array $_values; protected bool $_exact; + protected bool $_strict; - public function __construct(array $values, bool $exact) { + public function __construct(array $values, bool $exact, bool $strict) { $this->_values = $values; $this->_exact = $exact; + $this->_strict = $strict; } - public function getFormatDb(bool $strict) : string { + public function getFormatDb() : string { if (!($count = count($this->_values))) return ''; - $format_db = $strict ? '+' : ''; - $values = $this->_getValues(); + $format_db = $this->isStrict() ? '+' : ''; + $values = $this->_implodeValues(); if ($this->_exact) return $format_db . '"' . $values . '"'; - $format_db .= (!$strict || 1 === $count) + $format_db .= (!$this->isStrict() || 1 === $count) ? '%s' : '(%s)'; @@ -56,7 +58,7 @@ class Storm_Query_Clause_MatchTerms { public function containVolatile(string $contents) : bool { if ($this->_exact) - return $this->_containValue($contents, $this->_getValues()); + return $this->_containValue($contents, $this->_implodeValues()); foreach ($this->_values as $value) if ($this->_containValue($contents, $value)) @@ -68,7 +70,7 @@ class Storm_Query_Clause_MatchTerms { public function getCompareValue(string $contents) : int { if ($this->_exact) - return preg_match_all('/\b' . $this->_getValues() . '\b/', $contents); + return preg_match_all('/\b' . $this->_implodeValues() . '\b/', $contents); $compare = 0; foreach ($this->_values as $value) @@ -80,12 +82,17 @@ class Storm_Query_Clause_MatchTerms { } + public function isStrict() : bool { + return $this->_strict; + } + + protected function _containValue(string $contents, string $value) : bool { return preg_match('/\b' . $value . '\b/', $contents); } - protected function _getValues() : string { + protected function _implodeValues() : string { return implode(' ', $this->_values); } } diff --git a/src/Storm/Query/MatchBoolean.php b/src/Storm/Query/MatchBoolean.php index 15ab7d81df4b4133c4a6dd681eba14140f65b759..9aa2df68210f047991fc7a653848a3bd3d2cb64a 100644 --- a/src/Storm/Query/MatchBoolean.php +++ b/src/Storm/Query/MatchBoolean.php @@ -27,13 +27,25 @@ class Storm_Query_MatchBoolean extends Storm_Query_MatchRating { + protected bool $_boolean_mode = true; + public function __construct($array_or_key, bool $strict = false) { parent::__construct($array_or_key, $strict); - $this->_boolean_mode = true; + $this->_strict = $strict; } - public function exact($array_or_value) : self { - return $this->_addTerm($array_or_value, true); + public function exact($array_or_value, ?bool $strict = null) : self { + return $this->_addTerm($array_or_value, $strict, true); + } + + + protected function _createNewMatchTerms($array_or_value, ?bool $strict, bool $exact = false) : Storm_Query_Clause_MatchTerms { + if (null === $strict) + $strict = $this->_strict; + + return (new Storm_Query_Clause_MatchTerms($array_or_value, + $exact, + $strict)); } } diff --git a/src/Storm/Query/MatchRating.php b/src/Storm/Query/MatchRating.php index 8dfcb720f4fd7a485736a089073fa3e9e5a02de9..1a1ddfb93cf1e0f2b9ba66ee444186da42d40dd7 100644 --- a/src/Storm/Query/MatchRating.php +++ b/src/Storm/Query/MatchRating.php @@ -29,16 +29,15 @@ class Storm_Query_MatchRating { protected string $_key; protected array $_terms; - protected bool $_boolean_mode; - protected bool $_strict; + protected bool $_boolean_mode = false; + protected bool $_strict = false; public function __construct($array_or_key, bool $strict = false) { $this->_key = is_array($array_or_key) ? implode(', ', $array_or_key) : $array_or_key; + $this->_terms = []; - $this->_boolean_mode = false; - $this->_strict = $strict; } @@ -47,11 +46,6 @@ class Storm_Query_MatchRating { } - public function isStrict() : bool { - return $this->_strict; - } - - public function getKey() : string { return $this->_key; } @@ -62,17 +56,25 @@ class Storm_Query_MatchRating { } - public function against($array_or_value) : self { - return $this->_addTerm($array_or_value); + public function against($array_or_value, ?bool $strict = null) : self { + return $this->_addTerm($array_or_value, $strict); } - protected function _addTerm($array_or_value, bool $exact = false) : self { + protected function _addTerm($array_or_value, + ?bool $strict, + bool $exact = false) : self { if (!is_array($array_or_value)) $array_or_value = explode(' ', $array_or_value); - $this->_terms [] = (new Storm_Query_Clause_MatchTerms($array_or_value, - $exact)); + $this->_terms [] = $this->_createNewMatchTerms($array_or_value, $strict, $exact); return $this; } + + + protected function _createNewMatchTerms($array_or_value, ?bool $strict, bool $exact = false) : Storm_Query_Clause_MatchTerms { + return (new Storm_Query_Clause_MatchTerms($array_or_value, + $exact, + false)); + } } diff --git a/tests/Storm/Test/LoaderQueryTest.php b/tests/Storm/Test/LoaderQueryTest.php index 297c8bdb6384a9ec63385ba8514de9f5e1724896..9d318043b192406d160800d3ebd22a367cc4d079 100644 --- a/tests/Storm/Test/LoaderQueryTest.php +++ b/tests/Storm/Test/LoaderQueryTest.php @@ -263,7 +263,7 @@ class Storm_Test_LoaderQueryDbTest extends Storm_Test_LoaderQueryTestCase { /** @test */ - public function withClauseMatchStrictAndOneExactExpressionWithNoBooleanModeShouldReturnQuery() { + public function withClauseMatchStrictAndOneExactExpressionWithBooleanModeShouldReturnQuery() { Storm_Query::from(Storm_Test_Mock_User::class) ->match((new Storm_Query_MatchBoolean(['login', 'role'], true)) ->exact('ADMIN INVITE') @@ -273,6 +273,32 @@ class Storm_Test_LoaderQueryDbTest extends Storm_Test_LoaderQueryTestCase { $this->assertEquals(['MATCH(login, role) AGAINST(\'+"ADMIN INVITE" +HUGO\' IN BOOLEAN MODE)'], $this->_select->getAttributesForLastCallOn('where')); } + + + /** @test */ + public function withClauseMatchOneExactAndOneAgainstStrictInBooleanModeShouldReturnQuery() { + Storm_Query::from(Storm_Test_Mock_User::class) + ->match((new Storm_Query_MatchBoolean(['login', 'role'])) + ->exact('ADMIN INVITE', true) + ->against('HUGO')) + ->fetchAll(); + + $this->assertEquals(['MATCH(login, role) AGAINST(\'+"ADMIN INVITE" HUGO\' IN BOOLEAN MODE)'], + $this->_select->getAttributesForLastCallOn('where')); + } + + + /** @test */ + public function withClauseMatchOneExactStrictAndOneAgainstInBooleanModeShouldReturnQuery() { + Storm_Query::from(Storm_Test_Mock_User::class) + ->match((new Storm_Query_MatchBoolean(['login', 'role'])) + ->exact('ADMIN INVITE') + ->against('HUGO', true)) + ->fetchAll(); + + $this->assertEquals(['MATCH(login, role) AGAINST(\'"ADMIN INVITE" +HUGO\' IN BOOLEAN MODE)'], + $this->_select->getAttributesForLastCallOn('where')); + } } @@ -615,7 +641,7 @@ class Storm_Test_LoaderQueryVolatileClauseWhereTest extends Storm_Test_ModelTest /** @test */ - public function withMatchLevelAgainstExactDeuxiemeTroisiemeShouldAnswersOnlyUser_Admin() { + public function withMatchLevelFooExactDeuxiemeRedacteurShouldAnswersOnlyUser_Administrateur() { $query = Storm_Query::from(Storm_Test_LoaderQueryUser::class) ->match((new Storm_Query_MatchBoolean('level,foo')) ->exact('deuxieme redacteur')); @@ -626,6 +652,32 @@ class Storm_Test_LoaderQueryVolatileClauseWhereTest extends Storm_Test_ModelTest } + /** @test */ + public function withMatchLevelFooDeuxiemeAndAgainstRedacteurAnswers_AllUsers() { + $query = Storm_Query::from(Storm_Test_LoaderQueryUser::class) + ->match((new Storm_Query_MatchBoolean('level,foo')) + ->against('deuxieme') + ->against('redacteur')); + $this->assertEquals(['user_admin', 'user_administrateur', 'user_invite'], + (new Storm_Model_Collection($query->fetchAll())) + ->collect('login') + ->getArrayCopy()); + } + + + /** @test */ + public function withMatchLevelFooDeuxiemeAndAgainstStrictRedacteurAnswers_User_Admin_User_Administrateur() { + $query = Storm_Query::from(Storm_Test_LoaderQueryUser::class) + ->match((new Storm_Query_MatchBoolean('level,foo')) + ->against('deuxieme') + ->against('redacteur', true)); + $this->assertEquals(['user_admin', 'user_administrateur'], + (new Storm_Model_Collection($query->fetchAll())) + ->collect('login') + ->getArrayCopy()); + } + + /** @test */ public function withOrClause_LevelInviteOrFooLikePremierShouldAnswersUser_AdminAndUser_Invite() { $query = Storm_Query::from(Storm_Test_LoaderQueryUser::class)