0 follower

Abstract Class Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder

InheritanceYiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
ImplementsYiisoft\Db\QueryBuilder\DQLQueryBuilderInterface

It's used to query data from a database.

Public Methods

Hide inherited methods

Method Description Defined By
__construct() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
build() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildColumns() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildCondition() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildExpression() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildFor() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildFrom() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildGroupBy() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildHaving() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildJoin() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildLimit() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildOrderBy() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildOrderByAndLimit() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildSelect() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildUnion() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildWhere() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
buildWithQueries() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
createConditionFromArray() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
getExpressionBuilder() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
selectExists() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
setConditionClasses() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
setExpressionBuilders() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
setSeparator() Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder

Protected Methods

Hide inherited methods

Method Description Defined By
defaultConditionClasses() Has an array of default condition classes. Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
defaultExpressionBuilders() Has an array of default expression builders. Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder
extractAlias() Extracts table alias if there is one or returns false. Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder

Property Details

Hide inherited properties

$conditionClasses protected property

Map of condition aliases to condition classes. For example:

return [
    'LIKE' => \Yiisoft\Db\QueryBuilder\Condition\Like::class,
];

This property is used by createConditionFromArray() method.

See default condition classes list in defaultConditionClasses() method.

In case you want to add custom conditions support, use the setConditionClasses() method.

See also:

protected array $conditionClasses = []
$expressionBuilders protected property

Map of expression aliases to expression classes.

For example:

[
   Expression::class => ExpressionBuilder::class
]

This property is mainly used by buildExpression() to build SQL expressions form expression objects. See default values in defaultExpressionBuilders() method.

setExpressionBuilders() defaultExpressionBuilders()

protected array $expressionBuilders = []
$queryBuilder protected property
$separator protected property
protected string $separator ' '

Method Details

Hide inherited methods

__construct() public method

public __construct( Yiisoft\Db\QueryBuilder\QueryBuilderInterface $queryBuilder, Yiisoft\Db\Schema\QuoterInterface $quoter ): mixed
$queryBuilder Yiisoft\Db\QueryBuilder\QueryBuilderInterface
$quoter Yiisoft\Db\Schema\QuoterInterface

                public function __construct(
    protected QueryBuilderInterface $queryBuilder,
    private readonly QuoterInterface $quoter,
) {
    $this->expressionBuilders = $this->defaultExpressionBuilders();
    $this->conditionClasses = $this->defaultConditionClasses();
}

            
build() public method

public build( Yiisoft\Db\Query\QueryInterface $query, array $params = [] ): array
$query Yiisoft\Db\Query\QueryInterface
$params array

                public function build(QueryInterface $query, array $params = []): array
{
    $query = $query->prepare($this->queryBuilder);
    $params = empty($params) ? $query->getParams() : array_merge($params, $query->getParams());
    $clauses = [
        $this->buildSelect($query->getSelect(), $params, $query->getDistinct(), $query->getSelectOption()),
        $this->buildFrom($query->getFrom(), $params),
        $this->buildJoin($query->getJoins(), $params),
        $this->buildWhere($query->getWhere(), $params),
        $this->buildGroupBy($query->getGroupBy(), $params),
        $this->buildHaving($query->getHaving(), $params),
    ];
    $sql = implode($this->separator, array_filter($clauses));
    $sql = $this->buildOrderByAndLimit($sql, $query->getOrderBy(), $query->getLimit(), $query->getOffset(), $params);
    $for = $this->buildFor($query->getFor());
    if ($for !== '') {
        $sql .= $this->separator . $for;
    }
    $union = $this->buildUnion($query->getUnions(), $params);
    if ($union !== '') {
        $sql = "($sql)$this->separator$union";
    }
    $with = $this->buildWithQueries($query->getWithQueries(), $params);
    if ($with !== '') {
        $sql = "$with$this->separator$sql";
    }
    return [$sql, $params];
}

            
buildColumns() public method

public buildColumns( array|string $columns ): string
$columns array|string

                public function buildColumns(array|string $columns): string
{
    if (!is_array($columns)) {
        if (str_contains($columns, '(')) {
            return $columns;
        }
        /** @var list<string> We use valid regular expressions, so the result is always a list of strings */
        $columns = preg_split('/\s*,\s*/', $columns, -1, PREG_SPLIT_NO_EMPTY);
    }
    $columns = array_map(
        fn(string|ExpressionInterface $column): string => $column instanceof ExpressionInterface
            ? $this->buildExpression($column)
            : $this->quoter->quoteColumnName($column),
        $columns,
    );
    return implode(', ', $columns);
}

            
buildCondition() public method

public buildCondition( array|string|Yiisoft\Db\Expression\ExpressionInterface|null $condition, array &$params = [] ): string
$condition array|string|Yiisoft\Db\Expression\ExpressionInterface|null
$params array

                public function buildCondition(array|string|ExpressionInterface|null $condition, array &$params = []): string
{
    if (empty($condition)) {
        if ($condition === '0') {
            return '0';
        }
        return '';
    }
    if (is_array($condition)) {
        $condition = $this->createConditionFromArray($condition);
    } elseif (is_string($condition)) {
        $condition = new Expression($condition, $params);
        $params = [];
    }
    return $this->buildExpression($condition, $params);
}

            
buildExpression() public method

public buildExpression( Yiisoft\Db\Expression\ExpressionInterface $expression, array &$params = [] ): string
$expression Yiisoft\Db\Expression\ExpressionInterface
$params array

                public function buildExpression(ExpressionInterface $expression, array &$params = []): string
{
    return $this->queryBuilder
        ->getExpressionBuilder($expression)
        ->build($expression, $params);
}

            
buildFor() public method

public buildFor( array $values ): string
$values array

                public function buildFor(array $values): string
{
    if (empty($values)) {
        return '';
    }
    return 'FOR ' . implode($this->separator . 'FOR ', $values);
}

            
buildFrom() public method

public buildFrom( array $tables, array &$params ): string
$tables array
$params array

                public function buildFrom(array $tables, array &$params): string
{
    if (empty($tables)) {
        return '';
    }
    /** @var string[] $tables */
    $tables = $this->quoteTableNames($tables, $params);
    return 'FROM ' . implode(', ', $tables);
}

            
buildGroupBy() public method

public buildGroupBy( array $columns, array &$params = [] ): string
$columns array
$params array

                public function buildGroupBy(array $columns, array &$params = []): string
{
    if (empty($columns)) {
        return '';
    }
    /** @psalm-var array<string, ExpressionInterface|string> $columns */
    foreach ($columns as $i => $column) {
        if ($column instanceof ExpressionInterface) {
            $columns[$i] = $this->buildExpression($column, $params);
        } elseif (!str_contains($column, '(')) {
            $columns[$i] = $this->quoter->quoteColumnName($column);
        }
    }
    /** @psalm-var array<string, Expression|string> $columns */
    return 'GROUP BY ' . implode(', ', $columns);
}

            
buildHaving() public method

public buildHaving( array|Yiisoft\Db\Expression\ExpressionInterface|string|null $condition, array &$params = [] ): string
$condition array|Yiisoft\Db\Expression\ExpressionInterface|string|null
$params array

                public function buildHaving(array|ExpressionInterface|string|null $condition, array &$params = []): string
{
    $having = $this->buildCondition($condition, $params);
    return ($having === '') ? '' : ('HAVING ' . $having);
}

            
buildJoin() public method

public buildJoin( array $joins, array &$params ): string
$joins array
$params array

                public function buildJoin(array $joins, array &$params): string
{
    if (empty($joins)) {
        return '';
    }
    foreach ($joins as $i => $join) {
        /** @psalm-suppress DocblockTypeContradiction */
        if (!is_array($join) || !isset($join[0], $join[1])) {
            throw new InvalidArgumentException(
                'A join clause must be specified as an array of join type, join table, and optionally join condition.',
            );
        }
        [$joinType, $table] = $join;
        $tables = $this->quoteTableNames(is_array($table) ? $table : [$table], $params);
        $table = reset($tables);
        $joins[$i] = "$joinType $table";
        if (isset($join[2])) {
            if (is_array($join[2]) && !isset($join[2][0])) {
                foreach ($join[2] as &$column) {
                    if (is_string($column)) {
                        $column = new ColumnName($column);
                    }
                }
                unset($column);
            }
            $condition = $this->buildCondition($join[2], $params);
            if ($condition !== '') {
                $joins[$i] .= ' ON ' . $condition;
            }
        }
    }
    /** @psalm-var array<string> $joins */
    return implode($this->separator, $joins);
}

            
buildLimit() public method

public buildLimit( Yiisoft\Db\Expression\ExpressionInterface|integer|null $limit, Yiisoft\Db\Expression\ExpressionInterface|integer|null $offset ): string
$limit Yiisoft\Db\Expression\ExpressionInterface|integer|null
$offset Yiisoft\Db\Expression\ExpressionInterface|integer|null

                public function buildLimit(ExpressionInterface|int|null $limit, ExpressionInterface|int|null $offset): string
{
    $sql = '';
    if ($limit !== null) {
        $sql = 'LIMIT '
            . ($limit instanceof ExpressionInterface ? $this->buildExpression($limit) : (string) $limit);
    }
    if (!empty($offset)) {
        $sql .= ' OFFSET '
            . ($offset instanceof ExpressionInterface ? $this->buildExpression($offset) : (string) $offset);
    }
    return ltrim($sql);
}

            
buildOrderBy() public method

public buildOrderBy( array $columns, array &$params = [] ): string
$columns array
$params array

                public function buildOrderBy(array $columns, array &$params = []): string
{
    if (empty($columns)) {
        return '';
    }
    $orders = [];
    /** @psalm-var array<string, ExpressionInterface|int|string> $columns */
    foreach ($columns as $name => $direction) {
        if ($direction instanceof ExpressionInterface) {
            $orders[] = $this->buildExpression($direction, $params);
        } else {
            $orders[] = $this->quoter->quoteColumnName($name) . ($direction === SORT_DESC ? ' DESC' : '');
        }
    }
    return 'ORDER BY ' . implode(', ', $orders);
}

            
buildOrderByAndLimit() public method

public buildOrderByAndLimit( string $sql, array $orderBy, Yiisoft\Db\Expression\ExpressionInterface|integer|null $limit, Yiisoft\Db\Expression\ExpressionInterface|integer|null $offset, array &$params = [] ): string
$sql string
$orderBy array
$limit Yiisoft\Db\Expression\ExpressionInterface|integer|null
$offset Yiisoft\Db\Expression\ExpressionInterface|integer|null
$params array

                public function buildOrderByAndLimit(
    string $sql,
    array $orderBy,
    ExpressionInterface|int|null $limit,
    ExpressionInterface|int|null $offset,
    array &$params = [],
): string {
    $orderBy = $this->buildOrderBy($orderBy, $params);
    if ($orderBy !== '') {
        $sql .= $this->separator . $orderBy;
    }
    $limit = $this->buildLimit($limit, $offset);
    if ($limit !== '') {
        $sql .= $this->separator . $limit;
    }
    return $sql;
}

            
buildSelect() public method

public buildSelect( array $columns, array &$params, boolean $distinct false, string|null $selectOption null ): string
$columns array
$params array
$distinct boolean
$selectOption string|null

                public function buildSelect(
    array $columns,
    array &$params,
    bool $distinct = false,
    ?string $selectOption = null,
): string {
    $select = $distinct ? 'SELECT DISTINCT' : 'SELECT';
    if ($selectOption !== null) {
        $select .= ' ' . $selectOption;
    }
    if (empty($columns)) {
        return $select . ' *';
    }
    $quoter = $this->quoter;
    foreach ($columns as $i => $column) {
        $isIndexString = is_string($i);
        if (!is_string($column)) {
            $columns[$i] = $this->queryBuilder->buildValue($column, $params);
        } elseif (!str_contains($column, '(')) {
            if (!$isIndexString
                && preg_match('/^(.*?)(?i:\s+as\s+|\s+)([\w\-_.]+)$/', $column, $matches) === 1
            ) {
                $columns[$i] = $quoter->quoteColumnName($matches[1])
                    . ' AS ' . $quoter->quoteSimpleColumnName($matches[2]);
                continue;
            }
            $columns[$i] = $quoter->quoteColumnName($column);
        }
        if ($isIndexString && $i !== $column) {
            /**
             * @var string $i
             * @psalm-var string $columns[$i]
             */
            $columns[$i] .= ' AS ' . $quoter->quoteColumnName($i);
        }
    }
    /** @psalm-var array<string, Expression|string> $columns */
    return $select . ' ' . implode(', ', $columns);
}

            
buildUnion() public method

public buildUnion( array $unions, array &$params ): string
$unions array
$params array

                public function buildUnion(array $unions, array &$params): string
{
    if (empty($unions)) {
        return '';
    }
    $result = '';
    /** @psalm-var array<array{query:string|Query, all:bool}> $unions */
    foreach ($unions as $union) {
        if ($union['query'] instanceof QueryInterface) {
            [$union['query'], $params] = $this->build($union['query'], $params);
        }
        $result .= 'UNION ' . ($union['all'] ? 'ALL ' : '') . '( ' . $union['query'] . ' ) ';
    }
    return trim($result);
}

            
buildWhere() public method

public buildWhere( array|string|Yiisoft\Db\QueryBuilder\Condition\ConditionInterface|Yiisoft\Db\Expression\ExpressionInterface|null $condition, array &$params = [] ): string
$condition array|string|Yiisoft\Db\QueryBuilder\Condition\ConditionInterface|Yiisoft\Db\Expression\ExpressionInterface|null
$params array

                public function buildWhere(
    array|string|ConditionInterface|ExpressionInterface|null $condition,
    array &$params = [],
): string {
    $where = $this->buildCondition($condition, $params);
    return ($where === '') ? '' : ('WHERE ' . $where);
}

            
buildWithQueries() public method

public buildWithQueries( array $withQueries, array &$params ): string
$withQueries array
$params array

                public function buildWithQueries(array $withQueries, array &$params): string
{
    if (empty($withQueries)) {
        return '';
    }
    $recursive = false;
    $result = [];
    foreach ($withQueries as $withQuery) {
        if ($withQuery->recursive) {
            $recursive = true;
        }
        if ($withQuery->query instanceof QueryInterface) {
            [$querySql, $params] = $this->build($withQuery->query, $params);
        } else {
            $querySql = $withQuery->query;
        }
        $quotedAlias = $this->quoteCteAlias($withQuery->alias);
        $result[] = $quotedAlias . ' AS (' . $querySql . ')';
    }
    return 'WITH ' . ($recursive ? 'RECURSIVE ' : '') . implode(', ', $result);
}

            
createConditionFromArray() public method

public createConditionFromArray( array $condition ): Yiisoft\Db\QueryBuilder\Condition\ConditionInterface
$condition array

                public function createConditionFromArray(array $condition): ConditionInterface
{
    /** operator format: operator, operand 1, operand 2, ... */
    if (isset($condition[0])) {
        $operator = strtoupper((string) array_shift($condition));
        $className = $this->conditionClasses[$operator] ?? Simple::class;
        return $className::fromArrayDefinition($operator, $condition);
    }
    $conditions = [];
    foreach ($condition as $column => $value) {
        if (!is_string($column)) {
            throw new InvalidArgumentException('Condition array must have string keys.');
        }
        if (is_iterable($value) || $value instanceof QueryInterface) {
            $conditions[] = new Condition\In($column, $value);
            continue;
        }
        $conditions[] = new Condition\Equals($column, $value);
    }
    return count($conditions) === 1 ? $conditions[0] : new Condition\AndX(...$conditions);
}

            
defaultConditionClasses() protected method

Has an array of default condition classes.

Extend this method if you want to change default condition classes for the query builder.

See $conditionClasses docs for details.

protected defaultConditionClasses( ): array

                protected function defaultConditionClasses(): array
{
    return [
        'NOT' => Condition\Not::class,
        'AND' => Condition\AndX::class,
        'OR' => Condition\OrX::class,
        '=' => Condition\Equals::class,
        '!=' => Condition\NotEquals::class,
        '<>' => Condition\NotEquals::class,
        '>' => Condition\GreaterThan::class,
        '>=' => Condition\GreaterThanOrEqual::class,
        '<' => Condition\LessThan::class,
        '<=' => Condition\LessThanOrEqual::class,
        'BETWEEN' => Condition\Between::class,
        'NOT BETWEEN' => Condition\NotBetween::class,
        'IN' => Condition\In::class,
        'NOT IN' => Condition\NotIn::class,
        'LIKE' => Condition\Like::class,
        'NOT LIKE' => Condition\NotLike::class,
        'EXISTS' => Condition\Exists::class,
        'NOT EXISTS' => Condition\NotExists::class,
        'ARRAY OVERLAPS' => Condition\ArrayOverlaps::class,
        'JSON OVERLAPS' => Condition\JsonOverlaps::class,
    ];
}

            
defaultExpressionBuilders() protected method

Has an array of default expression builders.

Extend this method and override it if you want to change default expression builders for this query builder.

See $expressionBuilders docs for details.

protected defaultExpressionBuilders( ): array

                protected function defaultExpressionBuilders(): array
{
    return [
        Query::class => QueryExpressionBuilder::class,
        Param::class => ParamBuilder::class,
        Expression::class => ExpressionBuilder::class,
        CompositeExpression::class => CompositeExpressionBuilder::class,
        Condition\Not::class => Condition\Builder\NotBuilder::class,
        Condition\AndX::class => Condition\Builder\LogicalBuilder::class,
        Condition\OrX::class => Condition\Builder\LogicalBuilder::class,
        Condition\Between::class => Condition\Builder\BetweenBuilder::class,
        Condition\NotBetween::class => Condition\Builder\BetweenBuilder::class,
        Condition\In::class => Condition\Builder\InBuilder::class,
        Condition\NotIn::class => Condition\Builder\InBuilder::class,
        Condition\Like::class => Condition\Builder\LikeBuilder::class,
        Condition\NotLike::class => Condition\Builder\LikeBuilder::class,
        Condition\Equals::class => Condition\Builder\CompareBuilder::class,
        Condition\NotEquals::class => Condition\Builder\CompareBuilder::class,
        Condition\GreaterThan::class => Condition\Builder\CompareBuilder::class,
        Condition\GreaterThanOrEqual::class => Condition\Builder\CompareBuilder::class,
        Condition\LessThan::class => Condition\Builder\CompareBuilder::class,
        Condition\LessThanOrEqual::class => Condition\Builder\CompareBuilder::class,
        Condition\Exists::class => Condition\Builder\ExistsBuilder::class,
        Condition\NotExists::class => Condition\Builder\ExistsBuilder::class,
        Condition\All::class => Condition\Builder\AllBuilder::class,
        Condition\None::class => Condition\Builder\NoneBuilder::class,
        Simple::class => Condition\Builder\SimpleBuilder::class,
        JsonValue::class => JsonValueBuilder::class,
        ArrayValue::class => ArrayValueBuilder::class,
        StructuredValue::class => StructuredValueBuilder::class,
        CaseX::class => CaseXBuilder::class,
        ColumnName::class => ColumnNameBuilder::class,
        Value::class => ValueBuilder::class,
        DateTimeValue::class => DateTimeValueBuilder::class,
        Length::class => LengthBuilder::class,
        Greatest::class => GreatestBuilder::class,
        Least::class => LeastBuilder::class,
        Longest::class => LongestBuilder::class,
        Shortest::class => ShortestBuilder::class,
    ];
}

            
extractAlias() protected method

Extracts table alias if there is one or returns false.

protected extractAlias( string $table ): array|boolean
$table string

                protected function extractAlias(string $table): array|bool
{
    if (preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/', $table, $matches)) {
        return $matches;
    }
    return false;
}

            
getExpressionBuilder() public method

public getExpressionBuilder( Yiisoft\Db\Expression\ExpressionInterface $expression ): Yiisoft\Db\Expression\ExpressionBuilderInterface
$expression Yiisoft\Db\Expression\ExpressionInterface

                public function getExpressionBuilder(ExpressionInterface $expression): ExpressionBuilderInterface
{
    $className = $expression::class;
    if (!isset($this->expressionBuilders[$className])) {
        throw new NotSupportedException(
            'Expression of class ' . $className . ' can not be built in ' . static::class,
        );
    }
    return new $this->expressionBuilders[$className]($this->queryBuilder);
}

            
selectExists() public method

public selectExists( string $rawSql ): string
$rawSql string

                public function selectExists(string $rawSql): string
{
    return 'SELECT EXISTS(' . $rawSql . ') AS ' . $this->quoter->quoteSimpleColumnName('0');
}

            
setConditionClasses() public method

public setConditionClasses( array $classes ): void
$classes array

                public function setConditionClasses(array $classes): void
{
    $this->conditionClasses = array_merge($this->conditionClasses, $classes);
}

            
setExpressionBuilders() public method

public setExpressionBuilders( array $builders ): void
$builders array

                public function setExpressionBuilders(array $builders): void
{
    $this->expressionBuilders = array_merge($this->expressionBuilders, $builders);
}

            
setSeparator() public method

public setSeparator( string $separator ): void
$separator string

The separator between different fragments of an SQL statement.

Defaults to an empty space. This is mainly used by build() when generating a SQL statement.

                public function setSeparator(string $separator): void
{
    $this->separator = $separator;
}