Completed
Push — master ( f62cab...f0735a )
by SignpostMarv
03:01
created

AbstractDaftObjectEasyDBRepository   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 236
Duplicated Lines 0 %

Test Coverage

Coverage 98.99%

Importance

Changes 0
Metric Value
dl 0
loc 236
ccs 98
cts 99
cp 0.9899
rs 9.8
c 0
b 0
f 0
wmc 31

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B DaftObjectRepositoryByType() 0 27 5
A DaftObjectRepositoryByDaftObject() 0 5 1
A RememberDaftObjectDataValues() 0 18 4
A RememberDaftObjectDataUpdate() 0 7 3
A RememberDaftObjectDataCols() 0 14 2
A DaftObjectExistsInDatabase() 0 20 2
B RecallDaftObjectFromData() 0 57 6
A RememberDaftObjectData() 0 18 2
B RemoveDaftObjectById() 0 27 5
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 10
    protected function __construct(string $type, EasyDB $db)
21
    {
22 10
        parent::__construct($type);
23 10
        $this->db = $db;
24 10
    }
25
26 18
    public static function DaftObjectRepositoryByType(
27
        string $type,
28
        ? EasyDB $db = null
29
    ) : DaftObjectRepository {
30 18
        $a = is_a($type, DaftObjectCreatedByArray::class, true);
31
        if (
32 18
            false === $a ||
33 18
            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 12
        } elseif (false === ($db instanceof EasyDB)) {
43 2
            throw new DatabaseConnectionNotSpecifiedException(
44 2
                2,
45 2
                static::class,
46 2
                __FUNCTION__,
47 2
                EasyDB::class,
48 2
                'null'
49
            );
50
        }
51
52 10
        return new static($type, $db);
53
    }
54
55 10
    public static function DaftObjectRepositoryByDaftObject(
56
        DefinesOwnIdPropertiesInterface $object,
57
        ? EasyDB $db = null
58
    ) : DaftObjectRepository {
59 10
        return static::DaftObjectRepositoryByType(get_class($object), $db);
60
    }
61
62
    /**
63
    * @param mixed $id
64
    */
65 4
    public function RemoveDaftObjectById($id) : void
66
    {
67
        /**
68
        * @var array<int, scalar|bool> $id
69
        */
70 4
        $id = array_values(is_array($id) ? $id : [$id]);
0 ignored issues
show
introduced by
The condition is_array($id) is always true.
Loading history...
71
72
        /**
73
        * @var DefinesOwnIdPropertiesInterface $type
74
        */
75 4
        $type = $this->type;
76
77
        /**
78
        * @var array<string, scalar|bool> $idkv
79
        */
80 4
        $idkv = [];
81
82 4
        foreach (array_values($type::DaftObjectIdProperties()) as $i => $prop) {
83 4
            $idkv[$prop] = $id[$i];
84 4
            if (is_bool($idkv[$prop])) {
85 4
                $idkv[$prop] = $idkv[$prop] ? 1 : 0;
86
            }
87
        }
88
89 4
        $this->db->delete($this->DaftObjectDatabaseTable(), $idkv);
90
91 4
        $this->ForgetDaftObjectById($id);
92 4
    }
93
94
    abstract protected function DaftObjectDatabaseTable() : string;
95
96
    /**
97
    * @return string[]
98
    */
99 4
    protected function RememberDaftObjectDataCols(DaftObject $object, bool $exists) : array
100
    {
101 4
        $cols = $object::DaftObjectExportableProperties();
102 4
        if ($exists) {
103 4
            $changed = $object->ChangedProperties();
104 4
            $cols = array_filter(
105 4
                $cols,
106
                function (string $prop) use ($changed) : bool {
107 4
                    return in_array($prop, $changed, true);
108 4
                }
109
            );
110
        }
111
112 4
        return $cols;
113
    }
114
115
    /**
116
    * @return array<string, mixed>
117
    */
118 4
    protected function RememberDaftObjectDataValues(DaftObject $object, bool $exists) : array
119
    {
120
        /**
121
        * @var array<string, mixed>
122
        */
123 4
        $values = [];
124 4
        $cols = $this->RememberDaftObjectDataCols($object, $exists);
125
        /**
126
        * @var string $col
127
        */
128 4
        foreach ($cols as $col) {
129 4
            $values[$col] = $object->$col;
130 4
            if (is_bool($values[$col])) {
131 4
                $values[$col] = $values[$col] ? 1 : 0;
132
            }
133
        }
134
135 4
        return $values;
136
    }
137
138 4
    protected function RememberDaftObjectDataUpdate(bool $exists, array $id, array $values) : void
139
    {
140 4
        if (count($values) > 0) {
141 4
            if (false === $exists) {
142 4
                $this->db->insert($this->DaftObjectDatabaseTable(), $values);
143
            } else {
144 4
                $this->db->update($this->DaftObjectDatabaseTable(), $values, $id);
145
            }
146
        }
147 4
    }
148
149 4
    protected function RememberDaftObjectData(DefinesOwnIdPropertiesInterface $object) : void
150
    {
151
        /**
152
        * @var array<string, mixed> $id
153
        */
154 4
        $id = [];
155
156
        /**
157
        * @var string $prop
158
        */
159 4
        foreach ($object::DaftObjectIdProperties() as $prop) {
160 4
            $id[$prop] = $object->$prop;
161
        }
162
163
        $this->db->tryFlatTransaction(function () use ($id, $object) : void {
164 4
            $exists = $this->DaftObjectExistsInDatabase($id);
165 4
            $values = $this->RememberDaftObjectDataValues($object, $exists);
166 4
            $this->RememberDaftObjectDataUpdate($exists, $id, $values);
167 4
        });
168 4
    }
169
170 4
    protected function RecallDaftObjectFromData($id) : ? DaftObject
171
    {
172 4
        $type = $this->type;
173
174
        /**
175
        * @var array<string, mixed> $idkv
176
        */
177 4
        $idkv = [];
178
179
        /**
180
        * @var array<int, string> $idProps
181
        */
182 4
        $idProps = $type::DaftObjectIdProperties();
183
184 4
        if (is_scalar($id) && 1 === count($idProps)) {
185
            $id = [$id];
186
        }
187
188
        /**
189
        * @var array<int, scalar> $id
190
        */
191 4
        $id = $id;
192
193
        /**
194
        * @var int $i
195
        * @var string $prop
196
        */
197 4
        foreach (array_values($idProps) as $i => $prop) {
198 4
            $idkv[$prop] = $id[$i];
199
        }
200
201 4
        if (true === $this->DaftObjectExistsInDatabase($idkv)) {
202 4
            $where = [];
203 4
            foreach (array_keys($idkv) as $col) {
204 4
                $where[] = $this->db->escapeIdentifier($col) . ' = ?';
205
            }
206
207 4
            $data = $this->db->safeQuery(
208
                (
209
                    'SELECT * FROM ' .
210 4
                    $this->db->escapeIdentifier($this->DaftObjectDatabaseTable()) .
211 4
                    ' WHERE ' .
212 4
                    implode(' AND ', $where) .
213 4
                    ' LIMIT 1'
214
                ),
215 4
                array_values($idkv)
216
            );
217
218
            /**
219
            * @var DefinesOwnIdPropertiesInterface $out
220
            */
221 4
            $out = new $type($data[0]);
222
223 4
            return $out;
224
        }
225
226 4
        return null;
227
    }
228
229 4
    private function DaftObjectExistsInDatabase(array $id) : bool
230
    {
231 4
        $where = [];
232
        /**
233
        * @var string $col
234
        */
235 4
        foreach (array_keys($id) as $col) {
236 4
            $where[] = $this->db->escapeIdentifier($col) . ' = ?';
237
        }
238
239
        return
240 4
            (int) $this->db->single(
241
                (
242
                    'SELECT COUNT(*) FROM ' .
243 4
                    $this->db->escapeIdentifier($this->DaftObjectDatabaseTable()) .
244 4
                    ' WHERE ' .
245 4
                    implode(' AND ', $where)
246
                ),
247 4
                array_values($id)
248 4
            ) >= 1;
249
    }
250
}
251