Passed
Push — master ( efb6e0...f0f6bb )
by Dāvis
02:43
created

QuickInsertRepository::link()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 5
dl 0
loc 6
rs 9.4285
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, $noFkCheck = true, $manager = null)
190
    {
191
        self::init($noFkCheck, $manager);
192
        if (is_object($object)) {
193
            self::extract($object);
194
            $tableName = self::$tableName;
195
            $columns = self::$mock[$tableName] ?: [];
196
            $type = 'object';
197
        } else {
198
            $tableName = $object['table_name'];
199
            unset($object['table_name']);
200
            $type = 'table';
201
            $columns = array_keys($object) ?: [];
202
        }
203
    }
204
205
    public static function findNextId($tableName, &$out = null)
206
    {
207
        $result = self::get(['table_name' => 'information_schema.tables'], true, [
208
            'table_name' => $tableName,
209
            ['table_schema = DATABASE()'],
210
        ], true, ['AUTO_INCREMENT'], null, [], $out);
211
212
        if ($result) {
213
            return $result;
214
        }
215
216
        return 1;
217
    }
218
219
    public static function findNextIdExt($object, $entityManager = null, &$out = null)
220
    {
221
        self::init(true);
222
        $data = self::extractExt($object, $entityManager);
223
224
        return self::findNextId($data['table'], $out);
225
    }
226
227
    public static function runSQL($sql, $noFkCheck = true, $manager = null)
228
    {
229
        $sql = trim(preg_replace('/\s+/', ' ', $sql));
230
        self::init($noFkCheck, $manager);
231
        $sth = self::$connection->prepare($sql);
232
        $sth->execute();
233
234
        if (substr($sql, 0, 6) === "SELECT") {
235
            return $sth->fetchAll();
236
        }
237
    }
238
239
    public static function get($object, $one = false, $where = [], $noFkCheck = true, $fields = [], $manager = null, $extra = [], &$out = null)
240
    {
241
        self::getTable($object, $tableName, $columns, $type, $noFkCheck, $manager);
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::getTable($object, $tableName, $columns, $type, $noFkCheck, $manager);
303
304
        $id = self::findNextId($tableName);
305
        $keys = $values = [];
306
307 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...
308
            $columns = array_merge($columns, $extraFields[$tableName]);
309
        }
310
311
        $idd = null;
312
        foreach ($columns as $value => $key) {
313
            $variable = null;
314
            if (!is_array($key) && !is_array($value)) {
315
                $value = self::value($object, $value, $type);
316
                if ($value instanceof \DateTime) {
317
                    $variable = "'".addslashes(trim($value->format('Y-m-d H:i:s')))."'";
318
                } else {
319
                    $variable = "'".addslashes(trim($value))."'";
320
                }
321
                if (trim($variable) === '' || trim($variable) === "''" || (is_numeric($variable) && $variable === 0)) {
322
                    $variable = null;
323
                }
324
                if ($variable !== null) {
325
                    $values[] = $variable;
326
                    $keys[] = $key;
327
                    if ($key === 'id') {
328
                        $idd = $value;
329
                    }
330
                }
331
            }
332
        }
333
334
        $sql = null;
335
        if (!$full && !self::isEmpty($values)) {
336
            $sql = '
337
                INSERT INTO
338
                    '.$tableName.'
339
                        (id, '.implode(',', $keys).")
340
                VALUES
341
                    ({$id},".implode(',', $values).')
342
            ';
343
        } elseif ($full && !self::isEmpty($values)) {
344
            $id = $idd;
345
            $sql = '
346
                INSERT INTO
347
                    '.$tableName.'
348
                        ('.implode(',', $keys).")
349
                VALUES
350
                    (".implode(',', $values).')
351
            ';
352
        } else {
353
            $id = null;
354
        }
355
        if ($sql !== null && $id !== null) {
356
            if ($out) {
357
                $out = $sql;
358
            }
359
            self::runSQL($sql);
360
        }
361
362
        self::close($noFkCheck);
363
364
        return $id;
365
    }
366
367
    public static function update($id, $object, $extraFields = [], $noFkCheck = false, $manager = null, &$out = null)
368
    {
369
        self::getTable($object, $tableName, $columns, $type, $noFkCheck, $manager);
370
371
        $result = self::get(['table_name' => $tableName], true, ['id' => $id], true, ['*']);
372
        unset($result['id']);
373
374
        $data = [];
375
376 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...
377
            $columns = array_merge($columns, $extraFields[$tableName]);
378
        }
379
380
        $flip = array_flip($columns);
381
        if ($type === 'object') {
382
            if ($id) {
383
                foreach ($result as $key => $value) {
384 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...
385
                        $data[$columns[$flip[$key]]] = $object->{'get'.ucfirst($flip[$key])}();
386
                    }
387
                }
388
            } else {
389
                foreach ($result as $key => $value) {
390
                    if ($object->{'get'.ucfirst($flip[$key])}() !== null) {
391 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...
392
                            $data[$columns[$flip[$key]]] = $object->{'get'.ucfirst($flip[$key])}();
393
                        }
394
                    }
395
                }
396
            }
397
        } else {
398
            foreach ($result as $key => $value) {
399
                if (isset($object[$key]) && $object[$key] !== $value) {
400
                    $data[$key] = $extraFields[$key];
401
                }
402
            }
403
404
        }
405
406
        if ($data) {
407
            $sql = "
408
                UPDATE
409
                    ".$tableName."
410
                SET
411
412
            ";
413
            foreach ($data as $key => $value) {
414
                $meta = self::$metadata[$tableName]->getFieldMapping($flip[$key]);
415
                $meta = $meta['type'];
416
                if (in_array($meta, [
417
                    'boolean',
418
                    'integer',
419
                    'longint',
420
                ])) {
421
                    $value = intval($value);
422
                } else {
423
                    $value = "'".addslashes(trim($value))."'";
424
                }
425
                $sql .= " ".$key." = ".$value.",";
426
            }
427
            $sql = substr($sql, 0, -1);
428
            $sql .= " WHERE id = ".$id;
429
            if ($out) {
430
                $out = $sql;
431
            }
432
433
            self::runSQL($sql);
434
        }
435
436
        self::close($noFkCheck);
437
    }
438
439
    public static function delete($object, $where = [], $noFkCheck = false, $manager = null, &$out = null)
440
    {
441
        self::getTable($object, $tableName, $columns, $type, $noFkCheck, $manager);
442
443
        $whereSql = self::buildWhere($tableName, $where);
444
        $sql = 'DELETE FROM '.$tableName.' '.$whereSql;
445
        if ($out) {
446
            $out = $sql;
447
        }
448
        self::runSQL($sql);
449
450
        self::close($noFkCheck);
451
    }
452
453
    public static function link($object, $data, $noFkCheck = false, $manager = null, &$out = null)
454
    {
455
        self::getTable($object, $tableName, $columns, $type, $noFkCheck, $manager);
456
457
        $data['table_name'] = $tableName;
458
        self::persist($data, true, [], $noFkCheck, $manager, $out);
459
    }
460
}
461