Completed
Push — master ( ca5c4a...e71512 )
by Dmytro
03:37
created

DBPreparedQuery::sqlPushValues()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 24
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 5
eloc 18
c 2
b 1
f 0
nc 4
nop 2
dl 0
loc 24
rs 8.5125
1
<?php
2
3
namespace Asymptix\db;
4
5
use Asymptix\core\Tools;
6
7
/**
8
 * Complex DB query object for Prepared Statement.
9
 *
10
 * @category Asymptix PHP Framework
11
 * @author Dmytro Zarezenko <[email protected]>
12
 * @copyright (c) 2015 - 2016, Dmytro Zarezenko
13
 *
14
 * @git https://github.com/Asymptix/Framework
15
 * @license http://opensource.org/licenses/MIT
16
 */
17
class DBPreparedQuery extends DBQuery {
18
19
    /**
20
     * DB query template.
21
     *
22
     * @var string
23
     */
24
    public $query = "";
25
26
    /**
27
     * Parameters SQL types string ("idsb").
28
     *
29
     * @var string
30
     */
31
    public $types = "";
32
33
    /**
34
     * List of the DB SQL query parameters.
35
     *
36
     * @var array
37
     */
38
    public $params = [];
39
40
41
    /* Service variables */
42
43
    /**
44
     * Creates and initialize DBPreparedQuery object.
45
     *
46
     * @param string $query DB SQL query template.
47
     * @param string $types Parameters SQL types string ("idsb").
48
     * @param array $params List of the DB SQL query parameters.
49
     */
50
    public function __construct($query = "", $types = "", $params = []) {
51
        $this->query = $query;
52
        $this->types = $types;
53
        $this->params = $params;
54
55
        if (!empty($this->query)) {
56
            $this->type = $this->detectType();
57
        }
58
        parent::__construct($this->type);
59
    }
60
61
    /**
62
     * Verify if current DBPreparedQuery is have parameters for binding.
63
     *
64
     * @return bool
65
     */
66
    public function isBindable() {
67
        return ($this->params != null && count($this->params) > 0);
68
    }
69
70
    /**
71
     * Verify if current DBPreparedQuery is valid for the execution.
72
     *
73
     * @return bool
74
     */
75
    public function isValid() {
76
        self::checkParameterTypes($this->params, $this->types);
77
78
        return true;
79
    }
80
81
    /**
82
     * Executes SQL query.
83
     *
84
     * @param bool $debug Debug mode flag.
85
     *
86
     * @return mixed Statement object or FALSE if an error occurred if SELECT
87
     *           query executed or number of affected rows on success if other
88
     *           type of query executed.
89
     */
90
    public function go($debug = false) {
91
        if ($debug) {
92
            DBQuery::showQueryDebugInfo($this->query, $this->types, $this->params);
93
        } else {
94
            if ($this->isSelector()) {
95
                return DBCore::doSelectQuery($this);
96
            }
97
98
            return DBCore::doUpdateQuery($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Asymptix\db\DBPreparedQuery>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
99
        }
100
    }
101
102
    /**
103
     * Checks query parameters types correspondence.
104
     *
105
     * @param array $params Parameters of the query.
106
     * @param string $types Types of the parameters ("idsb").
107
     *
108
     * @throws DBCoreException
109
     */
110
    private static function checkParameterTypes($params, $types) {
111
        if (count($params) != strlen($types)) {
112
            throw new DBCoreException(
113
                "Number of types is not equal parameters number"
114
            );
115
        }
116
117
        foreach ($params as $key => $value) {
118
            $type = $types[$key];
119
120
            if (!in_array($type, ['i', 'd', 's', 'b'])) {
121
                throw new DBCoreException(
122
                    "Invalid query parameters types string (type '" . $type .
123
                    "' is undefined, only 'i', 'd', 's' and 'b' types are acceptable)"
124
                );
125
            }
126
127
            $typeByValue = DBField::getType($value);
128
            if ($typeByValue != 's') {
129
                if ($type != $typeByValue && !(
130
                       ($type == 'd' && $typeByValue == 'i') || // We can put integer as double
131
                       ($type == 's' && $typeByValue == 'i') // We can put integer as string
132
                   )
133
                ) {
134
                    throw new DBCoreException(
135
                        "Invalid query parameters types string ('" . $value .
136
                        "' is not '" . $type . "' type but '" . $typeByValue . "' detected)"
137
                    );
138
                }
139
            } else { // in case if we try send non-string parameters as a string value
140
                switch ($type) {
141
                    case 'i':
142
                        if (!(Tools::isNumeric($value) && ((string)(int)$value === $value))) {
143
                            throw new DBCoreException(
144
                                "Invalid query parameters types string ('" . $value . "' is not '" . $type . ")"
145
                            );
146
                        }
147
                        break;
148
                    case 'd':
149
                        if (!Tools::isDoubleString($value)) {
150
                            throw new DBCoreException(
151
                                "Invalid query parameters types string ('" . $value . "' is not '" . $type . ")"
152
                            );
153
                        }
154
                        break;
155
                    case 'b':
156
                        if (!in_array(strtolower($value), ['true', 'false'])) {
157
                            throw new DBCoreException(
158
                                "Invalid query parameters types string ('" . $value . "' is not '" . $type . ")"
159
                            );
160
                        }
161
                        break;
162
                }
163
            }
164
        }
165
    }
166
167
    /**
168
     * Return qwestion marks string for IN(...) SQL construction.
169
     *
170
     * @param int $length Length of the result string.
171
     *
172
     * @return string
173
     */
174
    public static function sqlQMString($length) {
175
        return implode(",", array_fill(0, $length, "?"));
176
    }
177
178
    /**
179
     * Return fields and qwestion marks string for SET field1=?, ... SQL construction.
180
     *
181
     * @param array<mixed> $fieldsList List of the table fields (syntax: array[fieldName] = fieldValue)
182
     * @param string $idFieldName Name of the primary key field.
183
     *
184
     * @return string
185
     */
186
    public static function sqlQMValuesString($fieldsList, $idFieldName = "") {
187
        $chunks = [];
188
        foreach (array_keys($fieldsList) as $fieldName) {
189
            if ($fieldName != $idFieldName) {
190
                $chunks[] = "`" . $fieldName . "` = ?";
191
            }
192
        }
193
194
        return implode(", ", $chunks);
195
    }
196
197
    /**
198
     * Return fields and values string for SET field1=value1, ... SQL construction.
199
     *
200
     * @param array<mixed> $fieldsList List of the table fields (syntax: array[fieldName] = fieldValue)
201
     * @param string $idFieldName Name of the primary key field.
202
     *
203
     * @return string
204
     */
205
    public static function sqlValuesString($fieldsList, $idFieldName) {
206
        $chunks = [];
207
        foreach ($fieldsList as $fieldName => $fieldValue) {
208
            if ($fieldName != $idFieldName) {
209
                $chunks[]= "`" . $fieldName . "` = '" . $fieldValue . "'";
210
            }
211
        }
212
213
        return implode(", ", $chunks);
214
    }
215
216
    /**
217
     * Returns SQL types string.
218
     * Type specification chars:
219
     *    i - corresponding variable has type integer
220
     *    d - corresponding variable has type double
221
     *    s - corresponding variable has type string
222
     *    b - corresponding variable is a blob and will be sent in packets.
223
     *
224
     * @param array<mixed> $fieldsList List of the table fields (syntax: array[fieldName] = fieldValue)
225
     * @param string $idFieldName Name of the primary key field.
226
     * @return string
227
     */
228
    public static function sqlTypesString($fieldsList, $idFieldName = "") {
229
        $typesString = "";
230
        foreach ($fieldsList as $fieldName => $fieldValue) {
231
            if ($fieldName != $idFieldName) {
232
                if (Tools::isDouble($fieldValue)) {
233
                    $typesString.= "d";
234
                } elseif (Tools::isInteger($fieldValue)) {
235
                    $typesString.= "i";
236
                } else {
237
                    $typesString.= "s";
238
                }
239
            }
240
        }
241
242
        return $typesString;
243
    }
244
245
    /**
246
     * Returns SQL types string of single type.
247
     *
248
     * @param string $type SQL type.
249
     * @param int $length Length of the SQL types string.
250
     *
251
     * @return string
252
     * @throws DBFieldTypeException If invalid type passed.
253
     */
254
    public static function sqlSingleTypeString($type, $length) {
255
        $type = DBField::castType($type);
256
        $typesString = "";
257
        while ($length > 0) {
258
            $typesString.= $type;
259
            $length--;
260
        }
261
262
        return $typesString;
263
    }
264
265
    /**
266
     * Push values to the DBPreparedQuery SQL query field end.
267
     *
268
     * @param array $values List of pairs key => value or SQL query parts with
269
     *           parameters.
270
     * @param string $separator Join separator.
271
     */
272
    public function sqlPushValues($values, $separator = ", ") {
273
        $chunks = [];
274
        foreach ($values as $fieldName => $fieldValue) {
275
            if (!is_array($fieldValue)) {
276
                if (!is_null($fieldValue)) {
277
                    $chunks[] = $fieldName . " = ?";
278
                    $this->types.= DBField::getType($fieldValue);
279
                    $this->params[] = $fieldValue;
280
                } else {
281
                    $chunks[] = $fieldName;
282
                }
283
            } else {
284
                $condition = $fieldName;
285
                $localParams = $fieldValue;
286
287
                $chunks[] = $condition;
288
                foreach ($localParams as $param) {
289
                    $this->types.= DBField::getType($param);
290
                    $this->params[] = $param;
291
                }
292
            }
293
        }
294
        $this->query.= implode($separator, $chunks);
295
    }
296
297
}
298