Test Failed
Push — master ( bacb55...6daee1 )
by SignpostMarv
02:21
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 10
c 0
b 0
f 0

1 Method

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