Completed
Push — master ( 505b3b...86fb92 )
by SignpostMarv
01:46
created

AbstractDaftObjectEasyDBRepository   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 237
Duplicated Lines 0 %

Test Coverage

Coverage 94.96%

Importance

Changes 0
Metric Value
dl 0
loc 237
ccs 113
cts 119
cp 0.9496
rs 10
c 0
b 0
f 0
wmc 28

7 Methods

Rating   Name   Duplication   Size   Complexity  
A DaftObjectRepositoryByType() 0 21 3
A __construct() 0 4 1
A DaftObjectRepositoryByDaftObject() 0 9 2
A DaftObjectExistsInDatabase() 0 19 2
B RecallDaftObjectFromData() 0 34 4
C RememberDaftObjectData() 0 93 12
B RemoveDaftObjectById() 0 29 4
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 6
        if (class_exists($type) === false) {
33 1
            throw new DaftObjectRepositoryTypeException(
34
                'Argument 1 passed to ' .
0 ignored issues
show
Unused Code introduced by
The call to SignpostMarv\DaftObject\...xception::__construct() has too many arguments starting with 'Argument 1 passed to ' ..., ' . $type . ' given.'. ( Ignorable by Annotation )

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

34
            throw /** @scrutinizer ignore-call */ new DaftObjectRepositoryTypeException(

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...
35 1
                static::class .
36
                '::' .
37
                __FUNCTION__ .
38
                '() must be an implementation of ' .
39
                DefinesOwnIdPropertiesInterface::class .
40 1
                ', ' .
41 1
                $type .
42 1
                ' given.'
43
            );
44 6
        } elseif (($db instanceof EasyDB) === false) {
45
            throw new RuntimeException('Database connection not specified!');
46
        }
47
48 6
        return new static($type, $db);
0 ignored issues
show
Bug introduced by
It seems like $db can also be of type null; however, parameter $db of SignpostMarv\DaftObject\...pository::__construct() does only seem to accept ParagonIE\EasyDB\EasyDB, maybe add an additional type check? ( Ignorable by Annotation )

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

48
        return new static($type, /** @scrutinizer ignore-type */ $db);
Loading history...
49
    }
50
51 5
    public static function DaftObjectRepositoryByDaftObject(
52
        DefinesOwnIdPropertiesInterface $object,
53
        ? EasyDB $db = null
54
    ) : DaftObjectRepository {
55 5
        if (($db instanceof EasyDB) === true) {
56 5
            return static::DaftObjectRepositoryByType(get_class($object), $db);
57
        }
58
59
        throw new RuntimeException('Database connection not specified!');
60
    }
61
62
    /**
63
    * @param mixed $id
64
    */
65 2
    public function RemoveDaftObjectById($id) : void
66
    {
67 2
        $id = array_values(is_array($id) ? $id : [$id]);
68 2
        $type = $this->type;
69 2
        $idkv = [];
70
71
        foreach (
72 2
            array_values($type::DaftObjectIdProperties()) as $i => $prop
73
        ) {
74 2
            $idkv[$prop] = $id[$i];
75
        }
76
77 2
        $where = [];
78 2
        foreach (array_keys($idkv) as $col) {
79 2
            $where[] = $this->db->escapeIdentifier($col) . ' = ?';
80
        }
81
82
        $query = (
83
            'DELETE FROM ' .
84 2
            $this->db->escapeIdentifier(
85 2
                $this->DaftObjectDatabaseTable()
86
            ) .
87 2
            ' WHERE ' .
88 2
            implode(' AND ', $where)
89
        );
90
91 2
        $this->db->safeQuery($query, array_values($idkv));
92
93 2
        $this->ForgetDaftObjectById($id);
94 2
    }
95
96
    abstract protected function DaftObjectDatabaseTable() : string;
97
98 2
    protected function RememberDaftObjectData(
99
        DefinesOwnIdPropertiesInterface $object
100
    ) : void {
101 2
        $id = [];
102
103 2
        foreach ($object::DaftObjectIdProperties() as $prop) {
104 2
            $id[$prop] = $object->$prop;
105
        }
106
107 2
        $autoStartTransaction = ($this->db->inTransaction() === false);
108
109 2
        if ($autoStartTransaction === true) {
110 2
            $this->db->beginTransaction();
111
        }
112
113
        try {
114 2
            $exists = $this->DaftObjectExistsInDatabase($id);
115 2
            if ($exists === false) {
116 2
                $cols = [];
117 2
                $values = [];
118
119 2
                foreach ($object::DaftObjectProperties() as $col) {
120
                    if (
121 2
                        method_exists(
122 2
                            $object,
123 2
                            'Get' . ucfirst($col)
124 2
                        ) === false
125
                    ) {
126 2
                        continue;
127
                    }
128 2
                    $cols[] = $this->db->escapeIdentifier($col);
129 2
                    $values[] = $object->$col;
130
                }
131
132 2
                $this->db->safeQuery(
133
                    (
134
                        'INSERT INTO ' .
135 2
                        $this->db->escapeIdentifier(
136 2
                            $this->DaftObjectDatabaseTable()
137
                        ) .
138 2
                        ' (' .
139 2
                        implode(', ', $cols) .
140 2
                        ') VALUES (' .
141 2
                        implode(', ', array_fill(0, count($cols), '?')) .
142 2
                        ')'
143
                    ),
144 2
                    $values
145
                );
146
            } else {
147 2
                $changed = $object->ChangedProperties();
148 2
                if (count($changed) > 0) {
149 2
                    $cols = [];
150 2
                    $values = [];
151
152 2
                    foreach ($changed as $col) {
153 2
                        $values[] = $object->$col;
154 2
                        $cols[] =
155 2
                            $this->db->escapeIdentifier($col) .
156 2
                            ' = ?';
157
                    }
158
159
                    $query =
160
                        'UPDATE ' .
161 2
                        $this->db->escapeIdentifier(
162 2
                            $this->DaftObjectDatabaseTable()
163
                        ) .
164 2
                        ' SET ' .
165 2
                        implode(', ', $cols);
166
167 2
                    $cols = [];
168
169 2
                    foreach ($id as $col => $value) {
170 2
                        $values[] = $value;
171 2
                        $cols[] =
172 2
                            $this->db->escapeIdentifier($col) .
173 2
                            ' = ?';
174
                    }
175
176 2
                    $query .= ' WHERE ' . implode(' AND ', $cols);
177
178 2
                    $this->db->safeQuery($query, $values);
179
                }
180
            }
181
182 2
            if ($autoStartTransaction === true) {
183 2
                $this->db->commit();
184
            }
185
        } catch (Throwable $e) {
186
            if ($autoStartTransaction === true) {
187
                $this->db->rollBack();
188
            }
189
190
            throw $e;
191
        }
192 2
    }
193
194
    /**
195
    * @param mixed $id
196
    */
197 2
    protected function RecallDaftObjectFromData($id) : ? DaftObject
198
    {
199 2
        $type = $this->type;
200 2
        $idkv = [];
201
202
        foreach (
203 2
            array_values($type::DaftObjectIdProperties()) as $i => $prop
204
        ) {
205 2
            $idkv[$prop] = $id[$i];
206
        }
207
208 2
        if ($this->DaftObjectExistsInDatabase($idkv) === true) {
209 2
            $where = [];
210 2
            foreach (array_keys($idkv) as $col) {
211 2
                $where[] = $this->db->escapeIdentifier($col) . ' = ?';
212
            }
213
214 2
            $data = $this->db->safeQuery(
215
                (
216
                    'SELECT * FROM ' .
217 2
                    $this->db->escapeIdentifier(
218 2
                        $this->DaftObjectDatabaseTable()
219
                    ) .
220 2
                    ' WHERE ' .
221 2
                    implode(' AND ', $where) .
222 2
                    ' LIMIT 1'
223
                ),
224 2
                array_values($idkv)
225
            );
226
227 2
            return new $type($data[0]);
0 ignored issues
show
Bug Best Practice introduced by
The expression return new $type($data[0]) returns the type object which includes types incompatible with the type-hinted return null|SignpostMarv\DaftObject\DaftObject.
Loading history...
228
        }
229
230 2
        return null;
231
    }
232
233 2
    private function DaftObjectExistsInDatabase(array $id) : bool
234
    {
235 2
        $where = [];
236 2
        foreach (array_keys($id) as $col) {
237 2
            $where[] = $this->db->escapeIdentifier($col) . ' = ?';
238
        }
239
240
        return
241 2
            (int) $this->db->single(
242
                (
243
                    'SELECT COUNT(*) FROM ' .
244 2
                    $this->db->escapeIdentifier(
245 2
                        $this->DaftObjectDatabaseTable()
246
                    ) .
247 2
                    ' WHERE ' .
248 2
                    implode(' AND ', $where)
249
                ),
250 2
                array_values($id)
251 2
            ) >= 1;
252
    }
253
}
254