PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.10.3
Independent Analytics – WordPress Analytics Plugin v2.10.3
2.15.5 2.15.4 2.15.3 2.15.2 2.15.1 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 / Tables / Table.php
independent-analytics / IAWP / Tables Last commit date
Columns 1 year ago Groups 2 years ago Table.php 1 year ago Table_Campaigns.php 1 year ago Table_Clicks.php 1 year ago Table_Devices.php 1 year ago Table_Geo.php 1 year ago Table_Pages.php 1 year ago Table_Referrers.php 1 year ago
Table.php
463 lines
1 <?php
2
3 namespace IAWP\Tables;
4
5 use IAWP\Campaign_Builder;
6 use IAWP\Dashboard_Options;
7 use IAWP\Date_Picker\Date_Picker;
8 use IAWP\Filters;
9 use IAWP\Form_Submissions\Form;
10 use IAWP\Icon_Directory_Factory;
11 use IAWP\Plugin_Group;
12 use IAWP\Rows\Filter;
13 use IAWP\Sort_Configuration;
14 use IAWP\Statistics\Statistics;
15 use IAWP\Tables\Columns\Column;
16 use IAWP\Tables\Groups\Group;
17 use IAWP\Tables\Groups\Groups;
18 use IAWP\Utils\CSV;
19 use IAWP\Utils\Currency;
20 use IAWP\Utils\Number_Formatter;
21 use IAWP\Utils\Security;
22 use IAWP\Utils\Timezone;
23 use IAWP\Utils\URL;
24 use IAWP\Utils\WordPress_Site_Date_Format_Pattern;
25 use IAWPSCOPED\Illuminate\Support\Str;
26 /** @internal */
27 abstract class Table
28 {
29 protected $default_sorting_column = 'visitors';
30 private $filters;
31 private $visible_columns;
32 private $group;
33 private $is_new_group;
34 /** @var ?Statistics */
35 private $statistics;
36 /**
37 * @param string|null $group_id
38 * @param bool $is_new_group
39 */
40 public function __construct(?string $group_id = null, bool $is_new_group = \false)
41 {
42 $this->visible_columns = Dashboard_Options::getInstance()->visible_columns();
43 $this->group = $this->groups()->find_by_id($group_id);
44 $this->is_new_group = $is_new_group;
45 $this->filters = new Filters();
46 }
47 protected abstract function groups() : Groups;
48 /**
49 * @return array<Column>
50 */
51 protected abstract function local_columns() : array;
52 protected abstract function table_name() : string;
53 public function visible_column_ids()
54 {
55 $visible_columns = [];
56 foreach ($this->get_columns() as $column) {
57 if ($column->is_visible()) {
58 $visible_columns[] = $column->id();
59 }
60 }
61 return $visible_columns;
62 }
63 public function group() : Group
64 {
65 return $this->group;
66 }
67 public function column_picker_html() : string
68 {
69 return \IAWPSCOPED\iawp_blade()->run('plugin-group-options', ['option_type' => 'columns', 'option_name' => \__('Toggle Columns', 'independent-analytics'), 'option_icon' => 'columns', 'plugin_groups' => Plugin_Group::get_plugin_groups(), 'options' => $this->get_columns(\true)]);
70 }
71 public function get_table_toolbar_markup()
72 {
73 return \IAWPSCOPED\iawp_blade()->run('tables.table-toolbar', ['plugin_groups' => Plugin_Group::get_plugin_groups(), 'columns' => $this->get_columns(\true), 'groups' => $this->groups(), 'current_group' => $this->group()]);
74 }
75 public function get_table_markup(string $sort_column, string $sort_direction)
76 {
77 return \IAWPSCOPED\iawp_blade()->run('tables.table', ['table' => $this, 'table_name' => $this->table_name(), 'all_columns' => $this->get_columns(), 'visible_column_count' => $this->visible_column_count(), 'number_of_shown_rows' => 0, 'rows' => [], 'render_skeleton' => \true, 'page_size' => \IAWPSCOPED\iawp()->pagination_page_size(), 'sort_column' => $sort_column, 'sort_direction' => $sort_direction, 'has_campaigns' => Campaign_Builder::has_campaigns()]);
78 }
79 public function set_statistics(Statistics $statistics)
80 {
81 $this->statistics = $statistics;
82 }
83 public function get_row_data_attributes($row)
84 {
85 $html = '';
86 foreach ($this->get_columns() as $column) {
87 $id = $column->id();
88 $data_val = $row->{$id}();
89 $html .= ' data-' . \esc_attr($column->id()) . '="' . \esc_attr($data_val) . '"';
90 }
91 return $html;
92 }
93 public function get_cell_content($row, Column $column)
94 {
95 $column_id = $column->id();
96 if (\is_null($row->{$column_id}())) {
97 return '-';
98 }
99 if ($column_id == 'title' && $row->is_deleted()) {
100 return Security::string($row->{$column_id}()) . ' <span class="deleted-label">' . \esc_html__('(deleted)', 'independent-analytics') . '</span>';
101 } elseif ($column_id == 'views') {
102 $views = Number_Formatter::decimal($row->views());
103 // Getting a divide by zero error from the line below?
104 // It's likely an issue with $this->views which is an instance of Views. Make sure the queries there are working.
105 $views_percentage = Number_Formatter::percent($row->views() / $this->statistics->get_statistic('views')->value() * 100, 2);
106 return '<span class="no-wrap">' . Security::string($views) . '</span> <span class="percentage">(' . Security::string($views_percentage) . ')</span>';
107 } elseif ($column_id == 'visitors') {
108 $visitors = Number_Formatter::decimal($row->visitors());
109 $visitors_percentage = Number_Formatter::percent($row->visitors() / $this->statistics->get_statistic('visitors')->value() * 100, 2);
110 return '<span class="no-wrap">' . Security::string($visitors) . '</span> <span class="percentage">(' . Security::string($visitors_percentage) . ')</span>';
111 } elseif ($column_id == 'sessions') {
112 $sessions = Number_Formatter::decimal($row->sessions());
113 $sessions_percentage = Number_Formatter::percent($row->sessions() / $this->statistics->get_statistic('sessions')->value() * 100, 2);
114 return '<span class="no-wrap">' . Security::string($sessions) . '</span> <span class="percentage">(' . Security::string($sessions_percentage) . ')</span>';
115 } elseif ($column_id === 'entrances') {
116 $entrances = Number_Formatter::decimal($row->entrances());
117 $entrances_percentage = Number_Formatter::percent($row->entrances() / $this->statistics->get_statistic('sessions')->value() * 100, 2);
118 return '<span class="no-wrap">' . Security::string($entrances) . '</span> <span class="percentage">(' . Security::string($entrances_percentage) . ')</span>';
119 } elseif ($column_id === 'exits') {
120 $exits = Number_Formatter::decimal($row->exits());
121 $exits_percentage = Number_Formatter::percent($row->exits() / $this->statistics->get_statistic('sessions')->value() * 100, 2);
122 return '<span class="no-wrap">' . Security::string($exits) . '</span> <span class="percentage">(' . Security::string($exits_percentage) . ')</span>';
123 } elseif ($column_id === 'bounce_rate') {
124 return Security::string(Number_Formatter::percent($row->bounce_rate()));
125 } elseif ($column_id === 'average_session_duration' || $column_id === 'average_view_duration') {
126 return Number_Formatter::second_to_minute_timestamp($row->{$column_id}());
127 } elseif ($column_id === 'views_growth' || $column_id === 'visitors_growth' || $column_id === 'wc_conversion_rate' || $column_id === 'exit_percent' || Str::startsWith($column_id, 'form_conversion_rate')) {
128 return Number_Formatter::percent($row->{$column_id}(), 2);
129 } elseif ($column_id == 'url') {
130 if ($row->is_deleted()) {
131 return \urldecode(\esc_url($row->url()));
132 } else {
133 return '<a href="' . \esc_url($row->url(\true)) . '" target="_blank" class="external-link">' . \urldecode(\esc_url($row->url())) . '<span class="dashicons dashicons-external"></span></a>';
134 }
135 } elseif ($column_id == 'author') {
136 return Security::html($row->avatar()) . ' ' . Security::string($row->author());
137 } elseif ($column_id == 'date') {
138 return Security::string(\date(WordPress_Site_Date_Format_Pattern::for_php(), \strtotime($row->date())));
139 } elseif ($column_id == 'type' && \method_exists($row, 'icon') && \method_exists($row, 'type')) {
140 return $row->icon(0) . ' ' . Security::string($row->type());
141 } elseif ($column_id == 'referrer' && $row->has_link()) {
142 return '<a href="' . \esc_url($row->referrer_url()) . '" target="_blank" class="external-link">' . Security::string($row->referrer()) . '<span class="dashicons dashicons-external"></span></a>';
143 } elseif ($column_id === 'device_type') {
144 return Icon_Directory_Factory::device_types()->find($row->device_type()) . Security::string($row->device_type());
145 } elseif ($column_id === 'browser') {
146 return Icon_Directory_Factory::browsers()->find($row->browser()) . Security::string($row->browser());
147 } elseif ($column_id === 'os') {
148 return Icon_Directory_Factory::operating_systems()->find($row->os()) . Security::string($row->os());
149 } elseif ($column_id === 'country') {
150 return Icon_Directory_Factory::flags()->find($row->country_code()) . Security::string($row->country());
151 } elseif ($column_id === 'wc_gross_sales' || $column_id === 'wc_refunded_amount' || $column_id === 'wc_net_sales' || $column_id === 'wc_average_order_volume') {
152 return Security::string(Currency::format($row->{$column_id}()));
153 } elseif ($column_id === 'wc_earnings_per_visitor') {
154 return Security::string(Currency::format($row->{$column_id}(), \false));
155 } elseif ($column_id === 'views_per_session') {
156 return Number_Formatter::decimal($row->{$column_id}(), 2);
157 } elseif ($column_id === 'link_target') {
158 $value = $row->{$column_id}();
159 if (\is_string($value) && URL::new($value)->is_valid_url()) {
160 return '<a href="' . Security::string($value) . '" target="_blank" class="external-link">' . Security::string($value) . '<span class="dashicons dashicons-external"></span></a>';
161 }
162 return $value;
163 } else {
164 return Security::string($row->{$column_id}());
165 }
166 }
167 public function output_report_toolbar()
168 {
169 $options = Dashboard_Options::getInstance();
170 $start = $options->get_date_range()->start()->setTimezone(Timezone::site_timezone());
171 $end = $options->get_date_range()->end()->setTimezone(Timezone::site_timezone());
172 ?>
173 <div id="toolbar" class="toolbar" data-filter-count="<?php
174 echo \count($options->filters());
175 ?>">
176 <div class="date-picker-parent">
177 <div class="modal-parent dates">
178 <button id="dates-button"
179 data-testid="open-calendar"
180 class="iawp-button"
181 data-action="dates#toggleModal"
182 data-dates-target="modalButton"
183 >
184 <span class="dashicons dashicons-calendar-alt"></span>
185 <span class="iawp-label"><?php
186 echo \esc_html($options->get_date_range()->label());
187 ?></span>
188 </button>
189 <div id="modal-dates"
190 class="iawp-modal large dates"
191 data-dates-target="modal"
192 >
193 <?php
194 echo (new Date_Picker($start, $end, $options->relative_range_id()))->calendar_html();
195 ?>
196 </div>
197 </div>
198 </div>
199 <div class="filter-parent">
200 <?php
201 echo $this->filters()->get_filters_html($this->get_columns());
202 ?>
203 </div>
204 <div class="download-options-parent" data-controller="modal">
205 <div class="modal-parent downloads">
206 <button id="download-options" data-modal-target="modalButton" data-action="click->modal#toggleModal" class="download-options">
207 <?php
208 \esc_html_e('Download Report', 'independent-analytics');
209 ?>
210 </button>
211 <div class="iawp-modal small downloads" data-modal-target="modal">
212 <div class="modal-inner">
213 <div class="title-small">
214 <?php
215 \esc_html_e('Choose a format', 'independent-analytics');
216 ?>
217 <span data-report-target="spinner" class="dashicons dashicons-update spin hidden"></span>
218 </div>
219 <div class="download-button-container">
220 <button id="download-csv" class="iawp-button" data-report-target="exportReportTable" data-action="report#exportReportTable">
221 <span class="dashicons dashicons-media-spreadsheet"></span>
222 <span class="iawp-label">
223 <?php
224 \esc_html_e('Download Table CSV', 'independent-analytics');
225 ?>
226 </span>
227 </button>
228 <button id="download-report-statistics-csv" class="iawp-button" data-report-target="exportReportStatistics" data-action="report#exportReportStatistics">
229 <span class="dashicons dashicons-media-spreadsheet"></span>
230 <span class="iawp-label">
231 <?php
232 \esc_html_e('Download Daily Metrics CSV', 'independent-analytics');
233 ?>
234 </span>
235 </button>
236 </div>
237 <div class="download-button-container">
238 <button id="download-pdf" class="iawp-button" data-report-target="exportPDF" data-action="report#exportPDF" disabled="disabled">
239 <span class="dashicons dashicons-pdf"></span>
240 <span class="iawp-label">
241 <?php
242 \esc_html_e('Download PDF', 'independent-analytics');
243 ?>
244 </span>
245 </button>
246 </div>
247 </div>
248 </div>
249 </div>
250 </div>
251 </div><?php
252 }
253 public function filters_template_html() : string
254 {
255 return $this->filters()->get_condition_html($this->get_columns());
256 }
257 public function filters_condition_buttons_html(array $filters) : string
258 {
259 return $this->filters()->condition_buttons_html($filters);
260 }
261 public final function csv(array $rows, bool $is_dashboard_export = \false) : CSV
262 {
263 $columns = $this->get_columns();
264 $csv_header = [];
265 $csv_rows = [];
266 foreach ($columns as $column) {
267 if (!$this->include_column_in_csv($column, $is_dashboard_export)) {
268 continue;
269 }
270 $csv_header[] = $column->name();
271 }
272 foreach ($rows as $row) {
273 $csv_row = [];
274 foreach ($columns as $column) {
275 if (!$this->include_column_in_csv($column, $is_dashboard_export)) {
276 continue;
277 }
278 $column_id = $column->id();
279 $value = $row->{$column_id}();
280 // Todo - This logic is similar to the rendering logic for table cells. This should
281 // all be handled via the column class itself.
282 if (\is_null($value)) {
283 $csv_row[] = '-';
284 } elseif ($column_id === 'date') {
285 $csv_row[] = \date(WordPress_Site_Date_Format_Pattern::for_php(), \strtotime($value));
286 } elseif ($column_id === 'average_session_duration' || $column_id === 'average_view_duration') {
287 $csv_row[] = Number_Formatter::second_to_minute_timestamp($value);
288 } elseif ($column_id === 'views_per_session') {
289 $csv_row[] = Number_Formatter::decimal($value, 2);
290 } elseif ($column_id === 'wc_gross_sales' || $column_id === 'wc_refunded_amount' || $column_id === 'wc_net_sales' || $column_id === 'wc_average_order_volume') {
291 $csv_row[] = Currency::format($value);
292 } elseif ($column_id === 'wc_earnings_per_visitor') {
293 $csv_row[] = Currency::format($value);
294 } else {
295 $csv_row[] = $row->{$column_id}();
296 }
297 }
298 $csv_rows[] = $csv_row;
299 }
300 $csv = new CSV($csv_header, $csv_rows);
301 return $csv;
302 }
303 /**
304 * @param array[] $filters Raw filter associative arrays
305 *
306 * @return Filter[]
307 */
308 public function sanitize_filters(array $filters) : array
309 {
310 return \array_values(\array_filter(\array_map(function ($filter) {
311 return $this->sanitize_filter($filter);
312 }, $filters)));
313 }
314 public function sanitize_filter(array $filter) : ?Filter
315 {
316 $column = $this->get_column($filter['column']);
317 if (\is_null($column)) {
318 return null;
319 }
320 $valid_inclusions = ['include', 'exclude'];
321 if (!\in_array($filter['inclusion'], $valid_inclusions)) {
322 return null;
323 }
324 if (!$column->is_valid_filter_operator($filter['operator'])) {
325 return null;
326 }
327 if (!$column->is_enabled_for_group($this->group())) {
328 return null;
329 }
330 $operand = \trim(Security::string($filter['operand']));
331 if (\strlen($operand) === 0) {
332 return null;
333 }
334 if ($column->database_column() === 'cached_url' && $filter['operator'] === 'exact') {
335 $url = new URL($filter['operand']);
336 if (!$url->is_valid_url()) {
337 $filter['operand'] = \site_url($filter['operand']);
338 }
339 }
340 // Link rules can be archived and then deleted by the user. That means that there's a very
341 // reasonable chance that a report is filtering by an id for a rule that's since been
342 // removed. We need to check and make sure that filters link rules still exist.
343 if ($column->id() === 'link_name') {
344 $match = \false;
345 foreach ($column->options() as $option) {
346 if ((int) $option[0] === (int) $filter['operand']) {
347 $match = \true;
348 }
349 }
350 if (!$match) {
351 return null;
352 }
353 }
354 return new Filter(['inclusion' => Security::string($filter['inclusion']), 'column' => $column->id(), 'operator' => Security::string($filter['operator']), 'operand' => Security::string($filter['operand']), 'database_column' => $column->database_column()]);
355 }
356 public function get_column(string $id) : ?Column
357 {
358 $matches = \array_filter($this->local_columns(), function (Column $column) use($id) {
359 return $column->id() === $id;
360 });
361 $column = \count($matches) === 1 ? \reset($matches) : null;
362 if (\is_null($column) || !$column->is_enabled()) {
363 return null;
364 }
365 return $column;
366 }
367 public function sanitize_sort_parameters(?string $sort_column = null, ?string $sort_direction = 'desc') : Sort_Configuration
368 {
369 if (\is_null($sort_column)) {
370 return new Sort_Configuration($this->default_sorting_column);
371 }
372 $column = $this->get_column($sort_column);
373 if (\is_null($column) || !$column->is_enabled_for_group($this->group)) {
374 return new Sort_Configuration($this->default_sorting_column);
375 }
376 return new Sort_Configuration($sort_column, $sort_direction, $column->is_nullable());
377 }
378 public function get_rendered_template(array $rows, bool $just_rows, string $sort_column, string $sort_direction)
379 {
380 if ($just_rows) {
381 return \IAWPSCOPED\iawp_blade()->run('tables.rows', ['table' => $this, 'table_name' => $this->table_name(), 'all_columns' => $this->get_columns(), 'visible_column_count' => $this->visible_column_count(), 'number_of_shown_rows' => \count($rows), 'rows' => $rows, 'render_skeleton' => \false, 'page_size' => \IAWPSCOPED\iawp()->pagination_page_size(), 'sort_column' => $sort_column, 'sort_direction' => $sort_direction, 'has_campaigns' => Campaign_Builder::has_campaigns()]);
382 }
383 return \IAWPSCOPED\iawp_blade()->run('tables.table', ['table' => $this, 'table_name' => $this->table_name(), 'all_columns' => $this->get_columns(), 'visible_column_count' => $this->visible_column_count(), 'number_of_shown_rows' => \count($rows), 'rows' => $rows, 'render_skeleton' => \false, 'page_size' => \IAWPSCOPED\iawp()->pagination_page_size(), 'sort_column' => $sort_column, 'sort_direction' => $sort_direction, 'has_campaigns' => Campaign_Builder::has_campaigns()]);
384 }
385 protected function get_woocommerce_columns() : array
386 {
387 return [new Column(['id' => 'wc_orders', 'name' => \__('Orders', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_gross_sales', 'name' => \__('Gross Sales', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_refunds', 'name' => \__('Refunds', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_refunded_amount', 'name' => \__('Refunded Amount', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_net_sales', 'name' => \__('Total Sales', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_conversion_rate', 'name' => \__('Conversion Rate', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_earnings_per_visitor', 'name' => \__('Earnings Per Visitor', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int']), new Column(['id' => 'wc_average_order_volume', 'name' => \__('Average Order Volume', 'independent-analytics'), 'plugin_group' => 'ecommerce', 'type' => 'int'])];
388 }
389 protected function get_form_columns() : array
390 {
391 $columns = [new Column(['id' => 'form_submissions', 'name' => \__('Submissions', 'independent-analytics'), 'plugin_group' => 'forms', 'type' => 'int']), new Column(['id' => 'form_conversion_rate', 'name' => \__('Conversion Rate', 'independent-analytics'), 'plugin_group' => 'forms', 'type' => 'int'])];
392 foreach (Form::get_forms() as $form) {
393 $columns[] = new Column(['id' => $form->submissions_column(), 'name' => $form->title() . ' ' . \__('Submissions', 'independent-analytics'), 'plugin_group' => 'forms', 'is_subgroup_plugin_active' => $form->is_plugin_active(), 'plugin_group_header' => $form->plugin_name(), 'type' => 'int']);
394 $columns[] = new Column(['id' => $form->conversion_rate_column(), 'name' => $form->title() . ' ' . \__('Conversion Rate', 'independent-analytics'), 'plugin_group' => 'forms', 'is_subgroup_plugin_active' => $form->is_plugin_active(), 'plugin_group_header' => $form->plugin_name(), 'type' => 'int']);
395 }
396 return $columns;
397 }
398 private function include_column_in_csv(Column $column, bool $is_dashboard_export) : bool
399 {
400 if (!$column->is_visible() && $is_dashboard_export) {
401 return \false;
402 }
403 if (!$column->exportable() && !$is_dashboard_export) {
404 return \false;
405 }
406 if (!$column->is_group_plugin_enabled()) {
407 return \false;
408 }
409 return \true;
410 }
411 /**
412 * @return Column[]
413 */
414 private function get_columns($show_disabled_columns = \false) : array
415 {
416 $columns_for_group = \array_filter($this->local_columns(), function (Column $column) {
417 return $column->is_enabled() && $column->is_enabled_for_group($this->group) && $column->is_subgroup_plugin_enabled();
418 });
419 if ($show_disabled_columns === \true) {
420 } else {
421 $columns_for_group = \array_filter($columns_for_group, function (Column $column) {
422 return $column->is_group_plugin_enabled();
423 });
424 }
425 if (\is_null($this->visible_columns) || \count($this->visible_columns) === 0) {
426 return $columns_for_group;
427 }
428 if (!$this->is_new_group) {
429 return \array_map(function ($column) {
430 $column->set_visibility(\in_array($column->id(), $this->visible_columns));
431 return $column;
432 }, $columns_for_group);
433 }
434 return \array_map(function ($column) {
435 if ($column->is_group_dependent()) {
436 $column->set_visibility(\true);
437 } elseif (!\in_array($column->id(), $this->visible_columns)) {
438 $column->set_visibility(\false);
439 }
440 return $column;
441 }, $columns_for_group);
442 }
443 /**
444 * Get the number of visible columns
445 *
446 * @return int
447 */
448 private function visible_column_count() : int
449 {
450 $visible_columns = 0;
451 foreach ($this->get_columns() as $column) {
452 if ($column->is_visible()) {
453 $visible_columns++;
454 }
455 }
456 return $visible_columns;
457 }
458 private function filters()
459 {
460 return $this->filters;
461 }
462 }
463