Completed
Push — master ( 39e8de...2b8686 )
by Rasmus
02:27
created

SelectQuery::setFlag()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 8
ccs 4
cts 5
cp 0.8
rs 9.4285
cc 2
eloc 5
nc 2
nop 2
crap 2.032
1
<?php
2
3
namespace mindplay\sql\model;
4
5
use mindplay\sql\framework\Countable;
6
use mindplay\sql\framework\Driver;
7
use mindplay\sql\framework\MapperProvider;
8
use mindplay\sql\framework\TypeProvider;
9
use mindplay\sql\model\components\Mappers;
10
use mindplay\sql\model\components\ReturnVars;
11
use mindplay\sql\types\IntType;
12
13
/**
14
 * This class represents a SELECT query.
15
 *
16
 * This class implements `__toString()` magic, enabling the use of this query builder
17
 * in the SELECT, WHERE or ORDER BY clause of a parent SELECT (or other type of) query.
18
 *
19
 * Note that, when constructing nested queries, parameters must be bound against the
20
 * parent query - binding parameters or applying Mappers against a nested query has no effect.
21
 */
22
class SelectQuery extends ProjectionQuery implements MapperProvider, Countable
23
{
24
    use Mappers;
25
26
    /**
27
     * @var bool[] map where flag => true
28
     */
29
    private $flags = [];
30
31
    /**
32
     * @var ReturnVars
33
     */
34
    protected $return_vars;
35
36
    /**
37
     * @var string[] list of GROUP BY expressions
38
     */
39
    protected $group_by = [];
40
41
    /**
42
     * @var string[] list of HAVING expressions
43
     */
44
    protected $having = [];
45
46
    /**
47
     * @param Table        $root
48
     * @param Driver       $driver
49
     * @param TypeProvider $types
50
     */
51 1
    public function __construct(Table $root, Driver $driver, TypeProvider $types)
52
    {
53 1
        parent::__construct($root, $driver, $types);
54
        
55 1
        $this->return_vars = new ReturnVars($root, $driver, $types);
56 1
    }
57
58
    /**
59
     * Add all the Columns of a full Table to be selected and returned
60
     *
61
     * @param Table $table Table to select and return
62
     *
63
     * @return $this
64
     */
65 1
    public function table(Table $table)
66
    {
67 1
        $this->return_vars->addTable($table);
68
69 1
        return $this;
70
    }
71
72
    /**
73
     * Add one or more Columns to select and return
74
     *
75
     * @param Column|Column[] one or more Columns to select and return
76
     *
77
     * @return $this
78
     */
79 1
    public function columns($cols)
80
    {
81 1
        $this->return_vars->addColumns($cols);
82
83 1
        return $this;
84
    }
85
86
    /**
87
     * Add an SQL expression to select and return
88
     *
89
     * @param string           $expr return expression
90
     * @param string|null      $name return variable name (optional, but usually required)
91
     * @param Type|string|null $type optional Type (or Type class-name)
92
     *
93
     * @return $this
94
     */
95 1
    public function value($expr, $name = null, $type = null)
96
    {
97 1
        $this->return_vars->addValue($expr, $name, $type);
98
99 1
        return $this;
100
    }
101
102
    /**
103
     * Add an expression to apply to a GROUP BY clause
104
     *
105
     * @param Column|string $expr SQL expression (or Column object) to apply to the GROUP BY clause
106
     *
107
     * @return $this
108
     */
109 1
    public function groupBy($expr)
110
    {
111 1
        $this->group_by[] = (string) $expr;
112
113 1
        return $this;
114
    }
115
116
    /**
117
     * @param string|string[] $exprs one or more condition expressions to apply to the HAVING clause
118
     *
119
     * @return $this
120
     */
121 1
    public function having($exprs)
122
    {
123 1
        foreach ((array) $exprs as $expr) {
124 1
            $this->having[] = $expr;
125
        }
126
127 1
        return $this;
128
    }
129
130
    /**
131
     * @inheritdoc
132
     */
133 1
    public function getMappers()
134
    {
135 1
        return array_merge([$this->return_vars->createTypeMapper()], $this->mappers);
136
    }
137
138
    /**
139
     * @inheritdoc
140
     */
141 1
    public function getSQL()
142
    {
143 1
        $flags = $this->buildFlags();
144
145 1
        $select = "SELECT " . ($flags ? "{$flags} " : "")
146 1
            . $this->return_vars->buildReturnVars();
147
148 1
        $from = "\nFROM " . $this->buildNodes();
149
150 1
        $where = count($this->conditions)
151 1
            ? "\nWHERE " . $this->buildConditions()
152 1
            : ''; // no conditions present
153
        
154 1
        $group_by = count($this->group_by)
155 1
            ? "\nGROUP BY " . implode(", ", $this->group_by)
156 1
            : ""; // no group-by expressions
157
158 1
        $having = count($this->having)
159 1
            ? "\nHAVING " . $this->buildHaving()
160 1
            : ''; // no having clause present
161
        
162 1
        $order = count($this->order)
163 1
            ? "\nORDER BY " . $this->buildOrderTerms()
164 1
            : ''; // no order terms
165
166 1
        $limit = $this->limit !== null
167 1
            ? "\nLIMIT {$this->limit}"
168 1
            . ($this->offset !== null ? " OFFSET {$this->offset}" : '')
169 1
            : ''; // no limit or offset
170
171 1
        return "{$select}{$from}{$where}{$group_by}{$having}{$order}{$limit}";
172
    }
173
174
    /**
175
     * @inheritdoc
176
     */
177 1
    public function createCountStatement()
178
    {
179 1
        $query = clone $this;
180
181 1
        $query->return_vars = new ReturnVars($this->root, $this->driver, $this->types);
182
183 1
        $query->return_vars->addValue("COUNT(*)", "count", IntType::class);
184
        
185 1
        $query->limit = null;
186 1
        $query->offset = null;
187
        
188 1
        $query->order = [];
189
        
190 1
        return $query;
191
    }
192
193
    /**
194
     * @ignore string magic (enables creation of nested SELECT queries)
195
     */
196 1
    public function __toString()
197
    {
198 1
        return "(" . $this->getSQL() . ")";
199
    }
200
201
    /**
202
     * @return string combined condition expression (for use in the WHERE clause of an SQL statement)
203
     */
204 1
    protected function buildHaving()
205
    {
206 1
        return implode(" AND ", $this->having);
207
    }
208
209
    /**
210
     * @param string $flag
211
     * @param bool   $state
212
     */
213 1
    protected function setFlag($flag, $state = true)
214
    {
215 1
        if ($state) {
216 1
            $this->flags[$flag] = true;
217
        } else {
218
            unset($this->flags[$flag]);
219
        }
220 1
    }
221
    
222
    /**
223
     * @return string query flags (such as "SQL_CALC_FOUND_ROWS" in a MySQL SELECT query)
224
     */
225 1
    protected function buildFlags()
226
    {
227 1
        return implode(" ", array_keys($this->flags));
228
    }
229
}
230