Passed
Branch feature-dbal (53df75)
by Thomas
02:50
created

Dbal::getBooleanFalse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace ORM;
4
5
use ORM\Dbal\Column;
6
use ORM\Dbal\Type;
7
use ORM\Dbal\TypeInterface;
8
use ORM\Exceptions\NotScalar;
9
use ORM\Exceptions\UnsupportedDriver;
10
11
/**
12
 * Class Dbal
13
 *
14
 * This is the base class for the database abstraction layer.
15
 *
16
 * @package ORM
17
 * @author  Thomas Flori <[email protected]>
18
 */
19
abstract class Dbal
20
{
21
    /** @var EntityManager */
22
    protected $em;
23
24
    protected static $quotingCharacter = '"';
25
    protected static $identifierDivider = '.';
26
    protected static $booleanTrue = '1';
27
    protected static $booleanFalse = '0';
28
29
    protected static $registeredTypes = [];
30
    protected static $typeMapping = [];
31
32
    /**
33
     * Dbal constructor.
34
     *
35
     * @param EntityManager $entityManager
36
     */
37 604
    public function __construct(EntityManager $entityManager)
38
    {
39 604
        $this->em = $entityManager;
40 604
    }
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 168
    public function escapeIdentifier($identifier)
49
    {
50 168
        $q = static::$quotingCharacter;
51 168
        $d = static::$identifierDivider;
52 168
        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 162
    public function escapeValue($value)
63
    {
64 162
        switch (strtolower(gettype($value))) {
65 162
            case 'string':
66 119
                return $this->em->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 $table
89
     * @return 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 bool|int
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->em->getConnection()->query($statement);
114 1
        $this->em->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->em->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->em->getConnection()->query($statement);
172
173 4
        return true;
174
    }
175
176 8
    public static function registerType($type)
177
    {
178 8
        if (!in_array($type, static::$registeredTypes)) {
179 8
            array_unshift(static::$registeredTypes, $type);
180
        }
181 8
    }
182
183 17
    public static function setQuotingCharacter($char)
184
    {
185 17
        static::$quotingCharacter = $char;
186 17
    }
187
188 17
    public static function setIdentifierDivider($divider)
189
    {
190 17
        static::$identifierDivider = $divider;
191 17
    }
192
193 17
    public static function setBooleanTrue($true)
194
    {
195 17
        static::$booleanTrue = $true;
196 17
    }
197
198 17
    public static function setBooleanFalse($false)
199
    {
200 17
        static::$booleanFalse = $false;
201 17
    }
202
203
    /**
204
     * @return string
205
     */
206 1
    public static function getQuotingCharacter()
207
    {
208 1
        return static::$quotingCharacter;
209
    }
210
211
    /**
212
     * @return string
213
     */
214 1
    public static function getIdentifierDivider()
215
    {
216 1
        return static::$identifierDivider;
217
    }
218
219
    /**
220
     * @return string
221
     */
222 1
    public static function getBooleanTrue()
223
    {
224 1
        return static::$booleanTrue;
225
    }
226
227
    /**
228
     * @return string
229
     */
230 1
    public static function getBooleanFalse()
231
    {
232 1
        return static::$booleanFalse;
233
    }
234
235
    /**
236
     * Build the insert statement for $entity
237
     *
238
     * @param Entity $entity
239
     * @return string
240
     */
241 11
    protected function buildInsertStatement($entity)
242
    {
243 11
        $data = $entity->getData();
244
245
        $cols = array_map(function ($key) {
246 11
            return $this->escapeIdentifier($key);
247 11
        }, array_keys($data));
248
249 11
        $values = array_map(function ($value) use ($entity) {
250 11
            return $this->escapeValue($value);
251 11
        }, array_values($data));
252
253 11
        $statement = 'INSERT INTO ' . $this->escapeIdentifier($entity::getTableName()) . ' ' .
254 11
                     '(' . implode(',', $cols) . ') VALUES (' . implode(',', $values) . ')';
255
256 11
        return $statement;
257
    }
258
259 66
    protected function normalizeType($type)
260
    {
261 66
        $type = strtolower($type);
262
263 66
        if (($p = strpos($type, '(')) !== false && $p > 0) {
264 23
            $type = substr($type, 0, $p);
265
        }
266
267 66
        return $type;
268
    }
269
270 9
    protected function extractParenthesis($type)
271
    {
272 9
        if (preg_match('/\(([\d,]+)\)/', $type, $match)) {
273 4
            return $match[1];
274
        }
275
276 5
        return null;
277
    }
278
279 90
    protected function getType($columnDefinition)
280
    {
281 90
        if (isset(static::$typeMapping[$columnDefinition['data_type']])) {
282 76
            return call_user_func([static::$typeMapping[$columnDefinition['data_type']], 'factory'], $columnDefinition);
283
        } else {
284 14
            foreach (self::$registeredTypes as $class) {
285 5
                if ($type = $class::fromDefinition($columnDefinition)) {
286 2
                    if (!$type instanceof TypeInterface) {
287 1
                        throw new Exception('Returned object does not implement TypeInterface');
288
                    }
289 4
                    return $type;
290
                }
291
            }
292
293 12
            return new Type\Text();
294
        }
295
    }
296
}
297