Passed
Push — master ( 00b45f...505b3b )
by SignpostMarv
01:41
created

DaftObjectRepositoryByDaftObject()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 3
cts 4
cp 0.75
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 2
crap 2.0625
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 DaftObjectRepositoryTypeException::__construct() has too many arguments starting with 'Argument 1 passed to ' ..., ' . $type . ' given.'.

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.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

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);
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]);
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