PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 1.30.0
Independent Analytics – WordPress Analytics Plugin v1.30.0
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 / Queries / Table_Data.php
independent-analytics / IAWP / Queries Last commit date
Campaigns.php 2 years ago Cities.php 2 years ago Countries.php 2 years ago Current_Traffic_Finder.php 3 years ago Device_Browsers.php 2 years ago Device_Operating_Systems.php 2 years ago Device_Types.php 2 years ago Referrers.php 2 years ago Resources.php 2 years ago Table_Data.php 3 years ago Visitors_Over_Time_Finder.php 3 years ago
Table_Data.php
216 lines
1 <?php
2
3 namespace IAWP_SCOPED\IAWP\Queries;
4
5 use IAWP_SCOPED\IAWP\Date_Range\Date_Range;
6 use IAWP_SCOPED\IAWP\Sort_Configuration;
7 use IAWP_SCOPED\IAWP\Statistics\Intervals\Interval;
8 use IAWP_SCOPED\IAWP\Statistics\Statistics;
9 abstract class Table_Data
10 {
11 private $results;
12 private $filtered_results;
13 private $date_range;
14 private $filters;
15 private $sort_configuration;
16 private $chart_interval;
17 public function __construct(Date_Range $date_range, array $filters = [], ?Sort_Configuration $sort_configuration = null, ?Interval $chart_interval = null)
18 {
19 $this->date_range = $date_range;
20 $this->filters = $filters;
21 $this->sort_configuration = $sort_configuration ?? new Sort_Configuration();
22 $this->chart_interval = $chart_interval;
23 $this->rows();
24 }
25 public function rows() : array
26 {
27 /**
28 * You can't remove rows with zero views from results or filtered_results.
29 *
30 * That array is used to figure out which records should be part of the statistics. We don't
31 * want to cut out all rows without views, because they may have previous period views that
32 * we need for filtered quick stats
33 */
34 if (\is_null($this->results)) {
35 $this->results = $this->query();
36 if ($this->has_filters()) {
37 $this->filtered_results = $this->filter_rows($this->results, $this->filters);
38 }
39 }
40 if (!\is_null($this->filtered_results)) {
41 $rows_with_views = \array_filter($this->filtered_results, function ($row) {
42 return $row->views() > 0;
43 });
44 return $this->sort_rows($rows_with_views);
45 }
46 $rows_with_views = \array_filter($this->results, function ($row) {
47 return $row->views() > 0;
48 });
49 return $this->sort_rows($rows_with_views);
50 }
51 public function statistics() : ?Statistics
52 {
53 $statistics_class = $this->statistics_class();
54 if (!$this->has_filters()) {
55 return null;
56 }
57 return new $statistics_class($this->date_range, $this->convert_results_to_ids($this->filtered_results), $this->chart_interval, $this->convert_results_to_resource_ids($this->filtered_results));
58 }
59 public function unfiltered_statistics() : Statistics
60 {
61 $statistics_class = $this->statistics_class();
62 return new $statistics_class($this->date_range, $this->convert_results_to_ids($this->results), $this->chart_interval, $this->has_filters() ? $this->convert_results_to_resource_ids($this->results) : null);
63 }
64 protected abstract function query() : array;
65 protected abstract function statistics_class() : string;
66 protected abstract function convert_results_to_ids($results) : array;
67 protected function convert_results_to_resource_ids(array $results = []) : ?array
68 {
69 return null;
70 }
71 protected final function date_range() : Date_Range
72 {
73 return $this->date_range;
74 }
75 private function has_filters() : bool
76 {
77 return $this->filters !== [];
78 }
79 private function sort_rows($rows)
80 {
81 \usort($rows, function ($a, $b) {
82 $column = $this->sort_configuration->column();
83 if (\method_exists($a, $column) && \method_exists($b, $column)) {
84 $a_val = $a->{$column}();
85 $b_val = $b->{$column}();
86 $switch = $this->sort_configuration->is_ascending() ? 1 : -1;
87 // Null and empty values at bottom in asc and top in desc
88 $a_empty = \is_null($a_val) || \strlen($a_val) === 0;
89 $b_empty = \is_null($b_val) || \strlen($b_val) === 0;
90 if ($a_empty && !$b_empty) {
91 return 1;
92 } elseif ($b_empty && !$a_empty) {
93 return -1;
94 } elseif ($a_empty && $b_empty) {
95 return 0;
96 }
97 // Numbers below letters
98 $a_num = \is_numeric($a_val);
99 $b_num = \is_numeric($b_val);
100 if ($a_num && !$b_num) {
101 return $switch;
102 } elseif ($b_num && !$a_num) {
103 return $switch * -1;
104 }
105 return (\strtolower($a_val) <=> \strtolower($b_val)) * $switch;
106 } else {
107 return 0;
108 }
109 });
110 return $rows;
111 }
112 private function filter_rows(array $rows, array $filters)
113 {
114 $filtered_rows = [];
115 foreach ($rows as $row) {
116 $match_count = 0;
117 foreach ($filters as $filter) {
118 if (self::include_row($row, $filter)) {
119 $match_count++;
120 }
121 }
122 if ($match_count == \count($filters)) {
123 $filtered_rows[] = $row;
124 }
125 }
126 return $filtered_rows;
127 }
128 private function include_row($row, $filter)
129 {
130 $inclusion = $filter['inclusion'];
131 $column = $filter['column'];
132 $operator = $filter['operator'];
133 $operand = \strtolower($filter['operand']);
134 $column_data_type = null;
135 $match = \false;
136 // This is a temporary way to get the type for a given column
137 if (\in_array($operator, ['contains', 'exact'])) {
138 $column_data_type = 'string';
139 } elseif (\in_array($operator, ['greater', 'lesser', 'equal'])) {
140 $column_data_type = 'int';
141 }
142 if ($column_data_type === 'int') {
143 if ($operator === 'greater') {
144 if ($row->{$column}() > $operand) {
145 $match = \true;
146 }
147 } elseif ($operator === 'lesser') {
148 if ($row->{$column}() < $operand && !\is_null($row->{$column}())) {
149 $match = \true;
150 }
151 } elseif ($operator === 'equal') {
152 if ($row->{$column}() == $operand) {
153 $match = \true;
154 }
155 }
156 } elseif ($column_data_type === 'string') {
157 $value = \strtolower($row->{$column}());
158 if ($operator == 'contains') {
159 if (\strpos($value, $operand) !== \false) {
160 $match = \true;
161 }
162 } elseif ($operator == 'exact') {
163 if ($value == $operand) {
164 $match = \true;
165 }
166 }
167 } elseif ($filter['column'] == 'referrer_type') {
168 $referrer_type = \strtolower($row->referrer_type());
169 if ($filter['operator'] == 'is' && $referrer_type == $operand) {
170 $match = \true;
171 } elseif ($filter['operator'] == 'isnt' && $referrer_type != $operand) {
172 $match = \true;
173 }
174 } elseif ($filter['column'] == 'author') {
175 if ($filter['operator'] == 'is' && $row->author_id() == $operand) {
176 $match = \true;
177 } elseif ($filter['operator'] == 'isnt' && $row->author_id() != $operand) {
178 $match = \true;
179 }
180 } elseif ($filter['column'] == 'type') {
181 if ($filter['operator'] == 'is' && $row->type(\true) == $operand) {
182 $match = \true;
183 } elseif ($filter['operator'] == 'isnt' && $row->type(\true) != $operand) {
184 $match = \true;
185 }
186 } elseif ($filter['column'] == 'date') {
187 // Don't "continue" or row won't be included when excluding
188 if ($row->date() != null) {
189 $date = new \DateTime($operand);
190 if ($filter['operator'] == 'before' && $row->date() < $date->format('U')) {
191 $match = \true;
192 } elseif ($filter['operator'] == 'after' && $row->date() > $date->format('U')) {
193 $match = \true;
194 } elseif ($filter['operator'] == 'on') {
195 $formatted_date = \DateTime::createFromFormat('U', $row->date());
196 $formatted_date = $formatted_date->format('Y-m-d');
197 if ($date->format('Y-m-d') == $formatted_date) {
198 $match = \true;
199 }
200 }
201 }
202 } elseif ($filter['column'] == 'category') {
203 if ($filter['operator'] == 'is' && \in_array($operand, $row->category(\false) ?? [])) {
204 $match = \true;
205 } elseif ($filter['operator'] == 'isnt' && !\in_array($operand, $row->category(\false) ?? [])) {
206 $match = \true;
207 }
208 }
209 if ($filter['inclusion'] == 'include' && $match || $filter['inclusion'] == 'exclude' && !$match) {
210 return \true;
211 } else {
212 return \false;
213 }
214 }
215 }
216