diff --git a/src/ORM/DataList.php b/src/ORM/DataList.php index e0dd048ab17..2fbf871dfc8 100644 --- a/src/ORM/DataList.php +++ b/src/ORM/DataList.php @@ -525,14 +525,23 @@ public function filterAny() throw new InvalidArgumentException('Incorrect number of arguments passed to filterAny()'); } - return $this->alterDataQuery(function (DataQuery $query) use ($whereArguments) { - $subquery = $query->disjunctiveGroup(); + $list = $this->alterDataQuery(function (DataQuery $query) use ($whereArguments) { + $clause = 'WHERE'; + foreach (array_keys($whereArguments) as $field) { + if (preg_match('#\.(COUNT|SUM|AVG|MIN|MAX)\(#', strtoupper($field))) { + $clause = 'HAVING'; + break; + } + } + $subquery = $query->disjunctiveGroup($clause); foreach ($whereArguments as $field => $value) { $filter = $this->createSearchFilter($field, $value); $filter->apply($subquery); } }); + + return $list; } /** diff --git a/src/ORM/DataQuery.php b/src/ORM/DataQuery.php index 18951ecaecb..5ae4aac2508 100644 --- a/src/ORM/DataQuery.php +++ b/src/ORM/DataQuery.php @@ -660,9 +660,9 @@ public function having($having) * * @return DataQuery_SubGroup */ - public function disjunctiveGroup() + public function disjunctiveGroup(string $clause = 'WHERE') { - return new DataQuery_SubGroup($this, 'OR'); + return new DataQuery_SubGroup($this, 'OR', $clause); } /** @@ -672,9 +672,9 @@ public function disjunctiveGroup() * * @return DataQuery_SubGroup */ - public function conjunctiveGroup() + public function conjunctiveGroup(string $clause = 'WHERE') { - return new DataQuery_SubGroup($this, 'AND'); + return new DataQuery_SubGroup($this, 'AND', $clause); } /** diff --git a/src/ORM/DataQuery_SubGroup.php b/src/ORM/DataQuery_SubGroup.php index 0f57d01ae5e..39aec826e62 100644 --- a/src/ORM/DataQuery_SubGroup.php +++ b/src/ORM/DataQuery_SubGroup.php @@ -14,21 +14,32 @@ */ class DataQuery_SubGroup extends DataQuery implements SQLConditionGroup { + private string $clause; /** - * * @var SQLSelect */ protected $whereQuery; - public function __construct(DataQuery $base, $connective) + /** + * @var SQLSelect + */ + protected $havingQuery; + + public function __construct(DataQuery $base, $connective, string $clause = 'WHERE') { parent::__construct($base->dataClass); $this->query = $base->query; - $this->whereQuery = new SQLSelect(); - $this->whereQuery->setConnective($connective); - - $base->where($this); + $this->clause = strtoupper($clause); + if ($this->clause === 'WHERE') { + $this->whereQuery = new SQLSelect(); + $this->whereQuery->setConnective($connective); + $base->where($this); + } elseif ($this->clause === 'HAVING') { + $this->havingQuery = new SQLSelect(); + $this->havingQuery->setConnective($connective); + $base->having($this); + } } public function where($filter) @@ -49,18 +60,33 @@ public function whereAny($filter) return $this; } + public function having($filter) + { + if ($filter) { + $this->havingQuery->addHaving($filter); + } + + return $this; + } + public function conditionSQL(&$parameters) { $parameters = []; - // Ignore empty conditions - $where = $this->whereQuery->getWhere(); - if (empty($where)) { - return null; + if ($this->clause === 'WHERE') { + $where = $this->whereQuery->getWhere(); + if (!empty($where)) { + $sql = DB::get_conn()->getQueryBuilder()->buildWhereFragment($this->whereQuery, $parameters); + return preg_replace('/^\s*WHERE\s*/i', '', $sql ?? ''); + } + } elseif ($this->clause === 'HAVING') { + $having = $this->havingQuery->getHaving(); + if (!empty($having)) { + $sql = DB::get_conn()->getQueryBuilder()->buildHavingFragment($this->havingQuery, $parameters); + return preg_replace('/^\s*HAVING\s*/i', '', $sql ?? ''); + } } - // Allow database to manage joining of conditions - $sql = DB::get_conn()->getQueryBuilder()->buildWhereFragment($this->whereQuery, $parameters); - return preg_replace('/^\s*WHERE\s*/i', '', $sql ?? ''); + return null; } } diff --git a/src/ORM/ManyManyList.php b/src/ORM/ManyManyList.php index ff841a9dc65..2223196d1f2 100644 --- a/src/ORM/ManyManyList.php +++ b/src/ORM/ManyManyList.php @@ -15,7 +15,6 @@ */ class ManyManyList extends RelationList { - /** * @var string $joinTable */