Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 52 |
|
0.00% |
0 / 13 |
CRAP | |
0.00% |
0 / 1 |
AbstractRdbmsCrud | |
0.00% |
0 / 52 |
|
0.00% |
0 / 13 |
650 | |
0.00% |
0 / 1 |
getClassColumnsPrefix | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getIdentityColumn | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getTable | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getColumns | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
getAllColumns | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
load | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
update | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
delete | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getByConditions | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
loadByConditions | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
listByConditions | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
6 | |||
deserializeRow | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
deserializeRowIdentity | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
serializeFields | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
deserializeString | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
deserializeInt | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
deserializeUuid | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
deserializeTimestamp | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | namespace MediaWiki\WikispeechSpeechDataCollector\Crud\Rdbms; |
4 | |
5 | /** |
6 | * @file |
7 | * @ingroup Extensions |
8 | * @license GPL-2.0-or-later |
9 | */ |
10 | |
11 | use MediaWiki\WikispeechSpeechDataCollector\Crud\AbstractCrud; |
12 | use MediaWiki\WikispeechSpeechDataCollector\Crud\CrudContext; |
13 | use MediaWiki\WikispeechSpeechDataCollector\Domain\Persistent; |
14 | use MediaWiki\WikispeechSpeechDataCollector\Uuid; |
15 | use MWTimestamp; |
16 | |
17 | /** |
18 | * Database mapping and access for |
19 | * instances of the corresponding underlying subclass of {@link Persistent}. |
20 | * |
21 | * @since 0.1.0 |
22 | */ |
23 | abstract class AbstractRdbmsCrud extends AbstractCrud { |
24 | |
25 | /** @var string Prefix of all extension tables in database. */ |
26 | protected const TABLES_PREFIX = 'wikispeech_sdc_'; |
27 | |
28 | /** @var string Prefix of all columns in database extension tables. */ |
29 | protected const COLUMNS_PREFIX = 'wssdc'; |
30 | |
31 | /** |
32 | * @return string COLUMNS_PREFIX . 'class prefix' . '_' |
33 | */ |
34 | abstract protected function getClassColumnsPrefix(): string; |
35 | |
36 | /** @var string Name of table column that holds the identity. */ |
37 | private $identityColumn; |
38 | |
39 | /** |
40 | * @param CrudContext $context |
41 | * @since 0.1.0 |
42 | */ |
43 | public function __construct( CrudContext $context ) { |
44 | parent::__construct( $context ); |
45 | $this->identityColumn = $this->getClassColumnsPrefix() . 'identity'; |
46 | } |
47 | |
48 | /** |
49 | * Single column identity for this CRUD. |
50 | * |
51 | * If you want to use a multi column identity you'll probably have to extract |
52 | * this method and all uses of it to a strategy pattern or something. |
53 | * |
54 | * @return string |
55 | * @since 0.1.0 |
56 | */ |
57 | public function getIdentityColumn(): string { |
58 | return $this->identityColumn; |
59 | } |
60 | |
61 | /** |
62 | * @return string Name of database table representing this class. |
63 | * @since 0.1.0 |
64 | */ |
65 | abstract protected function getTable(): string; |
66 | |
67 | /** |
68 | * @return string[] Columns in table required to deserialize an instance, identity excluded. |
69 | * @since 0.1.0 |
70 | */ |
71 | abstract protected function getColumns(): array; |
72 | |
73 | /** |
74 | * @var string[] Columns in table required to deserialize an instance, identity included. |
75 | * @since 0.1.0 |
76 | */ |
77 | private $allColumns; |
78 | |
79 | /** |
80 | * @return array|string[] Columns in table required to deserialize an instance, identity included |
81 | * @since 0.1.0 |
82 | */ |
83 | protected function getAllColumns(): array { |
84 | if ( !$this->allColumns ) { |
85 | $allColumns = $this->getColumns(); |
86 | array_push( $allColumns, $this->getIdentityColumn() ); |
87 | $this->allColumns = $allColumns; |
88 | } |
89 | return $this->allColumns; |
90 | } |
91 | |
92 | /** |
93 | * Given a persistent domain object instance with at least identity set, |
94 | * updates the domain object to correspond data retrieved from the database. |
95 | * |
96 | * @see read() |
97 | * @param Persistent $instance Instance to be loaded. Identity must be set. |
98 | * @return bool true if found, false if not found. |
99 | * @since 0.1.0 |
100 | */ |
101 | public function load( |
102 | Persistent $instance |
103 | ): bool { |
104 | return $this->loadByConditions( [ |
105 | $this->getIdentityColumn() => $instance->getIdentity() |
106 | ], $instance ); |
107 | } |
108 | |
109 | /** |
110 | * Given a persistent domain object instance with at least identity set, |
111 | * updates the database to correspond to the data set in the domain object. |
112 | * |
113 | * @param Persistent $instance |
114 | * @since 0.1.0 |
115 | */ |
116 | public function update( |
117 | Persistent $instance |
118 | ): void { |
119 | $set = $this->serializeFields( $instance ); |
120 | $dbw = $this->getContext()->getDbLoadBalancer()->getConnection( DB_PRIMARY ); |
121 | $dbw->update( $this->getTable(), $set, [ |
122 | $this->getIdentityColumn() => $instance->getIdentity() |
123 | ], __METHOD__ ); |
124 | } |
125 | |
126 | /** |
127 | * Given an identity, |
128 | * removes the corresponding persistent domain object from the database. |
129 | * |
130 | * @param mixed $identity |
131 | * @since 0.1.0 |
132 | */ |
133 | public function delete( |
134 | $identity |
135 | ): void { |
136 | $dbw = $this->getContext()->getDbLoadBalancer()->getConnection( DB_PRIMARY ); |
137 | $dbw->delete( $this->getTable(), [ |
138 | $this->getIdentityColumn() => $identity |
139 | ], __METHOD__ ); |
140 | } |
141 | |
142 | /** |
143 | * Picks up a single instance. Creates a new object instance. |
144 | * |
145 | * @param array $conditions See {@link \Wikimedia\Rdbms\IDatabase::select} conditions. |
146 | * @return Persistent|null |
147 | * @since 0.1.0 |
148 | */ |
149 | public function getByConditions( |
150 | array $conditions |
151 | ): ?Persistent { |
152 | $instance = $this->instanceFactory(); |
153 | return $this->loadByConditions( $conditions, $instance ) ? $instance : null; |
154 | } |
155 | |
156 | /** |
157 | * Picks up a single instance. Loads to existing object instance. |
158 | * |
159 | * @param array $conditions See {@link \Wikimedia\Rdbms\IDatabase::select} conditions. |
160 | * @param Persistent $instance Instance to be populated with data. |
161 | * @return bool true if found, false if not found. |
162 | * @since 0.1.0 |
163 | */ |
164 | public function loadByConditions( |
165 | array $conditions, |
166 | Persistent $instance |
167 | ): bool { |
168 | $dbr = $this->getContext()->getDbLoadBalancer()->getConnection( DB_REPLICA ); |
169 | $row = $dbr->selectRow( $this->getTable(), $this->getAllColumns(), $conditions, __METHOD__ ); |
170 | if ( !$row ) { |
171 | return false; |
172 | } |
173 | $rowArray = (array)$row; |
174 | $this->deserializeRowIdentity( $instance, $rowArray ); |
175 | $this->deserializeRow( $instance, $rowArray ); |
176 | return true; |
177 | } |
178 | |
179 | /** |
180 | * @param array $conditions |
181 | * @return Persistent[]|null |
182 | * @since 0.1.0 |
183 | */ |
184 | public function listByConditions( |
185 | array $conditions |
186 | ): ?array { |
187 | $dbr = $this->getContext()->getDbLoadBalancer()->getConnection( DB_REPLICA ); |
188 | $res = $dbr->select( $this->getTable(), $this->getAllColumns(), $conditions, __METHOD__ ); |
189 | $instances = []; |
190 | foreach ( $res as $row ) { |
191 | $rowArray = (array)$row; |
192 | $instance = $this->instanceFactory(); |
193 | $this->deserializeRowIdentity( $instance, $rowArray ); |
194 | $this->deserializeRow( $instance, $rowArray ); |
195 | array_push( $instances, $instance ); |
196 | } |
197 | return $instances; |
198 | } |
199 | |
200 | /** |
201 | * Reads all class fields except the identity field from the row. |
202 | * |
203 | * @param mixed $instance An instance of the corresponding underlying Persistent subclass. |
204 | * @param array $row |
205 | * @since 0.1.0 |
206 | */ |
207 | abstract protected function deserializeRow( |
208 | $instance, |
209 | array $row |
210 | ): void; |
211 | |
212 | /** |
213 | * @param Persistent $instance |
214 | * @param array $row |
215 | * @since 0.1.0 |
216 | */ |
217 | abstract protected function deserializeRowIdentity( |
218 | Persistent $instance, |
219 | $row |
220 | ): void; |
221 | |
222 | /** |
223 | * Adds all class fields except for the identity field |
224 | * to the array using the table column name as key. |
225 | * |
226 | * Used to execute create- and update statements. |
227 | * |
228 | * @param mixed $instance An instance of the corresponding underlying Persistent subclass. |
229 | * @return array |
230 | * @since 0.1.0 |
231 | */ |
232 | abstract protected function serializeFields( |
233 | $instance |
234 | ): array; |
235 | |
236 | /** |
237 | * @param array $row |
238 | * @param string $columnName |
239 | * @return string|null |
240 | * @since 0.1.0 |
241 | */ |
242 | protected function deserializeString( array $row, string $columnName ): ?string { |
243 | if ( !array_key_exists( $columnName, $row ) ) { |
244 | return null; |
245 | } |
246 | return $row[$columnName] !== null ? strval( $row[$columnName] ) : null; |
247 | } |
248 | |
249 | /** |
250 | * @param array $row |
251 | * @param string $columnName |
252 | * @return int|null |
253 | * @since 0.1.0 |
254 | */ |
255 | protected function deserializeInt( array $row, string $columnName ): ?int { |
256 | if ( !array_key_exists( $columnName, $row ) ) { |
257 | return null; |
258 | } |
259 | return $row[$columnName] !== null ? intval( $row[$columnName] ) : null; |
260 | } |
261 | |
262 | /** |
263 | * @param array $row |
264 | * @param string $columnName |
265 | * @return string|null |
266 | * @since 0.1.0 |
267 | */ |
268 | protected function deserializeUuid( array $row, string $columnName ): ?string { |
269 | if ( !array_key_exists( $columnName, $row ) ) { |
270 | return null; |
271 | } |
272 | return $row[$columnName] !== null ? Uuid::asBytes( strval( $row[$columnName] ) ) : null; |
273 | } |
274 | |
275 | /** |
276 | * @param array $row |
277 | * @param string $columnName |
278 | * @return MWTimestamp|null |
279 | * @since 0.1.0 |
280 | */ |
281 | protected function deserializeTimestamp( array $row, string $columnName ): ?MWTimestamp { |
282 | if ( !array_key_exists( $columnName, $row ) ) { |
283 | return null; |
284 | } |
285 | return $row[$columnName] !== null ? new MWTimestamp( $row[$columnName] ) : null; |
286 | } |
287 | } |