Completed
Push — master ( db2a29...bcfb67 )
by SignpostMarv
01:55
created

RememberDaftObjectDataValues()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

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