2019-06-21 01:01:38 +00:00
|
|
|
<?php
|
|
|
|
/**
|
2019-06-25 19:04:28 +00:00
|
|
|
* Handles reports CSV export batches.
|
2019-06-21 01:01:38 +00:00
|
|
|
*
|
|
|
|
* @package WooCommerce/Export
|
|
|
|
*/
|
|
|
|
|
2019-08-01 16:49:55 +00:00
|
|
|
namespace Automattic\WooCommerce\Admin;
|
|
|
|
|
2019-06-21 01:01:38 +00:00
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
2019-10-24 16:41:16 +00:00
|
|
|
use \Automattic\WooCommerce\Admin\API\Reports\ExportableInterface;
|
|
|
|
|
2019-06-21 01:01:38 +00:00
|
|
|
/**
|
|
|
|
* Include dependencies.
|
|
|
|
*/
|
|
|
|
if ( ! class_exists( 'WC_CSV_Batch_Exporter', false ) ) {
|
|
|
|
include_once WC_ABSPATH . 'includes/export/abstract-wc-csv-batch-exporter.php';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-08-12 21:52:09 +00:00
|
|
|
* ReportCSVExporter Class.
|
2019-06-21 01:01:38 +00:00
|
|
|
*/
|
2019-08-12 21:52:09 +00:00
|
|
|
class ReportCSVExporter extends \WC_CSV_Batch_Exporter {
|
2019-06-21 01:01:38 +00:00
|
|
|
/**
|
|
|
|
* Type of report being exported.
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $report_type;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parameters for the report query.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $report_args;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* REST controller for the report.
|
|
|
|
*
|
|
|
|
* @var WC_REST_Reports_Controller
|
|
|
|
*/
|
|
|
|
protected $controller;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*
|
|
|
|
* @param string $type Report type. E.g. 'customers'.
|
|
|
|
* @param array $args Report parameters.
|
|
|
|
*/
|
2019-06-27 02:06:11 +00:00
|
|
|
public function __construct( $type = false, $args = array() ) {
|
2019-06-21 01:01:38 +00:00
|
|
|
parent::__construct();
|
|
|
|
|
2019-06-27 02:06:11 +00:00
|
|
|
if ( ! empty( $type ) ) {
|
|
|
|
$this->set_report_type( $type );
|
|
|
|
$this->set_column_names( $this->get_report_columns() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! empty( $args ) ) {
|
|
|
|
$this->set_report_args( $args );
|
|
|
|
}
|
2019-06-21 01:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setter for report type.
|
|
|
|
*
|
|
|
|
* @param string $type The report type. E.g. customers.
|
|
|
|
*/
|
|
|
|
public function set_report_type( $type ) {
|
|
|
|
$this->report_type = $type;
|
|
|
|
$this->export_type = "admin_{$type}_report";
|
2019-06-25 19:04:28 +00:00
|
|
|
$this->filename = "wc-{$type}-report-export";
|
2019-06-21 01:01:38 +00:00
|
|
|
$this->controller = $this->map_report_controller();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setter for report args.
|
|
|
|
*
|
|
|
|
* @param array $args The report args.
|
|
|
|
*/
|
|
|
|
public function set_report_args( $args ) {
|
|
|
|
// Use our own internal limit and include all extended info.
|
|
|
|
$report_args = array_merge(
|
|
|
|
$args,
|
|
|
|
array(
|
|
|
|
'per_page' => $this->get_limit(),
|
|
|
|
'extended_info' => true,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
// Should this happen externally?
|
|
|
|
if ( isset( $report_args['page'] ) ) {
|
|
|
|
$this->set_page( $report_args['page'] );
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->report_args = $report_args;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a REST controller instance for the report type.
|
|
|
|
*
|
|
|
|
* @return bool|WC_REST_Reports_Controller Report controller instance or boolean false on error.
|
|
|
|
*/
|
|
|
|
protected function map_report_controller() {
|
2019-10-24 16:41:16 +00:00
|
|
|
// @todo - Add filter to this list.
|
2019-06-21 01:01:38 +00:00
|
|
|
$controller_map = array(
|
2019-08-03 02:26:35 +00:00
|
|
|
'products' => 'Automattic\WooCommerce\Admin\API\Reports\Products\Controller',
|
|
|
|
'variations' => 'Automattic\WooCommerce\Admin\API\Reports\Variations\Controller',
|
|
|
|
'orders' => 'Automattic\WooCommerce\Admin\API\Reports\Orders\Controller',
|
|
|
|
'categories' => 'Automattic\WooCommerce\Admin\API\Reports\Categories\Controller',
|
|
|
|
'taxes' => 'Automattic\WooCommerce\Admin\API\Reports\Taxes\Controller',
|
|
|
|
'coupons' => 'Automattic\WooCommerce\Admin\API\Reports\Coupons\Controller',
|
|
|
|
'stock' => 'Automattic\WooCommerce\Admin\API\Reports\Stock\Controller',
|
|
|
|
'downloads' => 'Automattic\WooCommerce\Admin\API\Reports\Downloads\Controller',
|
|
|
|
'customers' => 'Automattic\WooCommerce\Admin\API\Reports\Customers\Controller',
|
2019-10-24 16:41:16 +00:00
|
|
|
'revenue' => 'Automattic\WooCommerce\Admin\API\Reports\Revenue\Stats\Controller',
|
2019-06-21 01:01:38 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
if ( isset( $controller_map[ $this->report_type ] ) ) {
|
2019-06-25 19:04:28 +00:00
|
|
|
// Load the controllers if accessing outside the REST API.
|
|
|
|
if ( ! did_action( 'rest_api_init' ) ) {
|
|
|
|
do_action( 'rest_api_init' );
|
|
|
|
}
|
|
|
|
|
2019-06-21 01:01:38 +00:00
|
|
|
return new $controller_map[ $this->report_type ]();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Should this do something else?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-10-24 16:41:16 +00:00
|
|
|
* Get the report columns from the controller.
|
2019-06-21 01:01:38 +00:00
|
|
|
*
|
|
|
|
* @return array Array of report column names.
|
|
|
|
*/
|
|
|
|
protected function get_report_columns() {
|
2019-10-24 16:41:16 +00:00
|
|
|
// Default to the report's defined export columns.
|
|
|
|
if ( $this->controller instanceof ExportableInterface ) {
|
|
|
|
return $this->controller->get_export_columns();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fallback to generating columns from the report schema.
|
2019-06-21 01:01:38 +00:00
|
|
|
$report_columns = array();
|
|
|
|
$report_schema = $this->controller->get_item_schema();
|
|
|
|
|
|
|
|
if ( isset( $report_schema['properties'] ) ) {
|
|
|
|
foreach ( $report_schema['properties'] as $column_name => $column_info ) {
|
|
|
|
// Expand extended info columns into export.
|
|
|
|
if ( 'extended_info' === $column_name ) {
|
2019-06-24 21:40:41 +00:00
|
|
|
// Remove columns with questionable CSV values, like markup.
|
|
|
|
$extended_info = array_diff( array_keys( $column_info ), array( 'image' ) );
|
|
|
|
$report_columns = array_merge( $report_columns, $extended_info );
|
2019-06-21 01:01:38 +00:00
|
|
|
} else {
|
|
|
|
$report_columns[] = $column_name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $report_columns;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get total % complete.
|
|
|
|
*
|
|
|
|
* Forces an int from parent::get_percent_complete(), which can return a float.
|
|
|
|
*
|
|
|
|
* @return int Percent complete.
|
|
|
|
*/
|
|
|
|
public function get_percent_complete() {
|
|
|
|
return intval( parent::get_percent_complete() );
|
|
|
|
}
|
|
|
|
|
2019-06-25 19:04:28 +00:00
|
|
|
/**
|
|
|
|
* Get total number of rows in export.
|
|
|
|
*
|
|
|
|
* @return int Number of rows to export.
|
|
|
|
*/
|
|
|
|
public function get_total_rows() {
|
|
|
|
return $this->total_rows;
|
|
|
|
}
|
|
|
|
|
2019-06-21 01:01:38 +00:00
|
|
|
/**
|
|
|
|
* Prepare data for export.
|
|
|
|
*/
|
|
|
|
public function prepare_data_to_export() {
|
2019-11-12 18:15:55 +00:00
|
|
|
$request = new \WP_REST_Request( 'GET', "/wc-analytics/reports/{$this->report_type}" );
|
2019-06-24 18:57:07 +00:00
|
|
|
$params = $this->controller->get_collection_params();
|
|
|
|
$defaults = array();
|
|
|
|
|
|
|
|
foreach ( $params as $arg => $options ) {
|
|
|
|
if ( isset( $options['default'] ) ) {
|
|
|
|
$defaults[ $arg ] = $options['default'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$request->set_default_params( $defaults );
|
2019-06-21 01:01:38 +00:00
|
|
|
$request->set_query_params( $this->report_args );
|
|
|
|
|
2019-10-24 16:41:16 +00:00
|
|
|
// Does the controller have an export-specific item retrieval method?
|
|
|
|
// @todo - Potentially revisit. This is only for /revenue/stats/.
|
|
|
|
if ( is_callable( array( $this->controller, 'get_export_items' ) ) ) {
|
|
|
|
$response = $this->controller->get_export_items( $request );
|
|
|
|
} else {
|
|
|
|
$response = $this->controller->get_items( $request );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use WP_REST_Server::response_to_data() to embed links in data.
|
|
|
|
add_filter( 'woocommerce_rest_check_permissions', '__return_true' );
|
|
|
|
$rest_server = rest_get_server();
|
|
|
|
$report_data = $rest_server->response_to_data( $response, true );
|
|
|
|
remove_filter( 'woocommerce_rest_check_permissions', '__return_true' );
|
|
|
|
|
2019-06-21 01:01:38 +00:00
|
|
|
$report_meta = $response->get_headers();
|
|
|
|
$this->total_rows = $report_meta['X-WP-Total'];
|
|
|
|
$this->row_data = array_map( array( $this, 'generate_row_data' ), $report_data );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-10-24 16:41:16 +00:00
|
|
|
* Generate row data from a raw report item.
|
2019-06-21 01:01:38 +00:00
|
|
|
*
|
|
|
|
* @param object $item Report item data.
|
|
|
|
* @return array CSV row data.
|
|
|
|
*/
|
2019-10-24 16:41:16 +00:00
|
|
|
protected function get_raw_row_data( $item ) {
|
2019-06-21 01:01:38 +00:00
|
|
|
$columns = $this->get_column_names();
|
|
|
|
$row = array();
|
|
|
|
|
|
|
|
// Expand extended info.
|
|
|
|
if ( isset( $item['extended_info'] ) ) {
|
2019-06-21 16:38:36 +00:00
|
|
|
// Pull extended info property from report item object.
|
2019-06-24 21:40:41 +00:00
|
|
|
$extended_info = (array) $item['extended_info'];
|
2019-06-21 01:01:38 +00:00
|
|
|
unset( $item['extended_info'] );
|
2019-06-21 16:38:36 +00:00
|
|
|
|
|
|
|
// Merge extended info columns into report item object.
|
2019-06-21 01:01:38 +00:00
|
|
|
$item = array_merge( $item, $extended_info );
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ( $columns as $column_id => $column_name ) {
|
|
|
|
$value = isset( $item[ $column_name ] ) ? $item[ $column_name ] : null;
|
|
|
|
|
|
|
|
if ( has_filter( "woocommerce_export_{$this->export_type}_column_{$column_name}" ) ) {
|
|
|
|
// Filter for 3rd parties.
|
2019-06-21 16:36:18 +00:00
|
|
|
$value = apply_filters( "woocommerce_export_{$this->export_type}_column_{$column_name}", '', $item );
|
2019-06-21 01:01:38 +00:00
|
|
|
|
|
|
|
} elseif ( is_callable( array( $this, "get_column_value_{$column_name}" ) ) ) {
|
|
|
|
// Handle special columns which don't map 1:1 to item data.
|
2019-06-21 16:36:18 +00:00
|
|
|
$value = $this->{"get_column_value_{$column_name}"}( $item, $this->export_type );
|
2019-06-21 16:40:06 +00:00
|
|
|
|
|
|
|
} elseif ( ! is_scalar( $value ) ) {
|
|
|
|
// Ensure that the value is somewhat readable in CSV.
|
|
|
|
$value = wp_json_encode( $value );
|
2019-06-21 01:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$row[ $column_id ] = $value;
|
|
|
|
}
|
|
|
|
|
2019-10-24 16:41:16 +00:00
|
|
|
return $row;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the export row for a given report item.
|
|
|
|
*
|
|
|
|
* @param object $item Report item data.
|
|
|
|
* @return array CSV row data.
|
|
|
|
*/
|
|
|
|
protected function generate_row_data( $item ) {
|
|
|
|
// Default to the report's export method.
|
|
|
|
if ( $this->controller instanceof ExportableInterface ) {
|
|
|
|
$row = $this->controller->prepare_item_for_export( $item );
|
|
|
|
} else {
|
|
|
|
// Fallback to raw report data.
|
|
|
|
$row = $this->get_raw_row_data( $item );
|
|
|
|
}
|
|
|
|
|
2019-06-21 01:01:38 +00:00
|
|
|
return apply_filters( "woocommerce_export_{$this->export_type}_row_data", $row, $item );
|
|
|
|
}
|
|
|
|
}
|