• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

brick / orm / 23255296146

18 Mar 2026 04:24PM UTC coverage: 47.104%. Remained the same
23255296146

push

github

BenMorel
Avoid \Exception that somehow confuses ECS

1 of 5 new or added lines in 1 file covered. (20.0%)

402 existing lines in 24 files now uncovered.

553 of 1174 relevant lines covered (47.1%)

10.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.86
/src/SelectQueryBuilder.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Brick\ORM;
6

7
use function count;
8
use function implode;
9

10
/**
11
 * Low-level class to build SELECT queries.
12
 *
13
 * @internal
14
 */
15
class SelectQueryBuilder
16
{
17
    /**
18
     * The fields to SELECT.
19
     *
20
     * @var list<string>
21
     */
22
    private array $selectFields;
23

24
    /**
25
     * The table name.
26
     */
27
    private string $tableName;
28

29
    /**
30
     * An optional table alias.
31
     */
32
    private ?string $tableAlias;
33

34
    /**
35
     * @var list<string>
36
     */
37
    private array $joins = [];
38

39
    /**
40
     * @var list<string>
41
     */
42
    private array $whereConditions = [];
43

44
    /**
45
     * @var list<string>
46
     */
47
    private array $orderBy = [];
48

49
    private string $limit = '';
50

51
    private int $options = 0;
52

53
    /**
54
     * @param list<string> $selectFields The fields or expressions to SELECT.
55
     * @param string       $tableName    The table name.
56
     * @param string|null  $tableAlias   An optional table alias.
57
     */
58
    public function __construct(array $selectFields, string $tableName, ?string $tableAlias = null)
59
    {
60
        $this->selectFields = $selectFields;
63✔
61
        $this->tableName = $tableName;
63✔
62
        $this->tableAlias = $tableAlias;
63✔
63
    }
64

65
    /**
66
     * @param string       $joinType       The JOIN type, such as INNER or LEFT.
67
     * @param string       $tableName      The table name.
68
     * @param string       $tableAlias     The table alias.
69
     * @param list<string> $joinConditions The list of A=B join conditions.
70
     */
71
    public function addJoin(string $joinType, string $tableName, string $tableAlias, array $joinConditions): void
72
    {
73
        $this->joins[] = ' ' . $joinType . ' JOIN ' . $tableName .
1✔
74
            ' AS ' . $tableAlias .
1✔
75
            ' ON ' . implode(' AND ', $joinConditions);
1✔
76
    }
77

78
    /**
79
     * Adds WHERE conditions to be AND'ed to the current conditions.
80
     *
81
     * The conditions will be AND'ed or OR'ed together, according to the given operator, and AND'ed as a whole to the
82
     * existing conditions.
83
     *
84
     * @param list<string> $whereConditions The WHERE conditions.
85
     * @param 'AND'|'OR'   $operator        The operator.
86
     */
87
    public function addWhereConditions(array $whereConditions, string $operator = 'AND'): void
88
    {
89
        $parentheses = ($operator === 'OR' && count($whereConditions) > 1);
63✔
90

91
        $whereConditions = implode(' ' . $operator . ' ', $whereConditions);
63✔
92

93
        if ($parentheses) {
63✔
UNCOV
94
            $whereConditions = '(' . $whereConditions . ')';
×
95
        }
96

97
        $this->whereConditions[] = $whereConditions;
63✔
98
    }
99

100
    /**
101
     * @param string       $expression The expression to order by.
102
     * @param 'ASC'|'DESC' $direction  The order direction.
103
     */
104
    public function addOrderBy(string $expression, string $direction = 'ASC'): void
105
    {
106
        $this->orderBy[] = $expression . ' ' . $direction;
×
107
    }
108

109
    public function setLimit(int $limit, int $offset = 0): void
110
    {
UNCOV
111
        $this->limit = ' LIMIT ' . $limit;
×
112

UNCOV
113
        if ($offset !== 0) {
×
UNCOV
114
            $this->limit .= ' OFFSET ' . $offset;
×
115
        }
116
    }
117

118
    /**
119
     * @param int $options A bitmask of options.
120
     */
121
    public function setOptions(int $options): void
122
    {
123
        $this->options = $options;
63✔
124
    }
125

126
    public function build(): string
127
    {
128
        $query = 'SELECT ' . implode(', ', $this->selectFields) . ' FROM ' . $this->tableName;
63✔
129

130
        if ($this->tableAlias !== null) {
63✔
131
            $query .= ' AS ' . $this->tableAlias;
63✔
132
        }
133

134
        foreach ($this->joins as $join) {
63✔
135
            $query .= $join;
1✔
136
        }
137

138
        if ($this->whereConditions) {
63✔
139
            $query .= ' WHERE ' . implode(' AND ', $this->whereConditions);
63✔
140
        }
141

142
        if ($this->orderBy) {
63✔
UNCOV
143
            $query .= ' ORDER BY ' . implode(', ', $this->orderBy);
×
144
        }
145

146
        $query .= $this->limit;
63✔
147

148
        // @todo lock mode syntax is MySQL / PostgreSQL only
149

150
        if ($this->options & Options::LOCK_READ) {
63✔
151
            $query .= ' FOR SHARE';
3✔
152
        } elseif ($this->options & Options::LOCK_WRITE) {
60✔
153
            $query .= ' FOR UPDATE';
3✔
154
        }
155

156
        if ($this->options & Options::SKIP_LOCKED) {
63✔
157
            $query .= ' SKIP LOCKED';
2✔
158
        }
159

160
        if ($this->options & Options::NOWAIT) {
63✔
161
            $query .= ' NOWAIT';
2✔
162
        }
163

164
        return $query;
63✔
165
    }
166
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc