Completed
Push — master ( ff0bfb...db2a29 )
by SignpostMarv
04:29
created

AbstractDaftObjectEasyDBRepository::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
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 2
    protected function RememberDaftObjectData(
146
        DefinesOwnIdPropertiesInterface $object
147
    ) : void {
148 2
        $id = [];
149
150 2
        foreach ($object::DaftObjectIdProperties() as $prop) {
151 2
            $id[$prop] = $object->$prop;
152
        }
153
154 2
        $autoStartTransaction = (false === $this->db->inTransaction());
155
156 2
        if (true === $autoStartTransaction) {
157 2
            $this->db->beginTransaction();
158
        }
159
160
        try {
161 2
            $exists = $this->DaftObjectExistsInDatabase($id);
162 2
            $cols = $this->RememberDaftObjectDataCols($object, $exists);
163 2
            if (count($cols) > 0) {
164 2
                $values = [];
165
166 2
                foreach ($cols as $col) {
167 2
                    $values[$col] = $object->$col;
168
                }
169
170 2
                if (false === $exists) {
171 2
                    $this->db->insert(
172 2
                        $this->DaftObjectDatabaseTable(),
173 2
                        $values
174
                    );
175
                } else {
176 2
                    $this->db->update(
177 2
                        $this->DaftObjectDatabaseTable(),
178 2
                        $values,
179 2
                        $id
180
                    );
181
                }
182
            }
183
184 2
            if (true === $autoStartTransaction) {
185 2
                $this->db->commit();
186
            }
187
        } catch (Throwable $e) {
188
            if (true === $autoStartTransaction) {
189
                $this->db->rollBack();
190
            }
191
192
            throw $e;
193
        }
194 2
    }
195
196
    /**
197
    * @param mixed $id
198
    */
199 2
    protected function RecallDaftObjectFromData($id) : ? DaftObject
200
    {
201
        /**
202
        * @var DefinesOwnIdPropertiesInterface $type
203
        */
204 2
        $type = $this->type;
205 2
        $idkv = [];
206
207
        foreach (
208 2
            array_values($type::DaftObjectIdProperties()) as $i => $prop
209
        ) {
210 2
            $idkv[$prop] = $id[$i];
211
        }
212
213 2
        if (true === $this->DaftObjectExistsInDatabase($idkv)) {
214 2
            $where = [];
215 2
            foreach (array_keys($idkv) as $col) {
216 2
                $where[] = $this->db->escapeIdentifier($col) . ' = ?';
217
            }
218
219 2
            $data = $this->db->safeQuery(
220
                (
221
                    'SELECT * FROM ' .
222 2
                    $this->db->escapeIdentifier(
223 2
                        $this->DaftObjectDatabaseTable()
224
                    ) .
225 2
                    ' WHERE ' .
226 2
                    implode(' AND ', $where) .
227 2
                    ' LIMIT 1'
228
                ),
229 2
                array_values($idkv)
230
            );
231
232
            /**
233
            * @var \SignpostMarv\DaftObject\DaftObjectCreatedByArray $type
234
            */
235 2
            $type = $type;
236
237
            /**
238
            * @var DefinesOwnIdPropertiesInterface $out
239
            */
240 2
            $out = new $type($data[0]);
241
242 2
            return $out;
243
        }
244
245 2
        return null;
246
    }
247
248 2
    private function DaftObjectExistsInDatabase(array $id) : bool
249
    {
250 2
        $where = [];
251 2
        foreach (array_keys($id) as $col) {
252 2
            $where[] = $this->db->escapeIdentifier($col) . ' = ?';
253
        }
254
255
        return
256 2
            (int) $this->db->single(
257
                (
258
                    'SELECT COUNT(*) FROM ' .
259 2
                    $this->db->escapeIdentifier(
260 2
                        $this->DaftObjectDatabaseTable()
261
                    ) .
262 2
                    ' WHERE ' .
263 2
                    implode(' AND ', $where)
264
                ),
265 2
                array_values($id)
266 2
            ) >= 1;
267
    }
268
}
269