diff --git a/src/Storm/Model/PersistenceStrategy/Db.php b/src/Storm/Model/PersistenceStrategy/Db.php index ed70a15d2504ea309c69cdae59f3dbc6941d9c23..86541ea0d868491d9545f25395ad69114fe90867 100644 --- a/src/Storm/Model/PersistenceStrategy/Db.php +++ b/src/Storm/Model/PersistenceStrategy/Db.php @@ -98,9 +98,9 @@ class Storm_Model_PersistenceStrategy_Db protected function _generateWhereClauseForKeyAndValue(string $key, $value) : string { - $clause = ($value instanceof Storm_Model_PersistenceStrategy_Clause) + $clause = ($value instanceof Storm_Query_Clause) ? $value - : Storm_Model_PersistenceStrategy_Clause::newWith($key, $value); + : Storm_Query_Clause::newWith($key, $value); return $clause->getFormatDb($this->getTable()); } @@ -172,7 +172,7 @@ class Storm_Model_PersistenceStrategy_Db */ public function _generateSelectFor($args) { if ($args instanceof Storm_Query) - return $args->getSelectAndAssemble(); + return $this->_selectForQuery($args); if (array_key_exists('role', $args) && array_key_exists('model', $args)) { $model = $args['model']; @@ -196,6 +196,14 @@ class Storm_Model_PersistenceStrategy_Db } + protected function _selectForQuery(Storm_Query $query) { + $select = $this->getTable()->select(); + $query->assemble($select); + + return $select; + } + + protected function _addInSelect($select, string $field, $value_or_clause) : self { if (in_array($field, ['order', 'limit', 'where'], true)) { $select->$field($value_or_clause); @@ -212,8 +220,8 @@ class Storm_Model_PersistenceStrategy_Db return $this; } - if (!($value_or_clause instanceof Storm_Model_PersistenceStrategy_Clause)) - $value_or_clause = Storm_Model_PersistenceStrategy_Clause::newWith($field, $value_or_clause); + if (!($value_or_clause instanceof Storm_Query_Clause)) + $value_or_clause = Storm_Query_Clause::newWith($field, $value_or_clause); $select->where($this->_generateWhereClauseForKeyAndValue($field, $value_or_clause)); return $this; diff --git a/src/Storm/Model/PersistenceStrategy/Match.php b/src/Storm/Model/PersistenceStrategy/Match.php deleted file mode 100644 index e601ea22083d6a532c07f6f12cd4f234819e7d64..0000000000000000000000000000000000000000 --- a/src/Storm/Model/PersistenceStrategy/Match.php +++ /dev/null @@ -1,82 +0,0 @@ -<?php -/* -STORM is under the MIT License (MIT) - -Copyright (c) 2010-2022 Agence Française Informatique http://www.afi-sa.fr - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -*/ - -class Storm_Model_PersistenceStrategy_Match { - - protected array $_terms; - protected bool $_boolean_mode; - protected bool $_strict; - - public function __construct(array $terms, bool $strict, bool $boolean_mode) { - $this->_terms = $terms; - $this->_strict = $strict; - $this->_boolean_mode = $boolean_mode; - } - - - public function getFormatDb($table) : string { - $content = ''; - foreach ($this->_terms as $key => $term) - $content = implode(' ', array_filter([$content, - $term->getFormatDb($this->_strict)])); - - return sprintf('AGAINST(%s%s)', - $table->getAdapter()->quoteInto('?', $content, null, null), - ($this->_boolean_mode ? ' IN BOOLEAN MODE' : '')); - } - - - public function containVolatile(string $contents) : bool { - if (!$contents) - return false; - - foreach ($this->_terms as $term) { - if ($this->_strict && !$term->containVolatile($contents)) - return false; - if (!$this->_strict && $term->containVolatile($contents)) - return true; - } - - return $this->_strict; - } - - - public function getCompareValue(string $contents) : int { - $compare = 0; - - foreach ($this->_terms as $term) { - $new_compare = $term->getCompareValue($contents); - if ($this->_strict && 0 === $new_compare) - return 0; - - $compare += $term->getCompareValue($contents); - } - - return $this->_boolean_mode - ? min($compare, 1) - : ceil(($compare / count(explode(' ', $contents))) * 10); - } -} diff --git a/src/Storm/Model/PersistenceStrategy/MatchTerms.php b/src/Storm/Model/PersistenceStrategy/MatchTerms.php index bb5eb3032244eb3a00289989c3dc6af5ec44b48f..737d76fcc2b8dc6f33f891b9df4544bd9f426eac 100644 --- a/src/Storm/Model/PersistenceStrategy/MatchTerms.php +++ b/src/Storm/Model/PersistenceStrategy/MatchTerms.php @@ -30,12 +30,9 @@ class Storm_Model_PersistenceStrategy_MatchTerms { protected array $_values; protected bool $_exact; - public function __construct($array_or_value, ?bool $exact = false) { - if (!is_array($array_or_value)) - $array_or_value = explode(' ', $array_or_value); - - $this->_values = $array_or_value; - $this->_exact = $exact ?? false; + public function __construct(array $values, bool $exact) { + $this->_values = $values; + $this->_exact = $exact; } diff --git a/src/Storm/Model/PersistenceStrategy/Volatile.php b/src/Storm/Model/PersistenceStrategy/Volatile.php index afdd2b73c2120ae55b109503a5d421fbb427718c..9476f22f5c2dd06c3c716f88eab41d37338ea9fb 100644 --- a/src/Storm/Model/PersistenceStrategy/Volatile.php +++ b/src/Storm/Model/PersistenceStrategy/Volatile.php @@ -189,16 +189,16 @@ class Storm_Model_PersistenceStrategy_Volatile public function containsAttribute(array $model, string $key, $value) : bool { - $clause = ($value instanceof Storm_Model_PersistenceStrategy_Clause) + $clause = ($value instanceof Storm_Query_Clause) ? $value : null; if (!$clause && preg_match('/left\((.+),(.+)\)/', $key, $matches)) - $clause = Storm_Model_PersistenceStrategy_Clause::like(trim($matches[1]), + $clause = Storm_Query_Clause::like(trim($matches[1]), (substr($value, 0, (int)$matches[2]) . '%')); if (!$clause) - $clause = Storm_Model_PersistenceStrategy_Clause::newWith($key, $value); + $clause = Storm_Query_Clause::newWith($key, $value); return $clause->containAttibuteInVolatile($model); } @@ -269,7 +269,7 @@ class Storm_Model_PersistenceStrategy_Volatile } - protected function _allMatchingInstancesDo(array $clauses, callable $callback) : int { + protected function _allMatchingInstancesDo($clauses, callable $callback) : int { $matching_instances = array_filter($this->getInstancesArray(), function ($model) use ($clauses) { return $this->_modelMatchesClauses($model, $clauses); @@ -279,7 +279,10 @@ class Storm_Model_PersistenceStrategy_Volatile } - protected function _modelMatchesClauses(array $model, array $clauses) : bool { + protected function _modelMatchesClauses(array $model, $clauses) : bool { + if ($clauses instanceof Storm_Query) + return $clauses->containsAllAttributes($model); + return $this->containsAllAttributes($model, $clauses); } diff --git a/src/Storm/Model/PersistenceStrategy/Volatile/Filtered.php b/src/Storm/Model/PersistenceStrategy/Volatile/Filtered.php index 2f0da257a0ebf2e9a116cff4da9d4d43c5a095fc..84104d4208700ceeb7c37df360cd336df2ac25b3 100644 --- a/src/Storm/Model/PersistenceStrategy/Volatile/Filtered.php +++ b/src/Storm/Model/PersistenceStrategy/Volatile/Filtered.php @@ -75,9 +75,9 @@ class Storm_Model_PersistenceStrategy_Volatile_Filtered { } - public function getClauses() : array { + public function getClauses() { return $this->_query - ? $this->_query->getClauses() + ? $this->_query : $this->_select; } diff --git a/src/Storm/Query.php b/src/Storm/Query.php index 207e2110c0b32a7f8d15f77c1c5773cb228f9f26..a3fcbedeac395e88d45cce7b06c4626797fc7f97 100644 --- a/src/Storm/Query.php +++ b/src/Storm/Query.php @@ -25,308 +25,268 @@ */ -class Storm_Query { +class Storm_Query implements Storm_Query_CriteriaInterface { - protected array $_clauses; protected array $_orders; - protected array $_terms; protected Storm_Model_Loader $_loader; - protected ?Storm_Model_PersistenceStrategy_Clause $_clause_limit; - protected ?Storm_Model_PersistenceStrategy_Clause $_clause_limit_page; - protected ?Storm_Model_PersistenceStrategy_Clause $_clause_group_by; + protected Storm_Query_CriteriaInterface $_criteria; + protected ?Storm_Query_Clause $_clause_limit; + protected ?Storm_Query_Clause $_clause_limit_page; + protected ?Storm_Query_Clause $_clause_group_by; - public function __construct() { - $this->_clauses = []; + + protected function __construct(Storm_Model_Loader $loader) { + $this->_loader = $loader; $this->_orders = []; - $this->_terms = []; $this->_clause_limit = null; $this->_clause_limit_page = null; $this->_clause_group_by = null; + $this->_criteria = new Storm_Query_Criteria; } - public function __call($method, $args) { - return $this->_callQuery($method, $args); + public static function from(Storm_Model_Loader $loader) : self { + return new static($loader); } - public static function __callStatic($method, $args) { - return (new static)->_callQuery($method, $args); + public function limit($limit) : self { + $this->_clause_limit = Storm_Query_Clause::limit($limit); + return $this; } - protected function _callQuery($method, $args) { - if (!method_exists($this , '_' . $method)) - throw new Exception('Call undefined method ' . $method); - - return $this->{'_' . $method}(...$args); + public function limit_page(array $range) { + $this->_clause_limit_page = Storm_Query_Clause::limit_page($range); + return $this; } - public function getSelectAndAssemble() { - $select = $this->_loader->getTable()->select(); - - foreach ($this->getClauses() as $clause) - $clause->assemble($select); - - foreach ($this->getOrders() as $order) - $order->assemble($select); - - if ($this->_clause_limit) - $this->_clause_limit->assemble($select); - - if ($this->_clause_limit_page) - $this->_clause_limit_page->assemble($select); - - if ($this->_clause_group_by) - $this->_clause_group_by->assemble($select); - - return $select; + public function group(string $value) : self { + $this->_clause_group_by = Storm_Query_Clause::group($value); + return $this; } - public function orderVolatile(array $models) : array { - return (new Storm_Query_Order(array_reverse($this->getOrders()))) - ->compareVolatile($models); + public function order(string $key) : self { + $this->_orders [] = Storm_Query_Clause::order($key) + ->setOrder(false); + return $this; } - public function getClauses() : array { - return $this->_clauses; + public function order_desc(string $key) : self { + $this->_orders [] = Storm_Query_Clause::order($key) + ->setOrder(true); + return $this; } - public function getOrders() : array { - return $this->_orders; - } - + public function order_match(Storm_Query_MatchRating $match) : self { + $clause_match = Storm_Query_Clause::match($match); + $this->_orders [] = + Storm_Query_Clause::order($match->getKey(), + $clause_match) + ->setOrder(false); - public function getTerms() : array { - return $this->_terms; + return $this; } - public function getLimitValue() { - return $this->_clause_limit ? - $this->_clause_limit->getValueOrArray() - : ''; - } - + public function order_match_desc(Storm_Query_MatchRating $match) : self { + $clause_match = Storm_Query_Clause::match($match); + $this->_orders [] = + Storm_Query_Clause::order($match->getKey(), + $clause_match) + ->setOrder(true); - public function getLimitPageValue() : ?array { - return $this->_clause_limit_page - ? $this->_clause_limit_page->getValueOrArray() - : null; + return $this; } - public function getGroupByValue() : string { - return $this->_clause_group_by - ? $this->_clause_group_by->getValueOrArray() - : ''; + public function fetchAll() : array { + return $this->_loader->findAllBy($this); } - protected function _limit($limit) : self { - $this->_clause_limit = Storm_Model_PersistenceStrategy_Clause::limit($limit); - return $this; + public function count() : int { + return $this->_loader->countBy($this); } - protected function _limit_page(array $range) { - $this->_clause_limit_page = Storm_Model_PersistenceStrategy_Clause::limit_page($range); - return $this; + public function fetchFirst() : ?Storm_Model_Abstract { + return $this->_loader->findFirstBy($this); } - protected function _group(string $value) : self { - $this->_clause_group_by = Storm_Model_PersistenceStrategy_Clause::group($value); + /** interface Storm_Query_CriteriaInterface */ + + public function beOr() : self { + $this->_criteria->beOr(); return $this; } - protected function _eq(string $key, string $value) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::equal($key, $value); + public function or(Storm_Query_CriteriaInterface $criteria) : self { + $this->_criteria->or($criteria); return $this; } - public function _not_eq(string $key, string $value) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::equal($key, $value)->setNegated(true); + public function and(Storm_Query_CriteriaInterface $criteria) : self { + $this->_criteria->and($criteria); return $this; } - protected function _like(string $key, string $value) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::like($key, $value); + public function eq(string $key, string $value) : self { + $this->_criteria->eq($key, $value); return $this; } - protected function _not_like(string $key, string $value) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::like($key, $value)->setNegated(true); + public function not_eq(string $key, string $value) : self { + $this->_criteria->not_eq($key, $value); return $this; } - protected function _gt(string $key, string $value) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::greater($key, $value); + public function like(string $key, string $value) : self { + $this->_criteria->like($key, $value); return $this; } - protected function _gt_eq(string $key, string $value) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::greaterEqual($key, $value); + public function not_like(string $key, string $value) : self { + $this->_criteria->not_like($key, $value); return $this; } - protected function _lt(string $key, string $value) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::lesser($key, $value); + public function gt(string $key, string $value) : self { + $this->_criteria->gt($key, $value); return $this; } - protected function _lt_eq(string $key, string $value) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::lesserEqual($key, $value); + public function gt_eq(string $key, string $value) : self { + $this->_criteria->gt_eq($key, $value); return $this; } - protected function _is(string $key) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::is($key); + public function lt(string $key, string $value) : self { + $this->_criteria->lt($key, $value); return $this; } - protected function _not_is(string $key) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::is($key)->setNegated(true); + public function lt_eq(string $key, string $value) : self { + $this->_criteria->lt_eq($key, $value); return $this; } - protected function _in(string $key, array $array) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::in($key, $array); + public function is(string $key) : self { + $this->_criteria->is($key); return $this; } - protected function _not_in(string $key, array $array) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::in($key, $array)->setNegated(true); + public function not_is(string $key) : self { + $this->_criteria->not_is($key); return $this; } - protected function _start(string $key, string $value) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::start($key, $value); + public function in(string $key, array $array) : self { + $this->_criteria->in($key, $array); return $this; } - protected function _end(string $key, string $value) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::end($key, $value); + public function not_in(string $key, array $array) : self { + $this->_criteria->not_in($key, $array); return $this; } - protected function _or(Storm_Query ...$querys) : self { - $clauses = []; - foreach ($querys as $q) - $clauses = [...$clauses, ...$q->getClauses()]; - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::or($clauses); + public function start(string $key, string $value) : self { + $this->_criteria->start($key, $value); return $this; } - protected function _and(Storm_Query ...$querys) : self { - $clauses = []; - foreach ($querys as $q) - $clauses = [...$clauses, ...$q->getClauses()]; - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::and($clauses); + public function end(string $key, string $value) : self { + $this->_criteria->end($key, $value); return $this; } - protected function _match(string $key, - Storm_Query $query, - ?bool $strict = false, - ?bool $boolean_mode = true) : self { - $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::match($key, - $query->getTerms(), - $strict, - $boolean_mode); + public function match(Storm_Query_MatchRating $match) : self { + $this->_criteria->match($match); return $this; } - protected function _terms($value_or_array, ?bool $exact = false) : self { - $this->_terms [] = (new Storm_Model_PersistenceStrategy_MatchTerms($value_or_array, $exact)); - return $this; - } + /** DB management */ + /** + * @param $select Zend_Db_Table_Select|Storm_Test_ObjectWrapper + */ + public function assemble(object $select) : self { + $sql = new Storm_Query_Sql; + $this->_criteria->assemble($sql); + if ($where = $sql->implode($this->_criteria->separator())) + $select->where($where); - protected function _order(string $key) : self { - $this->_orders [] = Storm_Model_PersistenceStrategy_Clause::order($key)->setOrder(false); - return $this; - } + foreach ($this->_orders as $order) + $order->assemble($select); + if ($this->_clause_limit) + $this->_clause_limit->assemble($select); - protected function _order_desc(string $key) : self { - $this->_orders [] = Storm_Model_PersistenceStrategy_Clause::order($key)->setOrder(true); - return $this; - } + if ($this->_clause_limit_page) + $this->_clause_limit_page->assemble($select); + if ($this->_clause_group_by) + $this->_clause_group_by->assemble($select); - protected function _order_match(string $key, - Storm_Query $query, - ?bool $strict = false, - ?bool $boolean_mode = true) : self { - $match = Storm_Model_PersistenceStrategy_Clause::match($key, - $query->getTerms(), - $strict, - $boolean_mode); - $this->_orders [] = Storm_Model_PersistenceStrategy_Clause::order($key, $match)->setOrder(false); return $this; } - protected function _order_match_desc(string $key, - Storm_Query $query, - ?bool $strict = false, - ?bool $boolean_mode = true) : self { - $match = Storm_Model_PersistenceStrategy_Clause::match($key, - $query->getTerms(), - $strict, - $boolean_mode); - $this->_orders [] = Storm_Model_PersistenceStrategy_Clause::order($key, $match)->setOrder(true); - return $this; + /** Volatile management */ + + public function orderVolatile(array $models) : array { + return (new Storm_Query_Order(array_reverse($this->_orders))) + ->compareVolatile($models); } - protected function _from(Storm_Model_Loader $loader) : self { - $this->_loader = $loader; - return $this; + public function containsAllAttributes(array $model) : bool { + return $this->_criteria->containsAllAttributes($model); } - protected function _fetchAll() : array { - return $this->_loader - ? $this->_loader->findAllBy($this) - : []; + public function getLimitValue() { + return $this->_clause_limit ? + $this->_clause_limit->getValueOrArray() + : ''; } - protected function _count() : array { - return $this->_loader - ? $this->_loader->countBy($this) - : []; + public function getLimitPageValue() : ?array { + return $this->_clause_limit_page + ? $this->_clause_limit_page->getValueOrArray() + : null; } - protected function _fetchFirst() : ?Storm_Model_Abstract { - return $this->_loader - ? $this->_loader->findFirstBy($this) - : null; + public function getGroupByValue() : string { + return $this->_clause_group_by + ? $this->_clause_group_by->getValueOrArray() + : ''; } } @@ -336,7 +296,7 @@ class Storm_Query { class Storm_Query_Order { protected ?Storm_Query_Order $_next_query; - protected ?Storm_Model_PersistenceStrategy_Clause $_clause; + protected ?Storm_Query_Clause $_clause; protected int $_position; public function __construct(array $orders, ?int $position = 0) { @@ -359,7 +319,7 @@ class Storm_Query_Order { } - public function getClause() : ?Storm_Model_PersistenceStrategy_Clause { + public function getClause() : ?Storm_Query_Clause { return $this->_clause; } diff --git a/src/Storm/Model/PersistenceStrategy/Clause.php b/src/Storm/Query/Clause.php similarity index 54% rename from src/Storm/Model/PersistenceStrategy/Clause.php rename to src/Storm/Query/Clause.php index b41320c55089c9e1989c3daf3f1e55531f562dce..13ea5006e6b359821ffc2fe2be04933e3a3e90d1 100644 --- a/src/Storm/Model/PersistenceStrategy/Clause.php +++ b/src/Storm/Query/Clause.php @@ -25,7 +25,7 @@ THE SOFTWARE. */ -class Storm_Model_PersistenceStrategy_Clause { +class Storm_Query_Clause { protected string $_key; protected string $_operator; @@ -33,8 +33,6 @@ class Storm_Model_PersistenceStrategy_Clause { protected $_value_or_array; const - CLAUSE_OR = 'or', - CLAUSE_AND = 'and', CLAUSE_WHERE = 'where', CLAUSE_LIKE = 'like', CLAUSE_EQUAL = '=', @@ -61,36 +59,34 @@ class Storm_Model_PersistenceStrategy_Clause { public static function newFor(string $key, string $operator, $value_or_array) : self { - if (static::CLAUSE_OR === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseOr($key, $operator, $value_or_array)); - if (static::CLAUSE_AND === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseAnd($key, $operator, $value_or_array)); if (static::CLAUSE_LIKE === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseLike($key, $operator, $value_or_array)); + return (new Storm_Query_ClauseLike($key, $operator, $value_or_array)); if (static::CLAUSE_EQUAL === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseEqual($key, $operator, $value_or_array)); + return (new Storm_Query_ClauseEqual($key, $operator, $value_or_array)); if (static::CLAUSE_IN === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseIn($key, $operator, $value_or_array)); + return (new Storm_Query_ClauseIn($key, $operator, $value_or_array)); if (static::CLAUSE_IS === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseIs($key, $operator, $value_or_array)); + return (new Storm_Query_ClauseIs($key, $operator, $value_or_array)); if (static::CLAUSE_GREATER === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseGreater($key, $operator, $value_or_array)); + return (new Storm_Query_ClauseGreater($key, $operator, $value_or_array)); if (static::CLAUSE_GREATER_EQUAL === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseGreaterEqual($key, $operator, $value_or_array)); + return (new Storm_Query_ClauseGreaterEqual($key, $operator, $value_or_array)); if (static::CLAUSE_LESSER === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseLesser($key, $operator, $value_or_array)); + return (new Storm_Query_ClauseLesser($key, $operator, $value_or_array)); if (static::CLAUSE_LESSER_EQUAL === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseLesserEqual($key, $operator, $value_or_array)); + return (new Storm_Query_ClauseLesserEqual($key, $operator, $value_or_array)); if (static::CLAUSE_MATCH === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseMatch($key, $operator, $value_or_array)); + return (new Storm_Query_Clause_Match($key, $operator, $value_or_array)); if (static::CLAUSE_LIMIT === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseLimit($key, $operator, $value_or_array)); + return (new Storm_Query_ClauseLimit($key, $operator, $value_or_array)); if (static::CLAUSE_LIMIT_PAGE === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseLimitPage($key, $operator, $value_or_array)); + return (new Storm_Query_ClauseLimitPage($key, $operator, $value_or_array)); if (static::CLAUSE_ORDER_BY === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseOrderBy($key, $operator, $value_or_array)); + return (new Storm_Query_Clause_OrderBy($key, $operator, $value_or_array)); if (static::CLAUSE_GROUP_BY === $operator) - return (new Storm_Model_PersistenceStrategy_ClauseGroupBy($key, $operator, $value_or_array)); + return (new Storm_Query_ClauseGroupBy($key, $operator, $value_or_array)); + if (static::CLAUSE_WHERE === $operator) + return (new Storm_Query_ClauseWhere($key, $operator, $value_or_array)); return (new static($key, $operator, $value_or_array)); } @@ -169,23 +165,8 @@ class Storm_Model_PersistenceStrategy_Clause { } - public static function or(array $array) : self { - return static::newFor(static::CLAUSE_OR, static::CLAUSE_OR, $array); - } - - - public static function and(array $array) : self { - return static::newFor(static::CLAUSE_AND, static::CLAUSE_AND, $array); - } - - - public static function match(string $key, - array $array, - ?bool $strict = false, - ?bool $boolean_mode = true) : self { - return static::newFor($key, - static::CLAUSE_MATCH, - (new Storm_Model_PersistenceStrategy_Match($array, $strict, $boolean_mode))); + public static function match(Storm_Query_MatchRating $match) : self { + return static::newFor($match->getKey(), static::CLAUSE_MATCH, $match); } @@ -204,7 +185,7 @@ class Storm_Model_PersistenceStrategy_Clause { } - public static function order(string $key, ?Storm_Model_PersistenceStrategy_Clause $clause = null) : self { + public static function order(string $key, ?Storm_Query_Clause $clause = null) : self { return static::newFor($key, static::CLAUSE_ORDER_BY, $clause); } @@ -221,18 +202,18 @@ class Storm_Model_PersistenceStrategy_Clause { public function assemble($select) : self { - $select->where($this->getFormatDb($select->getTable())); + $select->where($this->getFormatDb()); return $this; } - public function getFormatDb($table) : string { + public function getFormatDb() : string { if (static::CLAUSE_WHERE === $this->_operator) return '(' . $this->getValueOrArray() . ')'; - return $table->getAdapter() - ->quoteInto($this->_clauseFormatDb(), - $this->getValueOrArray(), null, null); + return Zend_Db_Table_Abstract::getDefaultAdapter() + ->quoteInto($this->_clauseFormatDb(), + $this->getValueOrArray(), null, null); } @@ -262,54 +243,8 @@ class Storm_Model_PersistenceStrategy_Clause { -class Storm_Model_PersistenceStrategy_ClauseOr - extends Storm_Model_PersistenceStrategy_Clause { - - public function getValueOrArray() { - return $this->_value_or_array ?? []; - } - - - public function getFormatDb($table) : string { - $request = ''; - $operator = ' ' . $this->_operator . ' '; - foreach ($this->getValueOrArray() as $clause) - $request = implode($operator, array_filter([$request, - $clause->getFormatDb($table)])); - - return '(' . $request . ')'; - } - - - public function containAttibuteInVolatile(array $model) : bool { - foreach ($this->getValueOrArray() as $clause) - if ($clause->containAttibuteInVolatile($model)) - return true; - - return false; - } -} - - - - -class Storm_Model_PersistenceStrategy_ClauseAnd - extends Storm_Model_PersistenceStrategy_ClauseOr { - - public function containAttibuteInVolatile(array $model) : bool { - foreach ($this->getValueOrArray() as $clause) - if (!$clause->containAttibuteInVolatile($model)) - return false; - - return true; - } -} - - - - -class Storm_Model_PersistenceStrategy_ClauseLike - extends Storm_Model_PersistenceStrategy_Clause { +class Storm_Query_ClauseLike + extends Storm_Query_Clause { protected function _clauseFormatDb() : string { return $this->_key . ' ' . $this->_getOperator() . ' ?'; @@ -331,8 +266,8 @@ class Storm_Model_PersistenceStrategy_ClauseLike -class Storm_Model_PersistenceStrategy_ClauseEqual - extends Storm_Model_PersistenceStrategy_Clause { +class Storm_Query_ClauseEqual + extends Storm_Query_Clause { protected function _getOperator() : string { return ($this->_negated ? '!' : '') . $this->_operator; @@ -342,8 +277,8 @@ class Storm_Model_PersistenceStrategy_ClauseEqual -class Storm_Model_PersistenceStrategy_ClauseIn - extends Storm_Model_PersistenceStrategy_Clause { +class Storm_Query_ClauseIn + extends Storm_Query_Clause { public function getValueOrArray() { return $this->_value_or_array ?? []; @@ -372,15 +307,15 @@ class Storm_Model_PersistenceStrategy_ClauseIn -class Storm_Model_PersistenceStrategy_ClauseIs - extends Storm_Model_PersistenceStrategy_Clause { +class Storm_Query_ClauseIs + extends Storm_Query_Clause { public function getValueOrArray() { return null; } - public function getFormatDb($table) : string { + public function getFormatDb() : string { return $this->_key . ' ' . $this->_getOperator() . ' null'; } @@ -393,8 +328,8 @@ class Storm_Model_PersistenceStrategy_ClauseIs -class Storm_Model_PersistenceStrategy_ClauseGreater - extends Storm_Model_PersistenceStrategy_Clause { +class Storm_Query_ClauseGreater + extends Storm_Query_Clause { public function containAttibuteInVolatile(array $model) : bool { if (!$this->_existKeyInModel($model)) @@ -407,8 +342,8 @@ class Storm_Model_PersistenceStrategy_ClauseGreater -class Storm_Model_PersistenceStrategy_ClauseGreaterEqual - extends Storm_Model_PersistenceStrategy_Clause { +class Storm_Query_ClauseGreaterEqual + extends Storm_Query_Clause { public function containAttibuteInVolatile(array $model) : bool { if (!$this->_existKeyInModel($model)) @@ -421,8 +356,8 @@ class Storm_Model_PersistenceStrategy_ClauseGreaterEqual -class Storm_Model_PersistenceStrategy_ClauseLesser - extends Storm_Model_PersistenceStrategy_Clause { +class Storm_Query_ClauseLesser + extends Storm_Query_Clause { public function containAttibuteInVolatile(array $model) : bool { if (!$this->_existKeyInModel($model)) @@ -435,8 +370,8 @@ class Storm_Model_PersistenceStrategy_ClauseLesser -class Storm_Model_PersistenceStrategy_ClauseLesserEqual - extends Storm_Model_PersistenceStrategy_Clause { +class Storm_Query_ClauseLesserEqual + extends Storm_Query_Clause { public function containAttibuteInVolatile(array $model) : bool { if (!$this->_existKeyInModel($model)) @@ -449,63 +384,8 @@ class Storm_Model_PersistenceStrategy_ClauseLesserEqual -class Storm_Model_PersistenceStrategy_ClauseMatch - extends Storm_Model_PersistenceStrategy_Clause { - - public function getValueOrArray() { - return $this->_value_or_array ?? null; - } - - - public function getFormatDb($table) : string { - return ($value = $this->getValueOrArray()) - ? ($this->_getOperator() . ' ' . $value->getFormatDb($table)) - : ''; - } - - - public function compare(array $a, array $b) : int { - if (!($value = $this->getValueOrArray())) - return 0; - - return ($value->getCompareValue($this->_getContents($a)) - - $value->getCompareValue($this->_getContents($b))); - } - - - public function containAttibuteInVolatile(array $model) : bool { - if (!($value = $this->getValueOrArray())) - return false; - - return $value->containVolatile($this->_getContents($model)); - } - - - protected function _getOperator() : string { - return $this->_operator . '(' . $this->_key . ')'; - } - - - protected function _clauseFormatDb() : string { - return $this->_getOperator(); - } - - - protected function _getContents(array $model) : string { - $contents = ''; - foreach (explode(',', $this->_key) as $key) - if (array_key_exists($key, $model)) - $contents = implode(' ', array_filter([$contents, $model[$key]])); - - return $contents; - } -} - - - - -class Storm_Model_PersistenceStrategy_ClauseLimit - extends Storm_Model_PersistenceStrategy_Clause { +class Storm_Query_ClauseLimit + extends Storm_Query_Clause { public function assemble($select) : self { $select->limit($this->getValueOrArray()); @@ -513,7 +393,7 @@ class Storm_Model_PersistenceStrategy_ClauseLimit } - public function getFormatDb($table) : string { + public function getFormatDb() : string { return ''; } @@ -526,8 +406,8 @@ class Storm_Model_PersistenceStrategy_ClauseLimit -class Storm_Model_PersistenceStrategy_ClauseLimitPage - extends Storm_Model_PersistenceStrategy_Clause { +class Storm_Query_ClauseLimitPage + extends Storm_Query_Clause { public function getValueOrArray() { return $this->_value_or_array ?? []; @@ -543,7 +423,7 @@ class Storm_Model_PersistenceStrategy_ClauseLimitPage } - public function getFormatDb($table) : string { + public function getFormatDb() : string { return ''; } @@ -556,8 +436,8 @@ class Storm_Model_PersistenceStrategy_ClauseLimitPage -class Storm_Model_PersistenceStrategy_ClauseGroupBy - extends Storm_Model_PersistenceStrategy_Clause { +class Storm_Query_ClauseGroupBy + extends Storm_Query_Clause { public function assemble($select) : self { $select->group($this->getValueOrArray()); @@ -565,7 +445,7 @@ class Storm_Model_PersistenceStrategy_ClauseGroupBy } - public function getFormatDb($table) : string { + public function getFormatDb() : string { return ''; } @@ -578,65 +458,8 @@ class Storm_Model_PersistenceStrategy_ClauseGroupBy -class Storm_Model_PersistenceStrategy_ClauseOrderBy - extends Storm_Model_PersistenceStrategy_Clause { - - const ORDER_DESC = ' desc'; - protected ?string $_order_mode = null; - - public function getValueOrArray() { - return $this->_value_or_array ?? null; - } - - - public function assemble($select) : self { - $select->order((($clause = $this->getValueOrArray()) - ? $clause->getFormatDb($select->getTable()) - : $this->_key) - . $this->_order_mode); - return $this; - } - - - public function getFormatDb($table) : string { - return ''; - } - - +class Storm_Query_ClauseWhere extends Storm_Query_Clause { public function containAttibuteInVolatile(array $model) : bool { return true; } - - - public function setOrder(bool $mode) : self { - $this->_order_mode = $mode ? static::ORDER_DESC : ''; - return $this; - } - - - public function compare(Storm_Query_Order $query_order, array $a, array $b) : int { - $compare = $this->_compareValues($a, $b) - * $this->_descendant() - * $query_order->getPosition(); - - return ($next_order = $query_order->getNextQuery()) - ? ($compare + $next_order->getClause()->compare($next_order, $a, $b)) - : $compare; - } - - - protected function _compareValues(array $a, array $b) : int { - if ($match_clause = $this->getValueOrArray()) - return $match_clause->compare($a, $b); - - $first = $this->_existKeyInModel($a) ? $a[$this->_key] : ''; - $second = $this->_existKeyInModel($b) ? $b[$this->_key] : ''; - - return ($first <=> $second); - } - - - protected function _descendant() : int { - return static::ORDER_DESC === $this->_order_mode ? -1 : 1; - } } diff --git a/src/Storm/Query/Clause/Match.php b/src/Storm/Query/Clause/Match.php new file mode 100644 index 0000000000000000000000000000000000000000..0a45094e91807a42b00e72dd61f91ebe60816e5d --- /dev/null +++ b/src/Storm/Query/Clause/Match.php @@ -0,0 +1,117 @@ +<?php +/* +STORM is under the MIT License (MIT) + +Copyright (c) 2010-2022 Agence Française Informatique http://www.afi-sa.fr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + + +class Storm_Query_Clause_Match + extends Storm_Query_Clause { + + public function getValueOrArray() { + return $this->_value_or_array ?? null; + } + + + public function getFormatDb() : string { + if (!$value = $this->getValueOrArray()) + return ''; + + $content = ''; + foreach ($value->getTerms() as $key => $term) + $content = implode(' ', + array_filter([$content, + $term->getFormatDb($value->isStrict())])); + + $against = sprintf('AGAINST(%s%s)', + Zend_Db_Table_Abstract::getDefaultAdapter() + ->quoteInto('?', $content), + ($value->isBooleanMode() ? ' IN BOOLEAN MODE' : '')); + + return $this->_getOperator() . ' ' . $against; + } + + + public function compare(array $a, array $b) : int { + return ($this->_compare($this->_getContents($a)) + - $this->_compare($this->_getContents($b))); + } + + + protected function _compare(string $contents) : int { + if (!$value = $this->getValueOrArray()) + return 0; + + $compare = 0; + + foreach ($value->getTerms() as $term) { + $new_compare = $term->getCompareValue($contents); + if ($value->isStrict() && 0 === $new_compare) + return 0; + + $compare += $term->getCompareValue($contents); + } + + return $value->isBooleanMode() + ? min($compare, 1) + : ceil(($compare / count(explode(' ', $contents))) * 10); + } + + + public function containAttibuteInVolatile(array $model) : bool { + if (!($value = $this->getValueOrArray()) + || !($contents = $this->_getContents($model))) + return false; + + foreach ($value->getTerms() as $term) { + if ($value->isStrict() && !$term->containVolatile($contents)) + return false; + + if (!$value->isStrict() && $term->containVolatile($contents)) + return true; + } + + return $value->isStrict(); + } + + + protected function _getOperator() : string { + return $this->_operator . '(' . $this->_key . ')'; + } + + + protected function _clauseFormatDb() : string { + return $this->_getOperator(); + } + + + protected function _getContents(array $model) : string { + $contents = ''; + foreach (explode(',', $this->_key) as $key) + if (array_key_exists($key, $model)) + $contents = implode(' ', array_filter([$contents, $model[$key]])); + + return $contents; + } +} diff --git a/src/Storm/Query/Clause/MatchTerms.php b/src/Storm/Query/Clause/MatchTerms.php new file mode 100644 index 0000000000000000000000000000000000000000..7e07c6133f14a4198c9fbca9a7149bb1c38443fc --- /dev/null +++ b/src/Storm/Query/Clause/MatchTerms.php @@ -0,0 +1,77 @@ +<?php +/* +STORM is under the MIT License (MIT) + +Copyright (c) 2010-2022 Agence Française Informatique http://www.afi-sa.fr + +Permission is hereby granted, free of charge, to any person obtaining a copy +gof this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +class Storm_Query_Clause_MatchTerms { + + protected array $_values; + protected bool $_exact; + + public function __construct(array $values, bool $exact) { + $this->_values = $values; + $this->_exact = $exact; + } + + + public function getFormatDb(bool $strict) : string { + $values = implode(' ', $this->_values); + if ($this->_exact) + return $strict ? '+"' . $values . '"' : '"' . $values . '"'; + + return $strict ? '+(' . $values . ')' : $values; + } + + + public function containVolatile(string $contents) : bool { + if ($this->_exact) + return $this->_containValue($contents, implode(' ', $this->_values)); + + foreach ($this->_values as $value) + if ($this->_containValue($contents, $value)) + return true; + + return false; + } + + + public function getCompareValue(string $contents) : int { + if ($this->_exact) + return preg_match_all('/\b' . implode(' ', $this->_values) . '\b/', $contents); + + $compare = 0; + foreach ($this->_values as $value) + $compare += ($new_compare = preg_match_all('/\b' . $value . '\b/', $contents)) + ? $new_compare + : 0; + + return $compare; + } + + + protected function _containValue(string $contents, string $value) : bool { + return preg_match('/\b' . $value . '\b/', $contents); + } +} diff --git a/src/Storm/Query/Clause/OrderBy.php b/src/Storm/Query/Clause/OrderBy.php new file mode 100644 index 0000000000000000000000000000000000000000..72b742a64d38c9fa2dfa5e15ab7356b583ad02e7 --- /dev/null +++ b/src/Storm/Query/Clause/OrderBy.php @@ -0,0 +1,89 @@ +<?php +/* +STORM is under the MIT License (MIT) + +Copyright (c) 2010-2022 Agence Française Informatique http://www.afi-sa.fr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +class Storm_Query_Clause_OrderBy + extends Storm_Query_Clause { + + const ORDER_DESC = ' desc'; + protected ?string $_order_mode = null; + + public function getValueOrArray() { + return $this->_value_or_array ?? null; + } + + + public function assemble($select) : self { + $select->order((($clause = $this->getValueOrArray()) + ? $clause->getFormatDb($select->getTable()) + : $this->_key) + . $this->_order_mode); + return $this; + } + + + public function getFormatDb() : string { + return ''; + } + + + public function containAttibuteInVolatile(array $model) : bool { + return true; + } + + + public function setOrder(bool $mode) : self { + $this->_order_mode = $mode ? static::ORDER_DESC : ''; + return $this; + } + + + public function compare(Storm_Query_Order $query_order, array $a, array $b) : int { + $compare = $this->_compareValues($a, $b) + * $this->_descendant() + * $query_order->getPosition(); + + return ($next_order = $query_order->getNextQuery()) + ? ($compare + $next_order->getClause()->compare($next_order, $a, $b)) + : $compare; + } + + + protected function _compareValues(array $a, array $b) : int { + if ($match_clause = $this->getValueOrArray()) + return $match_clause->compare($a, $b); + + $first = $this->_existKeyInModel($a) ? $a[$this->_key] : ''; + $second = $this->_existKeyInModel($b) ? $b[$this->_key] : ''; + + return ($first <=> $second); + } + + + protected function _descendant() : int { + return static::ORDER_DESC === $this->_order_mode ? -1 : 1; + } +} diff --git a/src/Storm/Query/Criteria.php b/src/Storm/Query/Criteria.php new file mode 100644 index 0000000000000000000000000000000000000000..eb713fa37c93155dfaab6704d27eb2b45d55385a --- /dev/null +++ b/src/Storm/Query/Criteria.php @@ -0,0 +1,205 @@ +<?php +/* + STORM is under the MIT License (MIT) + + Copyright (c) 2010-2022 Agence Française Informatique http://www.afi-sa.fr + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + + +class Storm_Query_Criteria implements Storm_Query_CriteriaInterface { + + const + SEPARATOR_AND = 'and', + SEPARATOR_OR = 'or'; + + protected array $_clauses; + protected string $_separator; + + + public function __construct() { + $this->_clauses = []; + $this->_separator = static::SEPARATOR_AND; + } + + + public function beOr() : self { + $this->_separator = static::SEPARATOR_OR; + return $this; + } + + + public function separator() : string { + return ' ' . $this->_separator . ' '; + } + + + public function assemble(Storm_Query_Sql $sql) : self { + foreach ($this->_clauses as $clause) + $sql->write($this->_assembleOne($clause)); + + return $this; + } + + + /** + * @param $clause Storm_Query_CriteriaInterface|Storm_Query_Clause + */ + protected function _assembleOne(object $clause) : string { + if ($clause instanceof Storm_Query_CriteriaInterface) { + $sql = new Storm_Query_Sql; + $clause->assemble($sql); + + return '(' . $sql->implode($clause->separator()) . ')'; + } + + return $clause->getFormatDb(); + } + + + public function containsAllAttributes(array $model) : bool { + foreach ($this->_clauses as $clause) + if ($this->_isAnd() !== $this->_containsOne($clause, $model)) + return !$this->_isAnd(); + + return $this->_isAnd(); + } + + + protected function _containsOne($clause, array $model) : bool { + if ($clause instanceof Storm_Query_CriteriaInterface) + return $clause->containsAllAttributes($model); + + return $clause->containAttibuteInVolatile($model); + } + + + protected function _isAnd() : bool { + return static::SEPARATOR_AND === $this->_separator; + } + + + public function eq(string $key, string $value) : self { + $this->_clauses [] = Storm_Query_Clause::equal($key, $value); + return $this; + } + + + public function not_eq(string $key, string $value) : self { + $this->_clauses [] = Storm_Query_Clause::equal($key, $value) + ->setNegated(true); + return $this; + } + + + public function like(string $key, string $value) : self { + $this->_clauses [] = Storm_Query_Clause::like($key, $value); + return $this; + } + + + public function not_like(string $key, string $value) : self { + $this->_clauses [] = Storm_Query_Clause::like($key, $value) + ->setNegated(true); + return $this; + } + + + public function gt(string $key, string $value) : self { + $this->_clauses [] = Storm_Query_Clause::greater($key, $value); + return $this; + } + + + public function gt_eq(string $key, string $value) : self { + $this->_clauses [] = Storm_Query_Clause::greaterEqual($key, + $value); + return $this; + } + + + public function lt(string $key, string $value) : self { + $this->_clauses [] = Storm_Query_Clause::lesser($key, $value); + return $this; + } + + + public function lt_eq(string $key, string $value) : self { + $this->_clauses [] = Storm_Query_Clause::lesserEqual($key, $value); + return $this; + } + + + public function is(string $key) : self { + $this->_clauses [] = Storm_Query_Clause::is($key); + return $this; + } + + + public function not_is(string $key) : self { + $this->_clauses [] = Storm_Query_Clause::is($key) + ->setNegated(true); + return $this; + } + + + public function in(string $key, array $array) : self { + $this->_clauses [] = Storm_Query_Clause::in($key, $array); + return $this; + } + + + public function not_in(string $key, array $array) : self { + $this->_clauses [] = Storm_Query_Clause::in($key, $array) + ->setNegated(true); + return $this; + } + + + public function start(string $key, string $value) : self { + $this->_clauses [] = Storm_Query_Clause::start($key, $value); + return $this; + } + + + public function end(string $key, string $value) : self { + $this->_clauses [] = Storm_Query_Clause::end($key, $value); + return $this; + } + + + public function or(Storm_Query_CriteriaInterface $criteria) : self { + $this->_clauses [] = $criteria->beOr(); + return $this; + } + + + public function and(Storm_Query_CriteriaInterface $criteria) : self { + $this->_clauses [] = $criteria; + return $this; + } + + + public function match(Storm_Query_MatchRating $match) : self { + $this->_clauses [] = Storm_Query_Clause::match($match); + return $this; + } +} diff --git a/src/Storm/Query/CriteriaInterface.php b/src/Storm/Query/CriteriaInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..a26a7be164dcca491f9495b0ba0123b23457da56 --- /dev/null +++ b/src/Storm/Query/CriteriaInterface.php @@ -0,0 +1,82 @@ +<?php +/* + STORM is under the MIT License (MIT) + + Copyright (c) 2010-2022 Agence Française Informatique http://www.afi-sa.fr + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + + +interface Storm_Query_CriteriaInterface { + + public function beOr() : self; + + + public function eq(string $key, string $value) : self; + + + public function not_eq(string $key, string $value) : self; + + + public function like(string $key, string $value) : self; + + + public function not_like(string $key, string $value) : self; + + + public function gt(string $key, string $value) : self; + + + public function gt_eq(string $key, string $value) : self; + + + public function lt(string $key, string $value) : self; + + + public function lt_eq(string $key, string $value) : self; + + + public function is(string $key) : self; + + + public function not_is(string $key) : self; + + + public function in(string $key, array $array) : self; + + + public function not_in(string $key, array $array) : self; + + + public function start(string $key, string $value) : self; + + + public function end(string $key, string $value) : self; + + + public function or(Storm_Query_CriteriaInterface $criteria) : self; + + + public function and(Storm_Query_CriteriaInterface $criteria) : self; + + + public function match(Storm_Query_MatchRating $match) : self; +} diff --git a/src/Storm/Query/MatchBoolean.php b/src/Storm/Query/MatchBoolean.php new file mode 100644 index 0000000000000000000000000000000000000000..212f37aa75af15c6c6499d6fbe499be1d918ef1c --- /dev/null +++ b/src/Storm/Query/MatchBoolean.php @@ -0,0 +1,39 @@ +<?php +/* + STORM is under the MIT License (MIT) + + Copyright (c) 2010-2022 Agence Française Informatique http://www.afi-sa.fr + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + + +class Storm_Query_MatchBoolean extends Storm_Query_MatchRating { + + public function __construct(string $key) { + parent::__construct($key); + $this->_boolean_mode = true; + } + + + public function exact($array_or_value) : self { + return $this->_addTerm($array_or_value, true); + } +} diff --git a/src/Storm/Query/MatchRating.php b/src/Storm/Query/MatchRating.php new file mode 100644 index 0000000000000000000000000000000000000000..4dd2b1c565fe65f1d7771a8b1e9783d141fb7ac1 --- /dev/null +++ b/src/Storm/Query/MatchRating.php @@ -0,0 +1,82 @@ +<?php +/* + STORM is under the MIT License (MIT) + + Copyright (c) 2010-2022 Agence Française Informatique http://www.afi-sa.fr + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + + +class Storm_Query_MatchRating { + + protected string $_key; + protected array $_terms; + protected bool $_boolean_mode; + protected bool $_strict; + + public function __construct(string $key) { + $this->_key = $key; + $this->_terms = []; + $this->_boolean_mode = false; + $this->_strict = false; + } + + + public function isBooleanMode() : bool { + return $this->_boolean_mode; + } + + + public function isStrict() : bool { + return $this->_strict; + } + + + public function getKey() : string { + return $this->_key; + } + + + public function getTerms() : array { + return $this->_terms; + } + + + public function beStrict() : self { + $this->_strict = true; + return $this; + } + + + public function against($array_or_value) : self { + return $this->_addTerm($array_or_value); + } + + + protected function _addTerm($array_or_value, 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)); + return $this; + } +} diff --git a/src/Storm/Query/Sql.php b/src/Storm/Query/Sql.php new file mode 100644 index 0000000000000000000000000000000000000000..53b347978859740a6b0c070175a3c3e208c80a99 --- /dev/null +++ b/src/Storm/Query/Sql.php @@ -0,0 +1,41 @@ +<?php +/* +STORM is under the MIT License (MIT) + +Copyright (c) 2010-2022 Agence Française Informatique http://www.afi-sa.fr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + + +class Storm_Query_Sql { + + protected array $_sql = []; + + public function write(string $sql) : self { + $this->_sql [] = $sql; + return $this; + } + + + public function implode(string $glue) : string { + return implode($glue, $this->_sql); + } +} diff --git a/src/Storm/Test/ModelTestCase.php b/src/Storm/Test/ModelTestCase.php index 70fd693750af9719e6369b8bbbfb1e43a6b69071..274aa246d8aabb868c836dd0b1e53245512eb42f 100644 --- a/src/Storm/Test/ModelTestCase.php +++ b/src/Storm/Test/ModelTestCase.php @@ -27,13 +27,38 @@ THE SOFTWARE. abstract class Storm_Test_ModelTestCase extends PHPUnit_Framework_TestCase { use Storm_Test_THelpers; + protected $_old_adapter; + protected function setUp() { Storm_Model_Abstract::unsetLoaders(); + + $this->_old_adapter = Zend_Db_Table_Abstract::getDefaultAdapter(); + $adapter = new class() extends Zend_Db_Adapter_Mysqli + { + public function __construct($config=[]) { } + + + public function getConfig() { + return ['dbname' => 'mockdb']; + } + + + protected function _connect() { + $this->_connection = Storm_Test_ObjectWrapper::mock() + ->whenCalled('real_escape_string') + ->willDo(fn($value) => $value); + + return true; + } + }; + + Zend_Db_Table_Abstract::setDefaultAdapter($adapter); } protected function tearDown() { Storm_Model_Abstract::unsetLoaders(); + Zend_Db_Table_Abstract::setDefaultAdapter($this->_old_adapter); } @@ -44,4 +69,4 @@ abstract class Storm_Test_ModelTestCase extends PHPUnit_Framework_TestCase { } } -?> \ No newline at end of file +?> diff --git a/tests/Storm/Test/LoaderTest.php b/tests/Storm/Test/LoaderTest.php index f3b68db384ee10bfa498066ee560b3b60060395c..cc6a120f11be41a617add804b17cba464ed8a4d4 100644 --- a/tests/Storm/Test/LoaderTest.php +++ b/tests/Storm/Test/LoaderTest.php @@ -158,10 +158,10 @@ class Storm_Test_LoaderBasicTest extends Storm_Test_LoaderTestCase { return [ [ ['name' => null] , ['name is null'] ], - [ ['name' => ['Harlock', 'Nausicaa']], ['name in (\'Harlock\',\'Nausicaa\')'] ], + [ ['name' => ['Harlock', 'Nausicaa']], ['name in (\'Harlock\', \'Nausicaa\')'] ], [ ['name not' => 'Harlock'], ['name!=\'Harlock\''] ], [ ['name not' => ['Harlock', 'Nausicaa']], - ['name not in (\'Harlock\',\'Nausicaa\')'] ], + ['name not in (\'Harlock\', \'Nausicaa\')'] ], [ ['name not' => null], ['name is not null'] ], [ ['login like' => '%aus%'], ['login like \'%aus%\''] ], [ ['login not like' => '%aus%'], ['login not like \'%aus%\''] ], @@ -218,7 +218,7 @@ class Storm_Test_LoaderBasicTest extends Storm_Test_LoaderTestCase { $this->_table->whenCalled('delete')->answers(2); $this->_loader->basicDeleteBy(['nom' => ['bond', 'l\'upin']]); - $this->assertEquals("nom in ('bond','l'upin')", + $this->assertEquals("nom in ('bond', 'l'upin')", $this->_table->getFirstAttributeForLastCallOn('delete')); } @@ -261,7 +261,7 @@ class Storm_Test_LoaderBasicTest extends Storm_Test_LoaderTestCase { ['type' => 'fictive']); $this->assertEquals([['type' => 'fictive'], - "nom in ('bond','lupin') and type='real'"], + "nom in ('bond', 'lupin') and type='real'"], $this->_table->getAttributesForLastCallOn('update')); } @@ -292,7 +292,7 @@ class Storm_Test_LoaderSaveWithIdTest extends Storm_Test_LoaderTestCase { ->answers($this->_select = $this->mock()); $this->_select - ->whenCalled('where')->with('id=\'4\'')->answers($this->_select) + ->whenCalled('where')->with('id=4')->answers($this->_select) ->whenCalled('from')->with($this->_table, ['count(*) as numberof'])->answers($this->_select); } @@ -358,8 +358,8 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseGreaterThanShouldReturnQuery() { - Storm_Query::gt('id', '30') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->gt('id', '30') ->fetchAll(); $this->assertEquals(['id>\'30\''], @@ -369,8 +369,8 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseGreaterThanEqualShouldReturnQuery() { - Storm_Query::gt_eq('id', '30') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->gt_eq('id', '30') ->fetchAll(); $this->assertEquals(['id>=\'30\''], @@ -380,8 +380,8 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseLesserThanShouldReturnQuery() { - Storm_Query::lt('id', '30') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->lt('id', '30') ->fetchAll(); $this->assertEquals(['id<\'30\''], @@ -391,8 +391,8 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseLesserThanEqualShouldReturnQuery() { - Storm_Query::lt_eq('id', '30') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->lt_eq('id', '30') ->fetchAll(); $this->assertEquals(['id<=\'30\''], @@ -402,8 +402,8 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseIsShouldReturnQuery() { - Storm_Query::is('name') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->is('name') ->fetchAll(); $this->assertEquals(['name is null'], @@ -413,8 +413,8 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseIsNotShouldReturnQuery() { - Storm_Query::not_is('name') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->not_is('name') ->fetchAll(); $this->assertEquals(['name is not null'], @@ -424,30 +424,30 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseInShouldReturnQuery() { - Storm_Query::in('name', ['Harlock', 'Nausicaa']) - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->in('name', ['Harlock', 'Nausicaa']) ->fetchAll(); - $this->assertEquals(['name in (\'Harlock\',\'Nausicaa\')'], + $this->assertEquals(['name in (\'Harlock\', \'Nausicaa\')'], $this->_select->getAttributesForLastCallOn('where')); } /** @test */ public function withClauseNotInShouldReturnQuery() { - Storm_Query::not_in('name', ['Harlock', 'Nausicaa']) - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->not_in('name', ['Harlock', 'Nausicaa']) ->fetchAll(); - $this->assertEquals(['name not in (\'Harlock\',\'Nausicaa\')'], + $this->assertEquals(['name not in (\'Harlock\', \'Nausicaa\')'], $this->_select->getAttributesForLastCallOn('where')); } /** @test */ public function withClauseEqualShouldReturnQuery() { - Storm_Query::eq('left(name, 5)', 'ganda') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->eq('left(name, 5)', 'ganda') ->fetchAll(); $this->assertEquals(['left(name, 5)=\'ganda\''], @@ -457,8 +457,8 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseNotEqualShouldReturnQuery() { - Storm_Query::not_eq('name', 'Harlock') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->not_eq('name', 'Harlock') ->fetchAll(); $this->assertEquals(['name!=\'Harlock\''], @@ -468,8 +468,8 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseLikeShouldReturnQuery() { - Storm_Query::like('login', '%aus%') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->like('login', '%aus%') ->fetchAll(); $this->assertEquals(['login like \'%aus%\''], @@ -479,8 +479,8 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseNotLikeShouldReturnQuery() { - Storm_Query::not_like('login', '%aus%') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->not_like('login', '%aus%') ->fetchAll(); $this->assertEquals(['login not like \'%aus%\''], @@ -490,8 +490,8 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseStartShouldReturnQuery() { - Storm_Query::start('login', 'aus') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->start('login', 'aus') ->fetchAll(); $this->assertEquals(['login like \'aus%\''], @@ -501,8 +501,8 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseEndShouldReturnQuery() { - Storm_Query::end('login', 'aus') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->end('login', 'aus') ->fetchAll(); $this->assertEquals(['login like \'%aus\''], @@ -512,31 +512,35 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseOrShouldReturnQuery() { - Storm_Query::or(Storm_Query::eq('login', 'aus'), - Storm_Query::in('role', ['admin', 'invite'])) - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->or((new Storm_Query_Criteria) + ->eq('login', 'aus') + ->in('role', ['admin', 'invite'])) ->fetchAll(); - $this->assertEquals(['(login=\'aus\' or role in (\'admin\',\'invite\'))'], + $this->assertEquals(['(login=\'aus\' or role in (\'admin\', \'invite\'))'], $this->_select->getAttributesForLastCallOn('where')); } /** @test */ public function withClauseAndShouldReturnQuery() { - Storm_Query::and(Storm_Query::eq('login', 'aus')->in('role', ['admin', 'invite'])) - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->and((new Storm_Query_Criteria) + ->eq('login', 'aus') + ->in('role', ['admin', 'invite'])) ->fetchAll(); - $this->assertEquals(['(login=\'aus\' and role in (\'admin\',\'invite\'))'], + $this->assertEquals(['(login=\'aus\' and role in (\'admin\', \'invite\'))'], $this->_select->getAttributesForLastCallOn('where')); } /** @test */ public function withClauseMatchShouldReturnQueryInBooleanMode() { - Storm_Query::match('login, role', Storm_Query::terms(['ADMIN', 'INVITE'])) - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->match((new Storm_Query_MatchBoolean('login, role')) + ->against(['ADMIN', 'INVITE'])) ->fetchAll(); $this->assertEquals(['MATCH(login, role) AGAINST(\'ADMIN INVITE\' IN BOOLEAN MODE)'], @@ -546,8 +550,10 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseMatchMultipleTermsShouldReturnQueryInBooleanMode() { - Storm_Query::match('login,role', Storm_Query::terms('ADMIN INVITE')->terms('HUGO ADRIEN')) - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->match((new Storm_Query_MatchBoolean('login,role')) + ->against('ADMIN INVITE') + ->against('HUGO ADRIEN')) ->fetchAll(); $this->assertEquals(['MATCH(login,role) AGAINST(\'ADMIN INVITE HUGO ADRIEN\' IN BOOLEAN MODE)'], @@ -557,25 +563,28 @@ class Storm_Test_LoaderQueryTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseMatchStrictModeShouldRturnQueryInBooleanMode() { - Storm_Query::match('login,role', Storm_Query::terms('ADMIN INVITE')->terms('HUGO ADRIEN'), - true) - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->match((new Storm_Query_MatchRating('login,role')) + ->beStrict() + ->against('ADMIN INVITE') + ->against('HUGO ADRIEN')) ->fetchAll(); - $this->assertEquals(['MATCH(login,role) AGAINST(\'+(ADMIN INVITE) +(HUGO ADRIEN)\' IN BOOLEAN MODE)'], + $this->assertEquals(['MATCH(login,role) AGAINST(\'+(ADMIN INVITE) +(HUGO ADRIEN)\')'], $this->_select->getAttributesForLastCallOn('where')); } /** @test */ public function withClauseMatchStrictAndOneExactExpressionWithNoBooleanModeShouldReturnQuery() { - Storm_Query::match('login,role', Storm_Query::terms('ADMIN INVITE', true)->terms('HUGO ADRIEN'), - true, - false) - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->match((new Storm_Query_MatchBoolean('login,role')) + ->beStrict() + ->exact('ADMIN INVITE') + ->against('HUGO ADRIEN')) ->fetchAll(); - $this->assertEquals(['MATCH(login,role) AGAINST(\'+"ADMIN INVITE" +(HUGO ADRIEN)\')'], + $this->assertEquals(['MATCH(login,role) AGAINST(\'+"ADMIN INVITE" +(HUGO ADRIEN)\' IN BOOLEAN MODE)'], $this->_select->getAttributesForLastCallOn('where')); } } @@ -601,8 +610,8 @@ class Storm_Test_LoaderQueryLimitTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseLimit30ShouldReturnQuery() { - Storm_Query::limit(30) - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->limit(30) ->fetchAll(); $this->assertEquals([30], @@ -612,8 +621,8 @@ class Storm_Test_LoaderQueryLimitTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseLimit30Offset10ShouldReturnQuery() { - Storm_Query::limit('10, 30') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->limit('10, 30') ->fetchAll(); $this->assertEquals(['10, 30'], @@ -642,8 +651,8 @@ class Storm_Test_LoaderQueryLimitPageTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseLimitPageShouldReturnQuery() { - Storm_Query::limit_page([1, 100]) - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->limit_page([1, 100]) ->fetchAll(); $this->assertEquals([1, 100], @@ -673,8 +682,8 @@ class Storm_Test_LoaderQueryOrderTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseOrderIdShouldReturnOrderId() { - Storm_Query::order('id') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->order('id') ->fetchAll(); $this->assertEquals(['id'], @@ -684,8 +693,8 @@ class Storm_Test_LoaderQueryOrderTest extends Storm_Test_LoaderTestCase { /** @test */ public function withClauseOrderIdDescShouldReturnOrderIdDesc() { - Storm_Query::order_desc('id') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->order_desc('id') ->fetchAll(); $this->assertEquals(['id desc'], @@ -695,10 +704,10 @@ class Storm_Test_LoaderQueryOrderTest extends Storm_Test_LoaderTestCase { /** @test */ public function withMultipleClauseOrderShouldReturnAllOrders() { - Storm_Query::order_desc('id') + Storm_Query::from($this->_loader) + ->order_desc('id') ->order('name') ->order_desc('role') - ->from($this->_loader) ->fetchAll(); $this->assertEquals(['id desc', 'name', 'role desc'], @@ -710,8 +719,9 @@ class Storm_Test_LoaderQueryOrderTest extends Storm_Test_LoaderTestCase { /** @test */ public function withMatchClauseOrderShouldReturnMatchOrder() { - Storm_Query::order_match('login, role', Storm_Query::terms(['ADMIN', 'INVITE']), false, false) - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->order_match((new Storm_Query_MatchRating('login, role')) + ->against(['ADMIN', 'INVITE'])) ->fetchAll(); $this->assertEquals(['MATCH(login, role) AGAINST(\'ADMIN INVITE\')'], @@ -721,8 +731,9 @@ class Storm_Test_LoaderQueryOrderTest extends Storm_Test_LoaderTestCase { /** @test */ public function withMatchClauseOrderDescShouldReturnMatchOrder() { - Storm_Query::order_match_desc('login, role', Storm_Query::terms(['ADMIN', 'INVITE'])) - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->order_match_desc((new Storm_Query_MatchBoolean('login, role')) + ->against(['ADMIN', 'INVITE'])) ->fetchAll(); $this->assertEquals(['MATCH(login, role) AGAINST(\'ADMIN INVITE\' IN BOOLEAN MODE) desc'], @@ -751,8 +762,8 @@ class Storm_Test_LoaderQueryGroupByTest extends Storm_Test_LoaderTestCase { /** @test */ public function withGroupByLoaderShouldCallGroupOnDbSelect() { - Storm_Query::group('name') - ->from($this->_loader) + Storm_Query::from($this->_loader) + ->group('name') ->fetchAll(); $this->assertEquals(['name'], diff --git a/tests/Storm/Test/LoaderVolatileTest.php b/tests/Storm/Test/LoaderVolatileTest.php index 4dcd13c1a05b1e710f0a212a219befc02477f06e..243f24a2ac22424ca04816565c28aea8460ba2a2 100644 --- a/tests/Storm/Test/LoaderVolatileTest.php +++ b/tests/Storm/Test/LoaderVolatileTest.php @@ -610,8 +610,8 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { /** @test */ public function withClauseLimitOneShouldReturnOnlyUserOneAlbert() { $this->assertEquals([$this->albert], - Storm_Query::limit(1) - ->from(Storm_Test_VolatileUser::getLoader()) + Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->limit(1) ->fetchAll()); } @@ -619,8 +619,8 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { /** @test */ public function withClauseLimitOneTwoShouldReturnTwoUserHubertAndZoe() { $this->assertEquals([$this->hubert, $this->zoe], - Storm_Query::limit('1, 2') - ->from(Storm_Test_VolatileUser::getLoader()) + Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->limit('1, 2') ->fetchAll()); } @@ -826,8 +826,8 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { /** @test */ public function selectAllCatsWhereIdMoreThanThreeShouldAnswersFifiAndLoulou() { $this->assertEquals(['fifi', 'loulou'], - (new Storm_Model_Collection(Storm_Query::gt('id', 3) - ->from(Storm_Test_VolatileCat::getLoader()) + (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileCat::getLoader()) + ->gt('id', 3) ->fetchAll())) ->collect('name') ->getArrayCopy()); @@ -837,8 +837,8 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { /** @test */ public function selectAllCatsWhereIdMoreOrEqualThanForShouldAnswersFifiAndLoulou() { $this->assertEquals(['fifi', 'loulou'], - (new Storm_Model_Collection(Storm_Query::gt_eq('id', 4) - ->from(Storm_Test_VolatileCat::getLoader()) + (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileCat::getLoader()) + ->gt_eq('id', 4) ->fetchAll())) ->collect('name') ->getArrayCopy()); @@ -848,8 +848,8 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { /** @test */ public function selectAllCatsWhereIdLesserThanFiveShouldAnswersRiriAndFifi() { $this->assertEquals(['riri', 'fifi'], - (new Storm_Model_Collection(Storm_Query::lt('id', 5) - ->from(Storm_Test_VolatileCat::getLoader()) + (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileCat::getLoader()) + ->lt('id', 5) ->fetchAll())) ->collect('name') ->getArrayCopy()); @@ -859,8 +859,8 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { /** @test */ public function selectAllCatsWhereIdLesserOrEqualThanForShouldAnswersRiriAndFifi() { $this->assertEquals(['riri', 'fifi'], - (new Storm_Model_Collection(Storm_Query::lt_eq('id', 4) - ->from(Storm_Test_VolatileCat::getLoader()) + (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileCat::getLoader()) + ->lt_eq('id', 4) ->fetchAll())) ->collect('name') ->getArrayCopy()); @@ -870,8 +870,8 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { /** @test */ public function selectUserLoginNotHubertShouldReturnAlbertAndZoe() { $this->assertEquals(['albert', 'zoe'], - (new Storm_Model_Collection(Storm_Query::not_eq('login', 'hubert') - ->from(Storm_Test_VolatileUser::getLoader()) + (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->not_eq('login', 'hubert') ->fetchAll())) ->collect('login') ->getArrayCopy()); @@ -881,9 +881,9 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { /** @test */ public function selectUserLoginInAlbertZoeAndFooNotLikeSnafuShouldReturnAlbert() { $this->assertEquals(['albert'], - (new Storm_Model_Collection(Storm_Query::in('login', ['albert', 'zoe']) + (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->in('login', ['albert', 'zoe']) ->not_like('foo', '%naf%') - ->from(Storm_Test_VolatileUser::getLoader()) ->fetchAll())) ->collect('login') ->getArrayCopy()); @@ -893,9 +893,9 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { /** @test */ public function selectUserLoginInAlbertZoeAndFooStartSnaShouldReturnZoe() { $this->assertEquals(['zoe'], - (new Storm_Model_Collection(Storm_Query::in('login', ['albert', 'zoe']) + (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->in('login', ['albert', 'zoe']) ->start('foo', 'sna') - ->from(Storm_Test_VolatileUser::getLoader()) ->fetchAll())) ->collect('login') ->getArrayCopy()); @@ -905,9 +905,9 @@ class Storm_Test_LoaderVolatileTest extends Storm_Test_ModelTestCase { /** @test */ public function selectUserLoginInAlbertZoeAndFooEndAfuShouldReturnZoe() { $this->assertEquals(['zoe'], - (new Storm_Model_Collection(Storm_Query::in('login', ['albert', 'zoe']) + (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->in('login', ['albert', 'zoe']) ->end('foo', 'afu') - ->from(Storm_Test_VolatileUser::getLoader()) ->fetchAll())) ->collect('login') ->getArrayCopy()); @@ -953,10 +953,11 @@ class Storm_Test_LoaderVolatileClauseWhereTest extends Storm_Test_ModelTestCase /** @test */ public function withMatchLevelAgainstAdminShouldAnswersOnlyUser_Admin() { + $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->match((new Storm_Query_MatchBoolean('level')) + ->against(['admin'])); $this->assertEquals(['user_admin'], - (new Storm_Model_Collection(Storm_Query::match('level', Storm_Query::terms(['admin'])) - ->from(Storm_Test_VolatileUser::getLoader()) - ->fetchAll())) + (new Storm_Model_Collection($query->fetchAll())) ->collect('login') ->getArrayCopy()); } @@ -964,11 +965,11 @@ class Storm_Test_LoaderVolatileClauseWhereTest extends Storm_Test_ModelTestCase /** @test */ public function withMatchLevelAgainstAdminDeuxiemeShouldAnswersUser_AdminAndUser_AdministrateurAndUser_Invite() { + $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->match((new Storm_Query_MatchBoolean('level,foo')) + ->against(['admin', 'deuxieme'])); $this->assertEquals(['user_admin', 'user_administrateur', 'user_invite'], - (new Storm_Model_Collection(Storm_Query::match('level,foo', - Storm_Query::terms(['admin', 'deuxieme'])) - ->from(Storm_Test_VolatileUser::getLoader()) - ->fetchAll())) + (new Storm_Model_Collection($query->fetchAll())) ->collect('login') ->getArrayCopy()); } @@ -976,13 +977,13 @@ class Storm_Test_LoaderVolatileClauseWhereTest extends Storm_Test_ModelTestCase /** @test */ public function withMatchLevelAgainstStrictAdminRedacteur_DeuxiemeShouldAnswersUser_AdminAndUser_Administrateur() { + $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->match((new Storm_Query_MatchBoolean('level,foo')) + ->beStrict() + ->against(['admin', 'redacteur']) + ->against(['deuxieme'])); $this->assertEquals(['user_admin', 'user_administrateur'], - (new Storm_Model_Collection(Storm_Query::match('level,foo', - Storm_Query::terms(['admin', 'redacteur']) - ->terms(['deuxieme']), - true) - ->from(Storm_Test_VolatileUser::getLoader()) - ->fetchAll())) + (new Storm_Model_Collection($query->fetchAll())) ->collect('login') ->getArrayCopy()); } @@ -990,12 +991,11 @@ class Storm_Test_LoaderVolatileClauseWhereTest extends Storm_Test_ModelTestCase /** @test */ public function withMatchLevelAgainstExactDeuxiemeTroisiemeShouldAnswersOnlyUser_Admin() { + $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->match((new Storm_Query_MatchBoolean('level,foo')) + ->exact('deuxieme redacteur')); $this->assertEquals(['user_administrateur'], - (new Storm_Model_Collection(Storm_Query::match('level,foo', - Storm_Query::terms('deuxieme redacteur', - true)) - ->from(Storm_Test_VolatileUser::getLoader()) - ->fetchAll())) + (new Storm_Model_Collection($query->fetchAll())) ->collect('login') ->getArrayCopy()); } @@ -1003,11 +1003,12 @@ class Storm_Test_LoaderVolatileClauseWhereTest extends Storm_Test_ModelTestCase /** @test */ public function withOrClause_LevelInviteOrFooLikePremierShouldAnswersUser_AdminAndUser_Invite() { + $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->or((new Storm_Query_Criteria) + ->eq('level', 'invite') + ->like('foo', '%premier%')); $this->assertEquals(['user_admin', 'user_invite'], - (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileUser::getLoader()) - ->or(Storm_Query::eq('level', 'invite') - ->like('foo', '%premier%')) - ->fetchAll())) + (new Storm_Model_Collection($query->fetchAll())) ->collect('login') ->getArrayCopy()); } @@ -1015,11 +1016,12 @@ class Storm_Test_LoaderVolatileClauseWhereTest extends Storm_Test_ModelTestCase /** @test */ public function withAndClause_LevelInviteOrFooLikePremierShouldAnswersOnlyUser_Invite() { + $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->and((new Storm_Query_Criteria) + ->eq('level', 'invite') + ->like('foo', '%premier%')); $this->assertEquals(['user_invite'], - (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileUser::getLoader()) - ->and(Storm_Query::eq('level', 'invite') - ->like('foo', '%premier%')) - ->fetchAll())) + (new Storm_Model_Collection($query->fetchAll())) ->collect('login') ->getArrayCopy()); } @@ -1064,10 +1066,10 @@ class Storm_Test_LoaderVolatileClauseOrderTest extends Storm_Test_ModelTestCase /** @test */ public function with_Order1Desc_ShouldAnswersInOrdered() { + $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->order_desc('order1'); $this->assertEquals(['user_invite', 'user_administrateur', 'user_admin'], - (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileUser::getLoader()) - ->order_desc('order1') - ->fetchAll())) + (new Storm_Model_Collection($query->fetchAll())) ->collect('login') ->getArrayCopy()); } @@ -1075,11 +1077,11 @@ class Storm_Test_LoaderVolatileClauseOrderTest extends Storm_Test_ModelTestCase /** @test */ public function with_Order3Asc_Order2Desc_ShouldAnswersOrderedUser() { + $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->order('order3') + ->order_desc('order2'); $this->assertEquals(['user_administrateur', 'user_admin', 'user_invite'], - (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileUser::getLoader()) - ->order('order3') - ->order_desc('order2') - ->fetchAll())) + (new Storm_Model_Collection($query->fetchAll())) ->collect('login') ->getArrayCopy()); } @@ -1087,11 +1089,11 @@ class Storm_Test_LoaderVolatileClauseOrderTest extends Storm_Test_ModelTestCase /** @test */ public function with_Order3Desc_Order2Desc_ShouldAnswersOrderedUser() { + $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->order_desc('order3') + ->order_desc('order2'); $this->assertEquals(['user_invite', 'user_administrateur', 'user_admin'], - (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileUser::getLoader()) - ->order_desc('order3') - ->order_desc('order2') - ->fetchAll())) + (new Storm_Model_Collection($query->fetchAll())) ->collect('login') ->getArrayCopy()); } @@ -1100,8 +1102,8 @@ class Storm_Test_LoaderVolatileClauseOrderTest extends Storm_Test_ModelTestCase /** @test */ public function withMatch_Level_Administrateur_ShouldAnswersOrderedUser() { $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) - ->order_match('level', Storm_Query::terms('administrateur'), - false, false); + ->order_match((new Storm_Query_MatchRating('level')) + ->against('administrateur')); $this->assertEquals(['user_admin', 'user_invite', 'user_administrateur'], (new Storm_Model_Collection($query->fetchAll())) ->collect('login') @@ -1112,8 +1114,8 @@ class Storm_Test_LoaderVolatileClauseOrderTest extends Storm_Test_ModelTestCase /** @test */ public function withMatch_Level_Administrateur_Redacteur_Desc_ShouldAnswersOrderedUser() { $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) - ->order_match_desc('level', Storm_Query::terms('administrateur redacteur'), - false, false); + ->order_match_desc((new Storm_Query_MatchRating('level')) + ->against('administrateur redacteur')); $this->assertEquals(['user_administrateur', 'user_admin', 'user_invite'], (new Storm_Model_Collection($query->fetchAll())) ->collect('login') @@ -1124,7 +1126,8 @@ class Storm_Test_LoaderVolatileClauseOrderTest extends Storm_Test_ModelTestCase /** @test */ public function withMatchInBooleanMode_Level_Administrateur_Redacteur_Desc_ShouldAnswersOrderedUser() { $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) - ->order_match_desc('level', Storm_Query::terms('administrateur redacteur')); + ->order_match_desc((new Storm_Query_MatchBoolean('level')) + ->against('administrateur redacteur')); $this->assertEquals(['user_admin', 'user_administrateur', 'user_invite'], (new Storm_Model_Collection($query->fetchAll())) ->collect('login') @@ -1135,9 +1138,10 @@ class Storm_Test_LoaderVolatileClauseOrderTest extends Storm_Test_ModelTestCase /** @test */ public function withMatch_FooDescExacteInBooleanMode_Forth_Fifth_Level_Administrateur_Redacteur_ShouldAnswersOrderedUser() { $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) - ->order_match_desc('foo', Storm_Query::terms('forth fifth', true)) - ->order_match('level', Storm_Query::terms('administrateur redacteur'), - false, false); + ->order_match_desc((new Storm_Query_MatchBoolean('foo')) + ->exact('forth fifth')) + ->order_match((new Storm_Query_MatchRating('level')) + ->against('administrateur redacteur')); $this->assertEquals(['user_invite', 'user_admin', 'user_administrateur'], (new Storm_Model_Collection($query->fetchAll())) ->collect('login') @@ -1148,8 +1152,10 @@ class Storm_Test_LoaderVolatileClauseOrderTest extends Storm_Test_ModelTestCase /** @test */ public function withMatch_FooLevelStrict_InviteRedacteur_SecondThird_ShouldAnswersOrderedUser() { $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) - ->order_match('foo,level', Storm_Query::terms('invite redacteur') - ->terms('second third'), true); + ->order_match((new Storm_Query_MatchBoolean('foo,level')) + ->beStrict() + ->against('invite redacteur') + ->against('second third')); $this->assertEquals(['user_administrateur', 'user_invite', 'user_admin'], (new Storm_Model_Collection($query->fetchAll())) ->collect('login') @@ -1159,10 +1165,10 @@ class Storm_Test_LoaderVolatileClauseOrderTest extends Storm_Test_ModelTestCase /** @test */ public function selectUsersGroupByOrder3ShouldAnswersUserAdminAndUserInvite() { + $query = Storm_Query::from(Storm_Test_VolatileUser::getLoader()) + ->group('order3'); $this->assertEquals([0 => 'user_admin', 2 => 'user_invite'], - (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileUser::getLoader()) - ->group('order3') - ->fetchAll())) + (new Storm_Model_Collection($query->fetchAll())) ->collect('login') ->getArrayCopy()); }