Completed
Pull Request — master (#49)
by Thomas
03:23
created

Mysql   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 5
dl 0
loc 117
ccs 51
cts 51
cp 1
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A insertAndSyncWithAutoInc() 0 26 3
A describe() 0 15 3
B normalizeColumnDefinition() 0 34 11
1
<?php
2
3
namespace ORM\Dbal;
4
5
use ORM\Entity;
6
use ORM\Exception;
7
8
/**
9
 * Database abstraction for MySQL databases
10
 *
11
 * @package ORM\Dbal
12
 * @author  Thomas Flori <[email protected]>
13
 */
14
class Mysql extends Dbal
15
{
16
    protected static $typeMapping = [
17
        'tinyint'   => Type\Number::class,
18
        'smallint'  => Type\Number::class,
19
        'mediumint' => Type\Number::class,
20
        'int'       => Type\Number::class,
21
        'bigint'    => Type\Number::class,
22
        'decimal'   => Type\Number::class,
23
        'float'     => Type\Number::class,
24
        'double'    => Type\Number::class,
25
26
        'varchar' => Type\VarChar::class,
27
        'char'    => Type\VarChar::class,
28
29
        'text'       => Type\Text::class,
30
        'tinytext'   => Type\Text::class,
31
        'mediumtext' => Type\Text::class,
32
        'longtext'   => Type\Text::class,
33
34
        'datetime'  => Type\DateTime::class,
35
        'date'      => Type\DateTime::class,
36
        'timestamp' => Type\DateTime::class,
37
38
        'time' => Type\Time::class,
39
        'enum' => Type\Enum::class,
40
        'set'  => Type\Set::class,
41
        'json' => Type\Json::class,
42
    ];
43
44 4
    public function insertAndSyncWithAutoInc(Entity ...$entities)
45
    {
46 4
        if (count($entities) === 0) {
47
            return false;
48
        }
49 4
        static::assertSameType($entities);
50
51 4
        $entity = reset($entities);
52 4
        $table = $this->escapeIdentifier($entity::getTableName());
53 4
        $pKey = $this->escapeIdentifier($entity::getColumnName($entity::getPrimaryKeyVars()[0]));
54 4
        $pdo = $this->entityManager->getConnection();
55 4
        $pdo->beginTransaction();
56 3
        $pdo->query($this->buildInsertStatement(...$entities));
57 1
        $rows = $pdo->query('SELECT * FROM ' . $table . ' WHERE ' . $pKey . ' >= LAST_INSERT_ID()')
58 1
            ->fetchAll(\PDO::FETCH_ASSOC);
59 1
        $pdo->commit();
60
61
        /** @var Entity $entity */
62 1
        foreach (array_values($entities) as $key => $entity) {
63 1
            $entity->setOriginalData($rows[$key]);
64 1
            $entity->reset();
65 1
            $this->entityManager->map($entity, true);
66
        }
67
68 1
        return true;
69
    }
70
71 50
    public function describe($table)
72
    {
73
        try {
74 50
            $result = $this->entityManager->getConnection()->query('DESCRIBE ' . $this->escapeIdentifier($table));
75 1
        } catch (\PDOException $exception) {
76 1
            throw new Exception('Unknown table ' . $table, 0, $exception);
77
        }
78
79 49
        $cols = [];
80 49
        while ($rawColumn = $result->fetch(\PDO::FETCH_ASSOC)) {
81 49
            $cols[] = new Column($this, $this->normalizeColumnDefinition($rawColumn));
82
        }
83
84 49
        return new Table($cols);
85
    }
86
87
    /**
88
     * Normalize a column definition
89
     *
90
     * The column definition from "DESCRIBE <table>" is to special as useful. Here we normalize it to a more
91
     * ANSI-SQL style.
92
     *
93
     * @param array $rawColumn
94
     * @return array
95
     */
96 49
    protected function normalizeColumnDefinition($rawColumn)
97
    {
98 49
        $definition = [];
99
100 49
        $definition['data_type'] = $this->normalizeType($rawColumn['Type']);
101 49
        if (isset(static::$typeMapping[$definition['data_type']])) {
102 44
            $definition['type'] = static::$typeMapping[$definition['data_type']];
103
        }
104
105 49
        $definition['column_name']              = $rawColumn['Field'];
106 49
        $definition['is_nullable']              = $rawColumn['Null'] === 'YES';
107 49
        $definition['column_default']           = $rawColumn['Default'] !== null ? $rawColumn['Default'] :
108 46
            ($rawColumn['Extra'] === 'auto_increment' ? 'sequence(AUTO_INCREMENT)' : null);
109 49
        $definition['character_maximum_length'] = null;
110 49
        $definition['datetime_precision']       = null;
111
112 49
        switch ($definition['data_type']) {
113 49
            case 'varchar':
114 47
            case 'char':
115 4
                $definition['character_maximum_length'] = $this->extractParenthesis($rawColumn['Type']);
116 4
                break;
117 45
            case 'datetime':
118 41
            case 'timestamp':
119 37
            case 'time':
120 12
                $definition['datetime_precision'] = $this->extractParenthesis($rawColumn['Type']);
121 12
                break;
122 33
            case 'set':
123 31
            case 'enum':
124 4
                $definition['enumeration_values'] = $this->extractParenthesis($rawColumn['Type']);
125 4
                break;
126
        }
127
128 49
        return $definition;
129
    }
130
}
131