Passed
Branch feature-validator (0d7506)
by Thomas
02:52
created

Dbal   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 282
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 33
lcom 1
cbo 4
dl 0
loc 282
ccs 95
cts 95
cp 1
rs 9.3999
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A escapeIdentifier() 0 6 1
C escapeValue() 0 22 7
A describe() 0 4 1
A insert() 0 12 3
B update() 0 26 4
A delete() 0 15 2
A setQuotingCharacter() 0 4 1
A setIdentifierDivider() 0 4 1
A setBooleanTrue() 0 4 1
A setBooleanFalse() 0 4 1
A getQuotingCharacter() 0 4 1
A getIdentifierDivider() 0 4 1
A getBooleanTrue() 0 4 1
A getBooleanFalse() 0 4 1
A buildInsertStatement() 0 17 1
A normalizeType() 0 10 3
A extractParenthesis() 0 8 2
1
<?php
2
3
namespace ORM\Dbal;
4
5
use ORM\Entity;
6
use ORM\EntityManager;
7
use ORM\Exceptions\NotScalar;
8
use ORM\Exceptions\UnsupportedDriver;
9
10
/**
11
 * Base class for database abstraction
12
 *
13
 * @package ORM
14
 * @author  Thomas Flori <[email protected]>
15
 */
16
abstract class Dbal
17
{
18
    /** @var EntityManager */
19
    protected $entityManager;
20
21
    /** @var array */
22
    protected static $typeMapping = [];
23
    /** @var string */
24
    protected static $quotingCharacter = '"';
25
    /** @var string */
26
    protected static $identifierDivider = '.';
27
    /** @var string */
28
    protected static $booleanTrue = '1';
29
    /** @var string */
30
    protected static $booleanFalse = '0';
31
32
    /**
33
     * Dbal constructor.
34
     *
35
     * @param EntityManager $entityManager
36
     */
37 718
    public function __construct(EntityManager $entityManager)
38
    {
39 718
        $this->entityManager = $entityManager;
40 718
    }
41
42
    /**
43
     * Returns $identifier quoted for use in a sql statement
44
     *
45
     * @param string $identifier Identifier to quote
46
     * @return string
47
     */
48 181
    public function escapeIdentifier($identifier)
49
    {
50 181
        $q = static::$quotingCharacter;
51 181
        $d = static::$identifierDivider;
52 181
        return $q . str_replace($d, $q . $d . $q, $identifier) . $q;
53
    }
54
55
    /**
56
     * Returns $value formatted to use in a sql statement.
57
     *
58
     * @param  mixed  $value The variable that should be returned in SQL syntax
59
     * @return string
60
     * @throws NotScalar
61
     */
62 163
    public function escapeValue($value)
63
    {
64 163
        switch (strtolower(gettype($value))) {
65 163
            case 'string':
66 120
                return $this->entityManager->getConnection()->quote($value);
67
68 57
            case 'integer':
69 49
                return (string) $value;
70
71 8
            case 'double':
72 4
                return (string) $value;
73
74 4
            case 'null':
75 1
                return 'NULL';
76
77 3
            case 'boolean':
78 2
                return ($value) ? static::$booleanTrue : static::$booleanFalse;
79
80
            default:
81 1
                throw new NotScalar('$value has to be scalar data type. ' . gettype($value) . ' given');
82
        }
83
    }
84
85
    /**
86
     * Describe a table
87
     *
88
     * @param string $table
89
     * @return Table|Column[]
90
     * @throws UnsupportedDriver
91
     */
92 1
    public function describe($table)
93
    {
94 1
        throw new UnsupportedDriver('Not supported for this driver');
95
    }
96
97
    /**
98
     * Inserts $entity and returns the new ID for autoincrement or true
99
     *
100
     * @param Entity $entity
101
     * @param bool   $useAutoIncrement
102
     * @return mixed
103
     * @throws UnsupportedDriver
104
     */
105 2
    public function insert($entity, $useAutoIncrement = true)
106
    {
107 2
        $statement = $this->buildInsertStatement($entity);
108
109 2
        if ($useAutoIncrement && $entity::isAutoIncremented()) {
110 1
            throw new UnsupportedDriver('Auto incremented column for this driver is not supported');
111
        }
112
113 1
        $this->entityManager->getConnection()->query($statement);
114 1
        $this->entityManager->sync($entity, true);
115 1
        return true;
116
    }
117
118
    /**
119
     * Update $entity in database
120
     *
121
     * @param Entity $entity
122
     * @return bool
123
     * @internal
124
     */
125 6
    public function update(Entity $entity)
126
    {
127 6
        $data = $entity->getData();
128 6
        $primaryKey = $entity->getPrimaryKey();
129
130 6
        $where = [];
131 6
        foreach ($primaryKey as $var => $value) {
132 6
            $col = $entity::getColumnName($var);
133 6
            $where[] = $this->escapeIdentifier($col) . ' = ' . $this->escapeValue($value);
134 6
            if (isset($data[$col])) {
135 6
                unset($data[$col]);
136
            }
137
        }
138
139 6
        $set = [];
140 6
        foreach ($data as $col => $value) {
141 6
            $set[] = $this->escapeIdentifier($col) . ' = ' . $this->escapeValue($value);
142
        }
143
144 6
        $statement = 'UPDATE ' . $this->escapeIdentifier($entity::getTableName()) . ' ' .
145 6
                     'SET ' . implode(',', $set) . ' ' .
146 6
                     'WHERE ' . implode(' AND ', $where);
147 6
        $this->entityManager->getConnection()->query($statement);
148
149 3
        return true;
150
    }
151
152
    /**
153
     * Delete $entity from database
154
     *
155
     * This method does not delete from the map - you can still receive the entity via fetch.
156
     *
157
     * @param Entity $entity
158
     * @return bool
159
     */
160 6
    public function delete(Entity $entity)
161
    {
162 6
        $primaryKey = $entity->getPrimaryKey();
163 6
        $where = [];
164 6
        foreach ($primaryKey as $var => $value) {
165 6
            $col = $entity::getColumnName($var);
166 6
            $where[] = $this->escapeIdentifier($col) . ' = ' . $this->escapeValue($value);
167
        }
168
169 6
        $statement = 'DELETE FROM ' . $this->escapeIdentifier($entity::getTableName()) . ' ' .
170 6
                     'WHERE ' . implode(' AND ', $where);
171 6
        $this->entityManager->getConnection()->query($statement);
172
173 4
        return true;
174
    }
175
176
    /**
177
     * @param string $char
178
     */
179 17
    public static function setQuotingCharacter($char)
180
    {
181 17
        static::$quotingCharacter = $char;
182 17
    }
183
184
    /**
185
     * @param string $divider
186
     */
187 17
    public static function setIdentifierDivider($divider)
188
    {
189 17
        static::$identifierDivider = $divider;
190 17
    }
191
192
    /**
193
     * @param string $true
194
     */
195 17
    public static function setBooleanTrue($true)
196
    {
197 17
        static::$booleanTrue = $true;
198 17
    }
199
200
    /**
201
     * @param string $false
202
     */
203 17
    public static function setBooleanFalse($false)
204
    {
205 17
        static::$booleanFalse = $false;
206 17
    }
207
208
    /**
209
     * @return string
210
     */
211 1
    public static function getQuotingCharacter()
212
    {
213 1
        return static::$quotingCharacter;
214
    }
215
216
    /**
217
     * @return string
218
     */
219 1
    public static function getIdentifierDivider()
220
    {
221 1
        return static::$identifierDivider;
222
    }
223
224
    /**
225
     * @return string
226
     */
227 3
    public static function getBooleanTrue()
228
    {
229 3
        return static::$booleanTrue;
230
    }
231
232
    /**
233
     * @return string
234
     */
235 3
    public static function getBooleanFalse()
236
    {
237 3
        return static::$booleanFalse;
238
    }
239
240
    /**
241
     * Build the insert statement for $entity
242
     *
243
     * @param Entity $entity
244
     * @return string
245
     */
246 11
    protected function buildInsertStatement($entity)
247
    {
248 11
        $data = $entity->getData();
249
250
        $cols = array_map(function ($key) {
251 11
            return $this->escapeIdentifier($key);
252 11
        }, array_keys($data));
253
254 11
        $values = array_map(function ($value) use ($entity) {
255 11
            return $this->escapeValue($value);
256 11
        }, array_values($data));
257
258 11
        $statement = 'INSERT INTO ' . $this->escapeIdentifier($entity::getTableName()) . ' ' .
259 11
                     '(' . implode(',', $cols) . ') VALUES (' . implode(',', $values) . ')';
260
261 11
        return $statement;
262
    }
263
264
    /**
265
     * Normalize $type
266
     *
267
     * The type returned by mysql is for example VARCHAR(20) - this function converts it to varchar
268
     *
269
     * @param string $type
270
     * @return string
271
     */
272 79
    protected function normalizeType($type)
273
    {
274 79
        $type = strtolower($type);
275
276 79
        if (($p = strpos($type, '(')) !== false && $p > 0) {
277 33
            $type = substr($type, 0, $p);
278
        }
279
280 79
        return $type;
281
    }
282
283
    /**
284
     * Extract content from parenthesis in $type
285
     *
286
     * @param string $type
287
     * @return string
288
     */
289 24
    protected function extractParenthesis($type)
290
    {
291 24
        if (preg_match('/\((.+)\)/', $type, $match)) {
292 16
            return $match[1];
293
        }
294
295 8
        return null;
296
    }
297
}
298