Completed
Push — master ( 938ee3...996d38 )
by SignpostMarv
04:42
created

AbstractDaftObjectEasyDBRepository   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 275
Duplicated Lines 0 %

Test Coverage

Coverage 95.56%

Importance

Changes 0
Metric Value
dl 0
loc 275
ccs 129
cts 135
cp 0.9556
rs 10
c 0
b 0
f 0
wmc 29

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B DaftObjectRepositoryByType() 0 42 4
A DaftObjectRepositoryByDaftObject() 0 9 2
C RememberDaftObjectData() 0 93 12
B RemoveDaftObjectById() 0 33 4
A DaftObjectExistsInDatabase() 0 19 2
B RecallDaftObjectFromData() 0 47 4
1
<?php
2
/**
3
* Base daft objects.
4
*
5
* @author SignpostMarv
6
*/
7
declare(strict_types=1);
8
9
namespace SignpostMarv\DaftObject;
10
11
use ParagonIE\EasyDB\EasyDB;
12
use RuntimeException;
13
use Throwable;
14
15
abstract class AbstractDaftObjectEasyDBRepository extends DaftObjectMemoryRepository
16
{
17
    /**
18
    * @var EasyDB
19
    */
20
    protected $db;
21
22 5
    protected function __construct(string $type, EasyDB $db)
23
    {
24 5
        parent::__construct($type);
25 5
        $this->db = $db;
26 5
    }
27
28 8
    public static function DaftObjectRepositoryByType(
29
        string $type,
30
        ? EasyDB $db = null
31
    ) : DaftObjectRepository {
32
        if (
33 8
            false === is_a(
34 8
                $type,
35 8
                DaftObjectCreatedByArray::class,
36 8
                true
37
            )
38
        ) {
39 2
            throw new DaftObjectRepositoryTypeByClassMethodAndTypeException(
40 2
                1,
41 2
                static::class,
42 2
                __FUNCTION__,
43 2
                DaftObjectCreatedByArray::class,
44 2
                $type
45
            );
46
        } elseif (
47 6
            false === is_a(
48 6
                $type,
49 6
                DefinesOwnIdPropertiesInterface::class,
50 6
                true
51
            )
52
        ) {
53 1
            throw new DaftObjectRepositoryTypeByClassMethodAndTypeException(
54 1
                1,
55 1
                static::class,
56 1
                __FUNCTION__,
57 1
                DefinesOwnIdPropertiesInterface::class,
58 1
                $type
59
            );
60 5
        } elseif (false === ($db instanceof EasyDB)) {
61
            throw new RuntimeException('Database connection not specified!');
62
        }
63
64
        /**
65
        * @var EasyDB $db
66
        */
67 5
        $db = $db;
68
69 5
        return new static($type, $db);
70
    }
71
72 5
    public static function DaftObjectRepositoryByDaftObject(
73
        DefinesOwnIdPropertiesInterface $object,
74
        ? EasyDB $db = null
75
    ) : DaftObjectRepository {
76 5
        if (true === ($db instanceof EasyDB)) {
77 5
            return static::DaftObjectRepositoryByType(get_class($object), $db);
78
        }
79
80
        throw new RuntimeException('Database connection not specified!');
81
    }
82
83
    /**
84
    * @param mixed $id
85
    */
86 2
    public function RemoveDaftObjectById($id) : void
87
    {
88 2
        $id = array_values(is_array($id) ? $id : [$id]);
89
90
        /**
91
        * @var DefinesOwnIdPropertiesInterface $type
92
        */
93 2
        $type = $this->type;
94 2
        $idkv = [];
95
96
        foreach (
97 2
            array_values($type::DaftObjectIdProperties()) as $i => $prop
98
        ) {
99 2
            $idkv[$prop] = $id[$i];
100
        }
101
102 2
        $where = [];
103 2
        foreach (array_keys($idkv) as $col) {
104 2
            $where[] = $this->db->escapeIdentifier($col) . ' = ?';
105
        }
106
107
        $query = (
108
            'DELETE FROM ' .
109 2
            $this->db->escapeIdentifier(
110 2
                $this->DaftObjectDatabaseTable()
111
            ) .
112 2
            ' WHERE ' .
113 2
            implode(' AND ', $where)
114
        );
115
116 2
        $this->db->safeQuery($query, array_values($idkv));
117
118 2
        $this->ForgetDaftObjectById($id);
119 2
    }
120
121
    abstract protected function DaftObjectDatabaseTable() : string;
122
123 2
    protected function RememberDaftObjectData(
124
        DefinesOwnIdPropertiesInterface $object
125
    ) : void {
126 2
        $id = [];
127
128 2
        foreach ($object::DaftObjectIdProperties() as $prop) {
129 2
            $id[$prop] = $object->$prop;
130
        }
131
132 2
        $autoStartTransaction = (false === $this->db->inTransaction());
133
134 2
        if (true === $autoStartTransaction) {
135 2
            $this->db->beginTransaction();
136
        }
137
138
        try {
139 2
            $exists = $this->DaftObjectExistsInDatabase($id);
140 2
            if (false === $exists) {
141 2
                $cols = [];
142 2
                $values = [];
143
144 2
                foreach ($object::DaftObjectProperties() as $col) {
145
                    if (
146 2
                        false === method_exists(
147 2
                            $object,
148 2
                            'Get' . ucfirst($col)
149
                        )
150
                    ) {
151 2
                        continue;
152
                    }
153 2
                    $cols[] = $this->db->escapeIdentifier($col);
154 2
                    $values[] = $object->$col;
155
                }
156
157 2
                $this->db->safeQuery(
158
                    (
159
                        'INSERT INTO ' .
160 2
                        $this->db->escapeIdentifier(
161 2
                            $this->DaftObjectDatabaseTable()
162
                        ) .
163 2
                        ' (' .
164 2
                        implode(', ', $cols) .
165 2
                        ') VALUES (' .
166 2
                        implode(', ', array_fill(0, count($cols), '?')) .
167 2
                        ')'
168
                    ),
169 2
                    $values
170
                );
171
            } else {
172 2
                $changed = $object->ChangedProperties();
173 2
                if (count($changed) > 0) {
174 2
                    $cols = [];
175 2
                    $values = [];
176
177 2
                    foreach ($changed as $col) {
178 2
                        $values[] = $object->$col;
179 2
                        $cols[] =
180 2
                            $this->db->escapeIdentifier($col) .
181 2
                            ' = ?';
182
                    }
183
184
                    $query =
185
                        'UPDATE ' .
186 2
                        $this->db->escapeIdentifier(
187 2
                            $this->DaftObjectDatabaseTable()
188
                        ) .
189 2
                        ' SET ' .
190 2
                        implode(', ', $cols);
191
192 2
                    $cols = [];
193
194 2
                    foreach ($id as $col => $value) {
195 2
                        $values[] = $value;
196 2
                        $cols[] =
197 2
                            $this->db->escapeIdentifier($col) .
198 2
                            ' = ?';
199
                    }
200
201 2
                    $query .= ' WHERE ' . implode(' AND ', $cols);
202
203 2
                    $this->db->safeQuery($query, $values);
204
                }
205
            }
206
207 2
            if (true === $autoStartTransaction) {
208 2
                $this->db->commit();
209
            }
210
        } catch (Throwable $e) {
211
            if (true === $autoStartTransaction) {
212
                $this->db->rollBack();
213
            }
214
215
            throw $e;
216
        }
217 2
    }
218
219
    /**
220
    * @param mixed $id
221
    */
222 2
    protected function RecallDaftObjectFromData($id) : ? DaftObject
223
    {
224
        /**
225
        * @var DefinesOwnIdPropertiesInterface $type
226
        */
227 2
        $type = $this->type;
228 2
        $idkv = [];
229
230
        foreach (
231 2
            array_values($type::DaftObjectIdProperties()) as $i => $prop
232
        ) {
233 2
            $idkv[$prop] = $id[$i];
234
        }
235
236 2
        if (true === $this->DaftObjectExistsInDatabase($idkv)) {
237 2
            $where = [];
238 2
            foreach (array_keys($idkv) as $col) {
239 2
                $where[] = $this->db->escapeIdentifier($col) . ' = ?';
240
            }
241
242 2
            $data = $this->db->safeQuery(
243
                (
244
                    'SELECT * FROM ' .
245 2
                    $this->db->escapeIdentifier(
246 2
                        $this->DaftObjectDatabaseTable()
247
                    ) .
248 2
                    ' WHERE ' .
249 2
                    implode(' AND ', $where) .
250 2
                    ' LIMIT 1'
251
                ),
252 2
                array_values($idkv)
253
            );
254
255
            /**
256
            * @var \SignpostMarv\DaftObject\DaftObjectCreatedByArray $type
257
            */
258 2
            $type = $type;
259
260
            /**
261
            * @var DefinesOwnIdPropertiesInterface $out
262
            */
263 2
            $out = new $type($data[0]);
264
265 2
            return $out;
266
        }
267
268 2
        return null;
269
    }
270
271 2
    private function DaftObjectExistsInDatabase(array $id) : bool
272
    {
273 2
        $where = [];
274 2
        foreach (array_keys($id) as $col) {
275 2
            $where[] = $this->db->escapeIdentifier($col) . ' = ?';
276
        }
277
278
        return
279 2
            (int) $this->db->single(
280
                (
281
                    'SELECT COUNT(*) FROM ' .
282 2
                    $this->db->escapeIdentifier(
283 2
                        $this->DaftObjectDatabaseTable()
284
                    ) .
285 2
                    ' WHERE ' .
286 2
                    implode(' AND ', $where)
287
                ),
288 2
                array_values($id)
289 2
            ) >= 1;
290
    }
291
}
292