PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.14.2
Independent Analytics – WordPress Analytics Plugin v2.14.2
2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / IAWP / Rows / Filter.php
independent-analytics / IAWP / Rows Last commit date
Campaign_Landing_Pages.php 5 months ago Campaign_UTM_Campaigns.php 5 months ago Campaign_UTM_Mediums.php 5 months ago Campaign_UTM_Sources.php 5 months ago Campaigns.php 5 months ago Cities.php 5 months ago Countries.php 5 months ago Device_Browsers.php 5 months ago Device_OSS.php 5 months ago Device_Types.php 5 months ago Filter.php 5 months ago Forms.php 5 months ago Journeys.php 5 months ago Link_Patterns.php 5 months ago Links.php 5 months ago Pages.php 5 months ago Referrer_Types.php 5 months ago Referrers.php 5 months ago Rows.php 5 months ago
Filter.php
211 lines
1 <?php
2
3 namespace IAWP\Rows;
4
5 use IAWP\Tables\Columns\Column;
6 use IAWP\Utils\Format;
7 use IAWP\Utils\Timezone;
8 use IAWPSCOPED\Illuminate\Database\Query\Builder;
9 use IAWPSCOPED\Illuminate\Support\Str;
10 /** @internal */
11 class Filter
12 {
13 public static string $RECORD_FILTER = 'record';
14 public static string $AGGREGATE_FILTER = 'aggregate';
15 public static string $OUTER_FILTER = 'outer';
16 private string $inclusion;
17 private string $operator;
18 private string $operand;
19 private Column $column;
20 public function __construct(array $filter)
21 {
22 $this->inclusion = $filter['inclusion'];
23 $this->operator = $filter['operator'];
24 $this->operand = $filter['operand'];
25 $this->column = $filter['column'];
26 }
27 public function apply_to_query(Builder $query, string $filter_type, bool $in_or_chain = \false) : void
28 {
29 if ($this->column->id() === 'category') {
30 $this->apply_category_filter($query, $in_or_chain);
31 return;
32 }
33 if ($this->query_value_to_match() === 'is_not_null' && $this->query_operator() === '=') {
34 $query->whereNotNull($this->query_column($filter_type));
35 return;
36 }
37 if ($this->query_value_to_match() === 'is_not_null' && $this->query_operator() === '!=') {
38 $query->whereNull($this->query_column($filter_type));
39 return;
40 }
41 $method = $this->query_method($in_or_chain, $filter_type);
42 $query->{$method}($this->query_column($filter_type), $this->query_operator(), $this->query_value_to_match());
43 }
44 public function html_description() : string
45 {
46 $condition = $this->as_associative_array();
47 $full_string = '';
48 foreach ($condition as $key => $value) {
49 if (!\in_array($key, ['inclusion', 'column', 'operator', 'operand', 'name'])) {
50 continue;
51 }
52 if ($key == 'column') {
53 continue;
54 }
55 $condition_string = '';
56 if ($key == 'inclusion' && $value == 'include') {
57 $condition_string = \esc_html__('Include', 'independent-analytics');
58 } elseif ($key == 'inclusion' && $value == 'exclude') {
59 $condition_string = \esc_html__('Exclude', 'independent-analytics');
60 } elseif ($key == 'operator' && $value == 'lesser') {
61 $condition_string = '<';
62 } elseif ($key == 'operator' && $value == 'greater') {
63 $condition_string = '>';
64 } elseif ($key == 'operator' && $value == 'equal') {
65 $condition_string = '=';
66 } elseif ($key == 'operator' && $value == 'on') {
67 $condition_string = \esc_html__('On', 'independent-analytics');
68 } elseif ($key == 'operator' && $value == 'before') {
69 $condition_string = \esc_html__('Before', 'independent-analytics');
70 } elseif ($key == 'operator' && $value == 'after') {
71 $condition_string = \esc_html__('After', 'independent-analytics');
72 } elseif ($key == 'operator' && $value == 'contains') {
73 $condition_string = \esc_html__('Contains', 'independent-analytics');
74 } elseif ($key == 'operator' && $value == 'exact') {
75 $condition_string = \esc_html__('Exactly matches', 'independent-analytics');
76 } elseif ($key == 'operator' && $value == 'is') {
77 $condition_string = \esc_html__('Is', 'independent-analytics');
78 } elseif ($key == 'operator' && $value == 'isnt') {
79 $condition_string = \esc_html__("Isn't", 'independent-analytics');
80 } elseif ($key == 'operand' && $this->column->options()) {
81 $condition_string = $this->column->options()->label_for($value);
82 } elseif ($key == 'operand' && $condition['column'] == 'date') {
83 try {
84 $date = \DateTime::createFromFormat('U', $value, Timezone::utc_timezone());
85 $condition_string = $date->format(Format::date());
86 } catch (\Throwable $e) {
87 $condition_string = $value;
88 }
89 } else {
90 $condition_string = $value;
91 }
92 if ($key == 'name' || $key == 'operand') {
93 $condition_string = '<strong>' . $condition_string . '</strong> ';
94 }
95 $full_string .= $condition_string . ' ';
96 }
97 return \trim($full_string);
98 }
99 public function column() : string
100 {
101 return $this->column->id();
102 }
103 public function is_concrete_column() : bool
104 {
105 return $this->column->is_concrete_column();
106 }
107 public function is_calculated_column() : bool
108 {
109 return !$this->column->is_concrete_column();
110 }
111 public function as_associative_array() : array
112 {
113 // The order of the elements here matters
114 return ['inclusion' => $this->inclusion, 'name' => $this->column->name(), 'column' => $this->column->id(), 'operator' => $this->operator, 'operand' => $this->operand];
115 }
116 private function query_method(bool $in_or_chain, string $filter_type) : string
117 {
118 if ($filter_type === \IAWP\Rows\Filter::$AGGREGATE_FILTER) {
119 if ($in_or_chain) {
120 return 'orHaving';
121 }
122 return 'having';
123 }
124 if ($in_or_chain) {
125 return 'orWhere';
126 }
127 return 'where';
128 }
129 private function query_column(string $filter_type) : string
130 {
131 $column = $this->column->separate_database_column() ?? $this->column->separate_filter_column() ?? $this->column->id();
132 if ($filter_type === \IAWP\Rows\Filter::$OUTER_FILTER) {
133 $column = Str::afterLast($column, '.');
134 }
135 return $column;
136 }
137 // Use early returns here to make it more obvious what $result value is actually used
138 // without reading to the end
139 private function query_operator() : string
140 {
141 $operator = $this->operator;
142 $result = '';
143 if ($operator === 'equal' || $operator === 'is' || $operator === 'exact' || $operator === 'on') {
144 $result = '=';
145 }
146 if ($operator === 'contains') {
147 $result = 'like';
148 }
149 if ($operator === 'isnt') {
150 $result = '!=';
151 }
152 if ($operator === 'greater' || $operator === 'after') {
153 $result = '>';
154 }
155 if ($operator === 'lesser' || $operator === 'before') {
156 $result = '<';
157 }
158 if ($this->inclusion === 'exclude') {
159 if ($result === '=') {
160 return '!=';
161 } elseif ($result === '!=') {
162 return '=';
163 } elseif ($result === '>') {
164 return '<=';
165 } elseif ($result === '<') {
166 return '>=';
167 } elseif ($result === 'like') {
168 return 'not like';
169 }
170 }
171 return $result;
172 }
173 private function query_value_to_match() : string
174 {
175 if ($this->operator === 'contains') {
176 return '%' . $this->operand . '%';
177 }
178 // if ($this->column->id() === 'cached_date') {
179 if ($this->column->id() === 'date') {
180 try {
181 $date = \DateTime::createFromFormat('U', $this->operand, Timezone::utc_timezone());
182 } catch (\Throwable $e) {
183 $date = new \DateTime();
184 }
185 return $date->format('Y-m-d');
186 }
187 // ID is fine here, but should use whatever method gives the database column
188 if (\in_array($this->column->id(), ['wc_gross_sales', 'wc_refunded_amount', 'wc_net_sales', 'wc_earnings_per_visitor', 'wc_average_order_volume'])) {
189 return \strval(\floatval($this->operand) * 100);
190 }
191 return $this->operand;
192 }
193 private function apply_category_filter(Builder $query, bool $in_or_chain) : void
194 {
195 $wp_query = new \WP_Query(['posts_per_page' => -1, 'cat' => $this->operand, 'fields' => 'ids']);
196 $post_ids = $wp_query->posts;
197 $include = $this->inclusion === 'include';
198 $is = $this->operator === 'is';
199 $method = $in_or_chain ? 'orWhere' : 'where';
200 if ($include === $is) {
201 $query->{$method}(function (Builder $query) use($post_ids) {
202 $query->whereIn('singular_id', $post_ids);
203 });
204 } else {
205 $query->{$method}(function (Builder $query) use($post_ids) {
206 $query->whereNotIn('singular_id', $post_ids)->orWhereNull('singular_id');
207 });
208 }
209 }
210 }
211