PluginProbe
Packeta / 2.0.9
Packeta v2.0.9
2.3.2 2.3.1 trunk 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 All 56 releases
packeta / src / Packetery / Module / WpdbAdapter.php

WpdbAdapter.php in Packeta 2.0.9, at src/Packetery/Module/WpdbAdapter.php

459 lines 11.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class WpdbAdapter
4 *
5 * @package Packetery
6 */
7
8 declare( strict_types=1 );
9
10 namespace Packetery\Module;
11
12 use Packetery\Tracy\Debugger;
13 use WC_Logger;
14
15 /**
16 * Class WpdbAdapter
17 *
18 * @package Packetery
19 */
20 class WpdbAdapter {
21
22 /**
23 * Table name.
24 *
25 * @var string
26 */
27 public $packeteryCarrier;
28
29 /**
30 * Table name.
31 *
32 * @var string
33 */
34 public $packeteryOrder;
35
36 /**
37 * Table name.
38 *
39 * @var string
40 */
41 public $packeteryLog;
42
43 /**
44 * Table name.
45 *
46 * @var string
47 */
48 public $packeteryCustomsDeclaration;
49
50 /**
51 * Table name.
52 *
53 * @var string
54 */
55 public $packeteryCustomsDeclarationItem;
56
57 /**
58 * Table name.
59 *
60 * @var string
61 */
62 public $wcOrders;
63
64 /**
65 * Table name.
66 *
67 * @var string
68 */
69 public $posts;
70
71 /**
72 * Table name.
73 *
74 * @var string
75 */
76 public $options;
77
78 /**
79 * Table name.
80 *
81 * @var string
82 */
83 public $postmeta;
84
85 /**
86 * Wpdb.
87 *
88 * @var \wpdb
89 */
90 private $wpdb;
91
92 /**
93 * Constructor.
94 *
95 * @param \wpdb $wpdb Wpdb.
96 */
97 public function __construct( \wpdb $wpdb ) {
98 $this->wpdb = $wpdb;
99 }
100
101 /**
102 * @param string $query SQL query.
103 * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
104 * correspond to an stdClass object, an associative array, or a numeric array,
105 * respectively. Default OBJECT.
106 *
107 * @return array<string, mixed>|object|null Database query result or null on failure.
108 */
109 public function get_row( string $query, string $output = OBJECT ) {
110 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
111 $result = $this->wpdb->get_row( $query, $output );
112 if ( $result === null ) {
113 $this->handleError();
114 }
115
116 return $result;
117 }
118
119 /**
120 * Prepares a SQL query for safe execution.
121 *
122 * @param string $query Query.
123 * @param mixed ...$args Arguments.
124 *
125 * @return string
126 */
127 public function prepare( string $query, ...$args ): string {
128 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
129 $result = $this->wpdb->prepare( $query, ...$args );
130 if ( $result === null ) {
131 $this->logError( 'Query to prepare is invalid. Likely due placeholder count mismatch.' );
132 }
133
134 return (string) $result;
135 }
136
137 /**
138 * Executes SQL query.
139 *
140 * @param string $query Query.
141 *
142 * @return int|bool Boolean true for CREATE, ALTER, TRUNCATE and DROP queries. Number of rows
143 * affected/selected for all other queries. Boolean false on error.
144 */
145 public function query( string $query ) {
146 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
147 $result = $this->wpdb->query( $query );
148 if ( $result === false ) {
149 $this->handleError();
150 }
151
152 return $result;
153 }
154
155 /**
156 * Helper function for insert and replace.
157 *
158 * @param string $table Table name.
159 * @param array<string, mixed> $data Data to insert (in column => value pairs).
160 * @param string[]|null $format Optional. An array of formats to be mapped to each of the value in $data.
161 * @param string $type Optional. Type of operation. Possible values include 'INSERT' or 'REPLACE'.
162 *
163 * @return int|false The number of rows affected, or false on error.
164 */
165 public function insertReplaceHelper( string $table, array $data, ?array $format = null, string $type = 'INSERT' ) {
166 $result = $this->wpdb->_insert_replace_helper( $table, $data, $format, $type );
167 if ( $result === false ) {
168 $this->handleError();
169 }
170
171 return $result;
172 }
173
174 /**
175 * Deletes a row in the table.
176 *
177 * @param string $table Table name.
178 * @param array<string, int|string> $where A named array of WHERE clauses (in column => value pairs).
179 * @param string|null $whereFormat Optional. An array of formats to be mapped to each of the values in $where.
180 *
181 * @return int|false The number of rows updated, or false on error.
182 */
183 public function delete( string $table, array $where, ?string $whereFormat = null ) {
184 $result = $this->wpdb->delete( $table, $where, $whereFormat );
185 if ( $result === false ) {
186 $this->handleError();
187 }
188
189 return $result;
190 }
191
192 /**
193 * Inserts a row into the table.
194 *
195 * @param string $table Table name.
196 * @param array<string, mixed> $data Data to insert (in column => value pairs).
197 *
198 * @return int|false The number of rows inserted, or false on error.
199 */
200 public function insert( string $table, array $data ) {
201 $result = $this->wpdb->insert( $table, $data );
202 if ( $result === false ) {
203 $this->handleError();
204 }
205
206 return $result;
207 }
208
209 /**
210 * Updates a row in the table.
211 *
212 * @param string $table Table name.
213 * @param array<string, int|float|string|null|bool> $data Data to update (in column => value pairs).
214 * @param array<string, int|string> $where A named array of WHERE clauses (in column => value pairs).
215 *
216 * @return int|false The number of rows updated, or false on error.
217 */
218 public function update( string $table, array $data, array $where ) {
219 $result = $this->wpdb->update( $table, $data, $where );
220 if ( $result === false ) {
221 $this->handleError();
222 }
223
224 return $result;
225 }
226
227 /**
228 * Gets charset collate.
229 *
230 * @return string
231 */
232 public function get_charset_collate(): string {
233 return $this->wpdb->get_charset_collate();
234 }
235
236 /**
237 * Retrieves an entire SQL result set from the database (i.e., many rows).
238 *
239 * @param string $query SQL query.
240 * @param string $output Optional. Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants.
241 *
242 * @return array|object[]|null Database query results.
243 */
244 public function get_results( string $query, string $output = OBJECT ): ?array {
245 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
246 $result = $this->wpdb->get_results( $query, $output );
247 $this->handleError();
248
249 return $result;
250 }
251
252 /**
253 * Retrieves one variable from the database.
254 *
255 * @param string $query SQL query. Defaults to null, use the result from the previous query.
256 *
257 * @return string|null Database query result (as string), or null on failure.
258 */
259 public function get_var( string $query ): ?string {
260 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
261 $result = $this->wpdb->get_var( $query );
262 if ( $result === null ) {
263 $this->handleError();
264 }
265
266 return $result;
267 }
268
269 /**
270 * Tells if packetery table is queried.
271 *
272 * @param string $query Query.
273 *
274 * @return bool
275 */
276 private function isPacketeryTableQueried( string $query ): bool {
277 return preg_match( '~\s*(FROM|JOIN|INTO|UPDATE|TABLE)\s*`?' . preg_quote( $this->getPacketeryPrefix(), '~' ) . '~i', $query ) === 1;
278 }
279
280 /**
281 * Gets packetery prefix.
282 *
283 * @return string
284 */
285 public function getPacketeryPrefix(): string {
286 return sprintf( '%spacketery_', $this->wpdb->prefix );
287 }
288
289 /**
290 * Logs wpdb error.
291 *
292 * @param string $errorMessage Error message.
293 *
294 * @return void
295 */
296 private function logError( string $errorMessage ): void {
297 Debugger::log( $errorMessage, sprintf( 'wpdb-errors_%s', gmdate( 'Y-m-d' ) ) );
298 }
299
300 /**
301 * Handles wpdb error.
302 *
303 * @return void
304 */
305 private function handleError(): void {
306 if ( $this->getLastWpdbError() !== '' && $this->isPacketeryTableQueried( (string) $this->wpdb->last_query ) ) {
307 $this->logError( $this->getLastWpdbError() );
308 }
309 }
310
311 /**
312 * Gets last wpdb error.
313 *
314 * @return string
315 */
316 public function getLastWpdbError(): string {
317 return $this->wpdb->last_error;
318 }
319
320 /**
321 * Gets wpdb queries.
322 *
323 * @return \Generator
324 */
325 public function getWpdbQueries(): \Generator {
326 if ( $this->wpdb->queries !== null ) {
327 foreach ( $this->wpdb->queries as $queryInfo ) {
328 yield $queryInfo;
329 }
330 }
331 }
332
333 /**
334 * This method outputs a one dimensional array. If more than one column is returned by the query,
335 * only the specified column will be returned, but the entire result is cached for later use.
336 *
337 * @param string $query The query you wish to execute. Setting this parameter to null will return the specified column from the cached results of the previous query.
338 * @param int $columnOffset The desired column (0 being the first). Defaults to 0.
339 *
340 * @return array<int|float|string|null|bool> Returns an empty array if no result is found.
341 */
342 public function get_col( string $query, int $columnOffset = 0 ): array {
343 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
344 $result = $this->wpdb->get_col( $query, $columnOffset );
345 if ( $result === [] ) {
346 $this->handleError();
347 }
348
349 return $result;
350 }
351
352 /**
353 * Quote array of strings.
354 *
355 * @param string[] $input Input.
356 *
357 * @return string[]
358 */
359 private function quoteArrayOfStrings( array $input ): array {
360 return array_map(
361 function ( string $item ) {
362 return $this->prepare( '%s', $item );
363 },
364 $input
365 );
366 }
367
368 /**
369 * Prepare IN clause from array of strings.
370 *
371 * @param string[] $input Input array.
372 *
373 * @return string
374 */
375 public function prepareInClause( array $input ): string {
376 return implode( ',', $this->quoteArrayOfStrings( $input ) );
377 }
378
379 /**
380 * Wrapper for dbDelta function, logs result.
381 *
382 * @param string $createTableQuery Create table query.
383 * @param string $tableName Table name.
384 *
385 * @return bool
386 */
387 public function dbDelta( string $createTableQuery, string $tableName ): bool {
388 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
389 $result1 = dbDelta( $createTableQuery );
390 $result2 = dbDelta( $createTableQuery );
391
392 /**
393 * WC logger.
394 *
395 * @var WC_Logger $wcLogger
396 */
397 $wcLogger = wc_get_logger();
398 foreach ( $result1 as $tableOrColumn => $message ) {
399 $wcLogger->info( sprintf( 'dbDelta: %s => %s', $tableOrColumn, $message ), [ 'source' => 'packeta' ] );
400 }
401
402 // If the first command tries to create the table and so does the second, it means it failed.
403 // Otherwise, we assume everything is fine.
404 $parsedResult1 = $this->parseDbdeltaOutput( $result1 );
405 $parsedResult2 = $this->parseDbdeltaOutput( $result2 );
406 if (
407 in_array( $tableName, $parsedResult1['created_tables'], true ) &&
408 in_array( $tableName, $parsedResult2['created_tables'], true )
409 ) {
410 return false;
411 }
412
413 return true;
414 }
415
416 /**
417 * Parses the output given by dbDelta and returns information about it. Taken from DatabaseUtil 7.5.1.
418 *
419 * @param array<int|string, string> $dbdeltaOutput The output from the execution of dbDelta.
420 *
421 * @return array{created_tables: array<int<0, max>, (int|string)>} An array containing a 'created_tables' key whose value is an array with the names of the tables that have been (or would have been) created.
422 */
423 private function parseDbdeltaOutput( array $dbdeltaOutput ): array {
424 $createdTables = [];
425
426 foreach ( $dbdeltaOutput as $tableName => $result ) {
427 if ( "Created table $tableName" === $result ) {
428 $createdTables[] = $tableName;
429 }
430 }
431
432 return [ 'created_tables' => $createdTables ];
433 }
434
435 /**
436 * Gets last insert ID.
437 *
438 * @return string|null
439 */
440 public function getLastInsertId(): ?string {
441 if ( $this->wpdb->insert_id === 0 ) {
442 return null;
443 }
444
445 return (string) $this->wpdb->insert_id;
446 }
447
448 /**
449 * Wpdb esc_like method proxy.
450 *
451 * @param string $text Text to escape.
452 *
453 * @return string
454 */
455 public function escLike( string $text ): string {
456 return $this->wpdb->esc_like( $text );
457 }
458 }
459