Select   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 181
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 77
dl 0
loc 181
rs 9.76
c 1
b 0
f 0
wmc 33

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getColumn() 0 4 2
A getAll() 0 10 2
A getArgumentName() 0 5 3
A getOne() 0 4 1
C sqlColumns() 0 55 14
B sql() 0 46 11
1
<?php declare(strict_types=1);
2
3
/** 
4
 *  ___      _        _
5
 * | _ \__ _| |_ __ _| |__  __ _ ___ ___
6
 * |  _/ _` |  _/ _` | '_ \/ _` (_-</ -_)
7
 * |_| \__,_|\__\__,_|_.__/\__,_/__/\___|
8
 * 
9
 * This file is part of Kristuff\Patabase.
10
 * (c) Kristuff <[email protected]>
11
 *
12
 * For the full copyright and license information, please view the LICENSE
13
 * file that was distributed with this source code.
14
 *
15
 * @version    1.0.1
16
 * @copyright  2017-2022 Christophe Buliard
17
 */
18
19
namespace Kristuff\Patabase\Query;
20
21
use Kristuff\Patabase\Query\SelectBase;
22
23
/**
24
 * Class Select
25
 * 
26
 * Represents a [SELECT] SQL query
27
 *
28
 *      SELECT  [distinct?] [columnsdefintions]
29
 *        FROM  [tablename] 
30
 *        JOIN  [externaltables]
31
 *       WHERE  [conditions]
32
 *    GROUP BY  [expressions]
33
 *    ORDER BY  [expressions]
34
 *       LIMIT  [limit]
35
 *      OFFSET  [offset]
36
 */
37
class Select extends SelectBase
38
{
39
    /**
40
     * Get an argument name based on column name
41
     * Make sure the argument name is unique to Avoid collision in query parameters.
42
     *
43
     * @access protected
44
     * @param string   $column     The column name or base name
45
     *
46
     * @return string
47
     */
48
    protected function getArgumentName(string $column): string
49
    {
50
        $topQuery = $this->topQuery ?: $this;  
51
        $arg = ':_' . str_replace('.', '_', $column); 
52
        return $topQuery->sqlParameterExists($arg) ? $arg . uniqid() : $arg;
53
    }
54
    
55
    /**
56
     * Get the SQL SELECT [COLUMNS] statement 
57
     *
58
     * @access private
59
     * @return string
60
     */
61
    private function sqlColumns(): string
62
    {
63
        // no columns givens select all (SELECT *)
64
        if (!count($this->columns) > 0 ) {
65
            return '*';   
66
        }
67
68
        // use DISTINCT ?
69
        $sqlDistinct    = $this->distinct ? 'DISTINCT ': '';
70
71
        // parse columns
72
        $colsList = array();
73
        foreach ($this->columns as $val){
74
            switch ($val['type']){
75
                   
76
                // 'classic' column
77
                case 'column':
78
                    $name       = $this->escape($val['name']);
79
                    $alias      = isset($val['alias']) ? 'AS '. $this->escape($val['alias']) : '';
80
                    $colsList[] = trim(sprintf('%s %s', $name, $alias));
81
                    break;  
82
                   
83
                // COUNT() column
84
                case 'count':
85
                    $colsList[] = trim(sprintf('COUNT(*) AS %s', $this->escape($val['alias'])));
86
                    break;  
87
88
                // SUM() column
89
                case 'sum':
90
                    $name       = $this->escape($val['name']);
91
                    $alias      = isset($val['alias']) ? ' AS '. $this->escape($val['alias']) : '';
92
                    $colsList[] = sprintf('SUM(%s)', $name) . $alias;
93
                    break;  
94
95
                // MIN() column
96
                case 'min':
97
                    $name       = $this->escape($val['name']);
98
                    $alias      = isset($val['alias']) ? ' AS '. $this->escape($val['alias']) : '';
99
                    $colsList[] = sprintf('MIN(%s)', $name) . $alias;
100
                    break;   
101
                    
102
                // max() column
103
                case 'max':
104
                    $name       = $this->escape($val['name']);
105
                    $alias      = isset($val['alias']) ? ' AS '. $this->escape($val['alias']) : '';
106
                    $colsList[] = sprintf('MAX(%s)', $name) . $alias;
107
                    break;        
108
109
                // sub query
110
                case 'sub_query':
111
                    $colsList[] = '('. $val['query']->sql() .') AS '. $this->escape($val['alias']);
112
                    break;
113
           }
114
        }
115
        return $sqlDistinct . implode(', ', $colsList);
116
    }
117
    
118
    /**
119
     * Build the SQL [SELECT] query
120
     *
121
     * @access public
122
     * @return string
123
     */
124
    public function sql(): string
125
    {
126
        $topQuery = $this->topQuery ?: $this;  
127
        $sqlJoins = empty($this->joins) ? '' : implode(' ', $this->joins) ; 
128
        $sqlFromTable =  'FROM '. $this->escape($this->fromTable);
129
        $sqlWhere = isset($this->where) ? $this->where->sql() : '';
130
        $sqlGroupBy = empty($this->groupBy) ? '' : 'GROUP BY '.implode(', ', $this->escapeList($this->groupBy));
131
        $sqlHaving = isset($this->having) ? $this->having->sql() : '';
132
133
        // order by
134
        $sqlOrderBy = '';
135
        if (! empty($this->orderBy)){
136
            $sortArgs = [];
137
            foreach ($this->orderBy as $item){
138
                $sql = $item['column'] ? $this->escape($item['column']) . ' ' : '';
139
                $sortArgs[] = $sql . $item['order'];
140
            }
141
            $sqlOrderBy = 'ORDER BY ' . implode(', ', $sortArgs);
142
        }
143
144
        // limit
145
        $sqlLimit = '';
146
        if ($this->limit > 0){
147
            $argName = $this->getArgumentName('LIMIT');   
148
            $topQuery->setSqlParameter($argName, $this->limit); 
149
            $sqlLimit = 'LIMIT '.$argName;
150
        }
151
152
        // offset
153
        $sqlOffset = '';
154
        if ($this->offset > 0){
155
            $argName = $this->getArgumentName('OFFSET');   
156
            $topQuery->setSqlParameter($argName, $this->offset); 
157
            $sqlOffset = 'OFFSET ' . $argName;
158
        }
159
160
        return trim(implode(' ', ['SELECT', 
161
           $this->sqlColumns(), 
162
           $sqlFromTable,
163
           $sqlJoins,
164
           $sqlWhere,
165
           $sqlGroupBy,
166
           $sqlHaving,
167
           $sqlOrderBy,
168
           $sqlLimit,
169
           $sqlOffset]));
170
    }
171
     
172
    /**
173
     * Execute the select query and returns result in given format
174
     *
175
     * @access  public
176
     * @param   string      $outputFormat       The output format
177
     *
178
     * @return  mixed
179
     */
180
    public function getAll(string $outputFormat = 'default')
181
    {
182
        // execute query
183
       $exec = $this->execute();
184
185
       // format
186
       $format = ($outputFormat === 'default') ? $this->driver->defaultOutputFormat() : $outputFormat; 
187
188
        // return output
189
        return $this->fetchOutput($exec, $format);
190
    }
191
192
    /**
193
     * Execute the select query and returns the result limited to one row.
194
     *
195
     * @access  public
196
     * @param   string      $outputFormat       The output format
197
     * 
198
     * @return  mixed
199
     */
200
    public function getOne(string $outputFormat = 'default')
201
    {
202
        $this->limit(1);
203
        return $this->getAll($outputFormat);
204
    }
205
206
    /**
207
     * Execute the select query and returns the result of the first column in first row.
208
     *
209
     * @access  public
210
     * @param   string      $outputFormat       The output format
211
     *
212
     * @return  mixed|null
213
     */
214
    public function getColumn()
215
    {
216
        $this->limit(1);
217
        return $this->execute() ? $this->pdoStatement->fetchColumn() : null;
218
    }
219
}