223 lines
7.0 KiB
PHP
223 lines
7.0 KiB
PHP
<?php
|
||
|
||
namespace app\service;
|
||
|
||
use app\model\Campaign;
|
||
use app\model\CampaignBudget;
|
||
use app\model\AdGroup;
|
||
use app\model\Ad;
|
||
use GuzzleHttp\Client as GuzzleClient;
|
||
use GuzzleHttp\Exception\RequestException;
|
||
|
||
class GoogleAdsService
|
||
{
|
||
// Google Ads API 基础 URL
|
||
private $baseUrl = 'https://googleads.googleapis.com/v17';
|
||
|
||
// Google Ads API 客户 ID
|
||
private $customerId;
|
||
|
||
private $loginCustomerId; // 增加 login-customer-id 属性
|
||
|
||
// OAuth2 access token
|
||
private $accessToken;
|
||
|
||
// Developer Token
|
||
private $developerToken;
|
||
|
||
private $client;
|
||
|
||
public function __construct($accessToken, $customerId, $developerToken, $loginCustomerId = null)
|
||
{
|
||
$this->accessToken = $accessToken;
|
||
$this->customerId = $customerId;
|
||
$this->developerToken = $developerToken;
|
||
$this->loginCustomerId = $loginCustomerId;
|
||
|
||
// 初始化 Guzzle 客户端
|
||
$this->client = new GuzzleClient();
|
||
}
|
||
|
||
/**
|
||
* 发起 HTTP 请求
|
||
* @param string $method 请求方法(GET, POST, PATCH, DELETE)
|
||
* @param string $endpoint API 端点
|
||
* @param array $data 请求数据
|
||
* @return array API 响应
|
||
*/
|
||
private function sendRequest($method, $endpoint, $data = [])
|
||
{
|
||
// 构建 URL
|
||
$url = "{$this->baseUrl}/customers/{$this->customerId}/$endpoint";
|
||
|
||
// 设置请求头
|
||
$headers = [
|
||
'Authorization' => "Bearer {$this->accessToken}",
|
||
'developer-token' => $this->developerToken,
|
||
'Content-Type' => 'application/json'
|
||
];
|
||
// 如果有广告经理 ID,添加到请求头
|
||
if ($this->loginCustomerId) {
|
||
$headers['login-customer-id'] = $this->loginCustomerId;
|
||
}
|
||
|
||
// 调试:输出请求的 URL 和头部信息
|
||
// return [$url, $headers, $data];
|
||
// 使用 Guzzle 发起请求
|
||
try {
|
||
$response = $this->client->request($method, $url, [
|
||
'headers' => $headers,
|
||
'json' => $data
|
||
]);
|
||
|
||
|
||
// 获取响应体并解析为数组
|
||
$body = $response->getBody()->getContents();
|
||
return json_decode($body, true);
|
||
|
||
} catch (RequestException $e) {
|
||
// 处理请求错误
|
||
echo "HTTP Request failed: " . $e->getMessage();
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建广告预算并存储到数据库
|
||
*/
|
||
public function createCampaignBudget($budgetName, $amount)
|
||
{
|
||
// 构建请求数据
|
||
$data = [
|
||
'operations' => [
|
||
[
|
||
'create' => [
|
||
'name' => $budgetName,
|
||
'amountMicros' => $amount * 1000000, // 转换为微单位
|
||
// 'delivery_method' => 'STANDARD',
|
||
// 'status' => 'ENABLED'
|
||
]
|
||
]
|
||
]
|
||
];
|
||
// return $data;
|
||
// 调用 sendRequest 方法发起 POST 请求到 mutate 端点
|
||
$response = $this->sendRequest('POST', 'campaignBudgets:mutate', $data);
|
||
|
||
// 存储返回的广告预算数据到数据库
|
||
// if (isset($response['results'][0]['resource_name'])) {
|
||
// CampaignBudget::create([
|
||
// 'name' => $response['results'][0]['name'],
|
||
// 'amount_micros' => $response['results'][0]['amount_micros'],
|
||
// 'status' => $response['results'][0]['status'],
|
||
// 'delivery_method' => $response['results'][0]['delivery_method'],
|
||
// ]);
|
||
// }
|
||
|
||
return $response;
|
||
}
|
||
|
||
/**
|
||
* 创建广告系列并存储到数据库
|
||
*/
|
||
public function createCampaign($campaignName, $budgetId)
|
||
{
|
||
// 构建请求数据
|
||
$data = [
|
||
'name' => $campaignName,
|
||
'status' => 'PAUSED',
|
||
'advertising_channel_type' => 'SEARCH',
|
||
'campaign_budget' => "customers/{$this->customerId}/campaignBudgets/{$budgetId}",
|
||
'network_settings' => [
|
||
'target_google_search' => true,
|
||
'target_search_network' => true,
|
||
'target_content_network' => false,
|
||
'target_partner_search_network' => false
|
||
],
|
||
'start_date' => date('Y-m-d'),
|
||
'end_date' => date('Y-m-d', strtotime('+1 year'))
|
||
];
|
||
|
||
// 调用 sendRequest 方法发起 POST 请求
|
||
$response = $this->sendRequest('POST', 'campaigns', $data);
|
||
|
||
// 存储返回的广告系列数据到数据库
|
||
if (isset($response['resource_name'])) {
|
||
Campaign::create([
|
||
'name' => $response['name'],
|
||
'status' => $response['status'],
|
||
'advertising_channel_type' => $response['advertising_channel_type'],
|
||
'campaign_budget' => $response['campaign_budget'],
|
||
'start_date' => $response['start_date'],
|
||
'end_date' => $response['end_date'],
|
||
]);
|
||
}
|
||
|
||
return $response;
|
||
}
|
||
|
||
/**
|
||
* 创建广告组并存储到数据库
|
||
*/
|
||
public function createAdGroup($adGroupName, $campaignId)
|
||
{
|
||
// 构建请求数据
|
||
$data = [
|
||
'name' => $adGroupName,
|
||
'status' => 'PAUSED',
|
||
'campaign' => "customers/{$this->customerId}/campaigns/{$campaignId}",
|
||
'type' => 'SEARCH_STANDARD'
|
||
];
|
||
|
||
// 调用 sendRequest 方法发起 POST 请求
|
||
$response = $this->sendRequest('POST', 'adGroups', $data);
|
||
|
||
// 存储返回的广告组数据到数据库
|
||
if (isset($response['resource_name'])) {
|
||
AdGroup::create([
|
||
'name' => $response['name'],
|
||
'status' => $response['status'],
|
||
'campaign_id' => $campaignId,
|
||
'type' => $response['type'],
|
||
]);
|
||
}
|
||
|
||
return $response;
|
||
}
|
||
|
||
/**
|
||
* 创建广告并存储到数据库
|
||
*/
|
||
public function createAd($adGroupId, $adName, $finalUrl)
|
||
{
|
||
// 构建请求数据
|
||
$data = [
|
||
'ad' => [
|
||
'expanded_text_ad' => [
|
||
'headline_part1' => 'Headline 1',
|
||
'headline_part2' => 'Headline 2',
|
||
'description' => 'Description',
|
||
'final_urls' => [$finalUrl]
|
||
],
|
||
'status' => 'PAUSED'
|
||
],
|
||
'ad_group' => "customers/{$this->customerId}/adGroups/{$adGroupId}"
|
||
];
|
||
|
||
// 调用 sendRequest 方法发起 POST 请求
|
||
$response = $this->sendRequest('POST', 'ads', $data);
|
||
|
||
// 存储返回的广告数据到数据库
|
||
if (isset($response['resource_name'])) {
|
||
Ad::create([
|
||
'name' => $response['ad']['expanded_text_ad']['headline_part1'], // 使用广告的标题字段作为示例
|
||
'ad_group_id' => $adGroupId,
|
||
'status' => $response['ad']['status'],
|
||
'final_url' => $response['ad']['expanded_text_ad']['final_urls'][0],
|
||
]);
|
||
}
|
||
|
||
return $response;
|
||
}
|
||
}
|