Completed
Push — master ( e7358a...a8d41d )
by Alex
03:58 queued 01:47
created

PdoCrud::bindParameter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 3
1
<?php
2
namespace Mezon\PdoCrud;
3
4
/**
5
 * Class PdoCrud
6
 *
7
 * @package Mezon
8
 * @subpackage PdoCrud
9
 * @author Dodonov A.A.
10
 * @version v.1.0 (2019/08/16)
11
 * @copyright Copyright (c) 2019, aeon.org
12
 */
13
14
// TODO mark all old methods as deprecated
15
// TODO create method for simple getting records count
16
17
/**
18
 * Class provides simple CRUD operations
19
 */
20
class PdoCrud
21
{
22
23
    /**
24
     * PDO object
25
     *
26
     * @var \PDO
27
     */
28
    private $pdo = null;
29
30
    use PdoCrudStatement;
31
32
    /**
33
     * Method connects to the database
34
     *
35
     * @param array $connnectionData
36
     *            Connection settings
37
     * @codeCoverageIgnore
38
     */
39
    public function connect(array $connnectionData): void
40
    {
41
        // no need to test this single string. assume that PDO developers did it
42
        $this->pdo = new \PDO($connnectionData['dsn'], $connnectionData['user'], $connnectionData['password']);
43
44
        $this->query('SET NAMES utf8');
45
    }
46
47
    /**
48
     * Method handles request errors
49
     *
50
     * @param mixed $result
51
     *            Query result
52
     * @param string $query
53
     *            SQL Query
54
     * @codeCoverageIgnore
55
     */
56
    protected function processQueryError($result, string $query): void
57
    {
58
        if ($result === false) {
59
            $errorInfo = $this->pdo->errorInfo();
60
61
            throw (new \Exception($errorInfo[2] . ' in statement ' . $query));
62
        }
63
    }
64
65
    /**
66
     * Method executes select query and fetches results
67
     *
68
     * @param ?array $data
69
     *            query data
70
     * @return array query result as an array of objects
71
     * @codeCoverageIgnore
72
     */
73
    public function execSelect(?array $data = null): array
74
    {
75
        if ($this->pdoStatement->execute($data) === false) {
76
            $info = $this->pdoStatement->errorInfo();
77
78
            throw (new \Exception($info[2], - 1));
79
        }
80
81
        return $this->pdoStatement->fetchAll(\PDO::FETCH_OBJ);
82
    }
83
84
    /**
85
     * Getting records
86
     *
87
     * @param string $fields
88
     *            List of fields
89
     * @param string $tableNames
90
     *            List of tables
91
     * @param string $where
92
     *            Condition
93
     * @param int $from
94
     *            First record in query
95
     * @param int $limit
96
     *            Count of records
97
     * @return array List of records
98
     * @deprecated since 2020-06-16
99
     */
100
    public function select(
101
        string $fields,
102
        string $tableNames,
103
        string $where = '1 = 1',
104
        int $from = 0,
105
        int $limit = 1000000): array
106
    {
107
        $query = "SELECT $fields FROM $tableNames WHERE $where LIMIT " . intval($from) . ' , ' . intval($limit);
108
109
        $result = $this->query($query);
110
111
        $this->processQueryError($result, $query);
112
113
        return $result->fetchAll(\PDO::FETCH_ASSOC);
114
    }
115
116
    /**
117
     * Method compiles set-query
118
     *
119
     * @param array $record
120
     *            Inserting record
121
     * @return string Compiled query string
122
     */
123
    protected function compileGetQuery(array $record): string
124
    {
125
        $setFieldsStatement = [];
126
127
        foreach ($record as $field => $value) {
128
            if (is_string($value) && strtoupper($value) === 'INC') {
129
                $setFieldsStatement[] = $field . ' = ' . $field . ' + 1';
130
            } elseif (is_string($value) && strtoupper($value) !== 'NOW()') {
131
                $setFieldsStatement[] = $field . ' = "' . $value . '"';
132
            } elseif ($value === null) {
133
                $setFieldsStatement[] = $field . ' = NULL';
134
            } else {
135
                $setFieldsStatement[] = $field . ' = ' . $value;
136
            }
137
        }
138
139
        return implode(' , ', $setFieldsStatement);
140
    }
141
142
    /**
143
     * Method compiles set-multyple-query
144
     *
145
     * @param array $records
146
     *            Inserting records
147
     * @return string Compiled query string
148
     */
149
    protected function setMultypleQuery(array $records): string
150
    {
151
        $query = '( ' . implode(' , ', array_keys($records[0])) . ' ) VALUES ';
152
153
        $values = [];
154
155
        foreach ($records as $record) {
156
            $values[] = "( '" . implode("' , '", array_values($record)) . "' )";
157
        }
158
159
        return $query . implode(' , ', $values);
160
    }
161
162
    /**
163
     * Updating records
164
     *
165
     * @param string $tableName
166
     *            Table name
167
     * @param array $record
168
     *            Updating records
169
     * @param string $where
170
     *            Condition
171
     * @param int $limit
172
     *            Liti for afffecting records
173
     * @return int Count of updated records
174
     */
175
    public function update(string $tableName, array $record, string $where, int $limit = 10000000): int
176
    {
177
        $query = 'UPDATE ' . $tableName . ' SET ' . $this->compileGetQuery($record) . ' WHERE ' . $where . ' LIMIT ' .
178
            $limit;
179
180
        $result = $this->query($query);
181
182
        $this->processQueryError($result, $query);
183
184
        return $result->rowCount();
185
    }
186
187
    /**
188
     * Deleting records
189
     *
190
     * @param string $tableName
191
     *            Table name
192
     * @param string $where
193
     *            Condition
194
     * @param int $limit
195
     *            Liti for afffecting records
196
     * @return int Count of deleted records
197
     */
198
    public function delete($tableName, $where, $limit = 10000000): int
199
    {
200
        $query = 'DELETE FROM ' . $tableName . ' WHERE ' . $where . ' LIMIT ' . intval($limit);
201
202
        $result = $this->query($query);
203
204
        $this->processQueryError($result, $query);
205
206
        return $result->rowCount();
207
    }
208
209
    /**
210
     * Method compiles lock queries
211
     *
212
     * @param array $tables
213
     *            List of tables
214
     * @param array $modes
215
     *            List of lock modes
216
     * @return string Query
217
     */
218
    protected function lockQuery(array $tables, array $modes): string
219
    {
220
        $query = [];
221
222
        foreach ($tables as $i => $table) {
223
            $query[] = $table . ' ' . $modes[$i];
224
        }
225
226
        return 'LOCK TABLES ' . implode(' , ', $query);
227
    }
228
229
    /**
230
     * Method locks tables
231
     *
232
     * @param array $tables
233
     *            List of tables
234
     * @param array $modes
235
     *            List of lock modes
236
     */
237
    public function lock(array $tables, array $modes): void
238
    {
239
        $query = $this->lockQuery($tables, $modes);
240
241
        $result = $this->query($query);
242
243
        $this->processQueryError($result, $query);
244
    }
245
246
    /**
247
     * Method unlocks locked tables
248
     */
249
    public function unlock(): void
250
    {
251
        $result = $this->query('UNLOCK TABLES');
252
253
        $this->processQueryError($result, 'UNLOCK TABLES');
254
    }
255
256
    /**
257
     * Method starts transaction
258
     */
259
    public function startTransaction(): void
260
    {
261
        // setting autocommit off
262
        $result = $this->query('SET AUTOCOMMIT = 0');
263
264
        $this->processQueryError($result, 'SET AUTOCOMMIT = 0');
265
266
        // starting transaction
267
        $result = $this->query('START TRANSACTION');
268
269
        $this->processQueryError($result, 'START TRANSACTION');
270
    }
271
272
    /**
273
     * Commiting transaction
274
     */
275
    public function commit(): void
276
    {
277
        // commit transaction
278
        $result = $this->query('COMMIT');
279
280
        $this->processQueryError($result, 'COMMIT');
281
282
        // setting autocommit on
283
        $result = $this->query('SET AUTOCOMMIT = 1');
284
285
        $this->processQueryError($result, 'SET AUTOCOMMIT = 1');
286
    }
287
288
    /**
289
     * Rollback transaction
290
     */
291
    public function rollback(): void
292
    {
293
        // rollback transaction
294
        $result = $this->query('ROLLBACK');
295
296
        $this->processQueryError($result, 'ROLLBACK');
297
    }
298
299
    /**
300
     * Method executes query
301
     *
302
     * @param string $query
303
     *            Query
304
     * @return mixed Query execution result
305
     */
306
    public function query(string $query)
307
    {
308
        // @codeCoverageIgnoreStart
309
        return $this->pdo->query($query);
310
        // @codeCoverageIgnoreEnd
311
    }
312
313
    /**
314
     * Method returns id of the last inserted record
315
     *
316
     * @return int id of the last inserted record
317
     */
318
    public function lastInsertId(): int
319
    {
320
        // @codeCoverageIgnoreStart
321
        return (int) $this->pdo->lastInsertId();
322
        // @codeCoverageIgnoreEnd
323
    }
324
325
    /**
326
     * Method inserts record
327
     *
328
     * @param string $tableName
329
     *            Table name
330
     * @param array $record
331
     *            Inserting record
332
     * @return int New record's id
333
     */
334
    public function insert(string $tableName, array $record): int
335
    {
336
        $query = 'INSERT ' . $tableName . ' SET ' . $this->compileGetQuery($record);
337
338
        $result = $this->query($query);
339
340
        $this->processQueryError($result, $query);
341
342
        return $this->lastInsertId();
343
    }
344
345
    /**
346
     * Method inserts record
347
     *
348
     * @param string $tableName
349
     *            Table name
350
     * @param array $records
351
     *            Inserting records
352
     * @return int New record's id
353
     */
354
    public function insertMultyple(string $tableName, array $records): int
355
    {
356
        $query = 'INSERT INTO ' . $tableName . ' ' . $this->setMultypleQuery($records) . ';';
357
358
        $result = $this->query($query);
359
360
        $this->processQueryError($result, $query);
361
362
        return 0;
363
    }
364
365
    /**
366
     * Method destroys connection
367
     */
368
    public function __destruct()
369
    {
370
        $this->pdo = null;
371
372
        unset($this->pdo);
373
    }
374
}
375