HEX
Server: LiteSpeed
System: Linux eko108.isimtescil.net 4.18.0-477.21.1.lve.1.el8.x86_64 #1 SMP Tue Sep 5 23:08:35 UTC 2023 x86_64
User: uyarreklamcomtr (11202)
PHP: 7.4.33
Disabled: opcache_get_status
Upload Files
File: /var/www/vhosts/uyarreklam.com.tr/httpdocs/Query.tar
AttributeMappingRulesQuery.php000064400000002727151547443000012610 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\DB\Query;

use Automattic\WooCommerce\GoogleListingsAndAds\DB\Query;
use Automattic\WooCommerce\GoogleListingsAndAds\DB\Table\AttributeMappingRulesTable;
use wpdb;

defined( 'ABSPATH' ) || exit;

/**
 * Class defining the queries for the Attribute Mapping Rules Table
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\DB\Query
 */
class AttributeMappingRulesQuery extends Query {

	/**
	 * AttributeMappingRulesQuery constructor.
	 *
	 * @param wpdb                       $wpdb
	 * @param AttributeMappingRulesTable $table
	 */
	public function __construct( wpdb $wpdb, AttributeMappingRulesTable $table ) {
		parent::__construct( $wpdb, $table );
	}

	/**
	 * Sanitize a value for a given column before inserting it into the DB.
	 *
	 * @param string $column The column name.
	 * @param mixed  $value  The value to sanitize.
	 *
	 * @return mixed The sanitized value.
	 */
	protected function sanitize_value( string $column, $value ) {
		if ( $column === 'attribute' || $column === 'source' ) {
			return sanitize_text_field( $value );
		}

		if ( $column === 'categories' && is_null( $value ) ) {
			return '';
		}

		return $value;
	}

	/**
	 * Gets a specific rule from Database
	 *
	 * @param int $rule_id The rule ID to get from Database
	 * @return array The rule from database
	 */
	public function get_rule( int $rule_id ): array {
		return $this->where( 'id', $rule_id )->get_row();
	}
}
BudgetRecommendationQuery.php000064400000002355151547443000012412 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\DB\Query;

use Automattic\WooCommerce\GoogleListingsAndAds\DB\Query;
use Automattic\WooCommerce\GoogleListingsAndAds\DB\Table\BudgetRecommendationTable;
use Automattic\WooCommerce\GoogleListingsAndAds\Exception\InvalidQuery;
use wpdb;

defined( 'ABSPATH' ) || exit;

/**
 * Class BudgetRecommendationQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\DB\Query
 */
class BudgetRecommendationQuery extends Query {

	/**
	 * BudgetRecommendationQuery constructor.
	 *
	 * @param wpdb                      $wpdb
	 * @param BudgetRecommendationTable $table
	 */
	public function __construct( wpdb $wpdb, BudgetRecommendationTable $table ) {
		parent::__construct( $wpdb, $table );
	}

	/**
	 * Sanitize a value for a given column before inserting it into the DB.
	 *
	 * @param string $column The column name.
	 * @param mixed  $value  The value to sanitize.
	 *
	 * @return mixed The sanitized value.
	 * @throws InvalidQuery When the code tries to set the ID column.
	 */
	protected function sanitize_value( string $column, $value ) {
		if ( 'id' === $column ) {
			throw InvalidQuery::cant_set_id( BudgetRecommendationTable::class );
		}

		return $value;
	}
}
MerchantIssueQuery.php000064400000001710151547443000011057 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\DB\Query;

use Automattic\WooCommerce\GoogleListingsAndAds\DB\Query;
use Automattic\WooCommerce\GoogleListingsAndAds\DB\Table\MerchantIssueTable;
use wpdb;

defined( 'ABSPATH' ) || exit;

/**
 * Class MerchantIssueQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\DB\Query
 */
class MerchantIssueQuery extends Query {

	/**
	 * MerchantIssueQuery constructor.
	 *
	 * @param wpdb               $wpdb
	 * @param MerchantIssueTable $table
	 */
	public function __construct( wpdb $wpdb, MerchantIssueTable $table ) {
		parent::__construct( $wpdb, $table );
	}

	/**
	 * Sanitize a value for a given column before inserting it into the DB.
	 *
	 * @param string $column The column name.
	 * @param mixed  $value  The value to sanitize.
	 *
	 * @return mixed The sanitized value.
	 */
	protected function sanitize_value( string $column, $value ) {
		return $value;
	}
}
ShippingRateQuery.php000064400000003243151547443000010705 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\DB\Query;

use Automattic\WooCommerce\GoogleListingsAndAds\DB\Query;
use Automattic\WooCommerce\GoogleListingsAndAds\DB\Table\ShippingRateTable;
use Automattic\WooCommerce\GoogleListingsAndAds\Exception\InvalidQuery;
use wpdb;

defined( 'ABSPATH' ) || exit;

/**
 * Class ShippingRateQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\DB\Query
 */
class ShippingRateQuery extends Query {

	/**
	 * ShippingRateQuery constructor.
	 *
	 * @param wpdb              $wpdb
	 * @param ShippingRateTable $table
	 */
	public function __construct( wpdb $wpdb, ShippingRateTable $table ) {
		parent::__construct( $wpdb, $table );
	}

	/**
	 * Sanitize a value for a given column before inserting it into the DB.
	 *
	 * @param string $column The column name.
	 * @param mixed  $value  The value to sanitize.
	 *
	 * @return mixed The sanitized value.
	 * @throws InvalidQuery When the code tries to set the ID column.
	 */
	protected function sanitize_value( string $column, $value ) {
		if ( 'id' === $column ) {
			throw InvalidQuery::cant_set_id( ShippingRateTable::class );
		}

		if ( 'options' === $column ) {
			if ( ! is_array( $value ) ) {
				throw InvalidQuery::invalid_value( $column );
			}

			$value = wp_json_encode( $value );
		}

		return $value;
	}

	/**
	 * Perform the query and save it to the results.
	 */
	protected function query_results() {
		parent::query_results();

		$this->results = array_map(
			function ( $row ) {
				$row['options'] = ! empty( $row['options'] ) ? json_decode( $row['options'], true ) : $row['options'];

				return $row;
			},
			$this->results
		);
	}
}
ShippingTimeQuery.php000064400000003126151547443000010710 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\DB\Query;

use Automattic\WooCommerce\GoogleListingsAndAds\DB\Query;
use Automattic\WooCommerce\GoogleListingsAndAds\DB\Table\ShippingTimeTable;
use Automattic\WooCommerce\GoogleListingsAndAds\Exception\InvalidQuery;
use wpdb;

defined( 'ABSPATH' ) || exit;

/**
 * Class ShippingTimeQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\DB\Query
 */
class ShippingTimeQuery extends Query {

	/**
	 * ShippingTimeQuery constructor.
	 *
	 * @param wpdb              $wpdb
	 * @param ShippingTimeTable $table
	 */
	public function __construct( wpdb $wpdb, ShippingTimeTable $table ) {
		parent::__construct( $wpdb, $table );
	}

	/**
	 * Sanitize a value for a given column before inserting it into the DB.
	 *
	 * @param string $column The column name.
	 * @param mixed  $value  The value to sanitize.
	 *
	 * @return mixed The sanitized value.
	 * @throws InvalidQuery When the code tries to set the ID column.
	 */
	protected function sanitize_value( string $column, $value ) {
		if ( 'id' === $column ) {
			throw InvalidQuery::cant_set_id( ShippingTimeTable::class );
		}

		return $value;
	}

	/**
	 * Get all shipping times.
	 *
	 * @since 2.8.0
	 *
	 * @return array
	 */
	public function get_all_shipping_times() {
		$times = $this->get_results();
		$items = [];
		foreach ( $times as $time ) {
			$data = [
				'country_code' => $time['country'],
				'time'         => $time['time'],
				'max_time'     => $time['max_time'] ?: $time['time'],
			];

			$items[ $time['country'] ] = $data;
		}

		return $items;
	}
}
AdsAccountAccessQuery.php000064400000001027151554072170011460 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsAccountAccessQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsAccountAccessQuery extends AdsQuery {

	/**
	 * AdsAccountAccessQuery constructor.
	 */
	public function __construct() {
		parent::__construct( 'customer_user_access' );
		$this->columns( [ 'customer_user_access.resource_name', 'customer_user_access.access_role' ] );
	}
}
AdsAccountQuery.php000064400000001010151554072170010326 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsAccountQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsAccountQuery extends AdsQuery {

	/**
	 * AdsAccountQuery constructor.
	 */
	public function __construct() {
		parent::__construct( 'customer' );
		$this->columns( [ 'customer.id', 'customer.descriptive_name', 'customer.manager', 'customer.test_account' ] );
	}
}
AdsAssetGroupAssetQuery.php000064400000001201151554072170012030 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsAssetGroupAssetQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsAssetGroupAssetQuery extends AdsQuery {

	/**
	 * AdsAssetGroupAssetQuery constructor.
	 */
	public function __construct() {
		parent::__construct( 'asset_group_asset' );
		$this->columns( [ 'asset.id', 'asset.name', 'asset.type', 'asset.text_asset.text', 'asset.image_asset.full_size.url', 'asset.call_to_action_asset.call_to_action', 'asset_group_asset.field_type' ] );
	}
}
AdsAssetGroupQuery.php000064400000001163151554072170011037 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsAssetGroupQuery
 *
 * @since 1.12.2
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsAssetGroupQuery extends AdsQuery {

	/**
	 * AdsAssetGroupQuery constructor.
	 *
	 * @param array $search_args List of search args, such as pageSize.
	 */
	public function __construct( array $search_args = [] ) {
		parent::__construct( 'asset_group' );
		$this->columns( [ 'asset_group.resource_name' ] );
		$this->search_args = $search_args;
	}
}
AdsBillingStatusQuery.php000064400000001153151554072170011526 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsBillingStatusQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsBillingStatusQuery extends AdsQuery {

	/**
	 * AdsBillingStatusQuery constructor.
	 */
	public function __construct() {
		parent::__construct( 'billing_setup' );
		$this->columns(
			[
				'status'          => 'billing_setup.status',
				'start_date_time' => 'billing_setup.start_date_time',
			]
		);
		$this->set_order( 'start_date_time', 'DESC' );
	}
}
AdsCampaignBudgetQuery.php000064400000000740151554072170011615 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsCampaignBudgetQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsCampaignBudgetQuery extends AdsQuery {

	/**
	 * AdsCampaignBudgetQuery constructor.
	 */
	public function __construct() {
		parent::__construct( 'campaign' );
		$this->columns( [ 'campaign.campaign_budget' ] );
	}
}
AdsCampaignCriterionQuery.php000064400000001052151554072170012336 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsCampaignCriterionQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsCampaignCriterionQuery extends AdsQuery {

	/**
	 * AdsCampaignCriterionQuery constructor.
	 */
	public function __construct() {
		parent::__construct( 'campaign_criterion' );
		$this->columns(
			[
				'campaign.id',
				'campaign_criterion.location.geo_target_constant',
			]
		);
	}
}
AdsCampaignLabelQuery.php000064400000000727151554072170011427 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsCampaignLabelQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsCampaignLabelQuery extends AdsQuery {

	/**
	 * AdsCampaignLabelQuery constructor.
	 */
	public function __construct() {
		parent::__construct( 'label' );
		$this->columns(
			[
				'label.id',
			]
		);
	}
}
AdsCampaignQuery.php000064400000001164151554072170010463 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsCampaignQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsCampaignQuery extends AdsQuery {

	/**
	 * AdsCampaignQuery constructor.
	 */
	public function __construct() {
		parent::__construct( 'campaign' );
		$this->columns(
			[
				'campaign.id',
				'campaign.name',
				'campaign.status',
				'campaign.advertising_channel_type',
				'campaign.shopping_setting.feed_label',
				'campaign_budget.amount_micros',
			]
		);
	}
}
AdsCampaignReportQuery.php000064400000001561151554072170011660 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsCampaignReportQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsCampaignReportQuery extends AdsReportQuery {

	/**
	 * Set the initial columns for this query.
	 */
	protected function set_initial_columns() {
		$this->columns(
			[
				'id'     => 'campaign.id',
				'name'   => 'campaign.name',
				'status' => 'campaign.status',
				'type'   => 'campaign.advertising_channel_type',
			]
		);
	}

	/**
	 * Filter the query by a list of ID's.
	 *
	 * @param array $ids list of ID's to filter by.
	 *
	 * @return $this
	 */
	public function filter( array $ids ): QueryInterface {
		if ( empty( $ids ) ) {
			return $this;
		}

		return $this->where( 'campaign.id', $ids, 'IN' );
	}
}
AdsConversionActionQuery.php000064400000001244151554072170012226 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsConversionActionQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsConversionActionQuery extends AdsQuery {

	/**
	 * AdsConversionActionQuery constructor.
	 */
	public function __construct() {
		parent::__construct( 'conversion_action' );
		$this->columns(
			[
				'id'           => 'conversion_action.id',
				'name'         => 'conversion_action.name',
				'status'       => 'conversion_action.status',
				'tag_snippets' => 'conversion_action.tag_snippets',
			]
		);
	}
}
AdsProductLinkInvitationQuery.php000064400000001110151554072170013236 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsProductLinkInvitationQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsProductLinkInvitationQuery extends AdsQuery {

	/**
	 * AdsProductLinkInvitationQuery constructor.
	 */
	public function __construct() {
		parent::__construct( 'product_link_invitation' );
		$this->columns( [ 'product_link_invitation.merchant_center.merchant_center_id', 'product_link_invitation.status' ] );
	}
}
AdsProductReportQuery.php000064400000001466151554072170011565 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsProductReportQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class AdsProductReportQuery extends AdsReportQuery {

	/**
	 * Set the initial columns for this query.
	 */
	protected function set_initial_columns() {
		$this->columns(
			[
				'id'   => 'segments.product_item_id',
				'name' => 'segments.product_title',
			]
		);
	}

	/**
	 * Filter the query by a list of ID's.
	 *
	 * @param array $ids list of ID's to filter by.
	 *
	 * @return $this
	 */
	public function filter( array $ids ): QueryInterface {
		if ( empty( $ids ) ) {
			return $this;
		}

		return $this->where( 'segments.product_item_id', $ids, 'IN' );
	}
}
AdsQuery.php000064400000005405151554072170007025 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

use Automattic\WooCommerce\GoogleListingsAndAds\Exception\InvalidProperty;
use Automattic\WooCommerce\GoogleListingsAndAds\Google\Ads\GoogleAdsClient;
use Google\Ads\GoogleAds\V18\Services\GoogleAdsRow;
use Google\Ads\GoogleAds\V18\Services\SearchGoogleAdsRequest;
use Google\Ads\GoogleAds\V18\Services\SearchSettings;
use Google\ApiCore\ApiException;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
abstract class AdsQuery extends Query {

	/**
	 * Client which handles the query.
	 *
	 * @var GoogleAdsClient
	 */
	protected $client = null;

	/**
	 * Ads Account ID.
	 *
	 * @var int
	 */
	protected $id = null;

	/**
	 * Arguments to add to the search query.
	 *
	 * Note: While we allow pageSize to be set, we do not pass it to the API.
	 * pageSize has been deprecated in the API since V17 and is fixed to 10000 rows.
	 *
	 * @var array
	 */
	protected $search_args = [];

	/**
	 * Set the client which will handle the query.
	 *
	 * @param GoogleAdsClient $client Client instance.
	 * @param int             $id     Account ID.
	 *
	 * @return QueryInterface
	 * @throws InvalidProperty If the ID is empty.
	 */
	public function set_client( GoogleAdsClient $client, int $id ): QueryInterface {
		if ( empty( $id ) ) {
			throw InvalidProperty::not_null( get_class( $this ), 'id' );
		}

		$this->client = $client;
		$this->id     = $id;

		return $this;
	}

	/**
	 * Get the first row from the results.
	 *
	 * @return GoogleAdsRow
	 * @throws ApiException When no results returned or an error occurs.
	 */
	public function get_result(): GoogleAdsRow {
		$results = $this->get_results();

		if ( $results ) {
			foreach ( $results->iterateAllElements() as $row ) {
				return $row;
			}
		}

		throw new ApiException( __( 'No result from query', 'google-listings-and-ads' ), 404, '' );
	}

	/**
	 * Perform the query and save it to the results.
	 *
	 * @throws ApiException If the search call fails.
	 * @throws InvalidProperty If the client is not set.
	 */
	protected function query_results() {
		if ( ! $this->client || ! $this->id ) {
			throw InvalidProperty::not_null( get_class( $this ), 'client' );
		}

		$request = new SearchGoogleAdsRequest();

		if ( ! empty( $this->search_args['pageToken'] ) ) {
			$request->setPageToken( $this->search_args['pageToken'] );
		}

		// Allow us to get the total number of results.
		$request->setSearchSettings(
			new SearchSettings(
				[
					'return_total_results_count' => true,
				]
			)
		);

		$request->setQuery( $this->build_query() );
		$request->setCustomerId( $this->id );

		$this->results = $this->client->getGoogleAdsServiceClient()->search( $request );
	}
}
AdsReportQuery.php000064400000003713151554072170010221 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

use Google\Ads\GoogleAds\V18\Resources\ShoppingPerformanceView;

defined( 'ABSPATH' ) || exit;

/**
 * Class AdsReportQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
abstract class AdsReportQuery extends AdsQuery {

	use ReportQueryTrait;

	/**
	 * AdsReportQuery constructor.
	 * Uses the resource ShoppingPerformanceView.
	 *
	 * @param array $args Query arguments.
	 */
	public function __construct( array $args ) {
		parent::__construct( 'shopping_performance_view' );

		$this->set_initial_columns();
		$this->handle_query_args( $args );
	}

	/**
	 * Add all the requested fields.
	 *
	 * @param array $fields List of fields.
	 *
	 * @return $this
	 */
	public function fields( array $fields ): QueryInterface {
		$map = [
			'clicks'      => 'metrics.clicks',
			'impressions' => 'metrics.impressions',
			'spend'       => 'metrics.cost_micros',
			'sales'       => 'metrics.conversions_value',
			'conversions' => 'metrics.conversions',
		];

		$this->add_columns( array_intersect_key( $map, array_flip( $fields ) ) );

		return $this;
	}

	/**
	 * Add a segment interval to the query.
	 *
	 * @param string $interval Type of interval.
	 *
	 * @return $this
	 */
	public function segment_interval( string $interval ): QueryInterface {
		$map = [
			'day'     => 'segments.date',
			'week'    => 'segments.week',
			'month'   => 'segments.month',
			'quarter' => 'segments.quarter',
			'year'    => 'segments.year',
		];

		if ( isset( $map[ $interval ] ) ) {
			$this->add_columns( [ $interval => $map[ $interval ] ] );
		}

		return $this;
	}

	/**
	 * Set the initial columns for this query.
	 */
	abstract protected function set_initial_columns();

	/**
	 * Filter the query by a list of ID's.
	 *
	 * @param array $ids list of ID's to filter by.
	 *
	 * @return $this
	 */
	abstract public function filter( array $ids ): QueryInterface;
}
MerchantFreeListingReportQuery.php000064400000001247151554072170013407 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class MerchantFreeListingReportQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class MerchantFreeListingReportQuery extends MerchantReportQuery {

	/**
	 * Set the initial columns for this query.
	 */
	protected function set_initial_columns() {}

	/**
	 * Filter the query by a list of ID's.
	 *
	 * @param array $ids list of ID's to filter by.
	 *
	 * @return $this
	 */
	public function filter( array $ids ): QueryInterface {
		// No filtering available for free listings.
		return $this;
	}
}
MerchantProductReportQuery.php000064400000001415151554072170012611 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class MerchantProductReportQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class MerchantProductReportQuery extends MerchantReportQuery {

	/**
	 * Set the initial columns for this query.
	 */
	protected function set_initial_columns() {
		$this->columns(
			[
				'id' => 'segments.offer_id',
			]
		);
	}

	/**
	 * Filter the query by a list of ID's.
	 *
	 * @param array $ids list of ID's to filter by.
	 *
	 * @return $this
	 */
	public function filter( array $ids ): QueryInterface {
		if ( empty( $ids ) ) {
			return $this;
		}

		return $this->where( 'segments.offer_id', $ids, 'IN' );
	}
}
MerchantProductViewReportQuery.php000064400000002217151554072170013445 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class MerchantProductViewReportQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
class MerchantProductViewReportQuery extends MerchantQuery {

	use ReportQueryTrait;

	/**
	 * MerchantProductViewReportQuery constructor.
	 *
	 * @param array $args Query arguments.
	 */
	public function __construct( array $args ) {
		parent::__construct( 'ProductView' );
		$this->set_initial_columns();
		$this->handle_query_args( $args );
	}


	/**
	 * Filter the query by a list of ID's.
	 *
	 * @param array $ids list of ID's to filter by.
	 *
	 * @return $this
	 */
	public function filter( array $ids ): QueryInterface {
		// No filtering used for product view report.
		return $this;
	}

	/**
	 * Set the initial columns for this query.
	 */
	protected function set_initial_columns() {
		$this->columns(
			[
				'id'              => 'product_view.id',
				'expiration_date' => 'product_view.expiration_date',
				'status'          => 'product_view.aggregated_destination_status',
			]
		);
	}
}
MerchantQuery.php000064400000004137151554072170010060 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

use Automattic\WooCommerce\GoogleListingsAndAds\Exception\InvalidProperty;
use Automattic\WooCommerce\GoogleListingsAndAds\Vendor\Google\Exception as GoogleException;
use Automattic\WooCommerce\GoogleListingsAndAds\Vendor\Google\Service\ShoppingContent;
use Automattic\WooCommerce\GoogleListingsAndAds\Vendor\Google\Service\ShoppingContent\SearchRequest;
use Automattic\WooCommerce\GoogleListingsAndAds\Vendor\Google\Service\ShoppingContent\SearchResponse;

defined( 'ABSPATH' ) || exit;

/**
 * Class MerchantQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
abstract class MerchantQuery extends Query {

	/**
	 * Client which handles the query.
	 *
	 * @var ShoppingContent
	 */
	protected $client = null;

	/**
	 * Merchant Account ID.
	 *
	 * @var int
	 */
	protected $id = null;

	/**
	 * Arguments to add to the search query.
	 *
	 * @var array
	 */
	protected $search_args = [];

	/**
	 * Set the client which will handle the query.
	 *
	 * @param ShoppingContent $client Client instance.
	 * @param int             $id     Account ID.
	 *
	 * @return QueryInterface
	 */
	public function set_client( ShoppingContent $client, int $id ): QueryInterface {
		$this->client = $client;
		$this->id     = $id;

		return $this;
	}

	/**
	 * Perform the query and save it to the results.
	 *
	 * @throws GoogleException If the search call fails.
	 * @throws InvalidProperty If the client is not set.
	 */
	protected function query_results() {
		if ( ! $this->client || ! $this->id ) {
			throw InvalidProperty::not_null( get_class( $this ), 'client' );
		}

		$request = new SearchRequest();
		$request->setQuery( $this->build_query() );

		if ( ! empty( $this->search_args['pageSize'] ) ) {
			$request->setPageSize( $this->search_args['pageSize'] );
		}

		if ( ! empty( $this->search_args['pageToken'] ) ) {
			$request->setPageToken( $this->search_args['pageToken'] );
		}

		/** @var SearchResponse $this->results */
		$this->results = $this->client->reports->search( $this->id, $request );
	}
}
MerchantReportQuery.php000064400000003444151554072170011254 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Class MerchantReportQuery
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
abstract class MerchantReportQuery extends MerchantQuery {

	use ReportQueryTrait;

	/**
	 * MerchantReportQuery constructor.
	 *
	 * @param array $args Query arguments.
	 */
	public function __construct( array $args ) {
		parent::__construct( 'MerchantPerformanceView' );

		$this->set_initial_columns();
		$this->handle_query_args( $args );
		$this->where( 'segments.program', 'FREE_PRODUCT_LISTING' );
	}

	/**
	 * Add all the requested fields.
	 *
	 * @param array $fields List of fields.
	 *
	 * @return $this
	 */
	public function fields( array $fields ): QueryInterface {
		$map = [
			'clicks'      => 'metrics.clicks',
			'impressions' => 'metrics.impressions',
		];

		$this->add_columns( array_intersect_key( $map, array_flip( $fields ) ) );

		return $this;
	}

	/**
	 * Add a segment interval to the query.
	 *
	 * @param string $interval Type of interval.
	 *
	 * @return $this
	 */
	public function segment_interval( string $interval ): QueryInterface {
		$map = [
			'day'     => 'segments.date',
			'week'    => 'segments.week',
			'month'   => 'segments.month',
			'quarter' => 'segments.quarter',
			'year'    => 'segments.year',
		];

		if ( isset( $map[ $interval ] ) ) {
			$this->add_columns( [ $interval => $map[ $interval ] ] );
		}

		return $this;
	}

	/**
	 * Set the initial columns for this query.
	 */
	abstract protected function set_initial_columns();

	/**
	 * Filter the query by a list of ID's.
	 *
	 * @param array $ids list of ID's to filter by.
	 *
	 * @return $this
	 */
	abstract public function filter( array $ids ): QueryInterface;
}
Query.php000064400000017526151554072170006404 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

use Automattic\WooCommerce\GoogleListingsAndAds\Exception\InvalidQuery;
use DateTime;

defined( 'ABSPATH' ) || exit;

/**
 * Google Ads Query Language (GAQL)
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
abstract class Query implements QueryInterface {

	/**
	 * Resource name.
	 *
	 * @var string
	 */
	protected $resource;

	/**
	 * Set of columns to retrieve in the query.
	 *
	 * @var array
	 */
	protected $columns = [];

	/**
	 * Where clauses for the query.
	 *
	 * @var array
	 */
	protected $where = [];

	/**
	 * Where relation for multiple clauses.
	 *
	 * @var string
	 */
	protected $where_relation;

	/**
	 * Order sort attribute.
	 *
	 * @var string
	 */
	protected $order = 'ASC';

	/**
	 * Column to order by.
	 *
	 * @var string
	 */
	protected $orderby;

	/**
	 * The result of the query.
	 *
	 * @var mixed
	 */
	protected $results = null;

	/**
	 * Query constructor.
	 *
	 * @param string $resource_name
	 *
	 * @throws InvalidQuery When the resource name is not valid.
	 */
	public function __construct( string $resource_name ) {
		if ( ! preg_match( '/^[a-zA-Z_]+$/', $resource_name ) ) {
			throw InvalidQuery::resource_name();
		}

		$this->resource = $resource_name;
	}

	/**
	 * Set columns to retrieve in the query.
	 *
	 * @param array $columns List of column names.
	 *
	 * @return QueryInterface
	 */
	public function columns( array $columns ): QueryInterface {
		$this->validate_columns( $columns );
		$this->columns = $columns;

		return $this;
	}

	/**
	 * Add a set columns to retrieve in the query.
	 *
	 * @param array $columns List of column names.
	 *
	 * @return QueryInterface
	 */
	public function add_columns( array $columns ): QueryInterface {
		$this->validate_columns( $columns );
		$this->columns = array_merge( $this->columns, array_filter( $columns ) );

		return $this;
	}

	/**
	 * Add a where clause to the query.
	 *
	 * @param string $column  The column name.
	 * @param mixed  $value   The where value.
	 * @param string $compare The comparison to use. Valid values are =, <, >, IN, NOT IN.
	 *
	 * @return QueryInterface
	 */
	public function where( string $column, $value, string $compare = '=' ): QueryInterface {
		$this->validate_compare( $compare );
		$this->where[] = [
			'column'  => $column,
			'value'   => $value,
			'compare' => $compare,
		];

		return $this;
	}

	/**
	 * Add a where date between clause to the query.
	 *
	 * @since 1.7.0
	 *
	 * @link https://developers.google.com/shopping-content/guides/reports/query-language/date-ranges
	 *
	 * @param string $after  Start of date range. In ISO 8601(YYYY-MM-DD) format.
	 * @param string $before End of date range. In ISO 8601(YYYY-MM-DD) format.
	 *
	 * @return QueryInterface
	 */
	public function where_date_between( string $after, string $before ): QueryInterface {
		return $this->where( 'segments.date', [ $after, $before ], 'BETWEEN' );
	}

	/**
	 * Set the where relation for the query.
	 *
	 * @param string $relation
	 *
	 * @return QueryInterface
	 */
	public function set_where_relation( string $relation ): QueryInterface {
		$this->validate_where_relation( $relation );
		$this->where_relation = $relation;

		return $this;
	}

	/**
	 * Set ordering information for the query.
	 *
	 * @param string $column
	 * @param string $order
	 *
	 * @return QueryInterface
	 * @throws InvalidQuery When the given column is not in the list of included columns.
	 */
	public function set_order( string $column, string $order = 'ASC' ): QueryInterface {
		if ( ! array_key_exists( $column, $this->columns ) ) {
			throw InvalidQuery::invalid_order_column( $column );
		}

		$this->orderby = $this->columns[ $column ];
		$this->order   = $this->normalize_order( $order );

		return $this;
	}

	/**
	 * Get the results of the query.
	 *
	 * @return mixed
	 */
	public function get_results() {
		if ( null === $this->results ) {
			$this->query_results();
		}

		return $this->results;
	}

	/**
	 * Perform the query and save it to the results.
	 */
	protected function query_results() {
		$this->results = [];
	}

	/**
	 * Validate a set of columns.
	 *
	 * @param array $columns
	 *
	 * @throws InvalidQuery When one of columns in the set is not valid.
	 */
	protected function validate_columns( array $columns ) {
		array_walk( $columns, [ $this, 'validate_column' ] );
	}

	/**
	 * Validate that a given column is using a valid name.
	 *
	 * @param string $column
	 *
	 * @throws InvalidQuery When the given column is not valid.
	 */
	protected function validate_column( string $column ) {
		if ( ! preg_match( '/^[a-zA-Z0-9\._]+$/', $column ) ) {
			throw InvalidQuery::invalid_column( $column );
		}
	}

	/**
	 * Validate that a compare operator is valid.
	 *
	 * @param string $compare
	 *
	 * @throws InvalidQuery When the compare value is not valid.
	 */
	protected function validate_compare( string $compare ) {
		switch ( $compare ) {
			case '=':
			case '>':
			case '<':
			case '!=':
			case 'IN':
			case 'NOT IN':
			case 'BETWEEN':
			case 'IS NOT NULL':
			case 'CONTAINS ANY':
				// These are all valid.
				return;

			default:
				throw InvalidQuery::from_compare( $compare );
		}
	}


	/**
	 * Validate that a where relation is valid.
	 *
	 * @param string $relation
	 *
	 * @throws InvalidQuery When the relation value is not valid.
	 */
	protected function validate_where_relation( string $relation ) {
		switch ( $relation ) {
			case 'AND':
			case 'OR':
				// These are all valid.
				return;

			default:
				throw InvalidQuery::where_relation( $relation );
		}
	}

	/**
	 * Normalize the string for the order.
	 *
	 * Converts the string to uppercase, and will return only DESC or ASC.
	 *
	 * @param string $order
	 *
	 * @return string
	 */
	protected function normalize_order( string $order ): string {
		$order = strtoupper( $order );

		return 'DESC' === $order ? $order : 'ASC';
	}

	/**
	 * Build the query and return the query string.
	 *
	 * @return string
	 *
	 * @throws InvalidQuery When the set of columns is empty.
	 */
	protected function build_query(): string {
		if ( empty( $this->columns ) ) {
			throw InvalidQuery::empty_columns();
		}

		$columns = join( ',', $this->columns );
		$pieces  = [ "SELECT {$columns} FROM {$this->resource}" ];
		$pieces  = array_merge( $pieces, $this->generate_where_pieces() );

		if ( $this->orderby ) {
			$pieces[] = "ORDER BY {$this->orderby} {$this->order}";
		}

		return join( ' ', $pieces );
	}

	/**
	 * Generate the pieces for the WHERE part of the query.
	 *
	 * @return string[]
	 */
	protected function generate_where_pieces(): array {
		if ( empty( $this->where ) ) {
			return [];
		}

		$where_pieces = [ 'WHERE' ];
		foreach ( $this->where as $where ) {
			$column  = $where['column'];
			$compare = $where['compare'];

			if ( 'IN' === $compare || 'NOT_IN' === $compare || 'CONTAINS ANY' === $compare ) {
				$value = sprintf(
					"('%s')",
					join(
						"','",
						array_map(
							function ( $value ) {
								return $this->escape( $value );
							},
							$where['value']
						)
					)
				);
			} elseif ( 'BETWEEN' === $compare ) {
				$value = "'{$this->escape( $where['value'][0] )}' AND '{$this->escape( $where['value'][1] )}'";
			} elseif ( 'IS NOT NULL' === $compare ) {
				$value = '';
			} else {
				$value = "'{$this->escape( $where['value'] )}'";
			}

			if ( count( $where_pieces ) > 1 ) {
				$where_pieces[] = $this->where_relation ?? 'AND';
			}

			$where_pieces[] = "{$column} {$compare} {$value}";
		}

		return $where_pieces;
	}

	/**
	 * Escape the value to a string which can be used in a query.
	 *
	 * @param mixed $value Original value to escape.
	 *
	 * @return string
	 */
	protected function escape( $value ): string {
		if ( $value instanceof DateTime ) {
			return $value->format( 'Y-m-d' );
		}

		if ( ! is_numeric( $value ) ) {
			return (string) $value;
		}

		return addslashes( (string) $value );
	}
}
QueryInterface.php000064400000002406151554072170010214 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

defined( 'ABSPATH' ) || exit;

/**
 * Interface QueryInterface
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
interface QueryInterface {

	/**
	 * Set columns to retrieve in the query.
	 *
	 * @param array $columns List of column names.
	 *
	 * @return $this
	 */
	public function columns( array $columns ): QueryInterface;

	/**
	 * Add a set columns to retrieve in the query.
	 *
	 * @param array $columns List of column names.
	 *
	 * @return $this
	 */
	public function add_columns( array $columns ): QueryInterface;

	/**
	 * Set a where clause to query.
	 *
	 * @param string $column  The column name.
	 * @param mixed  $value   The where value.
	 * @param string $compare The comparison to use. Valid values are =, <, >, IN, NOT IN.
	 *
	 * @return $this
	 */
	public function where( string $column, $value, string $compare = '=' ): QueryInterface;

	/**
	 * Set the where relation for the query.
	 *
	 * @param string $relation
	 *
	 * @return QueryInterface
	 */
	public function set_where_relation( string $relation ): QueryInterface;

	/**
	 * Get the results of the query.
	 *
	 * @return mixed
	 */
	public function get_results();
}
ReportQueryTrait.php000064400000002477151554072170010603 0ustar00<?php
declare( strict_types=1 );

namespace Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query;

use DateTime;

defined( 'ABSPATH' ) || exit;

/**
 * Trait ReportQueryTrait
 *
 * @package Automattic\WooCommerce\GoogleListingsAndAds\API\Google\Query
 */
trait ReportQueryTrait {

	/**
	 * Handle the common arguments for this query.
	 *
	 * @param array $args List of arguments which were passed to the query.
	 */
	protected function handle_query_args( array $args ) {
		if ( ! empty( $args['fields'] ) ) {
			$this->fields( $args['fields'] );
		}

		if ( ! empty( $args['interval'] ) ) {
			$this->segment_interval( $args['interval'] );
		}

		if ( ! empty( $args['after'] ) && ! empty( $args['before'] ) ) {
			$after  = $args['after'];
			$before = $args['before'];

			$this->where_date_between(
				$after instanceof DateTime ? $after->format( 'Y-m-d' ) : $after,
				$before instanceof DateTime ? $before->format( 'Y-m-d' ) : $before
			);
		}

		if ( ! empty( $args['ids'] ) ) {
			$this->filter( $args['ids'] );
		}

		if ( ! empty( $args['orderby'] ) ) {
			$this->set_order( $args['orderby'], $args['order'] );
		}

		if ( ! empty( $args['per_page'] ) ) {
			$this->search_args['pageSize'] = $args['per_page'];
		}

		if ( ! empty( $args['next_page'] ) ) {
			$this->search_args['pageToken'] = $args['next_page'];
		}
	}
}