PluginProbe
Packeta / 1.5.1
Packeta v1.5.1
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 1.5.1, at src/Packetery/Module/WpdbAdapter.php

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