Completed
Push — master ( d8f380...b43514 )
by SignpostMarv
03:14
created

DaftObjectRepositoryArgsEasyDbActuallyRequired()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

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