Passed
Branch feature-dbal (014e98)
by Thomas
02:38
created

Dbal::update()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 17
cts 17
cp 1
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 17
nc 6
nop 1
crap 4
1
<?php
2
3
namespace ORM;
4
5
use ORM\Dbal\Column;
6
use ORM\Exceptions\NotScalar;
7
use ORM\Exceptions\UnsupportedDriver;
8
9
/**
10
 * Class Dbal
11
 *
12
 * This is the base class for the database abstraction layer.
13
 *
14
 * @package ORM
15
 * @author  Thomas Flori <[email protected]>
16
 */
17
abstract class Dbal
18
{
19
    /** @var EntityManager */
20
    protected $em;
21
22
    protected static $quotingCharacter = '"';
23
    protected static $identifierDivider = '.';
24
    protected static $booleanTrue = '1';
25
    protected static $booleanFalse = '0';
26
27 17
    public static function setQuotingCharacter($char)
28
    {
29 17
        static::$quotingCharacter = $char;
30 17
    }
31
32 17
    public static function setIdentifierDivider($divider)
33
    {
34 17
        static::$identifierDivider = $divider;
35 17
    }
36
37 17
    public static function setBooleanTrue($true)
38
    {
39 17
        static::$booleanTrue = $true;
40 17
    }
41
42 17
    public static function setBooleanFalse($false)
43
    {
44 17
        static::$booleanFalse = $false;
45 17
    }
46
47
    /**
48
     * @return string
49
     */
50 1
    public static function getQuotingCharacter()
51
    {
52 1
        return static::$quotingCharacter;
53
    }
54
55
    /**
56
     * @return string
57
     */
58 1
    public static function getIdentifierDivider()
59
    {
60 1
        return static::$identifierDivider;
61
    }
62
63
    /**
64
     * @return string
65
     */
66 1
    public static function getBooleanTrue()
67
    {
68 1
        return static::$booleanTrue;
69
    }
70
71
    /**
72
     * @return string
73
     */
74 1
    public static function getBooleanFalse()
75
    {
76 1
        return static::$booleanFalse;
77
    }
78
79
    /**
80
     * Dbal constructor.
81
     *
82
     * @param EntityManager $entityManager
83
     */
84 188
    public function __construct(EntityManager $entityManager)
85
    {
86 188
        $this->em = $entityManager;
87 188
    }
88
89
    /**
90
     * Returns $identifier quoted for use in a sql statement
91
     *
92
     * @param string $identifier Identifier to quote
93
     * @return string
94
     */
95 99
    public function escapeIdentifier($identifier)
96
    {
97 99
        $q = static::$quotingCharacter;
98 99
        $d = static::$identifierDivider;
99 99
        return $q . str_replace($d, $q . $d . $q, $identifier) . $q;
100
    }
101
102
    /**
103
     * Returns $value formatted to use in a sql statement.
104
     *
105
     * @param  mixed  $value      The variable that should be returned in SQL syntax
106
     * @return string
107
     * @throws NotScalar
108
     */
109 136
    public function escapeValue($value)
110
    {
111 136
        switch (strtolower(gettype($value))) {
112 136
            case 'string':
113 93
                return $this->em->getConnection()->quote($value);
114
115 57
            case 'integer':
116 49
                return (string) $value;
117
118 8
            case 'double':
119 4
                return (string) $value;
120
121 4
            case 'null':
122 1
                return 'NULL';
123
124 3
            case 'boolean':
125 2
                return ($value) ? static::$booleanTrue : static::$booleanFalse;
126
127
            default:
128 1
                throw new NotScalar('$value has to be scalar data type. ' . gettype($value) . ' given');
129
        }
130
    }
131
132
    /**
133
     * Describe a table
134
     *
135
     * @param $table
136
     * @return Column[]
137
     * @throws UnsupportedDriver
138
     */
139 1
    public function describe($table)
0 ignored issues
show
Unused Code introduced by
The parameter $table is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
140
    {
141 1
        throw new UnsupportedDriver('Not supported for this driver');
142
    }
143
144
    /**
145
     * Inserts $entity and returns the new ID for autoincrement or true
146
     *
147
     * @param Entity $entity
148
     * @param bool   $useAutoIncrement
149
     * @return bool|int
150
     * @throws UnsupportedDriver
151
     */
152 3
    public function insert($entity, $useAutoIncrement = true)
153
    {
154 3
        $statement = $this->buildInsertStatement($entity);
155
156 3
        if ($useAutoIncrement && $entity::isAutoIncremented()) {
157 1
            throw new UnsupportedDriver('Auto incremented column for this driver is not supported');
158
        }
159
160 2
        $this->em->getConnection()->query($statement);
161 2
        $this->em->sync($entity, true);
162 2
        return true;
163
    }
164
165
    /**
166
     * Update $entity in database
167
     *
168
     * @param Entity $entity
169
     * @return bool
170
     * @internal
171
     */
172 6
    public function update(Entity $entity)
173
    {
174 6
        $data = $entity->getData();
175 6
        $primaryKey = $entity->getPrimaryKey();
176
177 6
        $where = [];
178 6
        foreach ($primaryKey as $var => $value) {
179 6
            $col = $entity::getColumnName($var);
180 6
            $where[] = $this->escapeIdentifier($col) . ' = ' . $this->escapeValue($value);
181 6
            if (isset($data[$col])) {
182 6
                unset($data[$col]);
183
            }
184
        }
185
186 6
        $set = [];
187 6
        foreach ($data as $col => $value) {
188 6
            $set[] = $this->escapeIdentifier($col) . ' = ' . $this->escapeValue($value);
189
        }
190
191 6
        $statement = 'UPDATE ' . $this->escapeIdentifier($entity::getTableName()) . ' ' .
192 6
                     'SET ' . implode(',', $set) . ' ' .
193 6
                     'WHERE ' . implode(' AND ', $where);
194 6
        $this->em->getConnection()->query($statement);
195
196 3
        return true;
197
    }
198
199
    /**
200
     * Delete $entity from database
201
     *
202
     * This method does not delete from the map - you can still receive the entity via fetch.
203
     *
204
     * @param Entity $entity
205
     * @return bool
206
     */
207 6
    public function delete(Entity $entity)
208
    {
209 6
        $primaryKey = $entity->getPrimaryKey();
210 6
        $where = [];
211 6
        foreach ($primaryKey as $var => $value) {
212 6
            $col = $entity::getColumnName($var);
213 6
            $where[] = $this->escapeIdentifier($col) . ' = ' . $this->escapeValue($value);
214
        }
215
216 6
        $statement = 'DELETE FROM ' . $this->escapeIdentifier($entity::getTableName()) . ' ' .
217 6
                     'WHERE ' . implode(' AND ', $where);
218 6
        $this->em->getConnection()->query($statement);
219
220 4
        return true;
221
    }
222
223
    /**
224
     * Build the insert statement for $entity
225
     *
226
     * @param Entity $entity
227
     * @return string
228
     */
229 11
    protected function buildInsertStatement($entity)
230
    {
231 11
        $data = $entity->getData();
232
233
        $cols = array_map(function ($key) {
234 11
            return $this->escapeIdentifier($key);
235 11
        }, array_keys($data));
236
237 11
        $values = array_map(function ($value) use ($entity) {
238 11
            return $this->escapeValue($value);
239 11
        }, array_values($data));
240
241 11
        $statement = 'INSERT INTO ' . $this->escapeIdentifier($entity::getTableName()) . ' ' .
242 11
                     '(' . implode(',', $cols) . ') VALUES (' . implode(',', $values) . ')';
243
244 11
        return $statement;
245
    }
246
}
247