/wp-content/plugins/google-listings-and-ads/src/API/Google/MerchantReport.php

https://gitlab.com/remyvianne/krowkaramel · PHP · 206 lines · 119 code · 28 blank · 59 comment · 14 complexity · f1e99e306a8248555a7cdffb6be4b8b6 MD5 · raw file

  1. <?php
  2. declare( strict_types=1 );
  3. namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google;
  4. use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
  5. use Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query\MerchantFreeListingReportQuery;
  6. use Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query\MerchantProductReportQuery;
  7. use Automattic\WooCommerce\GoogleListingsAndAds\Exception\InvalidValue;
  8. use Automattic\WooCommerce\GoogleListingsAndAds\Options\OptionsAwareInterface;
  9. use Automattic\WooCommerce\GoogleListingsAndAds\Options\OptionsAwareTrait;
  10. use Automattic\WooCommerce\GoogleListingsAndAds\Product\ProductHelper;
  11. use DateTime;
  12. use Exception;
  13. use Google\Exception as GoogleException;
  14. use Google\Service\ShoppingContent;
  15. use Google\Service\ShoppingContent\ReportRow;
  16. use Google\Service\ShoppingContent\Segments;
  17. /**
  18. * Trait MerchantReportTrait
  19. *
  20. * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google
  21. */
  22. class MerchantReport implements OptionsAwareInterface {
  23. use OptionsAwareTrait;
  24. use ReportTrait;
  25. /**
  26. * The shopping service.
  27. *
  28. * @var ShoppingContent
  29. */
  30. protected $service;
  31. /**
  32. * Product helper class.
  33. *
  34. * @var ProductHelper
  35. */
  36. protected $product_helper;
  37. /**
  38. * Merchant Report constructor.
  39. *
  40. * @param ShoppingContent $service
  41. * @param ProductHelper $product_helper
  42. */
  43. public function __construct( ShoppingContent $service, ProductHelper $product_helper ) {
  44. $this->service = $service;
  45. $this->product_helper = $product_helper;
  46. }
  47. /**
  48. * Get report data for free listings.
  49. *
  50. * @param string $type Report type (free_listings or products).
  51. * @param array $args Query arguments.
  52. *
  53. * @return array
  54. * @throws Exception If the report data can't be retrieved.
  55. */
  56. public function get_report_data( string $type, array $args ): array {
  57. try {
  58. if ( 'products' === $type ) {
  59. $query = new MerchantProductReportQuery( $args );
  60. } else {
  61. $query = new MerchantFreeListingReportQuery( $args );
  62. }
  63. $results = $query
  64. ->set_client( $this->service, $this->options->get_merchant_id() )
  65. ->get_results();
  66. $this->init_report_totals( $args['fields'] ?? [] );
  67. foreach ( $results->getResults() as $row ) {
  68. $this->add_report_row( $type, $row, $args );
  69. }
  70. if ( $results->getNextPageToken() ) {
  71. $this->report_data['next_page'] = $results->getNextPageToken();
  72. }
  73. // Sort intervals to generate an ordered graph.
  74. if ( isset( $this->report_data['intervals'] ) ) {
  75. ksort( $this->report_data['intervals'] );
  76. }
  77. $this->remove_report_indexes( [ 'products', 'free_listings', 'intervals' ] );
  78. return $this->report_data;
  79. } catch ( GoogleException $e ) {
  80. do_action( 'woocommerce_gla_mc_client_exception', $e, __METHOD__ );
  81. throw new Exception( __( 'Unable to retrieve report data.', 'google-listings-and-ads' ), $e->getCode() );
  82. }
  83. }
  84. /**
  85. * Add data for a report row.
  86. *
  87. * @param string $type Report type (free_listings or products).
  88. * @param ReportRow $row Report row.
  89. * @param array $args Request arguments.
  90. */
  91. protected function add_report_row( string $type, ReportRow $row, array $args ) {
  92. $segments = $row->getSegments();
  93. $metrics = $this->get_report_row_metrics( $row, $args );
  94. if ( 'free_listings' === $type ) {
  95. $this->increase_report_data(
  96. 'free_listings',
  97. 'free',
  98. [
  99. 'subtotals' => $metrics,
  100. ]
  101. );
  102. }
  103. if ( 'products' === $type && $segments ) {
  104. $product_id = $segments->getOfferId();
  105. $this->increase_report_data(
  106. 'products',
  107. (string) $product_id,
  108. [
  109. 'id' => $product_id,
  110. 'subtotals' => $metrics,
  111. ]
  112. );
  113. // Retrieve product title and add to report.
  114. if ( empty( $this->report_data['products'][ $product_id ]['name'] ) ) {
  115. $name = $this->product_helper->get_wc_product_title( (string) $product_id );
  116. $this->report_data['products'][ $product_id ]['name'] = $name;
  117. }
  118. }
  119. if ( $segments && ! empty( $args['interval'] ) ) {
  120. $interval = $this->get_segment_interval( $args['interval'], $segments );
  121. $this->increase_report_data(
  122. 'intervals',
  123. $interval,
  124. [
  125. 'interval' => $interval,
  126. 'subtotals' => $metrics,
  127. ]
  128. );
  129. }
  130. $this->increase_report_totals( $metrics );
  131. }
  132. /**
  133. * Get metrics for a report row.
  134. *
  135. * @param ReportRow $row Report row.
  136. * @param array $args Request arguments.
  137. *
  138. * @return array
  139. */
  140. protected function get_report_row_metrics( ReportRow $row, array $args ): array {
  141. $metrics = $row->getMetrics();
  142. if ( ! $metrics || empty( $args['fields'] ) ) {
  143. return [];
  144. }
  145. $data = [];
  146. foreach ( $args['fields'] as $field ) {
  147. switch ( $field ) {
  148. case 'clicks':
  149. $data['clicks'] = (int) $metrics->getClicks();
  150. break;
  151. case 'impressions':
  152. $data['impressions'] = (int) $metrics->getImpressions();
  153. break;
  154. }
  155. }
  156. return $data;
  157. }
  158. /**
  159. * Get a unique interval index based on the segments data.
  160. *
  161. * Types:
  162. * day = <year>-<month>-<day>
  163. *
  164. * @param string $interval Interval type.
  165. * @param Segments $segments Report segment data.
  166. *
  167. * @return string
  168. * @throws InvalidValue When invalid interval type is given.
  169. */
  170. protected function get_segment_interval( string $interval, Segments $segments ): string {
  171. if ( 'day' !== $interval ) {
  172. throw InvalidValue::not_in_allowed_list( $interval, [ 'day' ] );
  173. }
  174. $date = $segments->getDate();
  175. $date = new DateTime( "{$date->getYear()}-{$date->getMonth()}-{$date->getDay()}" );
  176. return TimeInterval::time_interval_id( $interval, $date );
  177. }
  178. }