Completed
Push — master ( 951fd4...a1d189 )
by SignpostMarv
03:43
created

DaftObjectRepositoryByDaftObject()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 9
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 1
nop 2
dl 0
loc 9
ccs 3
cts 4
cp 0.75
crap 2.0625
rs 9.6666
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 RuntimeException;
13
use Throwable;
14
15
abstract class AbstractDaftObjectEasyDBRepository extends DaftObjectMemoryRepository
16
{
17
    /**
18
    * @var EasyDB
19
    */
20
    protected $db;
21
22 6
    protected function __construct(string $type, EasyDB $db)
23
    {
24 6
        parent::__construct($type);
25 6
        $this->db = $db;
26 6
    }
27
28 6
    public static function DaftObjectRepositoryByType(
29
        string $type,
30
        ? EasyDB $db = null
31
    ) : DaftObjectRepository {
32
        if (
33 6
            false === is_a(
34 6
                $type,
35 6
                DefinesOwnIdPropertiesInterface::class,
36 6
                true
37
            )
38
        ) {
39 1
            throw new DaftObjectRepositoryTypeByClassMethodAndTypeException(
40 1
                1,
41 1
                static::class,
42 1
                __FUNCTION__,
43 1
                DefinesOwnIdPropertiesInterface::class,
44 1
                $type
45
            );
46 6
        } elseif (false === ($db instanceof EasyDB)) {
47
            throw new RuntimeException('Database connection not specified!');
48
        }
49
50
        /**
51
        * @var EasyDB $db
52
        */
53 6
        $db = $db;
54
55 6
        return new static($type, $db);
56
    }
57
58 5
    public static function DaftObjectRepositoryByDaftObject(
59
        DefinesOwnIdPropertiesInterface $object,
60
        ? EasyDB $db = null
61
    ) : DaftObjectRepository {
62 5
        if (true === ($db instanceof EasyDB)) {
63 5
            return static::DaftObjectRepositoryByType(get_class($object), $db);
64
        }
65
66
        throw new RuntimeException('Database connection not specified!');
67
    }
68
69
    /**
70
    * @param mixed $id
71
    */
72 2
    public function RemoveDaftObjectById($id) : void
73
    {
74 2
        $id = array_values(is_array($id) ? $id : [$id]);
75
76
        /**
77
        * @var DefinesOwnIdPropertiesInterface $type
78
        */
79 2
        $type = $this->type;
80 2
        $idkv = [];
81
82
        foreach (
83 2
            array_values($type::DaftObjectIdProperties()) as $i => $prop
84
        ) {
85 2
            $idkv[$prop] = $id[$i];
86
        }
87
88 2
        $where = [];
89 2
        foreach (array_keys($idkv) as $col) {
90 2
            $where[] = $this->db->escapeIdentifier($col) . ' = ?';
91
        }
92
93
        $query = (
94
            'DELETE FROM ' .
95 2
            $this->db->escapeIdentifier(
96 2
                $this->DaftObjectDatabaseTable()
97
            ) .
98 2
            ' WHERE ' .
99 2
            implode(' AND ', $where)
100
        );
101
102 2
        $this->db->safeQuery($query, array_values($idkv));
103
104 2
        $this->ForgetDaftObjectById($id);
105 2
    }
106
107
    abstract protected function DaftObjectDatabaseTable() : string;
108
109 2
    protected function RememberDaftObjectData(
110
        DefinesOwnIdPropertiesInterface $object
111
    ) : void {
112 2
        $id = [];
113
114 2
        foreach ($object::DaftObjectIdProperties() as $prop) {
115 2
            $id[$prop] = $object->$prop;
116
        }
117
118 2
        $autoStartTransaction = (false === $this->db->inTransaction());
119
120 2
        if (true === $autoStartTransaction) {
121 2
            $this->db->beginTransaction();
122
        }
123
124
        try {
125 2
            $exists = $this->DaftObjectExistsInDatabase($id);
126 2
            if (false === $exists) {
127 2
                $cols = [];
128 2
                $values = [];
129
130 2
                foreach ($object::DaftObjectProperties() as $col) {
131
                    if (
132 2
                        false === method_exists(
133 2
                            $object,
134 2
                            'Get' . ucfirst($col)
135
                        )
136
                    ) {
137 2
                        continue;
138
                    }
139 2
                    $cols[] = $this->db->escapeIdentifier($col);
140 2
                    $values[] = $object->$col;
141
                }
142
143 2
                $this->db->safeQuery(
144
                    (
145
                        'INSERT INTO ' .
146 2
                        $this->db->escapeIdentifier(
147 2
                            $this->DaftObjectDatabaseTable()
148
                        ) .
149 2
                        ' (' .
150 2
                        implode(', ', $cols) .
151 2
                        ') VALUES (' .
152 2
                        implode(', ', array_fill(0, count($cols), '?')) .
153 2
                        ')'
154
                    ),
155 2
                    $values
156
                );
157
            } else {
158 2
                $changed = $object->ChangedProperties();
159 2
                if (count($changed) > 0) {
160 2
                    $cols = [];
161 2
                    $values = [];
162
163 2
                    foreach ($changed as $col) {
164 2
                        $values[] = $object->$col;
165 2
                        $cols[] =
166 2
                            $this->db->escapeIdentifier($col) .
167 2
                            ' = ?';
168
                    }
169
170
                    $query =
171
                        'UPDATE ' .
172 2
                        $this->db->escapeIdentifier(
173 2
                            $this->DaftObjectDatabaseTable()
174
                        ) .
175 2
                        ' SET ' .
176 2
                        implode(', ', $cols);
177
178 2
                    $cols = [];
179
180 2
                    foreach ($id as $col => $value) {
181 2
                        $values[] = $value;
182 2
                        $cols[] =
183 2
                            $this->db->escapeIdentifier($col) .
184 2
                            ' = ?';
185
                    }
186
187 2
                    $query .= ' WHERE ' . implode(' AND ', $cols);
188
189 2
                    $this->db->safeQuery($query, $values);
190
                }
191
            }
192
193 2
            if (true === $autoStartTransaction) {
194 2
                $this->db->commit();
195
            }
196
        } catch (Throwable $e) {
197
            if (true === $autoStartTransaction) {
198
                $this->db->rollBack();
199
            }
200
201
            throw $e;
202
        }
203 2
    }
204
205
    /**
206
    * @param mixed $id
207
    */
208 2
    protected function RecallDaftObjectFromData($id) : ? DaftObject
209
    {
210
        /**
211
        * @var DefinesOwnIdPropertiesInterface $type
212
        */
213 2
        $type = $this->type;
214 2
        $idkv = [];
215
216
        foreach (
217 2
            array_values($type::DaftObjectIdProperties()) as $i => $prop
218
        ) {
219 2
            $idkv[$prop] = $id[$i];
220
        }
221
222 2
        if (true === $this->DaftObjectExistsInDatabase($idkv)) {
223 2
            $where = [];
224 2
            foreach (array_keys($idkv) as $col) {
225 2
                $where[] = $this->db->escapeIdentifier($col) . ' = ?';
226
            }
227
228 2
            $data = $this->db->safeQuery(
229
                (
230
                    'SELECT * FROM ' .
231 2
                    $this->db->escapeIdentifier(
232 2
                        $this->DaftObjectDatabaseTable()
233
                    ) .
234 2
                    ' WHERE ' .
235 2
                    implode(' AND ', $where) .
236 2
                    ' LIMIT 1'
237
                ),
238 2
                array_values($idkv)
239
            );
240
241
            /**
242
            * @var DefinesOwnIdPropertiesInterface $out
243
            */
244 2
            $out = new $type($data[0]);
0 ignored issues
show
Unused Code introduced by
The call to SignpostMarv\DaftObject\...nterface::__construct() has too many arguments starting with $data[0]. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

244
            $out = /** @scrutinizer ignore-call */ new $type($data[0]);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
245
246 2
            return $out;
247
        }
248
249 2
        return null;
250
    }
251
252 2
    private function DaftObjectExistsInDatabase(array $id) : bool
253
    {
254 2
        $where = [];
255 2
        foreach (array_keys($id) as $col) {
256 2
            $where[] = $this->db->escapeIdentifier($col) . ' = ?';
257
        }
258
259
        return
260 2
            (int) $this->db->single(
261
                (
262
                    'SELECT COUNT(*) FROM ' .
263 2
                    $this->db->escapeIdentifier(
264 2
                        $this->DaftObjectDatabaseTable()
265
                    ) .
266 2
                    ' WHERE ' .
267 2
                    implode(' AND ', $where)
268
                ),
269 2
                array_values($id)
270 2
            ) >= 1;
271
    }
272
}
273