-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathclass-issues-query.php
More file actions
279 lines (214 loc) · 7.42 KB
/
Copy pathclass-issues-query.php
File metadata and controls
279 lines (214 loc) · 7.42 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
<?php
/**
* Class file for querying issues from the db
*
* @package Accessibility_Checker
*/
namespace EDAC\Admin;
/**
* Class that handles calculating scan report data
*/
class Issues_Query {
const FLAG_EXCLUDE_IGNORED = 0; // default.
const FLAG_INCLUDE_IGNORED = 1;
const FLAG_ONLY_IGNORED = 2;
const FLAG_INCLUDE_ALL_POST_TYPES = 4; // If enabled, will ignore the post_type filter and return results for all post types.
const RULETYPE_WARNING = 'warning';
const RULETYPE_ERROR = 'error';
const RULETYPE_COLOR_CONTRAST = 'color_contrast';
/**
* Name of table that stores issues
*
* @var string
*/
private $table;
/**
* Holds the max number of records we'll query
*
* @var [integer]
*/
private $record_limit;
/**
* Holds the sql safe elements used to build the query
*
* @var array
*/
private $query = [
'select' => 'select count(*)',
'from' => '',
'where_base' => '',
'filters' => '',
'limit' => '',
];
/**
* Constructor
*
* @param array $filter [post_types, rule_types, rule_slugs].
* @param integer $record_limit Max number of records we'll query.
* @param string $flags Flag used to determine how ignored issues sould be handled.
*/
public function __construct( $filter = [], $record_limit = 100000, $flags = self::FLAG_EXCLUDE_IGNORED ) {
$valid_filters = [
'post_types',
'rule_types',
'rule_slugs',
];
$validated_filters = [];
foreach ( $filter as $key => $val ) {
if ( in_array( $key, $valid_filters, true ) ) {
$validated_filters[ $key ] = $val;
}
}
$this->record_limit = $record_limit;
// Setup FROM.
global $wpdb;
$this->table = edac_get_valid_table_name( $wpdb->prefix . 'accessibility_checker' );
$this->query['from'] = " FROM {$this->table} ";
// Setup base WHERE.
$siteid = get_current_blog_id();
if ( $flags & self::FLAG_INCLUDE_IGNORED ) {
$this->query['where_base'] = $wpdb->prepare( 'WHERE siteid=%d', [ $siteid ] );
} elseif ( $flags & self::FLAG_ONLY_IGNORED ) {
$this->query['where_base'] = $wpdb->prepare( 'WHERE siteid=%d and (ignre=%d or ignre_global=%d) ', [ $siteid, 1, 1 ] );
} else { // This is the default.
$this->query['where_base'] = $wpdb->prepare( 'WHERE siteid=%d and ignre=%d and ignre_global=%d ', [ $siteid, 0, 0 ] );
}
// Exclude manual issues from all scanner counts; source IS NULL covers rows
// inserted before the 1.0.9 migration backfill has run.
$this->query['where_base'] .= " AND (source = 'automated' OR source IS NULL)";
$filter_defaults = [
'post_types' => [],
'rule_types' => [],
'rule_slugs' => [],
];
$filter = array_replace_recursive( $filter_defaults, $validated_filters );
// flag for including all post types is set, so remove that from the filters.
if ( $flags & self::FLAG_INCLUDE_ALL_POST_TYPES ) {
unset( $filter['post_types'] );
}
$this->add_filters( $filter );
if ( empty( $filter['post_types'] ) && false === ( $flags & self::FLAG_INCLUDE_ALL_POST_TYPES ) ) {
// no post_types were pass in, but the flag for including all post types is not set.
$this->query['filters'] .= ' and 1!=1'; // forces false so no results are returned.
}
// Setup LIMIT.
$this->query['limit'] = $wpdb->prepare( 'LIMIT %d', [ $record_limit ] );
}
/**
* Returns the prepared (safe) sql to be used for the query
*
* @return string $sql .
*/
public function get_sql() {
return $this->query['select'] . ' ' . $this->query['from'] . ' ' . $this->query['where_base'] . ' ' . $this->query['filters'] . ' ' . $this->query['limit'];
}
/**
* Returns the query array that can be used to build a custom query
*
* @return array $query .
*/
public function get_query() {
return $this->query;
}
/**
* Are the results from all the issues or did we truncate
*
* @return boolean
*/
public function has_truncated_results() {
global $wpdb;
$sql = 'SELECT COUNT(*) ' . $this->query['from'];
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$total_issues_count = $wpdb->get_var( $sql );
if ( $total_issues_count > $this->record_limit ) {
return true;
}
return false;
}
/**
* Gets issue count.
*
* @return integer issue_count .
*/
public function count() {
global $wpdb;
$this->query['select'] = 'SELECT COUNT(id) ';
$sql = $this->get_sql();
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_var( $sql );
}
/**
* Gets distinct issue count.
*
* @return integer issue_count .
*/
public function distinct_count() {
global $wpdb;
$this->query['select'] = 'SELECT COUNT( DISTINCT rule, object ) ';
$sql = $this->get_sql();
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_var( $sql );
}
/**
* Gets distinct posts count.
*
* @return integer posts_count .
*/
public function distinct_posts_count() {
global $wpdb;
$this->query['select'] = 'SELECT COUNT( DISTINCT postid ) ';
$sql = $this->get_sql();
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_var( $sql );
}
/**
* Get the ids of the issues.
*
* @return array issues .
*/
public function get_ids() {
global $wpdb;
$this->query['select'] = 'SELECT id';
$sql = $this->get_sql();
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
return $wpdb->get_results( $sql );
}
/**
* Adds the filters to be used by the query.
*
* @param array $filter .
*
* @return void
*/
private function add_filters( $filter ) {
if ( array_key_exists( 'post_types', $filter ) && count( $filter['post_types'] ) ) {
$scannable_post_types = Settings::get_scannable_post_types();
$post_types = array_intersect( $filter['post_types'], $scannable_post_types );
if ( count( $post_types ) ) {
$this->query['filters'] .= ' and type IN (' . Helpers::array_to_sql_safe_list( $post_types ) . ') ';
}
}
if ( array_key_exists( 'rule_types', $filter ) && ! empty( $filter['rule_types'] ) ) {
// Special handler for color contrast rule/ruletype.
if ( in_array( self::RULETYPE_COLOR_CONTRAST, $filter['rule_types'], true ) ) {
// We are filtering by color contrast but color contrast is a rule not a ruletype.
// Remove color_contrast from the rule_type filter.
$key = array_search( self::RULETYPE_COLOR_CONTRAST, $filter['rule_types'], true );
if ( false !== $key ) {
unset( $filter['rule_types'][ $key ] );
}
// Then add color_contrast_failure to the rule_slugs filter.
$key = array_search( 'color_contrast_failure', $filter['rule_slugs'], true );
if ( ! $key ) {
$filter['rule_slugs'][] = 'color_contrast_failure';
}
}
if ( ! empty( $filter['rule_types'] ) ) {
$this->query['filters'] .= ' and ruletype IN (' . Helpers::array_to_sql_safe_list( $filter['rule_types'] ) . ') ';
}
}
if ( array_key_exists( 'rule_slugs', $filter ) && ! empty( $filter['rule_slugs'] ) ) {
$this->query['filters'] .= ' and rule IN (' . Helpers::array_to_sql_safe_list( $filter['rule_slugs'] ) . ') ';
}
}
}