Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
54.76% covered (warning)
54.76%
23 / 42
46.15% covered (danger)
46.15%
6 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
Sessions_By_Location_Controller
53.66% covered (warning)
53.66%
22 / 41
46.15% covered (danger)
46.15%
6 / 13
59.81
0.00% covered (danger)
0.00%
0 / 1
 get_report_key
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_report_label
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_data_endpoint
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_column_headers
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 format_row_for_csv
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 get_location_label
57.14% covered (warning)
57.14%
4 / 7
0.00% covered (danger)
0.00%
0 / 1
6.97
 get_default_values
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 get_additional_params
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 get_fields
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 get_matching_field
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_identifying_fields
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_empty_row_check_field
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 apply_empty_row_label
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * REST API Reports Sessions by Location controller class.
4 *
5 * @package Automattic\Jetpack\PremiumAnalytics\Reports\Export\Exports
6 */
7
8declare( strict_types=1 );
9
10namespace Automattic\Jetpack\PremiumAnalytics\Reports\Export\Exports;
11
12defined( 'ABSPATH' ) || exit;
13
14use Automattic\Jetpack\PremiumAnalytics\Reports\Export\Abstract_Csv_Report_Controller;
15
16/**
17 * Sessions by Location CSV Export Controller.
18 *
19 * Handles CSV exports for the Sessions by Location report.
20 * Note: This is a ranked list report, not a time-series report.
21 * Comparison mode is supported using ID-based merging (matching by country_code).
22 *
23 * @since $$next-version$$
24 */
25class Sessions_By_Location_Controller extends Abstract_Csv_Report_Controller {
26
27    /**
28     * Get the report key for this controller.
29     *
30     * @return string The report key.
31     */
32    public function get_report_key(): string {
33        return 'sessionsbylocation';
34    }
35
36    /**
37     * Get the report label for this controller.
38     *
39     * @return string The report label.
40     */
41    public function get_report_label(): string {
42        return __( 'Sessions by Location', 'jetpack-premium-analytics' );
43    }
44
45    /**
46     * Get the data endpoint for this controller.
47     *
48     * @return string The data endpoint.
49     */
50    public function get_data_endpoint(): string {
51        return 'reports/sessions/by-location';
52    }
53
54    /**
55     * Get the column headers for this controller.
56     *
57     * @param string|null $interval Optional time interval for dynamic headers.
58     * @return array The column headers.
59     */
60    public function get_column_headers( ?string $interval = null ): array { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Signature required by the report controller interface.
61        return array(
62            'location' => __( 'Location', 'jetpack-premium-analytics' ),
63            'visitors' => __( 'Visitors', 'jetpack-premium-analytics' ),
64        );
65    }
66
67    /**
68     * Format a row for CSV export.
69     *
70     * Empty rows (empty label) are handled by the parent via get_empty_row_check_field()
71     * and get_empty_row_label(); do not skip them here.
72     *
73     * @param array       $item     The row data.
74     * @param string|null $interval Optional time interval for formatting.
75     * @return array The formatted row.
76     */
77    public function format_row_for_csv( array $item, ?string $interval = null ): array { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Signature required by the report controller interface.
78        $defaults = $this->get_default_values();
79        $location = $this->get_location_label( $item );
80
81        return array(
82            'location' => $location ? $location : $defaults['label'],
83            'visitors' => $item['visitors'] ?? $defaults['visitors'],
84        );
85    }
86
87    /**
88     * Get the location label, translated when possible via WooCommerce countries.
89     *
90     * Uses the store's locale for country names when country_code is present;
91     * otherwise falls back to the API label.
92     *
93     * @param array $item Row data with optional 'country_code' and 'label'.
94     * @return string Location label for CSV.
95     */
96    private function get_location_label( array $item ): string {
97        $country_code = $item['country_code'] ?? '';
98        $api_label    = $item['label'] ?? '';
99
100        if ( $country_code && function_exists( 'WC' ) && WC()->countries ) {
101            $countries = WC()->countries->get_countries();
102            if ( isset( $countries[ $country_code ] ) ) {
103                return $countries[ $country_code ];
104            }
105        }
106
107        return $api_label;
108    }
109
110    /**
111     * Get default values for missing data fields.
112     *
113     * @return array Array of field_name => default_value pairs.
114     */
115    public function get_default_values(): array {
116        return array(
117            'label'        => '',
118            'country_code' => '',
119            'visitors'     => 0,
120        );
121    }
122
123    /**
124     * Get additional request parameters for data fetching.
125     *
126     * Sets group_by to country and limit to 100.
127     *
128     * @return array Additional parameters to include in data requests.
129     */
130    public function get_additional_params(): array {
131        return array(
132            'group_by' => 'country',
133            'limit'    => 100,
134        );
135    }
136
137    /**
138     * Get the list of API fields needed for this report.
139     *
140     * @return array
141     */
142    public function get_fields(): array {
143        return array(
144            'country_code',
145            'label',
146            'visitors',
147        );
148    }
149
150    /**
151     * Get the matching field for comparison data alignment.
152     *
153     * Sessions by Location is a ranked report, so comparison data should be matched by country_code.
154     *
155     * @return string|null
156     */
157    public function get_matching_field(): ?string {
158        return 'country_code';
159    }
160
161    /**
162     * Get the identifying fields that should be preserved in comparison data.
163     *
164     * When a location exists in the original period but not in the comparison period,
165     * the label should still be shown for clarity.
166     *
167     * @return array Array of field names to preserve.
168     */
169    public function get_identifying_fields(): array {
170        return array( 'label' );
171    }
172
173    /**
174     * Get the field name to check for emptiness.
175     *
176     * Enables parent empty row handling: rows with empty label are either skipped
177     * or included with the customizable empty row label (e.g. "Unassigned").
178     *
179     * @return array The field names to check.
180     */
181    public function get_empty_row_check_field() {
182        return array( 'label' );
183    }
184
185    /**
186     * Apply the custom empty row label to the formatted row.
187     *
188     * Overridden because the API field is 'label' but the CSV column is 'location'.
189     *
190     * @param array $row          The formatted row data.
191     * @param array $check_fields The field names that were empty.
192     * @return array The row with custom label applied.
193     */
194    protected function apply_empty_row_label( array $row, array $check_fields ): array { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Signature required by the report controller interface.
195        $custom_label = $this->get_empty_row_label();
196        if ( isset( $row['location'] ) && '' === $row['location'] ) {
197            $row['location'] = $custom_label;
198        }
199        return $row;
200    }
201}