Completed
Pull Request — master (#437)
by Anton
04:37
created

AbstractBuilder::getParameter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Bluz Framework Component
4
 *
5
 * @copyright Bluz PHP Team
6
 * @link      https://github.com/bluzphp/framework
7
 */
8
9
declare(strict_types=1);
10
11
namespace Bluz\Db\Query;
12
13
use Bluz\Proxy\Db;
14
15
/**
16
 * Query Builders classes is responsible to dynamically create SQL queries
17
 * Based on Doctrine QueryBuilder code
18
 *
19
 * @package Bluz\Db\Query
20
 * @link    https://github.com/bluzphp/framework/wiki/Db-Query
21
 * @link    https://github.com/doctrine/dbal/blob/master/lib/Doctrine/DBAL/Query/QueryBuilder.php
22
 */
23
abstract class AbstractBuilder
24
{
25
    /**
26
     * @var array list of table aliases
27
     */
28
    protected $aliases = [];
29
30
    /**
31
     * @var string the complete SQL string for this query
32
     */
33
    protected $sql;
34
35
    /**
36
     * @var array the array of SQL parts collected
37
     */
38
    protected $sqlParts = [
39
        'select' => [],
40
        'from' => [],
41
        'join' => [],
42
        'set' => [],
43
        'where' => null,
44
        'groupBy' => [],
45
        'having' => null,
46
        'orderBy' => []
47
    ];
48
49
    /**
50
     * @var array the query parameters
51
     */
52
    protected $params = [];
53
54
    /**
55
     * @var array the parameter type map of this query
56
     */
57
    protected $types = [];
58
59
    /**
60
     * Execute this query using the bound parameters and their types
61
     *
62
     * @return integer|string|array
63
     */
64 8
    public function execute()
65
    {
66 8
        return Db::query($this->getSql(), $this->params, $this->types);
67
    }
68
69
    /**
70
     * Return the complete SQL string formed by the current specifications
71
     *
72
     * Example
73
     * <code>
74
     *     $sb = new SelectBuilder();
75
     *     $sb
76
     *         ->select('u')
77
     *         ->from('User', 'u');
78
     *     echo $qb->getSql(); // SELECT u FROM User u
79
     * </code>
80
     *
81
     * @return string The SQL query string
82
     */
83
    abstract public function getSql() : string;
84
85
    /**
86
     * Return the complete SQL string formed for use
87
     *
88
     * Example
89
     * <code>
90
     *     $sb = new SelectBuilder();
91
     *     $sb
92
     *         ->select('u')
93
     *         ->from('User', 'u')
94
     *         ->where('id = ?', 42);
95
     *     echo $qb->getQuery(); // SELECT u FROM User u WHERE id = "42"
96
     * </code>
97
     *
98
     * @return string
99
     */
100 7
    public function getQuery() : string
101
    {
102 7
        $sql = $this->getSql();
103
104 7
        $sql = str_replace(['%', '?'], ['%%', '"%s"'], $sql);
105
106
        // replace mask by data
107 7
        return vsprintf($sql, $this->getParameters());
108
    }
109
110
    /**
111
     * Sets a query parameter for the query being constructed
112
     *
113
     * Example
114
     * <code>
115
     *     $sb = new SelectBuilder();
116
     *     $sb
117
     *         ->select('u')
118
     *         ->from('users', 'u')
119
     *         ->where('u.id = :user_id')
120
     *         ->setParameter(':user_id', 1);
121
     * </code>
122
     *
123
     * @param  string|int|null $key   The parameter position or name
124
     * @param  mixed      $value The parameter value
125
     * @param  integer    $type  PDO::PARAM_*
126
     *
127
     * @return $this
128
     */
129 9
    public function setParameter($key, $value, $type = \PDO::PARAM_STR)
130
    {
131 9
        if (null === $key) {
132 9
            $key = count($this->params);
133
        }
134
135 9
        $this->params[$key] = $value;
136 9
        $this->types[$key] = $type;
137
138 9
        return $this;
139
    }
140
141
    /**
142
     * Sets a collection of query parameters for the query being constructed
143
     *
144
     * Example
145
     * <code>
146
     *     $sb = new SelectBuilder();
147
     *     $sb
148
     *         ->select('u')
149
     *         ->from('users', 'u')
150
     *         ->where('u.id = :user_id1 OR u.id = :user_id2')
151
     *         ->setParameters([
152
     *             ':user_id1' => 1,
153
     *             ':user_id2' => 2
154
     *         ]);
155
     * </code>
156
     *
157
     * @param  array $params The query parameters to set
158
     * @param  array $types  The query parameters types to set
159
     *
160
     * @return $this
161
     */
162 1
    public function setParameters(array $params, array $types = [])
163
    {
164 1
        $this->types = $types;
165 1
        $this->params = $params;
166
167 1
        return $this;
168
    }
169
170
    /**
171
     * Gets a (previously set) query parameter of the query being constructed
172
     *
173
     * @param  mixed $key The key (index or name) of the bound parameter
174
     *
175
     * @return mixed The value of the bound parameter.
176
     */
177 1
    public function getParameter($key)
178
    {
179 1
        return $this->params[$key] ?? null;
180
    }
181
182
    /**
183
     * Gets all defined query parameters for the query being constructed
184
     *
185
     * @return array The currently defined query parameters
186
     */
187 7
    public function getParameters() : array
188
    {
189 7
        return $this->params;
190
    }
191
192
    /**
193
     * Either appends to or replaces a single, generic query part
194
     *
195
     * The available parts are: 'select', 'from', 'set', 'where',
196
     * 'groupBy', 'having' and 'orderBy'
197
     *
198
     * @param  string       $sqlPartName
199
     * @param  string|array $sqlPart
200
     * @param  bool         $append
201
     *
202
     * @return $this
203
     */
204 15
    protected function addQueryPart($sqlPartName, $sqlPart, $append = false)
205
    {
206 15
        $isArray = is_array($sqlPart);
207 15
        $isMultiple = is_array($this->sqlParts[$sqlPartName]);
208
209 15
        if ($isMultiple && !$isArray) {
210 3
            $sqlPart = [$sqlPart];
211
        }
212
213 15
        if ($append) {
214 10
            if ($sqlPartName === 'orderBy' || $sqlPartName === 'groupBy'
215 10
                || $sqlPartName === 'select' || $sqlPartName === 'set'
216
            ) {
217 4
                foreach ((array)$sqlPart as $part) {
218 4
                    $this->sqlParts[$sqlPartName][] = $part;
219
                }
220 8
            } elseif ($isArray && is_array($sqlPart[key($sqlPart)])) {
221 4
                $key = key($sqlPart);
222 4
                $this->sqlParts[$sqlPartName][$key][] = $sqlPart[$key];
223 8
            } elseif ($isMultiple) {
224 8
                $this->sqlParts[$sqlPartName][] = $sqlPart;
225
            } else {
226 10
                $this->sqlParts[$sqlPartName] = $sqlPart;
227
            }
228
        } else {
229 15
            $this->sqlParts[$sqlPartName] = $sqlPart;
230
        }
231 15
        return $this;
232
    }
233
234
    /**
235
     * Get a query part by its name
236
     *
237
     * @param  string $queryPartName
238
     *
239
     * @return mixed
240
     */
241 5
    public function getQueryPart($queryPartName)
242
    {
243 5
        return $this->sqlParts[$queryPartName];
244
    }
245
246
    /**
247
     * Reset single SQL part
248
     *
249
     * @param  string $queryPartName
250
     *
251
     * @return $this
252
     */
253
    protected function resetQueryPart($queryPartName)
254
    {
255
        $this->sqlParts[$queryPartName] = is_array($this->sqlParts[$queryPartName])
256
            ? [] : null;
257
258
        return $this;
259
    }
260
261
    /**
262
     * setFromQueryPart
263
     *
264
     * @param  string $table
265
     *
266
     * @return $this
267
     */
268 11
    protected function setFromQueryPart($table)
269
    {
270 11
        $table = Db::quoteIdentifier($table);
271 11
        return $this->addQueryPart('from', ['table' => $table], false);
272
    }
273
274
    /**
275
     * Prepare condition
276
     *
277
     * <code>
278
     *     $builder->prepareCondition("WHERE id IN (?)", [..,..]);
279
     * </code>
280
     *
281
     * @param  array $args
282
     *
283
     * @return string
284
     */
285 9
    protected function prepareCondition($args = [])
286
    {
287 9
        $condition = array_shift($args);
288 9
        foreach ($args as &$value) {
289 9
            if (is_array($value)) {
290 1
                $replace = implode(',', array_fill(0, count($value), ':REPLACE:'));
291 1
                $condition = preg_replace('/\?/', $replace, $condition, 1);
292 1
                foreach ($value as $part) {
293 1
                    $this->setParameter(null, $part);
294
                }
295
            } else {
296 9
                $this->setParameter(null, $value);
297
            }
298
        }
299
300 9
        $condition = preg_replace('/(\:REPLACE\:)/', '?', $condition);
301
302 9
        return $condition;
303
    }
304
305
    /**
306
     * Gets a string representation of this QueryBuilder which corresponds to
307
     * the final SQL query being constructed.
308
     *
309
     * @return string The string representation of this QueryBuilder.
310
     */
311 1
    public function __toString()
312
    {
313 1
        return $this->getSql();
314
    }
315
}
316