Completed
Pull Request — master (#49)
by Thomas
16:34
created

Mysql::bulkInsert()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 38
ccs 0
cts 0
cp 0
rs 8.6897
c 0
b 0
f 0
cc 6
nc 5
nop 3
crap 42
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 6
    public function insert(Entity $entity, $useAutoIncrement = true)
45
    {
46 6
        $statement = $this->buildInsertStatement($entity);
47 6
        $pdo       = $this->entityManager->getConnection();
48
49 6
        $pdo->query($statement);
50
51 3
        if ($useAutoIncrement && $entity::isAutoIncremented()) {
52
            // we don't need a transaction here because the last insert id is bound to connection
53 1
            $this->updateAutoincrement($entity, $pdo->query("SELECT LAST_INSERT_ID()")->fetchColumn());
54
        }
55
56 3
        return $this->entityManager->sync($entity, true);
57
    }
58
59
    public function bulkInsert(array $entities, $update = true, $useAutoIncrement = true)
60
    {
61
        if (count($entities) === 0) {
62
            return false;
63
        }
64
        $statement = $this->buildInsertStatement(...$entities);
65
        $pdo = $this->entityManager->getConnection();
66
        $pdo->query($statement);
67
68
        if ($update) {
69
            $entity = reset($entities);
70
            if ($useAutoIncrement && $entity::isAutoIncremented()) {
71
                $table = $this->escapeIdentifier($entity::getTableName());
72
                $pKey = $this->escapeIdentifier($entity::getColumnName($entity::getPrimaryKeyVars()[0]));
73
                $pdo->beginTransaction();
74
                $pdo->query($statement);
75
                $rows = $pdo->query('SELECT * FROM ' . $table . ' WHERE ' . $pKey . ' >= LAST_INSERT_ID()')
76
                    ->fetchAll(\PDO::FETCH_ASSOC);
77
                $pdo->commit();
78
79
                /** @var Entity $entity */
80
                foreach (array_values($entities) as $key => $entity) {
81
                    $entity->setOriginalData($rows[$key]);
82
                    $entity->reset();
83
                    $this->entityManager->map($entity, true);
84
                }
85
                return true;
86
            } else {
87
                $pdo->query($statement);
88
            }
89
90
            $this->syncInserted(...$entities);
91
            return true;
92
        }
93
94
        $pdo->query($statement);
95
        return true;
96
    }
97
98 50
    public function describe($table)
99
    {
100
        try {
101 50
            $result = $this->entityManager->getConnection()->query('DESCRIBE ' . $this->escapeIdentifier($table));
102 1
        } catch (\PDOException $exception) {
103 1
            throw new Exception('Unknown table ' . $table, 0, $exception);
104
        }
105
106 49
        $cols = [];
107 49
        while ($rawColumn = $result->fetch(\PDO::FETCH_ASSOC)) {
108 49
            $cols[] = new Column($this, $this->normalizeColumnDefinition($rawColumn));
109
        }
110
111 49
        return new Table($cols);
112
    }
113
114
    /**
115
     * Normalize a column definition
116
     *
117
     * The column definition from "DESCRIBE <table>" is to special as useful. Here we normalize it to a more
118
     * ANSI-SQL style.
119
     *
120
     * @param array $rawColumn
121
     * @return array
122
     */
123 49
    protected function normalizeColumnDefinition($rawColumn)
124
    {
125 49
        $definition = [];
126
127 49
        $definition['data_type'] = $this->normalizeType($rawColumn['Type']);
128 49
        if (isset(static::$typeMapping[$definition['data_type']])) {
129 44
            $definition['type'] = static::$typeMapping[$definition['data_type']];
130
        }
131
132 49
        $definition['column_name']              = $rawColumn['Field'];
133 49
        $definition['is_nullable']              = $rawColumn['Null'] === 'YES';
134 49
        $definition['column_default']           = $rawColumn['Default'] !== null ? $rawColumn['Default'] :
135 46
            ($rawColumn['Extra'] === 'auto_increment' ? 'sequence(AUTO_INCREMENT)' : null);
136 49
        $definition['character_maximum_length'] = null;
137 49
        $definition['datetime_precision']       = null;
138
139 49
        switch ($definition['data_type']) {
140 49
            case 'varchar':
141 47
            case 'char':
142 4
                $definition['character_maximum_length'] = $this->extractParenthesis($rawColumn['Type']);
143 4
                break;
144 45
            case 'datetime':
145 41
            case 'timestamp':
146 37
            case 'time':
147 12
                $definition['datetime_precision'] = $this->extractParenthesis($rawColumn['Type']);
148 12
                break;
149 33
            case 'set':
150 31
            case 'enum':
151 4
                $definition['enumeration_values'] = $this->extractParenthesis($rawColumn['Type']);
152 4
                break;
153
        }
154
155 49
        return $definition;
156
    }
157
}
158