Passed
Push — master ( c6bdad...efb6e0 )
by Dāvis
02:51
created

QuickInsertRepository::runSQL()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 3
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
namespace Sludio\HelperBundle\Script\Repository;
4
5
class QuickInsertRepository
6
{
7
    private static $mock = [];
8
    private static $metadata = [];
9
    private static $tableName;
10
11
    public static $entityManager;
12
    public static $connection;
13
14
    public static function init($noFkCheck = false, $manager = null)
15
    {
16
        if (self::$connection) {
17
            return;
18
        }
19
        global $kernel;
20
21
        if ('AppCache' === get_class($kernel)) {
22
            $kernel = $kernel->getKernel();
23
        }
24
        $container = $kernel->getContainer();
25
26
        $manager = $manager ?: $container->getParameter('sludio_helper.entity.manager');
27
        self::$entityManager = $container->get('doctrine')->getManager($manager);
28
        self::$connection = self::$entityManager->getConnection();
29
30
        if (!$noFkCheck) {
31
            self::runSQL('SET FOREIGN_KEY_CHECKS = 0');
32
        }
33
    }
34
35
    public static function close($noFkCheck = false)
36
    {
37
        if (!$noFkCheck) {
38
            self::runSQL('SET FOREIGN_KEY_CHECKS = 1');
39
        }
40
    }
41
42
    public static function isEmpty($variable)
43
    {
44
        $result = true;
45
46
        if (is_array($variable) && count($variable) > 0) {
47
            foreach ($variable as $value) {
48
                $result = $result && self::isEmpty($value);
49
            }
50
        } else {
51
            $result = empty($variable);
52
        }
53
54
        return $result;
55
    }
56
57
    private static function extract($object)
58
    {
59
        self::init(false);
60
        $data = self::extractExt($object, self::$entityManager);
61
62
        self::$mock = $data['mock'];
63
        self::$tableName = $data['table'];
64
        self::$metadata[$data['table']] = $data['meta'];
65
    }
66
67
    public static function extractExt($object, $entityManager)
68
    {
69
        $metadata = $entityManager->getClassMetadata(get_class($object));
70
71
        $fields = $metadata->getFieldNames();
72
        $columns = $metadata->getColumnNames();
73
        $table = $metadata->getTableName();
74
75
        $result = [];
76
        foreach ($fields as $key => $field) {
77
            foreach ($columns as $key2 => $column) {
78
                if ($key === $key2) {
79
                    $result[$table][$field] = $column;
80
                }
81
            }
82
        }
83
84
        $data = [
85
            'mock' => $result,
86
            'table' => $table,
87
            'meta' => $metadata,
88
        ];
89
90
        return $data;
91
    }
92
93
    private static function buildExtra($extra)
94
    {
95
        $methods = [
96
            'GROUP BY',
97
            'HAVING',
98
            'ORDER BY',
99
        ];
100
        $sql = '';
101
102
        foreach ($methods as $method) {
103
            if (isset($extra[$method])) {
104
                $sql .= ' '.$method.' ';
105
                if (is_array($extra[$method])) {
106
                    foreach ($extra[$method] as $group) {
107
                        $sql .= $group.' ';
108
                    }
109
                } else {
110
                    $sql .= $extra[$method].' ';
111
                }
112
            }
113
        }
114
115
        if (isset($extra['LIMIT'])) {
116
            if (is_array($extra['LIMIT'])) {
117
                if (isset($extra['LIMIT'][1])) {
118
                    $offset = $extra['LIMIT'][0];
119
                    $limit = $extra['LIMIT'][1];
120
                } else {
121
                    $offset = 0;
122
                    $limit = $extra['LIMIT'][0];
123
                }
124
                $sql .= 'LIMIT '.$offset.', '.$limit;
125
            }
126
        }
127
128
        $sql = str_replace('  ', ' ', $sql);
129
130
        return $sql;
131
    }
132
133
    private static function buildWhere($tableName, $where)
134
    {
135
        $whereSql = $fvalue = $fkey = '';
136
        if (is_array($where) && !empty($where)) {
137
            $skip = false;
138
            foreach ($where as $key => $value) {
139
                $fkey = $key;
140
                if (is_array($value)) {
141
                    $skip = true;
142
                    $fvalue = trim($value[0]);
143
                } else {
144
                    $fvalue = trim($value);
145
                }
146
                break;
147
            }
148 View Code Duplication
            if (!$skip && isset(self::$mock[$tableName][$fkey])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
149
                if (is_numeric($fvalue)) {
150
                    $whereSql .= ' WHERE '.self::$mock[$tableName][$fkey]." = $fvalue";
151
                } else {
152
                    $whereSql .= ' WHERE '.self::$mock[$tableName][$fkey]." = '".addslashes(trim($fvalue))."'";
153
                }
154
            } else {
155
                if (!$skip && is_numeric($fvalue)) {
156
                    $whereSql .= ' WHERE '.$fkey." = $fvalue";
157
                } elseif (!$skip && !is_numeric($fvalue)) {
158
                    $whereSql .= ' WHERE '.$fkey." = '".addslashes(trim($fvalue))."'";
159
                } elseif ($skip && is_numeric($fkey)) {
160
                    $whereSql .= " WHERE $fvalue";
161
                }
162
            }
163
            unset($where[$fkey]);
164
            if (is_array($where) && !empty($where)) {
165
                foreach ($where as $key => $value) {
166
                    $skip = is_array($value);
167 View Code Duplication
                    if (!$skip && isset(self::$mock[$tableName][$key])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
168
                        if (is_numeric($value)) {
169
                            $whereSql .= ' AND '.self::$mock[$tableName][$key]." = $value";
170
                        } else {
171
                            $whereSql .= ' AND '.self::$mock[$tableName][$key]." = '".addslashes(trim($value))."'";
172
                        }
173
                    } else {
174
                        if (!$skip && is_numeric($value)) {
175
                            $whereSql .= ' AND '.$key." = $value";
176
                        } elseif (!$skip && !is_numeric($value)) {
177
                            $whereSql .= ' AND '.$key." = '".addslashes(trim($value))."'";
178
                        } elseif ($skip && is_numeric($key)) {
179
                            $whereSql .= " AND {$value[0]}";
180
                        }
181
                    }
182
                }
183
            }
184
        }
185
186
        return $whereSql;
187
    }
188
189
    private static function getTable(&$object, &$tableName, &$columns, &$type)
190
    {
191
        if (is_object($object)) {
192
            self::extract($object);
193
            $tableName = self::$tableName;
194
            $columns = self::$mock[$tableName] ?: [];
195
            $type = 'object';
196
        } else {
197
            $tableName = $object['table_name'];
198
            unset($object['table_name']);
199
            $type = 'table';
200
            $columns = array_keys($object) ?: [];
201
        }
202
    }
203
204
    public static function findNextId($tableName, &$out = null)
205
    {
206
        $result = self::get(['table_name' => 'information_schema.tables'], true, [
207
            'table_name' => $tableName,
208
            ['table_schema = DATABASE()'],
209
        ], true, ['AUTO_INCREMENT'], null, [], $out);
210
211
        if ($result) {
212
            return $result;
213
        }
214
215
        return 1;
216
    }
217
218
    public static function findNextIdExt($object, $entityManager = null, &$out = null)
219
    {
220
        self::init(true);
221
        $data = self::extractExt($object, $entityManager);
222
223
        return self::findNextId($data['table'], $out);
224
    }
225
226
    public static function runSQL($sql, $noFkCheck = true, $manager = null)
227
    {
228
        $sql = trim(preg_replace('/\s+/', ' ', $sql));
229
        self::init($noFkCheck, $manager);
230
        $sth = self::$connection->prepare($sql);
231
        $sth->execute();
232
233
        if (substr($sql, 0, 6) === "SELECT") {
234
            return $sth->fetchAll();
235
        }
236
    }
237
238
    public static function get($object, $one = false, $where = [], $noFkCheck = true, $fields = [], $manager = null, $extra = [], &$out = null)
239
    {
240
        self::init(true, $manager);
241
        self::getTable($object, $tableName, $columns, $type);
242
243
        $whereSql = self::buildWhere($tableName, $where);
244
        $select = (isset($extra['MODE']) ? 'SELECT '.$extra['MODE'] : 'SELECT').' ';
245
        if (!$fields) {
246
            $sql = $select.'id FROM '.$tableName.$whereSql;
247
        } else {
248
            $sql = $select.(implode(', ', $fields)).' FROM '.$tableName.$whereSql;
249
        }
250
        if (!empty($extra)) {
251
            $extraSql = self::buildExtra($extra);
252
            $sql .= $extraSql;
253
        }
254
        if ($out) {
255
            $out = $sql;
256
        }
257
        $result = self::runSQL($sql);
258
        if ($one && $result) {
259
            if (!$fields) {
260
                return intval($result[0]['id']);
261
            } else {
262
                if (count($fields) === 1 && $fields[0] !== '*') {
263
                    return $result[0][$fields[0]];
264
                } else {
265
                    return $result[0];
266
                }
267
            }
268
        }
269
270
        self::close(true);
271
        if ($one || !$result) {
272
            return null;
273
        }
274
275
        $field = null;
276
        if (!$fields) {
277
            $field = 'id';
278
        } elseif (count($fields) === 1 && $fields[0] !== '*') {
279
            $field = $fields[0];
280
        }
281
282
        if ($field) {
283
            foreach ($result as &$res) {
284
                $res = $res[$field];
285
            }
286
        }
287
288
        return $result;
289
    }
290
291
    private static function value($object, $variable, $type)
292
    {
293
        if ($type === 'object') {
294
            return $object->{'get'.ucfirst($variable)}();
295
        } else {
296
            return $object[$variable];
297
        }
298
    }
299
300
    public static function persist($object, $full = false, $extraFields = [], $noFkCheck = false, $manager = null, &$out = null)
301
    {
302
        self::init($noFkCheck, $manager);
303
        self::getTable($object, $tableName, $columns, $type);
304
305
        $id = self::findNextId($tableName);
306
        $keys = [];
307
        $values = [];
308
309 View Code Duplication
        if (!empty($extraFields) && isset($extraFields[$tableName])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
310
            $columns = array_merge($columns, $extraFields[$tableName]);
311
        }
312
313
        $idd = null;
314
        foreach ($columns as $value => $key) {
315
            $variable = null;
316
            if (!is_array($key) && !is_array($value)) {
317
                $value = self::value($object, $value, $type);
318
                if ($value instanceof \DateTime) {
319
                    $variable = "'".addslashes(trim($value->format('Y-m-d H:i:s')))."'";
320
                } else {
321
                    $variable = "'".addslashes(trim($value))."'";
322
                }
323
                if (trim($variable) === '' || trim($variable) === "''" || (is_numeric($variable) && $variable === 0)) {
324
                    $variable = null;
325
                }
326
                if ($variable !== null) {
327
                    $values[] = $variable;
328
                    $keys[] = $key;
329
                    if ($key === 'id') {
330
                        $idd = $value;
331
                    }
332
                }
333
            }
334
        }
335
336
        $sql = null;
337
        if (!$full && !self::isEmpty($values)) {
338
            $sql = '
339
                INSERT INTO
340
                    '.$tableName.'
341
                        (id, '.implode(',', $keys).")
342
                VALUES
343
                    ({$id},".implode(',', $values).')
344
            ';
345
        } elseif ($full && !self::isEmpty($values)) {
346
            $id = $idd;
347
            $sql = '
348
                INSERT INTO
349
                    '.$tableName.'
350
                        ('.implode(',', $keys).")
351
                VALUES
352
                    (".implode(',', $values).')
353
            ';
354
        } else {
355
            $id = null;
356
        }
357
        if ($sql !== null && $id !== null) {
358
            if ($out) {
359
                $out = $sql;
360
            }
361
            self::runSQL($sql);
362
        }
363
364
        self::close($noFkCheck);
365
366
        return $id;
367
    }
368
369
    public static function update($id, $object, $extraFields = [], $noFkCheck = false, $manager = null, &$out = null)
370
    {
371
        self::init($noFkCheck, $manager);
372
        self::getTable($object, $tableName, $columns, $type);
373
374
        $result = self::get(['table_name' => $tableName], true, ['id' => $id], true, ['*']);
375
        unset($result['id']);
376
377
        $data = [];
378
379 View Code Duplication
        if (!empty($extraFields) && isset($extraFields[$tableName])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
380
            $columns = array_merge($columns, $extraFields[$tableName]);
381
        }
382
383
        $flip = array_flip($columns);
384
        if ($type === 'object') {
385
            if ($id) {
386
                foreach ($result as $key => $value) {
387 View Code Duplication
                    if ($object->{'get'.ucfirst($flip[$key])}() !== $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
388
                        $data[$columns[$flip[$key]]] = $object->{'get'.ucfirst($flip[$key])}();
389
                    }
390
                }
391
            } else {
392
                foreach ($result as $key => $value) {
393
                    if ($object->{'get'.ucfirst($flip[$key])}() !== null) {
394 View Code Duplication
                        if ($object->{'get'.ucfirst($flip[$key])}() !== $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
395
                            $data[$columns[$flip[$key]]] = $object->{'get'.ucfirst($flip[$key])}();
396
                        }
397
                    }
398
                }
399
            }
400
        } else {
401
            foreach ($result as $key => $value) {
402
                if (isset($object[$key]) && $object[$key] !== $value) {
403
                    $data[$key] = $extraFields[$key];
404
                }
405
            }
406
407
        }
408
409
        if ($data) {
410
            $sql = "
411
                UPDATE
412
                    ".$tableName."
413
                SET
414
415
            ";
416
            foreach ($data as $key => $value) {
417
                $meta = self::$metadata[$tableName]->getFieldMapping($flip[$key]);
418
                $meta = $meta['type'];
419
                if (in_array($meta, [
420
                    'boolean',
421
                    'integer',
422
                    'longint',
423
                ])) {
424
                    $value = intval($value);
425
                } else {
426
                    $value = "'".addslashes(trim($value))."'";
427
                }
428
                $sql .= " ".$key." = ".$value.",";
429
            }
430
            $sql = substr($sql, 0, -1);
431
            $sql .= " WHERE id = ".$id;
432
            if ($out) {
433
                $out = $sql;
434
            }
435
436
            self::runSQL($sql);
437
        }
438
439
        self::close($noFkCheck);
440
    }
441
442
    public static function delete($object, $where = [], $noFkCheck = false, $manager = null, &$out = null)
443
    {
444
        self::init($noFkCheck, $manager);
445
        self::getTable($object, $tableName, $columns, $type);
446
447
        $whereSql = self::buildWhere($tableName, $where);
448
        $sql = 'DELETE FROM '.$tableName.' '.$whereSql;
449
        if ($out) {
450
            $out = $sql;
451
        }
452
        self::runSQL($sql);
453
454
        self::close($noFkCheck);
455
    }
456
457
    public static function link($object, $data, $noFkCheck = false, $manager = null, &$out = null)
458
    {
459
        self::init($noFkCheck, $manager);
460
        self::getTable($object, $tableName, $columns, $type);
461
462
        $data['table_name'] = $tableName;
463
        self::persist($data, true, [], $noFkCheck, $manager, $out);
464
    }
465
}
466