Completed
Push — master ( b2a814...5e7b57 )
by Rasmus
02:54
created

SelectQuery::createCountStatement()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

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