$types Associative array of type names used to bind values to query * @return $this * @see \Cake\Database\Query::where() */ public function filter(ExpressionInterface|Closure|array|string $conditions, array $types = []) { $this->filter ??= new QueryExpression(); if ($conditions instanceof Closure) { $conditions = $conditions(new QueryExpression()); } $this->filter->add($conditions, $types); return $this; } /** * Adds an empty `OVER()` window expression or a named window expression. * * @param string|null $name Window name * @return $this */ public function over(?string $name = null) { $window = $this->getWindow(); if ($name) { // Set name manually in case this was chained from FunctionsBuilder wrapper $window->name($name); } return $this; } /** * @inheritDoc */ public function partition(ExpressionInterface|Closure|array|string $partitions) { $this->getWindow()->partition($partitions); return $this; } /** * @inheritDoc */ public function order(ExpressionInterface|Closure|array|string $fields) { deprecationWarning( '5.0.0', 'AggregateExpression::order() is deprecated. Use AggregateExpression::orderBy() instead.', ); return $this->orderBy($fields); } /** * @inheritDoc */ public function orderBy(ExpressionInterface|Closure|array|string $fields) { $this->getWindow()->orderBy($fields); return $this; } /** * @inheritDoc */ public function range(ExpressionInterface|string|int|null $start, ExpressionInterface|string|int|null $end = 0) { $this->getWindow()->range($start, $end); return $this; } /** * @inheritDoc */ public function rows(?int $start, ?int $end = 0) { $this->getWindow()->rows($start, $end); return $this; } /** * @inheritDoc */ public function groups(?int $start, ?int $end = 0) { $this->getWindow()->groups($start, $end); return $this; } /** * @inheritDoc */ public function frame( string $type, ExpressionInterface|string|int|null $startOffset, string $startDirection, ExpressionInterface|string|int|null $endOffset, string $endDirection, ) { $this->getWindow()->frame($type, $startOffset, $startDirection, $endOffset, $endDirection); return $this; } /** * @inheritDoc */ public function excludeCurrent() { $this->getWindow()->excludeCurrent(); return $this; } /** * @inheritDoc */ public function excludeGroup() { $this->getWindow()->excludeGroup(); return $this; } /** * @inheritDoc */ public function excludeTies() { $this->getWindow()->excludeTies(); return $this; } /** * Returns or creates WindowExpression for function. * * @return \Cake\Database\Expression\WindowExpression */ protected function getWindow(): WindowExpression { return $this->window ??= new WindowExpression(); } /** * @inheritDoc */ public function sql(ValueBinder $binder): string { $sql = parent::sql($binder); if ($this->filter !== null) { $sql .= ' FILTER (WHERE ' . $this->filter->sql($binder) . ')'; } if ($this->window !== null) { if ($this->window->isNamedOnly()) { $sql .= ' OVER ' . $this->window->sql($binder); } else { $sql .= ' OVER (' . $this->window->sql($binder) . ')'; } } return $sql; } /** * @inheritDoc */ public function traverse(Closure $callback) { parent::traverse($callback); if ($this->filter !== null) { $callback($this->filter); $this->filter->traverse($callback); } if ($this->window !== null) { $callback($this->window); $this->window->traverse($callback); } return $this; } /** * @inheritDoc */ public function count(): int { $count = parent::count(); if ($this->window !== null) { $count += 1; } return $count; } /** * Clone this object and its subtree of expressions. * * @return void */ public function __clone() { parent::__clone(); if ($this->filter !== null) { $this->filter = clone $this->filter; } if ($this->window !== null) { $this->window = clone $this->window; } } }