Completed
Push — master ( 1c8a4e...1281e1 )
by SignpostMarv
02:44
created

RemoveDaftObjectById()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 24
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

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