Query.php
3.24 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
<?php
/**
* Rule engine query model.
*
* @package ContentControl
* @subpackage Models
*/
namespace ContentControl\Models\RuleEngine;
/**
* Handler for condition queries.
*
* @package ContentControl
*/
class Query {
/**
* Query logical comparison operator.
*
* @var string `and` | `or`
*/
public $logical_operator;
/**
* Query items.
*
* @var Item[]
*/
public $items;
/**
* Build a query.
*
* @param array{logicalOperator:string,items:array<mixed>} $query Query data.
*/
public function __construct( $query ) {
$query = wp_parse_args( $query, [
'logicalOperator' => 'and',
'items' => [],
]);
$this->logical_operator = $query['logicalOperator'];
$this->items = [];
foreach ( $query['items'] as $item ) {
$is_group = ( isset( $item['type'] ) && 'group' === $item['type'] )
|| isset( $item['query'] );
$this->items[] = $is_group ? new Group( $item ) : new Rule( $item );
}
}
/**
* Check if this query has any rules.
*
* @return bool
*/
public function has_rules() {
return ! empty( $this->items );
}
/**
* Check if this query has JS based rules.
*
* @return bool
*/
public function has_js_rules() {
foreach ( $this->items as $item ) {
if ( $item instanceof Rule ) {
if ( $item->is_js_rule() ) {
return true;
}
} elseif ( $item instanceof Group ) {
if ( $item->has_js_rules() ) {
return true;
}
}
}
return false;
}
/**
* Check rules in a recursive nested pattern.
*
* @return bool
*/
public function check_rules() {
$checks = [];
if ( empty( $this->items ) ) {
return true;
}
foreach ( $this->items as $item ) {
// Missing rules should result in restricted content.
$result = false;
if ( $item instanceof Rule ) {
$result = $item->check_rule();
} elseif ( $item instanceof Group ) {
$result = $item->check_rules();
}
$checks[] = $result;
// Bail as early as we can.
if (
// If we have a true result and are using `or`.
( true === $result && 'or' === $this->logical_operator ) ||
// If we have a false result and are using `and`.
( false === $result && 'and' === $this->logical_operator )
) {
break;
}
}
/*
* This method ignores null values (JS conditions),
* if changed, null needs to be accounted for.
*/
if ( 'or' === $this->logical_operator ) {
// If any values are true or null, return true.
return in_array( true, $checks, true );
} else {
// If any values are false, return false.
return ! in_array( false, $checks, true );
}
}
/**
* Return the checks as an array.
*
* Useful for debugging or passing to JS.
*
* @return array<bool|null|array<bool|null>>
*/
public function get_checks() {
$checks = [];
foreach ( $this->items as $item ) {
if ( $item instanceof Rule ) {
$checks[] = $item->get_check();
} elseif ( $item instanceof Group ) {
$checks[] = $item->get_checks();
}
}
return $checks;
}
/**
* Return the checks as an array of information.
*
* Useful for debugging.
*
* @return array<mixed>
*/
public function get_check_info() {
$checks = [];
foreach ( $this->items as $key => $item ) {
$checks[ $key ] = $item->get_check_info();
}
return $checks;
}
}