DB.php
7.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
<?php
/**
* @license GPL-2.0
*
* Modified by learndash on 20-September-2023 using Strauss.
* @see https://github.com/BrianHenryIE/strauss
*/
namespace StellarWP\Learndash\StellarWP\DB;
use Exception;
use StellarWP\Learndash\StellarWP\DB\Database\Exceptions\DatabaseQueryException;
use StellarWP\Learndash\StellarWP\DB\QueryBuilder\Clauses\RawSQL;
use StellarWP\Learndash\StellarWP\DB\QueryBuilder\QueryBuilder;
use WP_Error;
/**
* Class DB
*
* A static decorator for the $wpdb class and decorator function which does SQL error checking when performing queries.
* If a SQL error occurs a DatabaseQueryException is thrown.
*
* @method static int|bool query(string $query)
* @method static int|false insert(string $table, array $data, array|string|null $format = null)
* @method static int|false delete(string $table, array $where, array|string|null $where_format = null)
* @method static int|false update(string $table, array $data, array $where, array|string|null $format = null, array|string|null $where_format = null)
* @method static int|false replace(string $table, array $data, array|string|null $format = null)
* @method static null|string get_var(string|null $query = null, int $x = 0, int $y = 0)
* @method static array|object|null|void get_row(string|null $query = null, string $output = OBJECT, int $y = 0)
* @method static array get_col(string|null $query = null, int $x = 0)
* @method static array|object|null get_results(string|null $query = null, string $output = OBJECT)
* @method static string get_charset_collate()
* @method static string esc_like(string $text)
* @method static string remove_placeholder_escape(string $text)
* @method static Config config()
*/
class DB {
/**
* Is this library initialized?
*
* @var bool
*/
private static $initialized = false;
/**
* The Database\Provider instance.
*
* @var Database\Provider
*/
private static $provider;
/**
* Initializes the service provider.
*
* @since 1.0.0
*/
public static function init(): void {
if ( ! self::$initialized ) {
return;
}
self::$provider = new Database\Provider();
self::$provider->register();
self::$initialized = true;
}
/**
* Runs the dbDelta function and returns a WP_Error with any errors that occurred during the process
*
* @see dbDelta() for parameter and return details
*
* @since 1.0.0
*
* @param $delta
*
* @return array
* @throws DatabaseQueryException
*/
public static function delta( $delta ) {
return self::runQueryWithErrorChecking(
function () use ( $delta ) {
return dbDelta( $delta );
}
);
}
/**
* A convenience method for the $wpdb->prepare method
*
* @see WPDB::prepare() for usage details
*
* @since 1.0.0
*
* @param string $query
* @param mixed ...$args
*
* @return false|mixed
*/
public static function prepare( $query, ...$args ) {
global $wpdb;
return $wpdb->prepare( $query, ...$args );
}
/**
* Magic method which calls the static method on the $wpdb while performing error checking
*
* @since 1.0.0 add givewp_db_pre_query action
* @since 1.0.0
*
* @param $name
* @param $arguments
*
* @return mixed
* @throws DatabaseQueryException
*/
public static function __callStatic( $name, $arguments ) {
return self::runQueryWithErrorChecking(
static function () use ( $name, $arguments ) {
global $wpdb;
if ( in_array( $name, [ 'get_row', 'get_col', 'get_results', 'query' ], true) ) {
$hook_prefix = Config::getHookPrefix();
/**
* Allow for hooking just before query execution.
*
* @since 1.0.0
*
* @param string $argument First argument passed to the $wpdb method.
* @param string $hook_prefix Prefix for the hook.
*/
do_action( 'stellarwp_db_pre_query', current( $arguments ), $hook_prefix );
if ( $hook_prefix ) {
/**
* Allow for hooking just before query execution.
*
* @since 1.0.0
*
* @param string $argument First argument passed to the $wpdb method.
* @param string $hook_prefix Prefix for the hook.
*/
do_action( "{$hook_prefix}_stellarwp_db_pre_query", current( $arguments ), $hook_prefix );
}
}
return call_user_func_array( [ $wpdb, $name ], $arguments );
}
);
}
/**
* Get last insert ID
*
* @since 1.0.0
* @return int
*/
public static function last_insert_id() {
global $wpdb;
return $wpdb->insert_id;
}
/**
* Prefix given table name with $wpdb->prefix
*
* @param string $tableName
*
* @return string
*/
public static function prefix( $tableName ) {
global $wpdb;
return $wpdb->prefix . $tableName;
}
/**
* Create QueryBuilder instance
*
* @param string|RawSQL $table
* @param null|string $alias
*
* @return QueryBuilder
*/
public static function table( $table, $alias = null ) {
$builder = new QueryBuilder();
$builder->from( $table, $alias );
return $builder;
}
/**
* Runs a transaction. If the callable works then the transaction is committed. If the callable throws an exception
* then the transaction is rolled back.
*
* @since 1.0.0
*
* @param callable $callback
*
* @return void
* @throws Exception
*/
public static function transaction( callable $callback ) {
self::beginTransaction();
try {
$callback();
} catch ( Exception $e ) {
self::rollback();
throw $e;
}
self::commit();
}
/**
* Manually starts a transaction
*
* @since 1.0.0
*
* @return void
*/
public static function beginTransaction() {
global $wpdb;
$wpdb->query( 'START TRANSACTION' );
}
/**
* Manually rolls back a transaction
*
* @since 1.0.0
*
* @return void
*/
public static function rollback() {
global $wpdb;
$wpdb->query( 'ROLLBACK' );
}
/**
* Manually commits a transaction
*
* @since 1.0.0
*
* @return void
*/
public static function commit() {
global $wpdb;
$wpdb->query( 'COMMIT' );
}
/**
* Used as a flag to tell QueryBuilder not to process the provided SQL
* If $args are provided, we will assume that dev wants to use DB::prepare method with raw SQL
*
* @param string $sql
* @param array ...$args
*
* @return RawSQL
*/
public static function raw( $sql, ...$args ) {
return new RawSQL( $sql, ...$args );
}
/**
* Runs a query callable and checks to see if any unique SQL errors occurred when it was run
*
* @since 1.0.0
*
* @param Callable $queryCaller
*
* @return mixed
* @throws DatabaseQueryException
*/
private static function runQueryWithErrorChecking( $queryCaller ) {
global $wpdb, $EZSQL_ERROR;
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
$errorCount = is_array( $EZSQL_ERROR ) ? count( $EZSQL_ERROR ) : 0;
$hasShowErrors = $wpdb->hide_errors();
$output = $queryCaller();
if ( $hasShowErrors ) {
$wpdb->show_errors();
}
$wpError = self::getQueryErrors( $errorCount );
if ( ! empty( $wpError->errors ) ) {
/** @var DatabaseQueryException */
$exception_class = Config::getDatabaseQueryException();
throw new $exception_class( $wpdb->last_query, $wpError->errors );
}
return $output;
}
/**
* Retrieves the SQL errors stored by WordPress
*
* @since 1.0.0
*
* @param int $initialCount
*
* @return WP_Error
*/
private static function getQueryErrors( $initialCount = 0 ) {
global $EZSQL_ERROR;
$wpError = new WP_Error();
if ( is_array( $EZSQL_ERROR ) ) {
for ( $index = $initialCount, $indexMax = count( $EZSQL_ERROR ); $index < $indexMax; $index++ ) {
$error = $EZSQL_ERROR[ $index ];
if ( empty( $error['error_str'] ) || empty( $error['query'] ) || 0 === strpos(
$error['query'],
'DESCRIBE '
) ) {
continue;
}
$wpError->add( 'db_delta_error', $error['error_str'] );
}
}
return $wpError;
}
}